the erb way

¤³¤Î¥Ú¡¼¥¸¤Ç¤ÏERB¤ò¥é¥¤¥Ö¥é¥ê¤È¤·¤Æ»ÈÍѤ¹¤ë¡¢ERB¤é¤·¤¤±þÍѤò¾Ò²ð¤·¤Þ¤¹¡£ ¤Ï¤¸¤á¤ËÉôÉʤòÀâÌÀ¤·¡¢¥µ¥ó¥×¥ë¤ò¼¨¤·¤Þ¤¹¡£

binding

ERB¤Ïeval()¤òÍøÍѤ·¤ÆeRuby¥¹¥¯¥ê¥×¥È¤ò¼Â¹Ô¤·¤Þ¤¹¡£ eval()¤Ë¤Ï¼Â¹Ô´Ä¶­¤ò¼¨¤¹binding¤ò»ØÄê¤Ç¤­¤Þ¤¹¤¬¡¢ ERB¤Ç¤âƱÍͤËbinding¤ò»ØÄꤹ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£

binding¤ò»ØÄꤹ¤ë¤³¤È¤Ç¡¢Ç¤°Õ¤Î¥¹¥³¡¼¥×¤ÇeRuby¥¹¥¯¥ê¥×¥È¤ò¼Â¹Ô¤Ç¤­¡¢ eRuby¤ÎÉôÉʲ½¤òÍưפˤ·¤Þ¤¹¡£

binding¤òÍøÍѤ·¤¿Îã¤ò¼¨¤·¤Þ¤¹¡£

require 'erb'

class Foo
  SCRIPT = <<EOS
<h1><%= @name %></h1>
<ul>
<% ary.each do |x|%>
<li><%= x %></li>
<% end %>
</ul>
EOS
  def initialize(name)
    @name = name
    @erb = ERB.new(SCRIPT)
  end

  def foo(ary)
    @erb.result(binding)
  end
end

it = Foo.new('foo')
puts it.foo([1,2,'<dia>'])

SCRIPT¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤ëeRuby¥¹¥¯¥ê¥×¥È¤Ç¤Ï¡¢ ¥¤¥ó¥¹¥¿¥ó¥¹ÊÑ¿ô@name¤ä¡¢ÊÑ¿ôary¤ò»²¾È¤·¤Æ¤¤¤Þ¤¹¡£ TOPLEVEL_BINDING¤Ç¼Â¹Ô¤·¤Æ¤Ï¥¨¥é¡¼¤Ë¤Ê¤Ã¤Æ¤·¤Þ¤¦¤Ç¤·¤ç¤¦¡£

foo¥á¥½¥Ã¥É¤Ïbinding¤ò»ØÄꤷ¤Æ¡¢Foo¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤Î¥¹¥³¡¼¥×¤Ç eRuby¥¹¥¯¥ê¥×¥È¤ò¼Â¹Ô¤·¤Þ¤¹¡£

¤Þ¤¿¡¢eRuby¥¹¥¯¥ê¥×¥È¤«¤éERB¤ÎÀ¸À®¤Î¥³¥¹¥È¤òÀáÌ󤹤뤿¤á¡¢ foo¥á¥½¥Ã¥É¤ÇËè²ó¹Ô¤Ê¤¦¤Î¤Ç¤Ï¤Ê¤¯¡¢ initialize¥á¥½¥Ã¥É¤Ç°ìÅÙ¤À¤±¹Ô¤Ê¤¦¤è¤¦¤Ë¤·¤Æ¤¤¤Þ¤¹¡£

ERB::Util

ERB::Util¤Ïhtml¤ÎÀ¸À®¤Ê¤É¤ÇÊØÍø¤ÊÆó¤Ä¤Î¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Æ¤¢¤ë¥â¥¸¥å¡¼¥ë¤Ç¤¹¡£ include¤·¤Æ»ÈÍѤ·¤Þ¤¹¡£

ERB::Util.html_escape(s)
ERB::Util.h(s)

HTML¤Î &"<> ¤ò¥¨¥¹¥±¡¼¥×¤¹¤ë¡£

ERB::Util.url_encode(s)
ERB::Util.u(s)

ʸ»úÎó¤òURL¥¨¥ó¥³¡¼¥É¤¹¤ë¡£

