[LRUG] DSLs for newbies: HTML generation (discuss)

Alex Graul alex.graul at bloomsburyqi.com
Thu Dec 10 05:56:32 PST 2009


That's very close to the syntax of Builder, see http://builder.rubyforge.org/

Cheers,
Alex

On 10 Dec 2009, at 13:49, Daniel Barlow wrote:

> I'm playing with Ruby for the first time (pretty much) and having seen haml I thought it would be fun to play with alternate syntaxes.  This one has much less in the way of funny characters (% and #) and isn't whitespace-sensitive
> 
> It's probably also a really dumb idea.  Like I say, first time Ruby programmer.  Anyway, here's a motivating example of its use
> 
> h=HTML.new
> def h.content
>  html do
>    head { title(:id=>123) {"My page title" }}
>    body do
>      div do
>        h1(:class => "fancy_formatted") {"hello world"}
>        text "some stuff","more stuff"
>        ul {
>          %w(red orange yellow green blue indigo violent).map {|name|
>            li { text name }
>          }
>        }
>      end
>    end
>  end
> end
> h.output
> 
> It's all valid Ruby code.  There is a method (implemented with method_missing) for each HTML element: when called it expects HTML arguments as attributes and a block of element content: it outputs the markup for the start-tag/end-tag and calls the block.
> 
> Inside the block you can call more element-making methods, and/or you can call #text (as shown) to output plain text, and/or you can return some (preferably string) value which will also be output as if by #text
> 
> So,
> - a neat hack?
> - an offence against (your choice of) god?
> - dull and unoriginal and every other newbie did exactly the same thing when learning?
> - really ugly ruby style?
> 
> All criticism welcome.  I'm a Lisp programmer in my day job, so I've almost certainly heard worse.
> 
> Oh, the implementation?  The HTML it generates is not entirely valid (attribute quoting and empty elements are two obvious omissions: introducing all that whitespace, I hazily remember from reading SGML specs back in the day, is probably also wrong) and indenting is hacky, but you get the gist.  It's more about proof-of-concept and playing with the DSL syntax at this stage than production-quality output
> 
> Is Hash.map supposed to work like that, or is it accidental?  It's dashed useful, that I will say
> 
> ---cut here---
> class HTML
>  # this is a partial list for testing, and obviously needs to
>  # be extending to all tags in whatever version of HTML you want
>  # to produce
>  @@allowed_tags=%w(html head title body h1 h2 h3 h4 h5 h6
>                    p div span ul li).map {|n| n.to_sym}
> 
>  def texts(stuff)
>    stuff and
>      stuff.each {|x| x and @content << ("\n"+(" " * @indent)+x) }
>    nil
>  end
> 
>  def text(*stuff)
>    texts stuff
>  end
> 
>  def method_missing(name,*args,&body)
>    if @@allowed_tags.member?(name)
>      attributes = args[0] || [];
>      text "<#{name}"+attributes.map {|k,v| " "+k.to_s+"="+v.to_s }.to_s + ">"
>      @indent=@indent+4;
>      texts body.call
>      @indent=@indent-4;
>      text "</#{name}>"
>    else
>      super # not on our list, let it raise UndefinedMethodError
>    end
>  end
> 
>  def output
>    @content=[]
>    @indent=0
>    content
>    print @content
>    puts
>  end
> end
> ---cut here---
> _______________________________________________
> Chat mailing list
> Chat at lists.lrug.org
> http://lists.lrug.org/listinfo.cgi/chat-lrug.org




More information about the Chat mailing list