Class: Markaby::Builder
Overview
The Markaby::Builder class is the central gear in the system. When using from Ruby code, this is the only class you need to instantiate directly.
mab = Markaby::Builder.new
mab.html do
head { title "Boats.com" }
body do
h1 "Boats.com has great deals"
ul do
li "$49 for a canoe"
li "$39 for a raft"
li "$29 for a huge boot that floats and can fit 5 people"
end
end
end
puts mab.to_s
Direct Known Subclasses
Constant Summary collapse
- @@default =
{ :indent => 0, :output_helpers => true, :output_xml_instruction => true, :output_meta_tag => true, :auto_validation => true, :tagset => Markaby::XHTMLTransitional, :root_attributes => { :xmlns => 'http://www.w3.org/1999/xhtml', :'xml:lang' => 'en', :lang => 'en' } }
Instance Attribute Summary collapse
-
#output_helpers ⇒ Object
Returns the value of attribute output_helpers.
-
#tagset ⇒ Object
Returns the value of attribute tagset.
Class Method Summary collapse
Instance Method Summary collapse
-
#capture(&block) ⇒ Object
Captures the HTML code built inside the
block. -
#head(*args, &block) ⇒ Object
Builds a head tag.
-
#html_tag(sym, *args, &block) ⇒ Object
Every HTML tag method goes through an html_tag call.
-
#initialize(assigns = {}, helpers = nil, &block) ⇒ Builder
constructor
Create a Markaby builder object.
-
#method_missing(sym, *args, &block) ⇒ Object
This method is used to intercept calls to helper methods and instance variables.
-
#tag!(tag, *args, &block) ⇒ Object
Create a tag named
tag. -
#text(string) ⇒ Object
(also: #<<, #concat)
Write a
stringto the HTML stream without escaping it. -
#to_s ⇒ Object
Returns a string containing the HTML stream.
-
#xhtml_frameset(attrs = {}, &block) ⇒ Object
Builds an html tag with XHTML 1.0 Frameset doctype instead.
-
#xhtml_strict(attrs = {}, &block) ⇒ Object
Builds an html tag with XHTML 1.0 Strict doctype instead.
-
#xhtml_transitional(attrs = {}, &block) ⇒ Object
Builds an html tag.
Constructor Details
#initialize(assigns = {}, helpers = nil, &block) ⇒ Builder
Create a Markaby builder object. Pass in a hash of variable assignments to assigns which will be available as instance variables inside tag construction blocks. If an object is passed in to helpers, its methods will be available from those same blocks.
Pass in a block to new and the block will be evaluated.
mab = Markaby::Builder.new {
html do
body do
h1 "Matching Mole"
end
end
}
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/markaby/builder.rb', line 64 def initialize(assigns = {}, helpers = nil, &block) @streams = [[]] @assigns = assigns.dup @helpers = helpers @elements = {} @@default.each do |k, v| instance_variable_set("@#{k}", @assigns.delete(k) || v) end @assigns.each do |k, v| instance_variable_set("@#{k}", v) end @builder = XmlMarkup.new(:indent => @indent, :target => @streams.last) text(capture(&block)) if block end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args, &block) ⇒ Object
This method is used to intercept calls to helper methods and instance variables. Here is the order of interception:
-
If
symis a helper method, the helper method is called and output to the stream. -
If
symis a Builder::XmlMarkup method, it is passed on to the builder object. -
If
symis also the name of an instance variable, the value of the instance variable is returned. -
If
symhas come this far and notagsetis found,symand its arguments are passed to tag! -
If a tagset is found, though,
NoMethodErroris raised.
method_missing used to be the lynchpin in Markaby, but it’s no longer used to handle HTML tags. See html_tag for that.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/markaby/builder.rb', line 166 def method_missing(sym, *args, &block) if @helpers.respond_to?(sym, true) && !self.class.ignored_helpers.include?(sym) r = @helpers.send(sym, *args, &block) if @output_helpers and r.respond_to? :to_str fragment { @builder << r } else r end elsif @assigns.has_key?(sym) @assigns[sym] elsif @assigns.has_key?(stringy_key = sym.to_s) # Rails' ActionView assigns hash has string keys for # instance variables that are defined in the controller. @assigns[stringy_key] elsif instance_variables.include?(ivar = "@#{sym}") instance_variable_get(ivar) elsif !@helpers.nil? && @helpers.instance_variables.include?(ivar) @helpers.instance_variable_get(ivar) elsif ::Builder::XmlMarkup.instance_methods.include?(sym.to_s) @builder.__send__(sym, *args, &block) elsif @tagset.nil? tag!(sym, *args, &block) else raise NoMethodError, "no such method `#{sym}'" end end |
Instance Attribute Details
#output_helpers ⇒ Object
Returns the value of attribute output_helpers.
47 48 49 |
# File 'lib/markaby/builder.rb', line 47 def output_helpers @output_helpers end |
#tagset ⇒ Object
Returns the value of attribute tagset.
47 48 49 |
# File 'lib/markaby/builder.rb', line 47 def @tagset end |
Class Method Details
.ignore_helpers(*helpers) ⇒ Object
43 44 45 |
# File 'lib/markaby/builder.rb', line 43 def self.ignore_helpers(*helpers) ignored_helpers.concat helpers end |
.ignored_helpers ⇒ Object
39 40 41 |
# File 'lib/markaby/builder.rb', line 39 def self.ignored_helpers @@ignored_helpers ||= [] end |
.set(option, value) ⇒ Object
35 36 37 |
# File 'lib/markaby/builder.rb', line 35 def self.set(option, value) @@default[option] = value end |
Instance Method Details
#capture(&block) ⇒ Object
Captures the HTML code built inside the block. This is done by creating a new stream for the builder object, running the block and passing back its stream as a string.
>> Markaby::Builder.new.capture { h1 "TEST"; h2 "CAPTURE ME" }
=> "<h1>TITLE</h1>\n<h2>CAPTURE ME</h2>\n"
102 103 104 105 106 107 108 109 110 111 |
# File 'lib/markaby/builder.rb', line 102 def capture(&block) @streams.push(@builder.target = []) @builder.level += 1 str = instance_eval(&block) str = @streams.last.join if @streams.last.any? @streams.pop @builder.level -= 1 if @builder.level > 1 @builder.target = @streams.last str end |
#head(*args, &block) ⇒ Object
Builds a head tag. Adds a meta tag inside with Content-Type set to text/html; charset=utf-8.
221 222 223 224 225 226 |
# File 'lib/markaby/builder.rb', line 221 def head(*args, &block) tag!(:head, *args) do tag!(:meta, "http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8") if @output_meta_tag instance_eval(&block) end end |
#html_tag(sym, *args, &block) ⇒ Object
Every HTML tag method goes through an html_tag call. So, calling div is equivalent to calling html_tag(:div). All HTML tags in Markaby’s list are given generated wrappers for this method.
If the @auto_validation setting is on, this method will check for many common mistakes which could lead to invalid XHTML.
199 200 201 202 203 204 205 206 207 |
# File 'lib/markaby/builder.rb', line 199 def html_tag(sym, *args, &block) if @auto_validation and @tagset.self_closing.include?(sym) and block raise InvalidXhtmlError, "the `#{sym}' element is self-closing, please remove the block" elsif args.empty? and block.nil? CssProxy.new(self, @streams.last, sym) else tag!(sym, *args, &block) end end |
#tag!(tag, *args, &block) ⇒ Object
Create a tag named tag. Other than the first argument which is the tag name, the arguments are the same as the tags implemented via method_missing.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/markaby/builder.rb', line 115 def tag!(tag, *args, &block) ele_id = nil if @auto_validation and @tagset if !@tagset..has_key?(tag) raise InvalidXhtmlError, "no element `#{tag}' for #{.doctype}" elsif args.last.respond_to?(:to_hash) attrs = args.last.to_hash if @tagset.forms.include?(tag) and attrs[:id] attrs[:name] ||= attrs[:id] end attrs.each do |k, v| atname = k.to_s.downcase.intern unless k =~ /:/ or @tagset.[tag].include? atname raise InvalidXhtmlError, "no attribute `#{k}' on #{tag} elements" end if atname == :id ele_id = v.to_s if @elements.has_key? ele_id raise InvalidXhtmlError, "id `#{ele_id}' already used (id's must be unique)." end end end end end if block str = capture(&block) block = proc { text(str) } elsif !@tagset.self_closing.include?(tag.to_sym) && !args.find{|t|!t.kind_of?(Hash)} block = proc { } end f = fragment { @builder.method_missing(tag, *args, &block) } @elements[ele_id] = f if ele_id f end |
#text(string) ⇒ Object Also known as: <<, concat
Write a string to the HTML stream without escaping it.
89 90 91 92 |
# File 'lib/markaby/builder.rb', line 89 def text(string) @builder << string.to_s nil end |
#to_s ⇒ Object
Returns a string containing the HTML stream. Internally, the stream is stored as an Array.
84 85 86 |
# File 'lib/markaby/builder.rb', line 84 def to_s @streams.last.join end |
#xhtml_frameset(attrs = {}, &block) ⇒ Object
Builds an html tag with XHTML 1.0 Frameset doctype instead.
243 244 245 246 |
# File 'lib/markaby/builder.rb', line 243 def xhtml_frameset(attrs = {}, &block) self. = Markaby::XHTMLFrameset xhtml_html(attrs, &block) end |
#xhtml_strict(attrs = {}, &block) ⇒ Object
Builds an html tag with XHTML 1.0 Strict doctype instead.
237 238 239 240 |
# File 'lib/markaby/builder.rb', line 237 def xhtml_strict(attrs = {}, &block) self. = Markaby::XHTMLStrict xhtml_html(attrs, &block) end |
#xhtml_transitional(attrs = {}, &block) ⇒ Object
Builds an html tag. An XML 1.0 instruction and an XHTML 1.0 Transitional doctype are prepended. Also assumes :xmlns => "http://www.w3.org/1999/xhtml", :lang => "en".
231 232 233 234 |
# File 'lib/markaby/builder.rb', line 231 def xhtml_transitional(attrs = {}, &block) self. = Markaby::XHTMLTransitional xhtml_html(attrs, &block) end |