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.
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. |
[ + ]
# 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
Add directly to buffer.
[ + ]
# File lib/more/facets/buildable.rb, line 289 def <<(s) @buffer << s.to_s end
[ + ]
# 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
Could improve.
[ + ]
# File lib/more/facets/buildable.rb, line 300 def inspect r = super i = r.index(',') return r[0...i] + ">" end
[ + ]
# File lib/more/facets/buildable.rb, line 272 def method_missing(s, *a, &b) build!(s, *a, &b) end
Return buffer
[ + ]
# File lib/more/facets/buildable.rb, line 278 def to_buffer() @buffer end
Return buffer as string.
[ + ]
# File lib/more/facets/buildable.rb, line 284 def to_s() @buffer.to_s end
[ + ]
# File lib/more/facets/buildable.rb, line 285 def to_str() @buffer.to_str end