Àè¤Û¤É¤Î¥¹¥¯¥ê¥×¥È¤Ë¤ÏÌäÂ꤬¤¢¤Ã¤Æ¡¢@name¤äary¤ÎÆâÍÆ¤Ë Ãí°Õ¤òʧ¤Ã¤Æ¤¤¤Þ¤»¤ó¡£HTML¥¨¥¹¥±¡¼¥×¤ò¤·¤Ê¤¬¤é½ÐÎϤ¹¤ë¤è¤¦¤Ë Êѹ¹¤·¤Æ¤ß¤Þ¤·¤ç¤¦¡£

require 'erb'

class Foo
  include ERB::Util

  SCRIPT = <<EOS
<h1><%=h @name %></h1>
<ul>
<% ary.each do |x|%>
<li><%=h x %></li>
<% end %>
</ul>
EOS
  def initialize(name)
    @name = name
    @erb = ERB.new(SCRIPT)
  end

  def foo(ary)
    @erb.result(binding)
  end
end

it = Foo.new('foo')
puts it.foo([1,2,'<dia>'])

<%=h @name %>¤ä<%=h x %>¤¬HTML¥¨¥¹¥±¡¼¥×¤·¤Æ¤¤¤ëÉôʬ¤Ç¤¹¡£

<%=h ... %>

¤È½ñ¤¯¤È°ì¸«eRuby¤Î³ÈÄ¥¤Î¤è¤¦¤Ë¸«¤¨¤Þ¤¹¤¬¡¢¤è¤¯¸«¤ë¤È¤¿¤À¤Î ¥á¥½¥Ã¥É¸Æ¤Ó½Ð¤·¤Ç¤¢¤ë¤³¤È¤¬¤ï¤«¤ê¤Þ¤¹¡£ ¾åµ­¤Ï¤Ä¤Þ¤ê¼¡¤Î¤è¤¦¤Ê¥¹¥¯¥ê¥×¥È¤Ê¤Î¤Ç¤¹¡£

<%= h(...) %>

def_method

eRuby¥¹¥¯¥ê¥×¥È¤òeval()¤¹¤ë¤Î¤Ç¤Ï¤Ê¤¯¡¢¥á¥½¥Ã¥É¤È¤·¤ÆÄêµÁ¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£

ERB¤ò·«¤êÊÖ¤·¼Â¹Ô¤¹¤ë¾ì¹ç¤Ê¤É¡¢eval()¤Î¹Ô¤Ê¤¦¥¹¥¯¥ê¥×¥È¤Î¥Ñ¡¼¥º½èÍý¤Î ¥³¥¹¥È¤òÀáÌó¤Ç¤­¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£

ERB#def_method(mod, methodname, fname='(ERB)')

ÊÑ´¹¤·¤¿Ruby¥¹¥¯¥ê¥×¥È¤ò¥á¥½¥Ã¥É¤È¤·¤ÆÄêµÁ¤¹¤ë¡£ ÄêµÁÀè¤Î¥â¥¸¥å¡¼¥ë¤Ïmod¤Ç»ØÄꤷ¡¢¥á¥½¥Ã¥É̾¤Ïmethodname¤Ç»ØÄꤹ¤ë¡£ fname¤Ï¥¹¥¯¥ê¥×¥È¤òÄêµÁ¤¹¤ëºÝ¤Î¥Õ¥¡¥¤¥ë̾¤Ç¤¢¤ë¡£¼ç¤Ë¥¨¥é¡¼»þ¤Ë³èÌö¤¹¤ë¡£

erb = ERB.new(script)
erb.def_method(MyClass, 'foo(bar)', 'foo.erb')
ERB::DefMethod.def_erb_method(methodname, erb)

self¤Ëerb¤Î¥¹¥¯¥ê¥×¥È¤ò¥á¥½¥Ã¥É¤Æ¤·¤ÆÄêµÁ¤¹¤ë¡£¥á¥½¥Ã¥É̾¤Ïmethodname¤Ç»ØÄꤹ¤ë¡£ self¤¬Ê¸»úÎó¤Î»þ¡¢¤½¤Î¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ßERB¤ÇÊÑ´¹¤·¤¿¤Î¤Á¡¢¥á¥½¥Ã¥É¤È¤·¤ÆÄêµÁ¤¹¤ë¡£

class Writer
  extend ERB::DefMethod
  def_erb_method('to_html', 'writer.erb')
  ...
end
...
puts writer.to_html

Àè¤Û¤É¤Î¥¹¥¯¥ê¥×¥È¤òdef_method¤ò»È¤Ã¤Æ½ñ¤­Ä¾¤·¤Æ¤ß¤Þ¤·¤ç¤¦¡£

require 'erb'

