From: Jim Freeze Date: 2002-05-23T12:20:45+09:00 Subject: Re: method_missing is cool (was: are there unit tests for cgi.rb?) On Wed, May 22, 2002 at 06:09:37AM +0900, Ian Macdonald wrote: > On Tue 21 May 2002 at 01:00:22 +0900, Wakou Aoyama wrote: > > I saw this as a great opportunity to try out Object#method_missing. > > You can get a simple, yet quite effective method for handling any kind > of tag, by using the following interceptor method: > > module HTML > def method_missing(methId, data, attrs = {}) > tag = methId.id2name > tag.upcase! > attr_str = '' > attrs.each do |key, value| > attr_str << sprintf(' %s="%s"', key.upcase, value) > end > sprintf("<%s%s>%s", tag, attr_str, data, tag) > end > end > > > You then call it like this: > > require 'html' > include HTML > > puts a('Google', 'href' => 'http://www.google.com/') > puts ul(li('item1') + li('item2') + li('item3')) > > > The output looks like this: > > Google > > Very nice Ian. I played a little golf with your code and came up with the following: module HTML def method_missing(methId, data, attrs={}) tag = methId.id2name attr = attrs.collect { |k,v| " #{k}=\"#{v}\"" }.join "<#{tag}#{attr}>#{data}" end end It does the same thing, but is a little more compact. Then, I took an old html class I had written and added method missing. module HTML2 def method_missing(methId, attrs={}, &block) tag = methId.id2name attr = attrs.collect { |k,v| " #{k}=\"#{v}\"" }.join "<#{tag}#{attr}>" << yield << "" end end The modules can be used as: class A; include HTML; end a=A.new puts a.a("Link", {'href'=>'http://mylink'}) puts a.h1("Title") # Output Link

Title

-- class A2; include HTML2; end a=A2.new puts a.a({'href'=>'http://mylink'}) { a.h1 { "Title" } } # Output

Title

I like what you did, but I think I like the html2 better since it is seems easier to encapsulate with blocks (at least to me). Then, I made a slight modification to handle single instance entities: module HTML2 def method_missing(methId, attrs={}, &block) tag = methId.id2name attr = attrs.collect { |k,v| " #{k}=\"#{v}\"" }.join if block_given? "<#{tag}#{attr}>" << yield << "" else "<#{tag}#{attr}>" end end end class A2; include HTML2; end a=A2.new puts a.a({'href'=>'http://mylink'}) { a.h1 { "Title" } }, a.br #Output

Title


Thanks for the inspiration. However, as you said, I'm sure someone has done this long ago. But it definitely makes for a very short html utility, even if it doesn't check for validity. -- Jim Freeze If only I had something clever to say for my comment...