Class: BuildingBlock

Inherits:
Object show all
Defined in:
lib/more/facets/buildingblock.rb

Overview

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.

Constant Summary collapse

ESCAPE =

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.

[
  'singleton_method_undefined',
  'respond_to?',
  'instance_eval',
  'inspect',
  'initialize'
]

Instance Method Summary collapse

Constructor Details

#initialize(dslModule, constructor, output_buffer = nil) ⇒ BuildingBlock

Returns a new instance of BuildingBlock.



109
110
111
112
113
114
115
116
117
118
# File 'lib/more/facets/buildingblock.rb', line 109

def initialize(dslModule, constructor, output_buffer=nil)
  @buffer = output_buffer || ''
  @stack  = []

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

  @constructor = constructor
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(s, *a, &b) ⇒ Object



147
148
149
# File 'lib/more/facets/buildingblock.rb', line 147

def method_missing(s, *a, &b)
  build!(s, *a, &b)
end

Instance Method Details

#<<(s) ⇒ Object

Add directly to buffer.



164
165
166
# File 'lib/more/facets/buildingblock.rb', line 164

def <<(s)
  @buffer << s.to_s
end

#build!(s, *a, &b) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/more/facets/buildingblock.rb', line 122

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

#inspectObject

Could improve.



175
176
177
178
179
# File 'lib/more/facets/buildingblock.rb', line 175

def inspect
  r = super
  i = r.index(',')
  return r[0...i] + ">"
end

#to_bufferObject

Return buffer



153
154
155
# File 'lib/more/facets/buildingblock.rb', line 153

def to_buffer()
  @buffer
end

#to_sObject

Return buffer as string.



159
# File 'lib/more/facets/buildingblock.rb', line 159

def to_s()   @buffer.to_s   end

#to_strObject



160
# File 'lib/more/facets/buildingblock.rb', line 160

def to_str() @buffer.to_str end