railsで遊ぼう rails active support

標準ライブラリ集が付属しているので、requireメソッドを使います。

open-uriは、http/ftp に簡単にアクセスするためのクラスです。
例えば、東京都のソースを取得したい場合は、

require "open-uri"

open("http://www.metro.tokyo.jp/") do |f|
	f.each_line {|line| puts line }
end

rubyで遊ぼう ハッシュ

hashは配列のようにオブジェクトをまとめるもので、hashクラスのインスタンスです。値を入れたり、値を取り出したりすには、キーを使います。
順番に取り出すにはeachメソッドを使い、キーと値の二つがeachメソッドのブロックパラメーターになります。

test.rb

books = {}
File.open("books.txt", encoding: "utf-8") do |f|
	f.each_line do |line|
		cols = line.chomp.split(/\t/)
		books[cols[0]] = cols[1]
	end
end

books.each do |key, val|
	puts "#{key}、#{val}円"
end

books.txt

坊ちゃん	300
こころ	380
明暗	700
C:\rails>ruby test.rb
坊ちゃん、300円
こころ、380円
明暗、700円

Rails textのインクルード

PHPのように、テキストをインクルードできます。
コントローラのアクションに記述した変数がビューに反映されて、ブラウザ上に変数値が表示されます。

/app/controllers/top_controller.rb

class TopController < ApplicationController
  def index
  	@message = "Hello, rails"
  	@txtmessage = "what's up?"
  end
end

続いてです。
/app/viws/top/index.html.erb

<h1><%= @message %></h1>
<p><%= @txtmessage %></p>

ブラウザを更新し、リクエストを送ります。
%e7%84%a1%e9%a1%8c

サーバーのWEBrickは起動したままにしましょう。

Rails, make controller and action

コントローラの作成は、まず、コマンドプロンプトで rails generate controller name action で作成します。

C:\rails\hoge>rails g controller top index

続いて、アプリケーションのconfigの下にあるroutes.rbのルーティングの設定です。
./config/routes.rb

Rails.application.routes.draw do
root 'top#index'
end

ビューも編集しましょう。
./app/views/top

<h1>こんにちわ</h1>
<p>これからです</p>

rails s でサーバーを再度起動してlocalhostのブラウザを読み込むと以下のようになっている筈です。

%e7%84%a1%e9%a1%8c

もし、画面上で以下のようなメッセージが表示された場合は、

TypeError: オブジェクトでサポートされていないプロパティまたはメソッドです。

フォルダのGemfile.lockの「coffee-script-source (1.10.0)」を「coffee-script-source (1.8.0)」に修正します。
%e7%84%a1%e9%a1%8c

そして、コマンドプロンプトで、gemをインストールします。

C:\rails\hoge>gem install coffee-script-source -v '1.8.0'

再度rails s でサーバーをアップするとエラーは消えている筈です。

railsの起動

Railsのインストールが済んだら、コマンドプロンプトからアプリケーションを作成します。

C:\Users\hoge>cd \
C:\>mkdir rails
C:\>cd rails
C:\rails>rails new sakura
C:\rails>cd sakura
C:\rails\sakura>rails server

=> Booting WEBrick
=> Rails 4.2.7.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2016-10-25 04:13:56] INFO WEBrick 1.3.1
[2016-10-25 04:13:56] INFO ruby 2.3.1 (2016-04-26) [x64-mingw32]
[2016-10-25 04:13:56] INFO WEBrick::HTTPServer#start: pid=7256 port=3000

http://localhost:300 もしくは http://127.0.0.1:3000/ で、下記のようにrailsの初期画面が表示されたらインストール成功です。

ruby

画面上の「About your application’s environment」をクリックすると、状態が表示されます。

WEBrickは、Rubyで書かれたウェブサーバーで、Rubyをインストールすると一緒にインストールされます。ソースコードをウェブサーバーにアップロードすることなく、1台のパソコンでRailsアプリケーションの開発と動作確認ができます。

いったん Ctl + C でWEBrickを終了したら、作成したフォルダを見てみましょう。

