toRuby / Tochigi Ruby Meetup Pokémon TCG, WCS 2010 Tochigi Pref. winner 7 Makoto Inoue Web Developer @ New Bamboo (UK) Translator of “The dRuby Book” Rails is A Follower what we can learn from dRuby’s metaprogramming magic Masatoshi SEKI Makoto Inoue
toRuby / Tochigi Ruby Meetup Pokémon TCG, WCS 2010 Tochigi Pref. winner 8 Big Bird. (scaling twitter) Rinda • Shared Queue (TupleSpace) • Built with DRb • RingyDingy makes it stupid easy • See Eric Hodel’s documentation • O(N) for take(). Sigh.
ERbLight - eRuby w/o $stdout, String concatenation a library, build the page using String instead of puts() Support writing Ruby applications using eRuby notation 30 1999
= arg end ERB.new(<<EOS).def_method(self, 'bar') <ul> <% @list.each do |row| %> <li><%= row %></li> <% end %> </ul> EOS end Foo#bar instance var unpopular features
similar questions repeatedly Each question has a large table with an answer column Element IDs and form names must be unique Write in one template ↑矢板市北部で一番Herokuを使ってる「情報デザイン」のロゴ 39 Q A Q A Q A Q A Q A
%> <h3>Answer column for <%= arg %></h3> <table id="table-<%= arg %>"> ... </table> <% end %> <h3>Question 1</h3> this is the first question <% t.call("q1") %> <h3>Question 2</h3> That's the second question <% t.call("q2") %> <h3>Question 1</h3> this is the first question <h3>Answer column for q1</h3> <table id="table-q1"> ... </table> <h3>Question 2</h3> That's the second question <h3>Answer column for q2</h3> <table id="table-q2"> ... </table> call
|arg| %> <h3>Answer column for <%= arg %></h3> <table id="table-<%= arg %>"> ... </table> <% end %> <h3>Question 1</h3> this is the first question <% t.call("q1") %> <h3>Question 2</h3> That's the second question <% t.call("q2") %> <h3>Question 1</h3> this is the first question <h3>Answer column for q1</h3> <table id="table-q1"> ... </table> <h3>Question 2</h3> That's the second question <h3>Answer column for q2</h3> <table id="table-q2"> ... </table> call
he didn't like this part in ActionView + Erubis ! BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ ! This code scans the template with the Regexp and detects the Ruby block, but this kind of code could be imperfect ! So this is not acceptable as an ERB spec, said Seki- san.
_erbout << h "str" # SyntaxError _erbout.concat h "str" # OK but .... _erbout.concat form_with "arg" do |arg| # NG ... # end # concatʹϒϩοΫ͕Δ <<と括弧なし のメソッド呼び 出し <<でなくふつうのメソッド呼び出しにしても このブロックはconcatのブロック引数になる
_erbout << h "str" # SyntaxError _erbout = h "str" # _erbout = form_with "arg" do |arg| # ... end _erbout.concat h "str" # OK but .... _erbout.concat form_with "arg" do |arg| # NG ... # end # concatʹϒϩοΫ͕Δ 代入なら大丈夫なのに... <<と括弧なし のメソッド呼び 出し <<でなくふつうのメソッド呼び出しにしても このブロックはconcatのブロック引数になる
SafeBuffer if rails def initialize(s='') @str = Buffer.new(s) end def to_s @str end def <<(other) @str << other end def +(other) @str << other.to_s self end def capture(*arg, &block) save = @str @str = Buffer.new yield(*arg) return @str ensure @str = save end end
SafeBuffer if rails def initialize(s='') @str = Buffer.new(s) end def to_s @str end def <<(other) @str << other end def +(other) @str << other.to_s self end def capture(*arg, &block) save = @str @str = Buffer.new yield(*arg) return @str ensure @str = save end end
= String # SafeBuffer if rails def initialize(s='') @str = Buffer.new(s) end def to_s @str end def <<(other) @str << other end def +(other) @str << other.to_s self end def capture(*arg, &block) save = @str @str = Buffer.new yield(*arg) return @str ensure @str = save end end normalize and concatenate return itself
Buffer = String # SafeBuffer if rails def initialize(s='') @str = Buffer.new(s) end def to_s @str end def <<(other) @str << other end def +(other) @str << other.to_s self end def capture(*arg, &block) save = @str @str = Buffer.new yield(*arg) return @str ensure @str = save end end save restore call block and capture