class Foo
  include ERB::Util

  SCRIPT = <<EOS
<h1><%=h @name %></h1>
<ul>
<% ary.each do |x|%>
<li><%=h x %></li>
<% end %>
</ul>
EOS

  ERB.new(SCRIPT).def_method(self, 'foo(ary)')

  def initialize(name)
    @name = name
  end
end

it = Foo.new('foo')
puts it.foo([1,2,'<dia>'])

¥á¥½¥Ã¥Éfoo¤ÎÄêµÁ¤Ê¤¯¤Ê¤ê¡¢Âå¤ï¤ê¤Ëdef_method(self, 'foo(ary)')¤È¤Ê¤ê¤Þ¤·¤¿¡£

¤µ¤é¤ËRuby¥¹¥¯¥ê¥×¥È¤ÈeRuby¥¹¥¯¥ê¥×¥È¤Î¥Õ¥¡¥¤¥ë¤òʬ³ä¤·¤Æ¤ß¤Þ¤¹¡£

¤Þ¤ºeRuby¥¹¥¯¥ê¥×¥È(foo.erb)¤ò¼¨¤·¤Þ¤¹¡£ Äê¿ôFoo::SCRIPT¤¬¤½¤Î¤Þ¤ÞÆþ¤Ã¤Æ¤¤¤Þ¤¹¡£

<h1><%=h @name %></h1>
<ul>
<% ary.each do |x|%>
<li><%=h x %></li>
<% end %>
</ul>

¼¡¤ËRuby¥¹¥¯¥ê¥×¥È¤ò¼¨¤·¤Þ¤¹¡£

require 'erb'

class Foo
  include ERB::Util
  extend ERB::DefMethod

  def_erb_method('foo(ary)', 'foo.erb')

  def initialize(name)
    @name = name
  end
end

it = Foo.new('foo')
puts it.foo([1,2,'<dia>'])

¤Ï¤¸¤á¤Ë¡¢ERB::DefMethod¤òextend¤·¤ÆFoo¥¯¥é¥¹¤Çdef_erb_method ¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Þ¤¹¡£

extend ERB::DefMethod

¤Ä¤Å¤¤¤Æ def_erb_method ¤Ç¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Þ¤¹¡£ ºÇ½é¤Î°ú¿ô¤Ï¥á¥½¥Ã¥É̾¤È²¾°ú¿ô¤Ç¤¹¡£ ÆóÈÖÌܤΥ᥽¥Ã¥É¤ÏeRuby¥¹¥¯¥ê¥×¥È¤Î¥Õ¥¡¥¤¥ë̾¤Ç¤¹¡£

¥í¥¸¥Ã¥¯¤È¤Ê¤ëRuby¥¹¥¯¥ê¥×¥È¤È¥Ó¥å¡¼¤Ç¤¢¤ëeRuby¥¹¥¯¥ê¥×¥È¤¬ ʬΥ¤µ¤ì¤Æ¤¤¤ë¤Î¤¬¤ï¤«¤ë¤Ç¤·¤ç¤¦¤«?

Play with dRuby

dRuby¤ò»È¤Ã¤¿¥µ¡¼¥Ð¤ÈCGI¤Î¹½À®¤ÇERb¤ò»È¤Ã¤Æ¤ß¤Þ¤·¤ç¤¦¡£

  • ¤´¤¯´Êñ¤ÊWeb¥Á¥ã¥Ã¥ÈÉ÷¤Ê¤â¤Î
  • ȯ¸À¤È°ì½ï¤Ë¥¯¥é¥¤¥¢¥ó¥È¤ÎIP¥¢¥É¥ì¥¹¤È»þ¹ï¤òɽ¼¨¤¹¤ë
  • 120É俤ä¿È¯¸À¤Ï¾Ã¤¨¤Æ¤·¤Þ¤¦
  • ¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¤
  • ´Á»ú¥³¡¼¥É¤Ïµ¤¤Ë¤·¤Ê¤¤
  • dRuby¤Ë¤è¤ë¥µ¡¼¥Ðknock_s.rb¤ÈCGI¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹knock.rb¤Ç¹½À®¤¹¤ë

¤Þ¤º¡¢¼ç½èÍý¤Ç¤¢¤ëknock_s.rb¤ò¸«¤Æ¤ß¤Þ¤¹¡£ KnockPage¤È¤¤¤¦Äê¿ô¤ÇeRuby¥¹¥¯¥ê¥×¥È¤òÄêµÁ¤·¤Æ¤¤¤Þ¤¹¡£ KnockWriter¤¬¥Ú¡¼¥¸¤òÀ¸À®¤¹¤ë¥¯¥é¥¹¤Ç¡¢KnockPage¤«¤é¼¡¤Î¤è¤¦¤Ë¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Æ¤¤¤Þ¤¹¡£