railsで遊ぼう

開発環境を整えます。
普段macですが、今回はwindows 10でやります。

ルビーのサイトから、最新版のルビー(現時点では2.3.1)とDevKitをインストール。
http://rubyinstaller.org/downloads/

DevKitのインストール先は、

C:\devkit

そして、DevKitのコンパイラが使えるように、コマンドプロンプトで以下を実行

C:¥Users\hogehoke>C:\devkit\devkitvars

そして、railsをインストール

C:¥Users\hogehoke>gem install rails

バージョンを確認してみましょう

C:\Users\hoge>ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x64-mingw32]

C:\Users\hoge>rails -v
Rails 4.2.7.1

OK?

realloc()関数

割り当て済み猟奇のサイズを変更することができる。

#include 
#include 

#define BUFF_SIZE 256

int main(void)
{
    int i;
    unsigned char *pmem = NULL, *pmemsave = NULL, *pmemnew = NULL;
    
    pmemsave = pmem = (unsigned char *)malloc(BUFF_SIZE);
    if (pmem == NULL){
        fprintf(stderr, "メモリ割り当てに失敗しました。\n");
        exit(EXIT_FAILURE);
    }
    
    for (i = 0; i < BUFF_SIZE; i++)
        *pmem++ = (unsigned char)i;
    
    pmem = pmemsave;
    
    for (i = 0; i < BUFF_SIZE; i++)
        printf("%u ", *pmem++);
    printf("\n");
    
    pmemnew = realloc(pmemsave, BUFF_SIZE * 2);
    if (pmemnew != NULL){
        pmem = pmemnew;
        for (i = 0; i < BUFF_SIZE * 2; i++)
            printf("%u ", *pmem++);
        printf("\n");
        
        free(pmemnew); pmemnew = NULL;
    }
    else {
        free(pmemsave); pmemsave = NULL;
        
        fprintf(stderr, "メモリの再割り当てに失敗しました\n");
        exit(EXIT_FAILURE);
    }
    
    return 0;
}

bbi_misc.cpp

/*****************************/
/*filename:bbi_misc.cpp 雑関数*/
/*****************************/
#include "bbi.h"
#include "bbi_prot.h"

string dbl_to_s(double d)
{
    ostringstream ostr;
    ostr << d;
    return ostr.str();
}

string err_msg(const string& a, const string& b)
{
    if (a == "") return b + "が必要です。"
        if(b == "") return a + "が不正です。";
    return b + "が" + a + "の前に必要です。";
}

void err_exit(Tobj a, Tobj b, Tobj c, Tobj d)
{
    Tobj ob[5];
    ob[1] = a; ob[2] = b; ob[3] = c; ob[4]= d;
    cerr << "line:" << get_lineNo() << "ERROR";
    
    for (int i=1; i<=4 && ob[i].s! = "\1"; i++){
        if (ob[i].type == 'd') cout << ob[i].d;
        if (ob[i].type == 's') cout << ob[i].s;
    }
    cout << endl;
    exit(1);
}

bbi_code.cpp

/**************************************************/
/*filename:bbi_code.cpp メモリ管理と構文チェックと実行*/
/**************************************************/
#include "bbi.h"
#include "bbi_prot.h"

CodeSet code;
int startPc;
int Pc = -1;
int baseReg;
int spReg;
int maxLine;
vector intercode;
char *code_ptr;
double return value;
bool break_Flg, return_Flg, exit_Flg;
Mymemory Dmem;
vector strLITERAL;
vector nbrLITERAL;
bool syntaxChk_mode = false;
extern vector Gtable;

class Mystack {
private:
    stack st;
public:
    void push(double n){ st.push(n); }
    int size() { return (int)st.size(); }
    bool empty() { return st.empty(); }
    double pop(){
        if (st.empty()) err_exit("stack underflow");
        double d = st.top();
        st.pop(); return d;
    }
};

