2016/8/2(tue)の日記
shell起動時に自動的に指定のディレクトリに移動するようにした。
毎朝仕事を開始する時に、いつも仕事用のディレクトリにcdで移動するのが大変なので書いた。
以下のように .open_directory
にディレクトリを指定すると、shell 起動時に移動してくれる。
$ cat ~/.open_directory /Users/u16suzu/workGithub/rails_project
### 起動時に .open_directory ファイルで指定された directory に自動で移動する function auto_move(){ cd "`cat ~/.open_directory`" } auto_move
2016/8/1(mon)の日記
プロジェクトで使っている bundler で入れたgemの調査をするためのコマンドをbashで書いた。
Ruby 書くときは atom がメインエディタになりつつある。
RubyMineは重いので、コードリーディングの時だけ使っている。
### bundler でインストールした gem を編集したり、元に戻したりするコマンド # gem の内部動作を調査する際に使う # どちらのコマンドも操作対象のgemを引数で指定する必要がある function gem_edit(){ atom `bundle show $1` } alias gem_edit="gem_edit" alias gem_restore="bundle exec gem pristine"
ただ、一つだけ問題があって、gemを書き換えた後に rails consoleを再起動しないと読み込んでくれない。
pry
binding.pry を書くと、gemのコードの中で処理を止めてpryで変数の中身を見たりできる。
Arelの定義位置を調べたい時、pryコンソールで show-source Arel
とすると、arel のコードがどこで定義されているのかを調査することもできる。
2016/7/31(Sun)の日記
今日はマクドでRuby script 用のDSLを書いて遊んだ。
仕事でよく使うテスト用のスクリプトなんだけど、実行するタスクを引数で指定できるようになっている。
それをDSLで指定できるようにした。
@argv = [ {env: "pro"}, 'login', 'start' ] @env = "dev" p ARGV def debug(a) puts "---\n#{a}\n---" end def before_all(&block) @before_all = block end def after_all(&block) @after_all = block end def env(name, &block) @env = @argv.select{ |o| o.is_a?(Hash) }.first[:env] yield(block) if @env == name end before_all do debug 'before_all' end after_all do debug 'after_all' end def task(name, &block) @before_all.call if @before_all != nil && @argv.include?("all") yield block if block_given? && (@argv.include?( name ) || @argv.include?('all') ) @after_all.call if @after_all != nil && @argv.include?("all") end env 'test' do debug 'test' end env 'stg' do debug 'stg' end env 'pro' do debug 'pro' end task 'login' do debug 'login' end task 'start' do debug 'start' end task 'finish' do debug 'finish' end
2016/7/28(木)の日記
jbuilderについて
extract! # activerecord objectのアトリビュートを指定して書き出し ignore_nil! # このメソッドを書いた後は, nil のkey-valueをjsonに書き出さない. ignore_nil! false でオフにできる.
Splat演算子
a, b = *[1,2] # => a = 1, b = 2 *c = 1,2,3 # => c = [1,2,3]
Rubyで、配列を展開するときに使う *array
みたいな演算子 *
を Splat演算子と呼ぶ.
上の動作は知っていたけど、下の動作は気づいていなかった.
展開後の値を代入で指定しているわけですね.
メソッドの引数にハッシュを指定するときのつまづきポイント
[42] pry(main)> fuga a: 123 => {:a=>123} [43] pry(main)> fuga {a: 123} SyntaxError: unexpected ':', expecting '}' fuga {a: 123} [43] pry(main)> fuga( {a: 123}) => {:a=>123}
メソッドの引数にハッシュを指定したいときに, fuga {a: 123}
と書くとエラーになる。
これは、Rubyが引数の {
をブロック引数の {
として解釈してしまうため発生する。
fuga({a: 123})
と()
明示的に引数指定をすればエラーにならない
はじめ、Splat演算子と関係あるのかなと思ったけど、関係なかった。
今回、仕事で久しぶりに遭遇して、同僚のA氏に昔教えていただいたことを思い出した。
テスト周りで久しぶりにハマった
BaseController の rescue_from で例外の出力処理を書いていなかったため
テストは落ちるけど、スタックトレースが出力されず、原因の特定に困った。
いわゆる例外の握りつぶしに意図せずになってしまっていた。
これから rescue_from
で StandardError
を補足する場合は注意したい。
2016/7/27の日記
Rubyのメソッドに関する雑多なメモ
<< # 右ビットシフト `*2` と同じ意味 >> # 左ビットシフト `/2` と同じ意味 | # 論理和演算子. 0011|0101 => 0111 8.to_s(2) #=> "1000" : 2進数表現の文字列を取得 "0x4d2".hex #=> 1234 : 16進数を10進数に変換. 0xはなくてもあっても良い.
super
Rubyのsuperはオーバーライドしているメソッドを呼び出す.
注意点として、引数を省略してsuper
とコールすると、全ての引数を受け渡してコールしてしまう.
super()
と明示的に()をつけてコールすると、引数を渡さない.
このことは Effective Ruby でも書かれていた.
- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (3件) を見る
クラスマクロを自分で定義してみる.
クラスマクロを使うことで、 attr_accessor
みたいなメソッドを定義できる.
完全にクラスメソッドだけど、こういう attr_accessor
っぽい宣言的な構文で記述が出来る奴をクラスマクロと言うらしい.
Railsの has_many
, belongs_to
もクラスマクロだ.
class User attr_accessor :name def self.attr_special_accessor( *key ) p key end def self.before_hoge_hoge(key) p key end def self.after_hoge_hoge(k) p k end end class Boy < User attr_special_accessor :name, :age before_hoge_hoge :foo after_hoge_hoge :bar end
このQiitaの記事がとても参考になった.
「Rubyのしくみ」(Ruby Under a Microscope)を読んだ
「Rubyのしくみ」(Ruby Under a Microscope)を読みました。
Rubyのしくみ -Ruby Under a Microscope-
- 作者: Pat Shaughnessy,島田浩二,角谷信太郎
- 出版社/メーカー: オーム社
- 発売日: 2014/11/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
Rubyの内部における実行の流れを調べる
字句解析、構文解析、コンパイルが実際にどう行われているかを Rubyに添付されている、Rubyプログラムのパーサである Ripperクラス で調査することができます。その方法を説明します。
Ruby実行の流れは 1.8.xと1.9.xで大きく異なります。
1.9.xからYARV
(Yet Another Ruby Virtual Machine)が導入されました。
- v1.8.X
- v1.9.Xより上のバージョン
[Rubyコード] =字句解析=> [トークン列] =構文解析=> [AST] =コンパイル=> [YARV命令文] => YARVで実行される
ASTは構文解析木(Abstract syntax tree)の略です。 まずは字句解析からです。 Rubyのソースコードの読み込み処理です。
字句解析
require "ripper" require "pp" code = <<STR 10.times do |n| puts n end STR puts code pp Ripper.lex(code)
- 実行結果
[[[1, 0], :on_int, "10"], [[1, 2], :on_period, "."], [[1, 3], :on_ident, "times"], [[1, 7], :on_sp, " "], [[1, 8], :on_kw, "do"], [[1, 10], :on_sp, " "], [[1, 11], :on_op, "|"], [[1, 12], :on_ident, "n"], [[1, 13], :on_op, "|"], [[1, 14], :on_ignored_nl, "\n"], [[2, 0], :on_sp, " "], [[2, 2], :on_ident, "puts"], [[2, 6], :on_sp, " "], [[2, 7], :on_ident, "n"], [[2, 8], :on_nl, "\n"], [[3, 0], :on_kw, "end"], [[3, 3], :on_nl, "\n"]]
続いて、構文解析です。
構文解析
require "ripper" require "pp" code = <<STR 10.times do |n| puts n end STR puts code pp Ripper.sexp(code)
- 実行結果
[:program, [[:method_add_block, [:call, [:@int, "10", [1, 0]], :".", [:@ident, "times", [1, 3]]], [:do_block, [:block_var, [:params, [[:@ident, "n", [1, 12]]], nil, nil, nil, nil, nil, nil], false], [[:command, [:@ident, "puts", [2, 2]], [:args_add_block, [[:var_ref, [:@ident, "n", [2, 7]]]], false]]]]]]]
最後にYARV実行命令です。
コンパイル(YARV命令を表示)
code = <<END puts 2+2 END puts RubyVM::InstructionSequence.compile(code).disasm
- 実行結果
10.times do |n| puts n end == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 0000 trace 1 ( 1) 0002 putself 0003 putobject 2 0005 putobject 2 0007 opt_mult <callinfo!mid:*, argc:1, ARGS_SKIP> 0009 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0011 leave