ERB.new(KnockPage).def_method(self, "to_html")

¥á¥½¥Ã¥É²½¤µ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢¼Â¹Ô»þ¤Ëeval¤¹¤ë¤³¤È¤Ï¤¢¤ê¤Þ¤»¤ó¡£

http://www2a.biglobe.ne.jp/%7eseki/ruby/erbd.jpg

knock_s.rb¤ÎÁ´ÂΤÎή¤ì¤Ï¤è¤¯¸«¤«¤±¤ëdRuby¤Î¥×¥í¥°¥é¥à¤Ê¤Î¤Ç²òÀâ¤Ï¾Êά¤·¤Þ¤¹¡£

CGI¤ò¼Â¹Ô¤¹¤ëÁ°¤Ë¡¢knock_s.rb¤òµ¯Æ°¤·¤Æ¤ª¤«¤Ê¤¯¤Æ¤Ï¤Ê¤ê¤Þ¤»¤ó¡£

% cat knock_s.rb
require 'drb/drb'
require 'erb'
require 'monitor'

class Knock
  def initialize(host, str)
    @host = host
    @str = str
    @time = Time.now
  end
  attr_reader :host, :str, :time
end

class KnockHistory
  include MonitorMixin

  def initialize(expire=120)
    super()
    @history = []
    @expire = expire
    @keeper = make_keeper
  end

  def add(host, str)
    synchronize do
      @history.push(Knock.new(host, str))
    end
    true
  end

  def each(&block)
    synchronize do
      @history.each(&block)
    end
  end

  private
  def forget
    time = Time.now - @expire
    synchronize do
      while (knock = @history[0])
        return if knock.time > time
        @history.shift
      end
    end
  end

  def make_keeper
    Thread.new do 
      loop do
	       sleep 5
        forget
      end
    end
  end
end

KnockPage = <<EOP
<ul>
<% @history.each do |k| %>
<li>
<%=h k.host %>(<%= k.time.strftime("%H:%M:%S") %>): <%=h k.str %>
</li>
<% end %>
</ul>
<form action="knock.rb" method="post">
<input type="text" name="knock" />
<input type="submit" name="send" value="send" />
</form>
EOP

class KnockWriter
  include DRbUndumped
  include ERB::Util

  def initialize(history)
    @history = history
  end

  def add(host, str)
    @history.add(host, str)
  end

  ERB.new(KnockPage).def_method(self, "to_html")
end

knock = KnockHistory.new
writer = KnockWriter.new(knock)

DRb.start_service('druby://localhost:8411', writer)
gets

¼¡¤ÏCGI¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹¤Îknock.rb¤Ç¤¹¡£ ´Î¿´¤Ê½èÍý¤òknock_s.rb¤Î¥×¥í¥»¥¹¤ËǤ¤»¤Æ¤¤¤ë¤Î¤Ç »Å»ö¤¬¤¢¤Þ¤ê¤¢¤ê¤Þ¤»¤ó¡£

CGI¤Î¥ê¥¯¥¨¥¹¥È¤«¤éREMOTE_HOST¤Èȯ¸À¤ò¼è¤ê½Ð¤·¤Æ knock¥µ¡¼¥Ð¤ØÁ÷¤ê¤Þ¤¹¡£ ¤½¤Î¸å¡¢knock.to_html¤Ë¤è¤Ã¤Æ¥Ú¡¼¥¸ËÜÂΤÎbody¤ò¼èÆÀ¤·¤Æ¥Ú¡¼¥¸¤òÁȤßΩ¤Æ¤Þ¤¹¡£

% cat knock.rb
#!/usr/local/bin/ruby
require 'drb/drb'
require 'cgi'

cgi = CGI.new('html3')

DRb.start_service
knock = DRbObject.new(nil, 'druby://localhost:8411')

str ,= cgi['knock']

if str && str.size > 0
  host = cgi.remote_host || cgi.remote_addr || 'unknown'
  knock.add(host, str) 
end

cgi.out {
  cgi.html() {
    cgi.head { 
      cgi.title { 'Knock' } +
      '<meta http-equiv="refresh" content="15; url=knock.rb" />'
    } + cgi.body { knock.to_html }
  }
}