void syntaxChk()
{
    syntaxChk_mode = true;
    for (Pc=1; Pc<(int)intercode.size(); Pc++){
        code = firstCode(Pc);
        switch(code.kind){
            case Func: case Option: case Var:
                break;
            case Else: case End: case Exit:
                code =nextCode(); chk_EofLine();
                break;
            case If: case Elif: case While:
                code = nextCode(); (void)get_expression(0, EofLine);
                break;
            case For:
                code = nextCode();
                (void)get_memAdrs(code);
                (void)get_expression('=', 0);
                (void)get_expression(To, 0);
                if (code.kind == Step) (void)get_expression(Step, 0);
                chk_EofLine();
                break;
            case Fcall:
                fncCall_syntax(code.symNbr);
                chk_EofLine();
                (void)stk.pop();
                break;
            case Print: case Println:
                sysFncExec_syntax(code.kind);
                break;
            case Gvar: case Lvar:
                (void)get_memAdrs(code);
                (void)get_expression('-', EofLine);
                break;
            case Return:
                code = nextCode();
                if (code.kind!='?' && code.kind!=EofLine)(void)get_expression();
                if(code.kind=='?')(void)get_expression('?', 0);
                chk_EofLine();
                break;
            case Break:
                code = nextCode();
                if (code.kind == '?') (void)get_expression('?', 0);
                chk_EofLine();
                break;
            case EofLine:
                break;
            default:
                err_exit("不正な記述です: ", kind_to_s(code.kind));
        }
    }
    syntaxChk_mode = false;
}

void set_startPc(int n)
{
    startPc = n;
}

void execute()
{
    baseReg = 0;
    spReg = Dmem.size();
    Dmem.resize(spReg+1000);
    break_Flg = return_Flg = exit_Flg = false;
    Pc = startPc;
    maxLine = intercode.size() - 1;
    while (Pc<=maxLine && !exit_Flg){
        statement();
    }
    Pc = -1;
}

void statement()
{
    CodeSet save;
    int top_line, end_line, varAdrs;
    double wkVal, endDt, stepDt;
    
    if (Pc>maxLine || exit_Flg) return;
    code = save = firstCode(Pc);
    top_line = Pc; end_line = code.jmpAdrs;
    if (code.kind == If) end_line = endline_of_If(Pc);
    
    switch(code.kind){
        case If:
            if (get_expression(If, 0)){
                ++Pc; block(); Pc = end_line + 1;
                return;
            }
            Pc = save.jmpAdrs;
            while (lookCode(Pc) == Elif){
                save = firstCode(Pc); code = nextCode();
                if (get_expression()){
                    ++Pc; block(); Pc = end_line + 1;
                    return;
                }
                Pc = save.jmpAdrs;
            }
            if (lookCode(Pc) == Else){
                ++Pc; block(); Pc = end_line + 1;
                return;
            }
            ++Pc;
            break;
        case While:
            for(;;){
                if (!get_expression(While, 0)) break;
                ++Pc; block();
                if (break_Flg || return_Flg || exit_Flg){
                    break_Flg = false; break;
                }
                Pc = top_line; code = firstCode(Pc);
            }
            Pc = end_line + 1;
            break;
        case For:
            save = nextCode();
            varAdrs = get_memAdrs(save);
            
            expression('=', 0);
            set_dtTyp(save, DBL_T);
            Dmem.set(varAdrs, stk.pop());
            
            endDt = get_expression(To, 0);
            
            if (code.kind == Step) stepDt = get_expression(Step, 0); else stepDt = 1.0;
            for(;; PC=top_line){
                if (Dmem.get(varAdrs) > endDt) break;
            } else {
                if (Dmem.get(varAdrs) < endDt) break;
            }
            ++Pc; block();
            if (break_Flg || return_Flg || exit_Flg) {
                break_Flg = false; break;
            }
            Dmem.add(varAdrs, stepDt);
            }
    Pc = end_line+1;
    break;
case Fcall:
    fncCall(code.symNbr);
    (void)stk.pop();
    ++Pc;
    break;
case Func:
    Pc = end_line + 1;
    break;
case Print: case Println:
    sysFncExec(code.kind);
    ++Pc;
    break;
case Gvar: case Lvar:
    varAdrs = get_memAdrs(code);
    expression('=', 0);
    set_dtTyp(save, DBL_T);
    Dmem.set(varAdrs, stk.pop());
    ++Pc;
    break;
case Return:
    wkVal = returnValue;
    code = nextCode();
    if (code.kind!='?' && code.kind!=EofLine)
        wkVal = get_expression();
    post_if_set(return_Flg);
    if (return_Flg) returnValue = wkVal;
    if(!return_Flg) ++Pc;
    break;
case Break:
    code = nextCode(); post_if_set(break_Flg);
    if(!break_Flg) ++ Pc;
    break;
case Exit:
    code = nextCode(); exit_Flg = true;
    break;
case Option: case Var: case EofLine:
    ++Pc;
    break;
default:
    err_exit("不正な記述です:", kind_to_s(code.kind));
    }
}

