xengineer’s diary

結果、メモ的な内容になっています。

続 iTerm2(MacOSX)でpromptが激しく文字化けしたとき

以前、こんな記事を書きました。

xengineer.hatenablog.com

そう、MacOSXでiterm2使っていて、コマンドプロンプトが文字化けして仕方ない。

そんなときの対処方法です。

最近、またこれが発生して、同じ方法で対応したんですが、、、

全然直らない!!!!

「むきーーー!!!」ってなってぐぐりました。

unix.stackexchange.com

そしたら、terminalで、resetコマンド叩けば?

ということで、、、

$ reset

(当然文字化けしてるので、resetって出ないけど)

直った!!!すぐ直った!こっちのほうが強力!

ちなみに、man resetしてみたら、resetコマンド自体は、tputコマンドのsubcommandで、

$ tput reset

と同義らしい。

tputは、terminfo DBをみて、terminalを初期化したりresetしたりするそうです。

ちなみに、man terminfo したところ、terminfo DBは、CSVで、/usr/share/terminfo配下にあるみたい。

でもここにあるファイルは、tic(terminfo compiler) で、コンパイルされたファイルなので、直接はみれまてん。

$ infocmp xterm
#       Reconstructed via infocmp from file: /usr/share/terminfo/78/xterm
xterm|xterm terminal emulator (X Window System),
        am, bce, km, mc5i, mir, msgr, npc, xenl,
        colors#8, cols#80, it#8, lines#24, pairs#64,
        acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
        bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
        clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M,
        csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
        cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
        cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
        cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
        dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K,
        flash=\E[?5h$<100/>\E[?5l, home=\E[H, hpa=\E[%i%p1%dG,
        ht=^I, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L,
        ind=^J, indn=\E[%p1%dS, invis=\E[8m,
        is2=\E[!p\E[?3;4l\E[4l\E>, kDC=\E[3;2~, kEND=\E[1;2F,
        kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~,
        kPRV=\E[5;2~, kRIT=\E[1;2C, kb2=\EOE, kbs=^H, kcbt=\E[Z,
        kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
        kdch1=\E[3~, kend=\EOF, kent=\EOM, kf1=\EOP, kf10=\E[21~,
        kf11=\E[23~, kf12=\E[24~, kf13=\E[1;2P, kf14=\E[1;2Q,
        kf15=\E[1;2R, kf16=\E[1;2S, kf17=\E[15;2~, kf18=\E[17;2~,
        kf19=\E[18;2~, kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~,
        kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~,
        kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S,
        kf29=\E[15;5~, kf3=\EOR, kf30=\E[17;5~, kf31=\E[18;5~,
        kf32=\E[19;5~, kf33=\E[20;5~, kf34=\E[21;5~,
        kf35=\E[23;5~, kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q,
        kf39=\E[1;6R, kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~,
        kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~,
        kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~,
        kf48=\E[24;6~, kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q,
        kf51=\E[1;3R, kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
        kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
        kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
        kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
        kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
        kind=\E[1;2B, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
        kri=\E[1;2A, mc0=\E[i, mc4=\E[4i, mc5=\E[5i, meml=\El,
        memu=\Em, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM,
        rin=\E[%p1%dT, rmacs=\E(B, rmam=\E[?7l, rmcup=\E[?1049l,
        rmir=\E[4l, rmkx=\E[?1l\E>, rmm=\E[?1034l, rmso=\E[27m,
        rmul=\E[24m, rs1=\Ec, rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7,
        setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
        setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
        setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
        sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
        sgr0=\E(B\E[m, smacs=\E(0, smam=\E[?7h, smcup=\E[?1049h,
        smir=\E[4h, smkx=\E[?1h\E=, smm=\E[?1034h, smso=\E[7m,
        smul=\E[4m, tbc=\E[3g, u6=\E[%i%d;%dR, u7=\E[6n,
        u8=\E[?1;2c, u9=\E[c, vpa=\E[%i%p1%dd,

みたいに、terminal指定して、infocmp実行すると、中身がみえます。

ここに、各terminalの情報が書いてあって、tputはこれをもとに初期化/resetをしてくれる、と。

そんな感じでした。

まぁそうなると、前回書いた、resetとの違いが何かは気になるけど・・・・

ま、それはまたそのうち・・・w

New Relic、どのProductを使えばいいの!?

概要

newrelic.com

久しぶりに、New Relicをみてみたら、PRODUCTが多すぎて、

自分が何を使えばいいのかわからない!w

Zabbixなのか、New Relicなのか、検討しようと思ったけど、

New Relicの中でもどれなんだ!?っていう。。。

こんなにあるのです。

  • New Relic APM
  • New Relic INSIGHTS
  • New Relic MOBILE
  • New Relic BROWSER
  • New Relic SYNTHETICS
  • New Relic SERVERS
  • New Relic PLUGINS
  • New Relic for iOS & Android

Software Analytics SaaS Application Monitoring Products: New Relic | New Relic

ちなみに、今回は、普通に、ApサーバとRDSの単純構成のサービスを

監視したいだけ。難しいことは一切なし。

ということで、New Relicのプロダクトをざっと並べてみました。

New Relic APM

まず、APMは、Application Performance Monitoringの略でした。すっきり。

アプリケーションのパフォーマンスを詳細に分析して、DBのボトルネックやら、

どのAPIが処理が遅いか、そもそも、NWが遅いのか、アプリの内部処理が遅いのか、

viewのDOM構築が遅いのか、レンダリングが遅いのか、などなどを見せてくれる。

すごい便利ツール。これ!これは今回みたかったやつ!

New Relic MOBILE

どうやら、MOBILEは、モバイルのネイティブアプリのツールぽい。

例えば、どの辺の地域でパフォーマンスがよくないか、とか

どのサードパーティAPIがパフォーマンス劣化につながってるか、

とか、OS毎、デバイス毎、アプリバージョン毎のパフォーマンスの

違いをみれたりするんだと。

あとキャリアによる違いとか。これは、今回ほしいのではない、なと。

New Relic BROWSER

これはほんとにフロントのブラウザ処理を徹底解析!って感じ。

AJAXの処理時間を細かく出してくれるので、それに基づいた改善をしていける。

ユーザがロードした、全asset/ajax request/ユーザインタラクションなどなど、

タイムラインにしてみせてくれるから改善しやすい。

APMでざっくりみて、DOM ProcessingとかRenderingに問題あったらこっちみる感じかな。

でも今回はここじゃないからいいや、と。

New Relic SYNTHETICS

これは、世界中からレスポンスタイム測ってくれるってやつか。

すげーな。でもこれも今回違うからいいや。

New Relic SERVERS

書いてあるとおり、サーバ監視です。

CPUとか、メモリとか、ディスク使用量とかトラフィックとか監視してくれる。

しかも、、、

New Relic Servers is 100% free, setup is easy, and you can start seeing valuable data in just minutes.

ムリョウ!!!!すごい。太っ腹。

New Relic PLUGINS

これは、単に沢山Pluginがあるよ、ってことでした。

もちろん、、、

All the data, insights, and customized plugins you need. All for FREE.

ムリョウ!!!

New Relic INSIGHTS

INSIGHTSは、データ解析ツール

SYNTHETICS/MOBILE/BROWSER/APMから取得したデータに、

appId/appName/databaseDurationなんていう、アトリビュートをつけて、

全部溜め込んでくれます。

で、NRQLっていうDSLでリアルタイムに処理して、GUIに見せるらしいです。

何がみれるかはわからないけど、今回のとはちと違う。

というわけで、今回は、APMとSERVERの組み合わせが一番いいのかな、と。

で、ここまできて友人に聞いたところ、New Relicは、メトリクスとるのとかは

少し弱くて、カスタマイズ性もそこまで高くないので、Zabbixと併用パターンが

多い気がする、と。

はふ、そうなのか。結局あの見づらいZabbixなのか・・・

というわけで、次はmackerelもみてみることにしよう。

ざびちゃんができる子なのは知ってるけど、見づらいのよ。

rubyのオブジェクトのメソッド探索ルール

概要

最近、ActiveRecordのコードを読み始めてすぐにやめたわけです。

"super" つっても、どこの何を呼び出してるか全然わからんちんですよ。

それでまずは、表題の件(rubyでオブジェクトのメソッド探索ルール)について

調べてから立ち向かおうかと。

この辺を参考に。(本記事もこの辺を参考にオマージュしております) Rubyメソッド探索 [Ruby] オブジェクトのメソッド探索順序 - Qiita

まず、下記メソッドを沢山使いました。

# 継承ツリーを取得
<クラス>.ancestors

あと、本記事では使い忘れてしまったけど、下記メソッドも便利そうです。

# メソッドのオーナーを取得
<インスタンス>.method(:<メソッド名>).owner

本記事では、下記メソッドを使った場合のメソッド探索ルールについて調べてみます。

  • extend
  • include
  • prepend
  • 継承

まずは普通に継承してみる

# test.rb
require 'rubygems'
require 'bundler'
Bundler.require

require 'pry'

class Super
  def method1
    p "super#method1"
  end
end

class Sub < Super
  def method1
    p "sub#method1"
  end
end

sub = Sub.new.method1

これは実行すると、当然の結果が返ってくる。

$ ruby ./test.rb
"sub#method1"

次に、Subクラスの、method1を削除して実行する。(↓の状態)

# test.rb
require 'rubygems'
require 'bundler'
Bundler.require

require 'pry'

class Super
  def method1
    p "super#method1"
  end
end

class Sub < Super
end

sub = Sub.new.method1

えい。実行。

$ ruby ./test.rb
"super#method1"

おお。これも当然。Subのancestorsをみてみると、どっちの場合も同じ。

[1] pry(main)> Sub.ancestors
=> [Sub, Super, Object, PP::ObjectMixin, Kernel, BasicObject]

includeをみてみる

次は、Greatモジュールを作って、Subクラスにincludeしてみた。

# test.rb
require 'rubygems'
require 'bundler'
Bundler.require

require 'pry'

module Great
  def method1
    p "great#method1"
  end
end

class Super
  def method1
    p "super#method1"
  end
end

class Sub < Super
  include Great
end

sub = Sub.new.method1

これで実行。

$ ruby ./test.rb
"great#method1"

今度は、Greatモジュールのが実行された。ancestorsは・・・

[1] pry(main)> Sub.ancestors
=> [Sub, Great, Super, Object, PP::ObjectMixin, Kernel, BasicObject]

おお。Superの手前に突っ込まれる、と。

prependをみてみる

次は、Fabulousモジュールを作って、Subクラスにprependしてみた。

$ ruby ./test.rb
"fabulous#method1"

おおおお。更に前に突っ込まれた!ancestorsというと・・・

[1] pry(main)> Sub.ancestors
=> [Fabulous, Sub, Great, Super, Object, PP::ObjectMixin, Kernel, BasicObject]

おお。自分よりも前に突っ込まれている。prepend最強。

prependはruby2.0から実装された機能みたいです。

少し調べてみたところ、alias_method_chain撲滅できるぜ!なもののようです。

それが主目的で開発されたわけではないかもしれませんが。

» Ruby2.0のModule#prependは如何にしてalias_method_chainを撲滅するのか!? TECHSCORE BLOG

さてさて、ここまできたら最後だ。

extendをみてみる

extendは少し意味合いが違うメソッドな気がするけど、

似たようなことをやってるので、比べてみよう。

今度は、Miracleモジュールを作って、Subクラスにextendしてみた。

# test.rb
require 'rubygems'
require 'bundler'
Bundler.require

require 'pry'

module Miracle
  def method1
    p "miracle#method1"
  end
end

module Fabulous
  def method1
    p "fabulous#method1"
  end
end

module Great
  def method1
    p "great#method1"
  end
end

class Super
  def method1
    p "super#method1"
  end
end

class Sub < Super
  include Great
  prepend Fabulous
  extend Miracle
end

Sub.new.method1
Sub.method1

実行すると、こんな感じ。

$ ruby ./test.rb
"fabulous#method1"
"miracle#method1"

Subクラスの特異メソッドとして動作している、と。

ancestorsは・・・

[1] pry(main)> Sub.ancestors
=> [Fabulous, Sub, Great, Super, Object, PP::ObjectMixin, Kernel, BasicObject]

あ、そうなのね。そうか。

instance method Object#extend (Ruby 2.0.0)

↑↑に、

" extend は、ある特定のオブジェクトだけにモジュールの機能を追加 したいときに使用します。 "

って書いてあるとおり、Subクラスのオブジェクトだけに機能が追加されてるから、

ancestorsに出てくるものではないのか。

でもメソッド探索上でいうと、特異メソッドなので、一番優先度が高い、と。

include/prependを何回も呼ぶと?

何回も呼んだときは、どれが優先度高くなるのかね。

include Great1
prepend Fabulous1
include Great2
prepend Fabulous2

こんなことをした場合。

# test.rb
require 'rubygems'
require 'bundler'
Bundler.require

require 'pry'

module Fabulous1
  def method1
    p "fabulous1#method1"
  end
end

module Fabulous2
  def method1
    p "fabulous2#method1"
  end
end

module Great1
  def method1
    p "great1#method1"
  end
end

module Great2
  def method1
    p "great2#method1"
  end
end

class Super
  def method1
    p "super#method1"
  end
end

class Sub < Super
  include Great1
  prepend Fabulous1
  include Great2
  prepend Fabulous2
end

Sub.new.method1

これで実行してみる。えいやー。

$ ruby ./test.rb
"fabulous2#method1"

お、一番最後にprependしたFabulous2が呼ばれた。

そしてancestorsは・・・

[1] pry(main)> Sub.ancestors
=> [Fabulous2, Fabulous1, Sub, Great2, Great1, Super, Object, PP::ObjectMixin, Kernel, BasicObject]

おー。見事に後発優先ですな。

Fabulous2, Fabulous1
Great2, Great1

の順だもんね。なるほどなるほどー。勉強になりました。

ちなみに、少し規模が大きくなってくると、rubyは、include/prepend/extend/継承などなどの

嵐になるので、コード上書いてあるメソッドが、実際どこを呼び出してるか、

全然わかりません。なので、ちゃんとテストを書いて、ちゃんと動作するよね、

っていうのは最低限守らないと大変みたいです。

というわけで、今日はおしまい。

Facebookアプリの通信量を減らす

最近、僕そんなにFacebookみてないのに通信量だけは結構あるなー、

と思って調べてみました。

ほむほむ。動画だね、きっとね。

勝手に再生されるもんね。

そんなに見ないので自動再生じゃなくていいです。

というわけで、設定から、

f:id:xengineer:20151116235840j:plain アカウント設定をタップ

f:id:xengineer:20151116235859j:plain 動画を自動再生をタップ

f:id:xengineer:20151116235833j:plain うぃふぃーのみ、をタップ

いぇーい。自動再生オフにしたのでこれで様子見。

かんたんぽん。

rubyのヒアドキュメント

プルリのレビューをしていたら、

  method(arg1, <<-EOS.strip_heredoc, arg2)
    "hoge"
  EOS

的なコードが出現して、「これは一体なんだろう・・・」と固まりました。

グーグル先生に聞いたら、こんなサイトを紹介いただきまして、無事解決しました。

http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fliteral.html (この記事は、1.9.3の記事のようですが、僕の環境は、2.2.3です)

どうやら、rubyではヒアドキュメントはとても便利なようで、

その要素が沢山詰まったコードのようです。

  1. rubyのヒアドキュメントは、"<<"ではじまるけど、"<<-"で開始した場合、終端行をインデントして書ける
  2. rubyのヒアドキュメントは、methodをチェインして繋げられる
  3. rubyのヒアドキュメントは、methodの引数として渡した場合、ヒアドキュメント全体を引数として渡せる
    • つまり、上のコードでいうと、第二引数には、"hoge"が渡る
  4. strip_heredocをコールした場合、行頭の余分な空白を削除してくれる

などなど、他にもあると思いますが、勉強になりました。

ruby code readingメモ

概要

ちょっと知りたいことがあって、ふとrubyのコードをみたのでメモ。

ちなみに初めてみるのと、そんなに舐め回すようにみたわけじゃないので、

間違ってるかもしれないです。

ただ、メモっておかないと、次みるとき忘れちゃうので・・・

なぜそんなのをみることになったか。

railsのコードの中でよく出てくる、ClassMethodsモジュールって何かね?

っていうのを調べてて、こんな記事に辿り着いたため。

Rails4 - Rails の module ClassMethods がやっている事 - Qiita

記事中に、include文の中で、append_featuresが呼ばれるんだよね、って書いてあったので、

どれどれ、どこなのかな、と思ってみてみることにしました。

詳細

なにはともあれ、rubyのソースをcloneします。

$ cd <WORKDIR>
$ git clone https://github.com/ruby/ruby.git

rubyっていうディレクトリができるので、入って、lsしてみる。

$ cd ruby
$ ls
BSDL             README.md      compile.c     dmydln.c       eval_jump.c      include       man         parse.y          regerror.c     sparc.c           thread_pthread.h  vm.c             vm_trace.c
CONTRIBUTING.md  aclocal.m4     complex.c     dmyenc.c       ext              inits.c       marshal.c   prelude.rb       regexec.c      spec              thread_sync.c     vm_args.c        vsnprintf.c
COPYING          addr2line.c    configure.in  dmyext.c       file.c           insns.def     math.c      probes.d         regint.h       sprintf.c         thread_win32.c    vm_backtrace.c   win32
COPYING.ja       addr2line.h    constant.h    doc            gc.c             internal.h    method.h    probes_helper.h  regparse.c     st.c              thread_win32.h    vm_core.h
ChangeLog        array.c        cont.c        enc            gc.h             io.c          miniinit.c  proc.c           regparse.h     strftime.c        time.c            vm_debug.h
GPL              benchmark      coverage      encindex.h     gem_prelude.rb   iseq.c        misc        process.c        regsyntax.c    string.c          timev.h           vm_dump.c
KNOWNBUGS.rb     bignum.c       cygwin        encoding.c     gems             iseq.h        missing     random.c         ruby.c         struct.c          tool              vm_eval.c
LEGAL            bin            debug.c       enum.c         golf_prelude.rb  lex.c.blt     nacl        range.c          ruby_atomic.h  symbol.c          transcode.c       vm_exec.c
Makefile.in      bootstraptest  defs          enumerator.c   goruby.c         lib           node.c      rational.c       safe.c         symbol.h          transcode_data.h  vm_exec.h
NEWS             ccan           dir.c         error.c        hash.c           load.c        node.h      re.c             sample         template          util.c            vm_insnhelper.c
README.EXT       class.c        dln.c         eval.c         ia64.s           loadpath.c    numeric.c   regcomp.c        signal.c       test              variable.c        vm_insnhelper.h
README.EXT.ja    common.mk      dln.h         eval_error.c   id_table.c       localeinit.c  object.c    regenc.c         siphash.c      thread.c          version.c         vm_method.c
README.ja.md     compar.c       dln_find.c    eval_intern.h  id_table.h       main.c        pack.c      regenc.h         siphash.h      thread_pthread.c  version.h         vm_opts.h

おお、直下に沢山。

Cとか読むの10年ぶりくらいですけど大丈夫でしょうか。

遠い記憶を掘り起こして・・・Cはまずmain.cだ!!!

$ cat main.c
/**********************************************************************

  main.c -

  $Author$
  created at: Fri Aug 19 13:19:58 JST 1994

  Copyright (C) 1993-2007 Yukihiro Matsumoto

**********************************************************************/

#undef RUBY_EXPORT
#include "ruby.h"
#include "vm_debug.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef RUBY_DEBUG_ENV
#include <stdlib.h>
#endif

int
main(int argc, char **argv)
{
#ifdef RUBY_DEBUG_ENV
    ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
    setlocale(LC_CTYPE, "");
#endif

    ruby_sysinit(&argc, &argv);
    {
        RUBY_INIT_STACK;
        ruby_init();
        return ruby_run_node(ruby_options(argc, argv));
    }
}

色々書いてあるけど、

ruby_init();
return ruby_run_node(ruby_options(argc, argv));

が次かな。ここから色々grep

$ grep -E 'ruby_init' *.c | grep -v 'ruby_init_'
debug.c:    SET_WHEN("gc_stress", *ruby_initial_gc_stress_ptr, Qtrue);
eval.c:ruby_init(void)
gc.c:#define ruby_initial_gc_stress     gc_params.gc_stress
gc.c:VALUE *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
gc.c:    gc_stress_set(objspace, ruby_initial_gc_stress);
loadpath.c:const char ruby_initial_load_paths[] =
main.c: ruby_init();
miniinit.c:const char ruby_initial_load_paths[] = "";
ruby.c:    const char *paths = ruby_initial_load_paths;

ファイル名的に怪しいのは、eval.cである。で、開いてみたところ、

起動時のキーになりそうな関数が沢山。

int
ruby_setup(void)

void
ruby_init(void)

void *
ruby_options(int argc, char **argv)

static void
ruby_finalize_0(void)

などなど

ruby_init()でなにやってるかというと・・・

書いてあるとおり、

Calls ruby_setup() and check error. Prints errors and calls exit(3) if an error occurred.

です。てコメントに書いてあるけど、EXIT_FAILUREは、defineで 1 になってる気がする。まぁいい。

/* Calls ruby_setup() and check error.
 *
 * Prints errors and calls exit(3) if an error occurred.
 */
void
ruby_init(void)
{
    int state = ruby_setup();
    if (state) {
        if (RTEST(ruby_debug))
          error_print();
      exit(EXIT_FAILURE);
    }
}

ruby_setup()は・・・Ruby VMとビルトインライブラリの初期化、と。

Initializes the Ruby VM and builtin libraries.

/* Initializes the Ruby VM and builtin libraries.
 * @retval 0 if succeeded.
 * @retval non-zero an error occurred.
 */
int
ruby_setup(void)
{
    int state;

    if (GET_VM())
      return 0;

    ruby_init_stack((void *)&state);
    Init_BareVM();
    Init_heap();
    Init_vm_objects();

    PUSH_TAG();
    if ((state = EXEC_TAG()) == 0) {
      rb_call_inits();
      ruby_prog_init();
      GET_VM()->running = 1;
    }
    POP_TAG();

    return state;
}

ここから、さっと追ってみて気になったのは、rb_call_inits()くらいかな。

inits.cに定義されている。

$ cat inits.c
/**********************************************************************

  inits.c -

  $Author$
  created at: Tue Dec 28 16:01:58 JST 1993

  Copyright (C) 1993-2007 Yukihiro Matsumoto

**********************************************************************/

#include "internal.h"

#define CALL(n) {void Init_##n(void); Init_##n();}

void
rb_call_inits(void)
{
    CALL(Method);
    CALL(RandomSeed);
    CALL(sym);
    CALL(var_tables);
    CALL(Object);
    CALL(top_self);
    CALL(Encoding);
    CALL(Comparable);
    CALL(Enumerable);
    CALL(String);
    CALL(Exception);
    CALL(eval);
    CALL(safe);
    CALL(jump);
    CALL(Numeric);
    CALL(Bignum);
    CALL(syserr);
    CALL(Array);
    CALL(Hash);
    CALL(Struct);
    CALL(Regexp);
    CALL(pack);
    CALL(transcode);
    CALL(marshal);
    CALL(Range);
    CALL(IO);
    CALL(Dir);
    CALL(Time);
    CALL(Random);
    CALL(signal);
    CALL(load);
    CALL(Proc);
    CALL(Binding);
    CALL(Math);
    CALL(GC);
    CALL(Enumerator);
    CALL(VM);
    CALL(ISeq);
    CALL(Thread);
    CALL(process);
    CALL(Cont);
    CALL(Rational);
    CALL(Complex);
    CALL(version);
    CALL(vm_trace);
}
#undef CALL

ひたすら、Init_XXXXっていうのを呼び出す関数のようで。

その中の、Init_evalってのをみてみると、

Init_eval(void)
{
    ..........
    ...中略...
    ..........
    rb_define_method(rb_cModule, "include", rb_mod_include, -1);
    rb_define_method(rb_cModule, "prepend", rb_mod_prepend, -1);

    rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
    rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
    rb_define_private_method(rb_cModule, "prepend_features", rb_mod_prepend_features, 1);
    rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
    rb_define_private_method(rb_cModule, "using", mod_using, 1);
    ..........
    ...中略...
    ..........
}

・・・・append_featuresがいる。includeも。

rb_define_private_methodは、名前からして、"append_features"って言ったら、rb_mod_append_featuresってことだよ。

なんだろねきっと。

そうすると、rb_mod_includeと、rb_mod_prependを調べると何かわかりそう。

$ grep rb_mod_include *.c
class.c:rb_mod_included_modules(VALUE mod)
class.c:rb_mod_include_p(VALUE mod, VALUE mod2)
eval.c:rb_mod_include(int argc, VALUE *argv, VALUE module)
eval.c: return rb_mod_include(argc, argv, th->top_wrapper);
eval.c:    return rb_mod_include(argc, argv, rb_cObject);
eval.c:    rb_define_method(rb_cModule, "include", rb_mod_include, -1);
object.c:    rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
object.c:    rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */

またeval.cかな。

static VALUE
rb_mod_include(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id_append_features, id_included;

    CONST_ID(id_append_features, "append_features");
    CONST_ID(id_included, "included");

    for (i = 0; i < argc; i++)
      Check_Type(argv[i], T_MODULE);
    while (argc--) {
      rb_funcall(argv[argc], id_append_features, 1, module);
      rb_funcall(argv[argc], id_included, 1, module);
    }
    return module;
}

というわけで、includeされたらきっとこれが呼ばれるのかな。

んで、紆余曲折あって、

      rb_funcall(argv[argc], id_append_features, 1, module);
      rb_funcall(argv[argc], id_included, 1, module);

きっとこれで、append_featuresが呼ばれるのだろう。

これ以上みると夜になりそうなので、今日はここでおしまい。

ActiveRecordを単体で使う(rails なしで)

概要

  • ActiveRecordの挙動をみたいなー
  • 多少中身知りたいなー

と、思ったので、ActiveRecordだけ単体で使ってみました。

グーグル先生に聞いてみたら、やってる方を発見したので、

その通りにやってみましたメモです。

uehi.info

前提条件

テスト環境

詳細

今回は、mysqlに直接手作業でデータを突っ込んで、

それを読みだすとこまでの簡単なお仕事です。

まずは、作業用にテキトウなディレクトリを掘る

$ mkdir ar_test
$ cd ar_test

Gemfileに必要なGemを書いてインストール

Gemfileはこれ。

# Gemfile

source "https://rubygems.org/"

gem 'mysql2', '~> 0.3.20'
gem 'activerecord'
gem 'pry'
gem 'pry-byebug'
  • DBは、mysqlにするので、mysql2
  • debugというか、調査にも使いたいので、pryとpry-byebug
  • mysql2だけバージョン指定してるのは、最新だとなんかがうまくいかなかったから

でbundlerでインストール。

$ bundle install

今回は、ActiveRecordは、ver4.2.4。

# Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:
    activemodel (4.2.4)
      activesupport (= 4.2.4)
      builder (~> 3.1)
    activerecord (4.2.4)
      activemodel (= 4.2.4)
      activesupport (= 4.2.4)
      arel (~> 6.0)
    activesupport (4.2.4)
      i18n (~> 0.7)
      json (~> 1.7, >= 1.7.7)
      minitest (~> 5.1)
      thread_safe (~> 0.3, >= 0.3.4)
      tzinfo (~> 1.1)
    arel (6.0.3)
    builder (3.2.2)
    byebug (8.0.1)
    coderay (1.1.0)
    i18n (0.7.0)
    json (1.8.3)
    method_source (0.8.2)
    minitest (5.8.2)
    mysql2 (0.3.20)
    pry (0.10.3)
      coderay (~> 1.1.0)
      method_source (~> 0.8.1)
      slop (~> 3.4)
    pry-byebug (3.3.0)
      byebug (~> 8.0)
      pry (~> 0.10)
    slop (3.6.0)
    thread_safe (0.3.5)
    tzinfo (1.2.2)
      thread_safe (~> 0.1)

PLATFORMS
  ruby

DEPENDENCIES
  activerecord
  mysql2 (~> 0.3.20)
  pry
  pry-byebug

インストール完了。

mysql準備

ARを使いたいので、次は、mysqlを準備。

DB作成

まずはDBの作成。今回は名前は、ar_testにしよう。

$ mysql -u<username> -p<password>
mysql> create database ar_test;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| ar_test               |
| mysql                 |
| performance_schema    |
| tpcc                  |
+-----------------------+
5 rows in set (0.04 sec)
テーブル作成とデータ挿入

テーブル名は、test_tables。

カラムとデータは、こんなのを作っておきます。

mysql> select * from test_table;
+-------+---------+
| col01 | col02   |
+-------+---------+
|     1 | value01 |
|     2 | value02 |
+-------+---------+
2 rows in set (0.00 sec)

コマンドは、こんなん。

mysql> create table test_tables(col01 int not null primary key, col02 varchar(64));
Query OK, 0 rows affected (2.17 sec)

mysql> show tables;
+-------------------+
| Tables_in_ar_test |
+-------------------+
| test_tables       |
+-------------------+
1 row in set (0.01 sec)

mysql> insert into test_tables (col01, col02) values (1, 'value01');
Query OK, 1 row affected (0.19 sec)

mysql> insert into test_tables (col01, col02) values (2, 'value02');
Query OK, 1 row affected (0.97 sec)

mysql> select * from test_tables;
+-------+---------+
| col01 | col02   |
+-------+---------+
|     1 | value01 |
|     2 | value02 |
+-------+---------+
2 rows in set (0.00 sec)

これで準備はできた。

ActiveRecordを使ってみる

早速本題。使ってみよー!

↓↓こんなtest.rbを作ってみる。

# test.rb

require 'rubygems'
require 'bundler'
Bundler.require

require 'active_record'
require 'pry'

database_name = :ar_test

ActiveRecord::Base.establish_connection adapter: 'mysql2', database: database_name, host: 'localhost'

###################################
# ここより下にテスト用のコードをかく
###################################
class TestTable < ActiveRecord::Base
end

test_tables = TestTable.all
test_tables.each do |test_table|
  puts test_table.col01
  puts test_table.col02
end

これを実行すると・・・

$ ruby ./test.rb
1
value01
2
value02

おーー。読めた読めた。

ちゃんとDBの値が出てきておりますよー!

これで一旦は使えるようになったのかな。

おしまい。