BuildingBlock

Build content programatically with Ruby and Ruby‘s blocks.

  require 'facets'
  require 'xmlhelper'

  builder = BuildingBlock.new(XMLHelper, :element)

  doc = builder.html do

    head do
      title "Test"
    end

    body do
      i "Hello"
      br
      text "Test"
      text "Hey"
    end

  end

produces

  <html><head><title>Test</title><body><i>Hello</i><br />TestHey</body></html>

All calls within the block are routed via the Helper Module‘s constructor method (element in the above example) unless they are defined by the helper module, in which case they are sent to the helper module directly. The results of these invocations are appended to the output buffer. To prevent this, prefix the method with ‘call_’.

Sometimes keywords can get in the way of a construction. In these cases you can ensure use of constructor method by calling the special build! command. You can also add verbatium text to the output via the #<< operator. Some common Ruby‘s built-in methods treated as keywords:

     inspect
     instance_eval
     respond_to?
     singleton_method_undefined
     initialize
     method_missing
     to_str
     to_s

And a few other speciality methods besides:

     to_buffer
     build!
     <<

This work was of course inspired by many great minds, and represents a concise and simple means of accomplishing this pattern of design, which is unique to Ruby.

Methods
<< build! inspect method_missing new to_buffer to_s to_str
Constants
ESCAPE = [ 'singleton_method_undefined', 'respond_to?', 'instance_eval', 'inspect', 'initialize'
  NOTE: When debugging, you may want to add the ‘p’ entry. TODO: There may be other methods that need to be in this exception list.
Public Class methods
new(dslModule, constructor, output_buffer=nil)
# File lib/more/facets/buildable.rb, line 234
  def initialize(dslModule, constructor, output_buffer=nil)
    @buffer = output_buffer || ''
    @stack  = []

    @dsl = Class.new{
      include dslModule
    }.new

    @constructor = constructor
  end
Public Instance methods
<<(s)

Add directly to buffer.

# File lib/more/facets/buildable.rb, line 289
  def <<(s)
    @buffer << s.to_s
  end
build!(s, *a, &b)
# File lib/more/facets/buildable.rb, line 247
  def build!(s, *a, &b)
    s = s.to_s

    if b
      @stack << @buffer
      @buffer = ''
      instance_eval(&b)
      out = @buffer
      @buffer = @stack.pop
      a.unshift(out)
    end

    if s =~ /^call_/
      m = s[5..-1].to_sym
      @dsl.send(m, *a, &b).to_s
    elsif @dsl.respond_to?(s) #o =~ /^build_/
      @buffer << @dsl.send(s, *a, &b).to_s
    else
      s = s.chomp('?') if s[-1,1] == '?'
      @buffer << @dsl.send(@constructor, s, *a).to_s
    end
  end
inspect()

Could improve.

# File lib/more/facets/buildable.rb, line 300
  def inspect
    r = super
    i = r.index(',')
    return r[0...i] + ">"
  end
method_missing(s, *a, &b)
# File lib/more/facets/buildable.rb, line 272
  def method_missing(s, *a, &b)
    build!(s, *a, &b)
  end
to_buffer()

Return buffer

# File lib/more/facets/buildable.rb, line 278
  def to_buffer()
    @buffer
  end
to_s()

Return buffer as string.

# File lib/more/facets/buildable.rb, line 284
  def to_s()   @buffer.to_s   end
to_str()
# File lib/more/facets/buildable.rb, line 285
  def to_str() @buffer.to_str end