void block()
{
    TknKind k;
    while (!break_Flg && !return_Flg && !exit_Flg){
        k = lookCode(Pc);
        if (k==Elif || k==Else || k==End) break;
        statement();
    }
}

double get_expression(int kind1, int kind2)
{
    expression(kind1, kind2); return stk.pop();
}

void expression(int kind1, int kind2)
{
    if (kind1 != 0) code =chk_nextCode(code, kind1);
    expression();
    if (kind2 != 0) code = chk_nextCode(code, kind2);
}

void expression()
{
    term(1);
}

void term(int n)
{
    TknKind op;
    if (n == 7){ factor(); return; }
    term(n+1);
    while(n == opOrder(code.kind)){
        op = code.kind;
        code = nextCode(); term(n+1);
        if (syntaxChk_mode){ stk.pop(); stk.pop(); stk.push(1.0); }
        else binaryExpr(op);
    }
}

void factor()
{
    TknKind kd = code.kind;
    
    if (syntaxChk_mode){
        switch (kd){
            case Not: case Minus: case Plus:
                code = nextCode(); factor(); stk.pop(); stk.push(1.0);
                break;
            case Lparen:
                expression('(', ')');
                break;
            case IntNum: case DblNum:
                stk.push(1.0); code = nextCode();
                break;
            case Gvar: case Lvar:
                (void)get_memAdrs(code); stk.push(1.0);
                break;
            case Toint: case Input:
                sysFncExec_syntax(kd);
                break;
            case Fcall:
                fncCall_syntax(code.symNbr);
                break;
            case EofLine:
                err_exit("式が不正です。");
            default:
                err_exit("式誤り:", kind_to_s(code));
        }
        return;
    }
    
    switch (kd){
        case Not: case Minus: case Plus:
            code = nextCode(); factor();
            if (kd == Not) stk.push(!stk.pop());
            if (kd == Minus) stk.push(-stk.pop());
            break;
        case Lparen:
            expression('(', ')');
            break;
        case IntNum: case DblNum:
            stk.push(code.dblVal); code = nextCode();
            break;
        case Gvar: case Lvar:
            chk_dtTyp(code);
            stk.push(Dmem.get(get_memAdrs(code)));
            break;
        case Toint: case Input:
            sysFncExec(kd);
            break;
        case Fcall:
            fncCall(code.symNbr);
            break;
    }
}

int opOrder(TknKind kd)
{
    switch(kd){
        case Multi: case Divi: case Mod:
        case IntDivi: return 6;
        case Plus: case Minus: return 5;
        case Less: case LessEq:
        case Great: case GreatEq: return 4;
        case Equal: case NotEq: return 3;
        case And: return 2;
        case Or: return 1;
        default: return 0;
    }
}

