About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
2
Slide 3
Slide 3 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
40年くらいプログラマだよ
3
Slide 4
Slide 4 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
Complex embedded systems with concurrency and GUI
4
Gallstones
Slide 5
Slide 5 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
I wrote them in 1999-2000
5
Slide 6
Slide 6 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
I wrote them in 1999-2000
6
Slide 7
Slide 7 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
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
Slide 8
Slide 8 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
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.
Slide 9
Slide 9 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
9
Slide 10
Slide 10 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
第205回toRubyは2024-06-05
10
情報デザインのロゴ
Slide 11
Slide 11 text
About me
Masatoshi Seki
Ruby Core Committer (dRuby, Rinda, ERB)
toRuby / Tochigi Ruby Meetup
Pokémon TCG, WCS 2010 Tochigi Pref. winner
RubyKaigi 2022, 2023
11
Before ERB
When I posted a template engine that replaces &entity;, Shugo told me
about his plans for eRuby.
ruby-dev:5286 (1999-02-19) Re: htmlelem.rb (Re: HTML generator)
16
1999
Slide 17
Slide 17 text
eRuby specs
ePerlの影響を強くうけているみたいだぞ
17
print ≒ <%= .. %> !?
I'm not the one implementing it
(Tsundere)
ePerl! ?
Shugo CEO was a part-time
worker at the time.
1999
Slide 18
Slide 18 text
ePerl !?
e is for embedded. 文書にPerlが埋め込まれてる感じみたい
18
... !> !?
mod_perl !!!
1999
Slide 19
Slide 19 text
I'll write it
embedding control structures 😊
CGI-oriented 😭
CGIに寄せすぎでは?
19
1999
This specification is not good
CGI programming style will change in the near future
Page generation becomes more complex
Will change to something more server-like
26
1999
Slide 27
Slide 27 text
becomes more complex
Part of the page will be generated by a method
Helper?
27
report hoge
<% result.each do |row| %>
<%= format_date(row.date) %>
<% end %>
def format_date(date)
date.strftime("%Y-%m-%d")
end
ERB conjecture
1999
Slide 28
Slide 28 text
becomes more complex
nest
common header, navigation, footer and content
標準出力に出すよりも連結した方がよいのでは?
28
ERB conjecture
<%= header %>
<%= navi %>
<%= content %>
<%= footer %>
1999
Slide 29
Slide 29 text
CGI programming model will change
A long-lived server is required due to preprocessing costs and
information exchange between requests.
e.g. dRuby + ERB
Concurrency and $stdout will conflict
29
ERB conjecture
1999
Slide 30
Slide 30 text
ERb and ERbLight
ERb - eRuby's spec, like a command
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
Slide 31
Slide 31 text
Ruby x 256 book
Legendary hacker explains the power of this specification
2001, ASCII
たださんとartonさんがeRuby/dRubyを絶賛するすごい本
31
2001
Slide 32
Slide 32 text
renamed ERbLight to ERB
And ERB was included in Ruby's standard library.
ERb is obsolete
ERb is obsolete
32
2003
Slide 33
Slide 33 text
25 years have passed
almost correct !
ERB-inspired libraries make me happy
Merb, Rails... 自分用のライブラリは自分で書いてるけど、そういうものがあるのはうれしい
33
2024
ERB conjecture
ERB#def_method
def_method(mod, methodname, fname='(ERB)')
37
class Foo
def initialize(arg)
@list = arg
end
ERB.new(<
<% @list.each do |row| %>
<%= row %>
<% end %>
EOS
end
Foo#bar
instance var
unpopular features
Slide 38
Slide 38 text
ERB#def_method
Avoid parsing the source multiple times
Compose with small template objects
Used only in Ikezawa's products
38
unpopular features
Slide 39
Slide 39 text
Proc in template
Case study: Create a survey page with 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
Slide 40
Slide 40 text
Actual survey page
Slide 41
Slide 41 text
Each question has an answer sheet... !?
Slide 42
Slide 42 text
Each cell has detailed answer tables
10MB HTML
Slide 43
Slide 43 text
Proc in template
43
<% t = Proc.new do |arg| %>
Answer column for <%= arg %>
...
<% end %>
Question 1
this is the first question
<% t.call("q1") %>
Question 2
That's the second question
<% t.call("q2") %>
Question 1
this is the first question
Answer column for q1
...
Question 2
That's the second question
Answer column for q2
...
call
Slide 44
Slide 44 text
Proc in template
いやなことを思い出した
44
<% t = Proc.new do |arg| %>
I tried
やりましょう
47
I noticed this 2 years ago,
!
And asked Seki-san if we could
extend ERB to be "Rails
compatible" before Ruby 2.0
release
2012
Slide 48
Slide 48 text
and gave up
できませんでした
48
But gave up.
!
Because 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.
Slide 49
Slide 49 text
Railsに正規表現でブロックの開始を検知して処理を切り替えるコードがあった
49
That is why this syntax is
not acceptable in ERB
<%= form_for @article do |f| %>
...
<% end %>
Slide 50
Slide 50 text
Maybe it's solved
I noticed this while writing the slides for RWC2023.
https://gist.github.com/seki/610a42932a85209aaa33547ae983bbdf
50
2023
<%= ... %> with block
ブロック付きメソッドを <%= ... %>に置くのが難しい
52
<%= form_with do %>
...
<% end %>
Slide 53
Slide 53 text
<%= ... %> with block
こうなっちゃう
53
<%= form_with do %>
...
<% end %>
#coding:UTF-8
_erbout = +''; _erbout.<<(( form_with do ).to_s); _erbout.<< "\n ...
\n".freeze
; end ; _erbout.<< "\n".freeze
; _erbout
Slide 54
Slide 54 text
(( ... ).to_s)
((...).to_s)の括弧がじゃまなのでバッファクラスへ移動すればよい?
54
<%= form_with do %>
...
<% end %>
#coding:UTF-8
_erbout = +''; _erbout.<<(( form_with do ).to_s); _erbout.<< "\n ...
\n".freeze
; end ; _erbout.<< "\n".freeze
; _erbout
Slide 55
Slide 55 text
Customizable
Rubyへの変換方法はカスタマイズできる
55
<%= form_with do %>
...
<% end %>
#coding:UTF-8
_erbout = +''; _erbout.<<(( form_with do ).to_s); _erbout.<< "\n ...
\n".freeze
; end ; _erbout.<< "\n".freeze
; _erbout
Slide 56
Slide 56 text
Ruby is difficult
Rubyむずかしい
56
_erbout << h("str") # OK
_erbout << h "str" # SyntaxError
<<と括弧なし
のメソッド呼び
出し
Slide 57
Slide 57 text
Ruby is difficult
Rubyむずかしい
57
_erbout << h("str") # OK
_erbout << h "str" # SyntaxError
_erbout.concat h "str" # OK but ....
_erbout.concat form_with "arg" do |arg| # NG
... #
end # concatʹϒϩοΫ͕Δ
<<と括弧なし
のメソッド呼び
出し
<<でなくふつうのメソッド呼び出しにしても
このブロックはconcatのブロック引数になる
Slide 58
Slide 58 text
Ruby is difficult
Rubyむずかしい
58
_erbout << h("str") # OK
_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のブロック引数になる
Slide 59
Slide 59 text
Addition Asignment
+= works fine
代入しながらメソッド呼べばよい?
59
_erbout += h "str" # OK
_erbout += form_with "arg" do |arg| # OK
...
end
Slide 60
Slide 60 text
ERBOut
result buffer
60
class ERBOut
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
Slide 61
Slide 61 text
ERBOut
result buffer
61
class ERBOut
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
Slide 62
Slide 62 text
ERBOut
result buffer
many tricks
+
62
class ERBOut
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
normalize and
concatenate
return itself
Slide 63
Slide 63 text
ERBOut
result buffer
many tricks
+
capture
63
class ERBOut
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
Slide 64
Slide 64 text
なんかできちゃった
64
<%= form_with do %>
...
<% end %>
#coding:UTF-8
_erbout = ERB::ERBOut.new; _erbout += form_with do ; _erbout <<
"\n ...\n".freeze
; end ; _erbout << "\n".freeze
; _erbout.to_s
result buffer
addition assignment
Slide 65
Slide 65 text
capture
ブロックのローカル変数をさわってcaptureのしかけを呼び出す
65
def capture(*arg, &block)
block.binding.local_variable_get(:_erbout).capture(*arg, &block)
end
<% it = capture do %>
...
<% end %>
このブロックのbinding
local var :_erbout of block
Slide 66
Slide 66 text
I want someone to make it work in a Rails environment.
I made no progress since last year
進捗ダメです
66