void binaryExpr(TknKind op)
{
    double d = 0, d2 = stk.pop(), dl = stk.pop();
    
    if ((op == Divi || op == Mod || op==IntDivi) && d2 == 0)
        err_exit("ゼロ除算です。");
    
    switch(op){
        case Plus: d = d1 + d2; break;
        case Minus: d = d1 - d2; break;
        case Multi: d = d1 * d2; break;
        case Divi: d = d1 / d2; break;
        case Mod: d = (int)d1 % (int)d2; break;
        case IntDivi: d = (int)d1 / (int)d2; break;
        case Less: d = d1 < d2; break;
        case LessEq: d = d1 <= d2; break;
        case Great: d = d1 > d2; break;
        case GreatEq: d = d1 >= d2; break;
        case Equal: d = d1 == d2; break;
        case NotEq: d = d1 != d2; break;
        case And: d = d && d2; break;
        case Or: d = d1 || d2; break;
    }
    stk.push(d);
}

void post_if_set(bool& flg)
{
    if (code.kind == EofLine){flg = true; return; }
    if (get_expression('?', 0)) flg = true;
}

void fncCall_syntax(int fncNbr)
{
    int argCt = 0;
    
    code = nextCode(); code = chk_nextCode(code, '(');
    if (code.kind != ')'){
        for (;; code=nextCode()){
            (void)get_expression(); ++argCt;
            if (code.kind != ',') break;
        }
    }
    code = chk_nextCode(code, ')');
    if (argCt != Gtable[fncNbr].args)
        err_exit(Gtable[fncNbr].name, "関数の引数個数が誤っています。");
    stk.push(1.0);
}

void fncCall(int fncNbr)
{
    int n, argCt = 0;
    vector vc;
    
    nextCode(); code = nextCode();
    if (code.kind != ')'){
        for(;; code=nextCode()){
            expression(); ++argCt;
            if(code.kind != ',') break;
        }
    }
    code = nextCode();
    
    for (n = 0; naryLen;
            code = nextCode();
            if (len == 0) return adr;
            
            d = get_expression('[', ']');
            if ((int)d != d)err_exit("添字は端数のない数字で指定してください。");
            if (syntaxChk_mode) return adr;
            
            index = (int)d;
            line = cd.jmpAdrs;
            cd = firstCode(line);
            if (cd.kind==Elif || cd.kind==Else) continue;
            if(cd.kind == End) break;
            return adr + index;
        }

int get_topAdrs(const CodeSet& cd)
        {
            switch(cd.kind){
                case Gvar: return tableP(cd)->adrs;
                case Lvar: return tableP(cd)->adrs + baseReg;
                default: err_exit("変数名が必要です:", kind_to_s(cd));
            }
            return 0;
        }

int endline_of_If(int line)
        {
            CodeSet cd;
            char *save = code_ptr;
            
            cd = firstCode(line);
            for(;;){
                if(index < 0 || len <= index)
                    err_exit(index, "は添字範囲外です(添字範囲:0-", len-1, ")");
            }
            code_ptr = save;
            return line;
        }

    void chk_EofLine()
        {
            if (code.kind != EofLine) err_exit("不正な記述です:", kind_to_s(code));
        }

    TknKind lookCode(int line)
        {
            return (TknKind)(unsigned char)intercode[line][0];
        }

    CodeSet chk_nextCode(const CodeSet& cd, int kind2)
        {
            if (cd.kind != kind2){
                if (kind2 == EofLine) err_exit("不正な記述です: ", kind_to_s(cd));
                if (cd.kind == EofLine) err_exit(kind_to_s(kind2), "が必要です。");
                err_exit(kind_to_s(kind2)+ "が"+ kind_to_s(cd) + "の前に必要です。");
            }
            return nextCode();
        }

    CodeSet firstCode(int line)
        {
            code_ptr = intercode[line];
            return nextCode();
        }

                     CodeSet nextCode()
                     {
                         TknKind kd;
                         short int jmpAdrs, tblNbr;
                         
                         if (*code_ptr == '\0') return CodeSet(EofLine);
                         kd = (TknKind)*UCHAR_P(code_ptr++);
                         switch Func:
                     case While: case For: case If: case Elif: case Else:
                         jmpAdrs = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, -1, jmpAdrs);
                     case String:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, strLITERAL[tblNbr].c_str());
                     case IntNum: case DblNum:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, nbrLITERAL[tblNbr]);
                     case Fcall: case Gvar: case Lvar:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, tblNbr, -1);
                     default:
                         return CodeSet(kd);
                     }
                     }
    void chk_dtTpy(const CodeSet& cd)
        {
            if (tableP(cd)->dtTyp == NON_T)
                err_exit("初期化されていない変数が使用されました:", kind_to_s(cd));
        }

void set_dtTyp(const CodeSet& cd, char typ)
        {
            int memAdrs = get_topAdrs(cd);
            vector::iterator p = tableP(cd);
            
            if (p->dtTyp != NON_T)return:
                p->dtTyp = typ;
            if (p->aryLen != 0){
                for (int n=0; n < p->aryLen; n++){ Dmem.set(memAdrs+n, 0);}
            }
        }

    int set_LITERAL(double d)
        {
            for (int n=0; n<(int)nbrLITERAL.size(); n++){
                if (nbrLITERAL[n] == d) return n;
            }
            nbrLITERAL.push_back(d);
            return nbrLITERAL.size() - 1;
        }

    int set_LITERAL(const string& s)
        {
            for (int n=0; n<(int)strLITERAL.size(); n++){
                if (strLITERAL[n] == s) return n;
            }
            strLITERAL.push_back(s);
            return strLITERAL.size() -1;
        }

bbi_tbl.cpp

/**************************************/
/*  filename:bbi_tbl.cpp 記号表処理   */
/**************************************/
#include "bbi.h"
"include "bbi_prot.h"

vector<SymTbl> Gtable;
vector<SymTbl> Ltable;
int startLtable;

int enter(SymTbl& tb, SymKind kind)
{
    int n, mem_size;
    bool isLocal = is_localName(tb.name, kind);
    extern int localAdrs;
    extern Mymemory Dmem;
    
    mem_size = tb.aryLen;
    if (mem_size == 0) mem_size = 1;
    if (kind!=varId && tb.name[0] == '$')
        err_exit("変数名以外で$を使うことはできません:", tb.name);
    tb.nmKind = kind;
    n = -1;
    if (kind == fncId) n = searchName(tb.name, 'G');
    if (kind == paraId) n = searchName(tb.name, 'L');
    if (n != -1) err_exit("名前が重複しています:", tb.name);
    
    if(kind == fncId) tb.adrs = get_lineNo();
    else {
        if (isLocal){ tb.adrs = localAdrs; localAdrs += mem_size; }
        else {
            tb.adrs = Dmem.size();
            Dmem.resize(Dmem.size() + mem_size);
        }
    }
    if (isLocal){ n = Ltable.size(); Ltable.push_back(tb); }
    else { n= Gtable.size(); Gtable.push_back(tb); }
    return n;
}

void set_startLtable()
{
    startLtable = Ltable.size();
}

bool is_localName(const string& name, SymKind kind)
{
    if (kind == paraId) return true;
    if (kind == varId){
        if (is_localScope() && name[0]!='$') return true; else return false;
    }
    return false;
}

int searchName(const string& s, int mode)
{
    int n;
    switch (mode){
            caes 'G':
            for (n=0; n<(int)Gtable.size(); n++){
                if (Gtable&#91;n&#93;.name == s) return n;
            }
            break;
            case 'L':
            for (n=startLtable; n<(int)Ltable.size(); n++)
            {  if(Ltable&#91;n&#93;.name == s) return n;
            }
            break;
            case 'F':
            n = searchName(s, 'G');
            if(n != -1 && Gtable&#91;n&#93;.nmKind==fncId) return n;
            break;
            case 'V':
            if (searchName(s, 'F') != -1) err_exit("関数名と重複しています: ", s);
            if (s&#91;0&#93; == '$') return searchNAme(s, 'G');
            if (is_localScope()) return searchName(s, 'L');
            else return searchName(s, 'G');
    }
    return -1;
}

vector<SymTbl>::iterator tableP(const CodeSet& cd)
{
    if (cd.kind == Lvar) return Ltable.begin() + cd.symNbr;
    return Gtable.begin() + cd.symNbr;
}