erector 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.txt CHANGED
@@ -25,20 +25,25 @@ project site at http://erector.rubyforge.org for more documentation.
25
25
  end
26
26
  body do
27
27
  text "Hello, "
28
- b "#{target}!", :class => 'big'
28
+ b target, :class => 'big'
29
+ text "!"
29
30
  end
30
31
  end
31
32
  end
32
33
  end
33
34
 
34
35
  Hello.new(:target => 'world').to_s
35
- => "<html><head><title>Hello</title></head><body>Hello, <b class=\"big\">world!</b></body></html>"
36
+ => "<html><head><title>Hello</title></head><body>Hello, <b class=\"big\">world</b>!</body></html>"
37
+
38
+ include Erector::Mixin
39
+ erector { div "love", :class => "big" }
40
+ => "<div class=\"big\">love</div>"
36
41
 
37
42
  == REQUIREMENTS
38
43
 
39
- The gem depends on rake and treetop, although this is just for using the "erect" tool,
40
- so deployed applications won't need these. Currently it also requires rails, although
41
- we plan to separate the rails-dependent code so you can use Erector cleanly in a non-Rails app.
44
+ The gem depends on rake and treetop, although this is just for using the command-line tool,
45
+ so deployed applications won't need these. The Rails-dependent code is now separated so
46
+ you can use Erector cleanly in a non-Rails app.
42
47
 
43
48
  == INSTALL
44
49
 
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 6
4
- :patch: 3
4
+ :patch: 4
5
5
 
data/bin/erector CHANGED
@@ -4,4 +4,6 @@ $LOAD_PATH.unshift("#{dir}/../lib")
4
4
  require "erector"
5
5
  require "erector/erect"
6
6
 
7
- Erector::Erect.new(ARGV).run
7
+ unless Erector::Erect.new(ARGV).run
8
+ exit 1
9
+ end
data/lib/erector.rb CHANGED
@@ -10,6 +10,7 @@ require "#{dir}/erector/widget"
10
10
  require "#{dir}/erector/unicode"
11
11
  require "#{dir}/erector/widgets"
12
12
  require "#{dir}/erector/version"
13
+ require "#{dir}/erector/mixin"
13
14
  if Object.const_defined?(:RAILS_ROOT)
14
15
  require "#{dir}/erector/rails"
15
16
  end
data/lib/erector/erect.rb CHANGED
@@ -78,7 +78,9 @@ module Erector
78
78
  end
79
79
 
80
80
  def run
81
+ @success = true
81
82
  self.send(mode)
83
+ @success
82
84
  end
83
85
 
84
86
  def to_erector
@@ -91,7 +93,7 @@ module Erector
91
93
  rescue => e
92
94
  puts e
93
95
  puts e.backtrace.join("\n\t")
94
- puts
96
+ @success = false
95
97
  end
96
98
  end
97
99
  end
@@ -103,7 +105,6 @@ module Erector
103
105
  begin
104
106
  #todo: fail if file isn't a .rb file
105
107
  require file
106
- #todo: understand modulized widgets (e.g. class Foo::Bar::Baz < Erector::Widget in baz.rb)
107
108
  filename = file.split('/').last.gsub(/\.rb$/, '')
108
109
  widget_name = camelize(filename)
109
110
  widget_class = constantize(widget_name)
@@ -124,6 +125,7 @@ module Erector
124
125
  rescue => e
125
126
  puts e
126
127
  puts e.backtrace.join("\n\t")
128
+ @success = false
127
129
  end
128
130
  end
129
131
  end
@@ -6,6 +6,7 @@ Treetop.load("#{dir}/rhtml.treetop")
6
6
 
7
7
  module Erector
8
8
  class Erected
9
+
9
10
  def initialize(in_file)
10
11
  @in_file = in_file
11
12
  end
@@ -14,14 +15,23 @@ module Erector
14
15
  dir + basename + ".rb"
15
16
  end
16
17
 
17
- def classname
18
+ def classnames
18
19
  base = classize(basename)
19
20
  parent = File.dirname(@in_file)
20
21
  grandparent = File.dirname(parent)
21
22
  if File.basename(grandparent) == "views"
22
- base = "Views::" + classize(File.basename(parent)) + "::" + base
23
+ ["Views::" + classize(File.basename(parent)) + "::" + base, "Erector::RailsWidget"]
24
+ else
25
+ [base, "Erector::Widget"]
23
26
  end
24
- base
27
+ end
28
+
29
+ def classname
30
+ classnames[0]
31
+ end
32
+
33
+ def parent_class
34
+ classnames[1]
25
35
  end
26
36
 
27
37
  def text
@@ -36,7 +46,7 @@ module Erector
36
46
  parser.failure_reason
37
47
  else
38
48
  File.open(filename, "w") do |f|
39
- f.puts("class #{classname} < Erector::Widget")
49
+ f.puts("class #{classname} < #{parent_class}")
40
50
  f.puts(" def content")
41
51
  f.puts(parsed.set_indent(2).convert)
42
52
  f.puts(" end")
@@ -0,0 +1,7 @@
1
+ module Erector
2
+ module Mixin
3
+ def erector(options = {}, &block)
4
+ Erector::Widget.new(&block).to_s(options)
5
+ end
6
+ end
7
+ end
@@ -13,7 +13,35 @@ grammar Rhtml
13
13
  end
14
14
 
15
15
  rule node
16
- hprintlet / printlet / scriptlet / doctype / self_closing_tag / imgtag / closetag / opentag / text
16
+ yield_with_name / yield / hprintlet / printlet / scriptlet / doctype / directive / self_closing_tag / imgtag / closetag / opentag / text
17
+ end
18
+
19
+ # Argh. For some reason I can't get this to work, so I split it into two rules
20
+ # rule yield
21
+ # '<%=' space 'yield' space (':' varname space)? '%>' <Erector::Indenting> {
22
+ # def convert
23
+ # var = "@content_for_" + varname.nil? ? "layout" : varname.text_value
24
+ # line "rawtext #{var} # Note: you must define #{var} elsewhere"
25
+ # end
26
+ # }
27
+ # end
28
+
29
+ rule yield_with_name
30
+ '<%=' space 'yield' space ':' varname space '%>' <Erector::Indenting> {
31
+ def convert
32
+ var = "@content_for_" + varname.text_value
33
+ line "rawtext #{var} # Note: you must define #{var} elsewhere"
34
+ end
35
+ }
36
+ end
37
+
38
+ rule yield
39
+ '<%=' space 'yield' space '%>' <Erector::Indenting> {
40
+ def convert
41
+ var = "@content_for_layout"
42
+ line "rawtext #{var} # Note: you must define #{var} elsewhere"
43
+ end
44
+ }
17
45
  end
18
46
 
19
47
  rule scriptlet
@@ -53,10 +81,6 @@ grammar Rhtml
53
81
  code = text_value.strip
54
82
  # matches a word, followed by either a word, a string, or a symbol
55
83
  result = code.gsub(/^(\w+) ([\w:"'].*)$/, '\1(\2)')
56
-
57
- # Convert yield, for layouts
58
- #result.gsub!(/^yield$/, '@content')
59
-
60
84
  result
61
85
  end
62
86
  }
@@ -69,15 +93,27 @@ grammar Rhtml
69
93
  end
70
94
  }
71
95
  end
96
+
97
+ rule directive
98
+ '<!' [^>]* '>' <Erector::Indenting> {
99
+ def convert
100
+ line "rawtext '#{text_value}'"
101
+ end
102
+ }
103
+ end
72
104
 
73
105
  rule tagname
74
106
  [A-Za-z0-9_:-]+
75
107
  end
108
+
109
+ rule varname
110
+ [A-Za-z0-9_]+
111
+ end
76
112
 
77
113
  rule self_closing_tag
78
114
  '<' tag_name:tagname attrs:attributes? space '/>' <Erector::Indenting> {
79
115
  def convert
80
- line "#{tag_name.text_value}#{attrs.blank? ? "" : attrs.convert}"
116
+ line "#{tag_name.text_value}#{attrs.empty? ? "" : attrs.convert}"
81
117
  end
82
118
  }
83
119
  end
@@ -85,7 +121,7 @@ grammar Rhtml
85
121
  rule opentag
86
122
  '<' tag_name:tagname attrs:attributes? space '>' <Erector::Indenting> {
87
123
  def convert
88
- line_in "#{tag_name.text_value}#{attrs.blank? ? "" : attrs.convert} do"
124
+ line_in "#{tag_name.text_value}#{attrs.empty? ? "" : attrs.convert} do"
89
125
  end
90
126
  }
91
127
  end
@@ -93,7 +129,7 @@ grammar Rhtml
93
129
  rule imgtag
94
130
  '<' tag_name:'img' attrs:attributes? space '>' <Erector::Indenting> {
95
131
  def convert
96
- line "#{tag_name.text_value}#{attrs.blank? ? "" : attrs.convert}"
132
+ line "#{tag_name.text_value}#{attrs.empty? ? "" : attrs.convert}"
97
133
  end
98
134
  }
99
135
  end
@@ -110,10 +146,11 @@ grammar Rhtml
110
146
  (([<>] !(tagname / [/%!])) / [^<>])+ <Erector::Indenting> {
111
147
  def convert
112
148
  stripped = text_value.strip
113
- if stripped.blank?
149
+ if stripped.empty?
114
150
  ""
115
151
  else
116
- line "text '#{text_value.strip.html_unescape}'"
152
+ line "text '#{stripped.html_unescape.gsub(/\'/, "\\\\'")
153
+ }'"
117
154
  end
118
155
  end
119
156
  }
@@ -123,7 +160,7 @@ grammar Rhtml
123
160
  first:attribute rest:attributes* {
124
161
  def convert
125
162
  " " + first.convert +
126
- if rest.blank?
163
+ if rest.empty?
127
164
  ""
128
165
  else
129
166
  ",#{rest.elements.first.convert}" # this is hacky -- is there a better way?
@@ -2,45 +2,49 @@ module Erector
2
2
 
3
3
  # A Widget is the center of the Erector universe.
4
4
  #
5
- # To create a widget, extend Erector::Widget and implement
6
- # the +content+ method. Inside this method you may call any of the tag methods like +span+ or +p+ to emit HTML/XML
7
- # tags.
8
- #
9
- # You can also define a widget on the fly by passing a block to +new+. This block will get executed when the widget's
10
- # +content+ method is called.
5
+ # To create a widget, extend Erector::Widget and implement the +content+
6
+ # method. Inside this method you may call any of the tag methods like +span+
7
+ # or +p+ to emit HTML/XML tags.
8
+ #
9
+ # You can also define a widget on the fly by passing a block to +new+. This
10
+ # block will get executed when the widget's +content+ method is called.
11
11
  #
12
- # To render a widget from the outside, instantiate it and call its +to_s+ method.
12
+ # To render a widget from the outside, instantiate it and call its +to_s+
13
+ # method.
13
14
  #
14
- # A widget's +new+ method optionally accepts an options hash. Entries in this hash are converted to instance
15
- # variables, and +attr_reader+ accessors are defined for each.
15
+ # A widget's +new+ method optionally accepts an options hash. Entries in
16
+ # this hash are converted to instance variables, and +attr_reader+ accessors
17
+ # are defined for each.
16
18
  #
17
- # TODO: You can add runtime input checking via the +needs+ macro. If any of the variables named via
18
- # +needs+ are absent, an exception is thrown. Optional variables are specified with +wants+. If a variable appears
19
- # in the options hash that is in neither the +needs+ nor +wants+ lists, then that too provokes an exception.
20
- # This mechanism is meant to ameliorate development-time confusion about exactly what parameters are supported
21
- # by a given widget, avoiding confusing runtime NilClass errors.
22
- #
23
- # To call one widget from another, inside the parent widget's +content+ method, instantiate the child widget and call
24
- # the +widget+ method. This assures that the same output stream
25
- # is used, which gives better performance than using +capture+ or +to_s+. It also preserves the indentation and
26
- # helpers of the enclosing class.
27
- #
28
- # In this documentation we've tried to keep the distinction clear between methods that *emit* text and those that
29
- # *return* text. "Emit" means that it writes to the output stream; "return" means that it returns a string
30
- # like a normal method and leaves it up to the caller to emit that string if it wants.
19
+ # You can add runtime input checking via the +needs+ macro. See #needs.
20
+ # This mechanism is meant to ameliorate development-time confusion about
21
+ # exactly what parameters are supported by a given widget, avoiding
22
+ # confusing runtime NilClass errors.
23
+ #
24
+ # To call one widget from another, inside the parent widget's +content+
25
+ # method, instantiate the child widget and call the +widget+ method. This
26
+ # assures that the same output stream is used, which gives better
27
+ # performance than using +capture+ or +to_s+. It also preserves the
28
+ # indentation and helpers of the enclosing class.
29
+ #
30
+ # In this documentation we've tried to keep the distinction clear between
31
+ # methods that *emit* text and those that *return* text. "Emit" means that
32
+ # it writes to the output stream; "return" means that it returns a string
33
+ # like a normal method and leaves it up to the caller to emit that string if
34
+ # it wants.
31
35
  class Widget
32
36
  class << self
33
37
  def all_tags
34
38
  Erector::Widget.full_tags + Erector::Widget.empty_tags
35
39
  end
36
40
 
37
- # tags which are always self-closing
41
+ # Tags which are always self-closing. Click "[Source]" to see the full list.
38
42
  def empty_tags
39
43
  ['area', 'base', 'br', 'col', 'frame',
40
44
  'hr', 'img', 'input', 'link', 'meta']
41
45
  end
42
46
 
43
- # tags which can contain other stuff
47
+ # Tags which can contain other stuff. Click "[Source]" to see the full list.
44
48
  def full_tags
45
49
  [
46
50
  'a', 'abbr', 'acronym', 'address',
@@ -81,36 +85,37 @@ module Erector
81
85
  end
82
86
  end
83
87
 
84
- # Class method by which widget classes can declare that they need certain parameters.
85
- # If needed parameters are not passed in to #new, then an exception will be thrown
86
- # (with a hopefully useful message about which parameters are missing). This is intended
87
- # to catch silly bugs like passing in a parameter called 'name' to a widget that expects
88
- # a parameter called 'title'. Every variable declared in 'needs' will get an attr_reader
89
- # accessor declared for it.
88
+ # Class method by which widget classes can declare that they need certain
89
+ # parameters. If needed parameters are not passed in to #new, then an
90
+ # exception will be thrown (with a hopefully useful message about which
91
+ # parameters are missing). This is intended to catch silly bugs like
92
+ # passing in a parameter called 'name' to a widget that expects a
93
+ # parameter called 'title'. Every variable declared in 'needs' will get an
94
+ # attr_reader accessor declared for it.
90
95
  #
91
- # You can also declare default values for parameters using hash syntax. You can put #needs
92
- # declarations on multiple lines or on the same line; the only caveat is that if there are
93
- # default values, they all have to be at the end of the line (so they go into the magic
94
- # hash parameter).
96
+ # You can also declare default values for parameters using hash syntax.
97
+ # You can put #needs declarations on multiple lines or on the same line;
98
+ # the only caveat is that if there are default values, they all have to be
99
+ # at the end of the line (so they go into the magic hash parameter).
95
100
  #
96
- # If a widget has no #needs declaration then it will accept any combination of parameters
97
- # (and make accessors for them) just like normal. In that case there will be no 'attr_reader's
98
- # declared.
99
- # If a widget wants to declare that it
100
- # takes no parameters, use the special incantation "needs nil" (and don't declare any other
101
- # needs, or kittens will cry).
101
+ # If a widget has no #needs declaration then it will accept any
102
+ # combination of parameters (and make accessors for them) just like
103
+ # normal. In that case there will be no 'attr_reader's declared. If a
104
+ # widget wants to declare that it takes no parameters, use the special
105
+ # incantation "needs nil" (and don't declare any other needs, or kittens
106
+ # will cry).
102
107
  #
103
108
  # Usage:
104
109
  # class FancyForm < Erector::Widget
105
110
  # needs :title, :show_okay => true, :show_cancel => false
106
111
  # ...
107
112
  # end
108
- #
109
- # That means that
113
+ #
114
+ # That means that
110
115
  # FancyForm.new(:title => 'Login')
111
- # will succeed, as will
116
+ # will succeed, as will
112
117
  # FancyForm.new(:title => 'Login', :show_cancel => true)
113
- # but
118
+ # but
114
119
  # FancyForm.new(:name => 'Login')
115
120
  # will fail.
116
121
  #
@@ -237,25 +242,38 @@ module Erector
237
242
  to_s(:prettyprint => true)
238
243
  end
239
244
 
240
- # Entry point for rendering a widget (and all its children). This method creates a new output string (if necessary),
241
- # calls this widget's #content method and returns the string.
245
+ # Entry point for rendering a widget (and all its children). This method
246
+ # creates a new output string (if necessary), calls this widget's #content
247
+ # method and returns the string.
242
248
  #
243
249
  # Options:
244
250
  # output:: the string to output to. Default: a new empty string
245
- # prettyprint:: whether Erector should add newlines and indentation. Default: the value of prettyprint_default (which is false by default).
246
- # indentation:: the amount of spaces to indent. Ignored unless prettyprint is true.
247
- # helpers:: a helpers object containing utility methods. Usually this is a Rails view object.
248
- # content_method_name:: in case you want to call a method other than #content, pass its name in here.
249
- #
250
- # Note: Prettyprinting is an experimental feature and is subject to change
251
- # (either in terms of how it is enabled, or in terms of
252
- # what decisions Erector makes about where to add whitespace).
251
+ # prettyprint:: whether Erector should add newlines and indentation.
252
+ # Default: the value of prettyprint_default (which is false
253
+ # by default).
254
+ # indentation:: the amount of spaces to indent. Ignored unless prettyprint
255
+ # is true.
256
+ # helpers:: a helpers object containing utility methods. Usually this is a
257
+ # Rails view object.
258
+ # content_method_name:: in case you want to call a method other than
259
+ # #content, pass its name in here.
253
260
  def to_s(options = {}, &blk)
254
-
255
261
  raise "Erector::Widget#to_s now takes an options hash, not a symbol. Try calling \"to_s(:content_method_name=> :#{options})\"" if options.is_a? Symbol
256
-
262
+ _render(options, &blk).to_s
263
+ end
264
+
265
+ # Entry point for rendering a widget (and all its children). Same as #to_s
266
+ # only it returns an array, for theoretical performance improvements when using a
267
+ # Rack server (like Sinatra or Rails Metal).
268
+ #
269
+ # # Options: see #to_s
270
+ def to_a(options = {}, &blk)
271
+ _render(options, &blk).to_a
272
+ end
273
+
274
+ def _render(options = {}, &blk)
257
275
  options = {
258
- :output => "",
276
+ :output => "", # "" is apparently faster than [] in a long-running process
259
277
  :prettyprint => prettyprint_default,
260
278
  :indentation => 0,
261
279
  :helpers => nil,
@@ -263,24 +281,29 @@ module Erector
263
281
  }.merge(options)
264
282
  context(options[:output], options[:prettyprint], options[:indentation], options[:helpers]) do
265
283
  send(options[:content_method_name], &blk)
266
- output.to_s
284
+ output
267
285
  end
268
286
  end
269
287
 
270
288
  alias_method :inspect, :to_s
271
289
 
272
- # Template method which must be overridden by all widget subclasses. Inside this method you call the magic
273
- # #element methods which emit HTML and text to the output string.
290
+ # Template method which must be overridden by all widget subclasses.
291
+ # Inside this method you call the magic #element methods which emit HTML
292
+ # and text to the output string. If you call "super" (or don't override
293
+ # +content+) then your widget will render any block that was passed into
294
+ # its constructor (in the current instance context so it can get access
295
+ # to parent widget methods via method_missing).
274
296
  def content
275
297
  if @block
276
298
  instance_eval(&@block)
277
299
  end
278
300
  end
279
301
 
280
- # To call one widget from another, inside the parent widget's +content+ method, instantiate the child widget and call
281
- # its +write_via+ method, passing in +self+. This assures that the same output string
282
- # is used, which gives better performance than using +capture+ or +to_s+.
283
- # You can also use the +widget+ method.
302
+ # To call one widget from another, inside the parent widget's +content+
303
+ # method, instantiate the child widget and call its +write_via+ method,
304
+ # passing in +self+. This assures that the same output string is used,
305
+ # which gives better performance than using +capture+ or +to_s+. You can
306
+ # also use the +widget+ method.
284
307
  def write_via(parent)
285
308
  @parent = parent
286
309
  context(parent.output, parent.prettyprint, parent.indentation, parent.helpers) do
@@ -288,13 +311,14 @@ module Erector
288
311
  end
289
312
  end
290
313
 
291
- # Emits a (nested) widget onto the current widget's output stream. Accepts either
292
- # a class or an instance. If the first argument is a class, then the second argument
293
- # is a hash used to populate its instance variables. If the first argument is an
294
- # instance then the hash must be unspecified (or empty).
314
+ # Emits a (nested) widget onto the current widget's output stream. Accepts
315
+ # either a class or an instance. If the first argument is a class, then
316
+ # the second argument is a hash used to populate its instance variables.
317
+ # If the first argument is an instance then the hash must be unspecified
318
+ # (or empty).
295
319
  #
296
- # The sub-widget will have access to the methods of the parent class, via some method_missing
297
- # magic and a "parent" pointer.
320
+ # The sub-widget will have access to the methods of the parent class, via
321
+ # some method_missing magic and a "parent" pointer.
298
322
  def widget(target, assigns={}, &block)
299
323
  child = if target.is_a? Class
300
324
  target.new(assigns, &block)
@@ -315,40 +339,46 @@ module Erector
315
339
  #-- methods for subclasses to call
316
340
  #++
317
341
 
318
- # Internal method used to emit an HTML/XML element, including an open tag, attributes (optional, via the default hash),
319
- # contents (also optional), and close tag.
342
+ # Internal method used to emit an HTML/XML element, including an open tag,
343
+ # attributes (optional, via the default hash), contents (also optional),
344
+ # and close tag.
320
345
  #
321
- # Using the arcane powers of Ruby, there are magic methods that call +element+ for all the standard
322
- # HTML tags, like +a+, +body+, +p+, and so forth. Look at the source of #full_tags for the full list.
323
- # Unfortunately, this big mojo confuses rdoc, so we can't see each method in this rdoc page, but trust
324
- # us, they're there.
346
+ # Using the arcane powers of Ruby, there are magic methods that call
347
+ # +element+ for all the standard HTML tags, like +a+, +body+, +p+, and so
348
+ # forth. Look at the source of #full_tags for the full list.
349
+ # Unfortunately, this big mojo confuses rdoc, so we can't see each method
350
+ # in this rdoc page, but trust us, they're there.
325
351
  #
326
- # When calling one of these magic methods, put attributes in the default hash. If there is a string parameter,
327
- # then it is used as the contents. If there is a block, then it is executed (yielded), and the string parameter is ignored.
328
- # The block will usually be in the scope of the child widget, which means it has access to all the
329
- # methods of Widget, which will eventually end up appending text to the +output+ string. See how
330
- # elegant it is? Not confusing at all if you don't think about it.
352
+ # When calling one of these magic methods, put attributes in the default
353
+ # hash. If there is a string parameter, then it is used as the contents.
354
+ # If there is a block, then it is executed (yielded), and the string
355
+ # parameter is ignored. The block will usually be in the scope of the
356
+ # child widget, which means it has access to all the methods of Widget,
357
+ # which will eventually end up appending text to the +output+ string. See
358
+ # how elegant it is? Not confusing at all if you don't think about it.
331
359
  #
332
360
  def element(*args, &block)
333
361
  __element__(*args, &block)
334
362
  end
335
363
 
336
- # Internal method used to emit a self-closing HTML/XML element, including a tag name and optional attributes
337
- # (passed in via the default hash).
338
- #
339
- # Using the arcane powers of Ruby, there are magic methods that call +empty_element+ for all the standard
340
- # HTML tags, like +img+, +br+, and so forth. Look at the source of #empty_tags for the full list.
341
- # Unfortunately, this big mojo confuses rdoc, so we can't see each method in this rdoc page, but trust
342
- # us, they're there.
364
+ # Internal method used to emit a self-closing HTML/XML element, including
365
+ # a tag name and optional attributes (passed in via the default hash).
366
+ #
367
+ # Using the arcane powers of Ruby, there are magic methods that call
368
+ # +empty_element+ for all the standard HTML tags, like +img+, +br+, and so
369
+ # forth. Look at the source of #empty_tags for the full list.
370
+ # Unfortunately, this big mojo confuses rdoc, so we can't see each method
371
+ # in this rdoc page, but trust us, they're there.
343
372
  #
344
373
  def empty_element(*args, &block)
345
374
  __empty_element__(*args, &block)
346
375
  end
347
376
 
348
- # Returns an HTML-escaped version of its parameter. Leaves the output string untouched. Note that
349
- # the #text method automatically HTML-escapes its parameter, so be careful *not* to do something like
350
- # text(h("2<4")) since that will double-escape the less-than sign (you'll get "2&amp;lt;4" instead of
351
- # "2&lt;4").
377
+ # Returns an HTML-escaped version of its parameter. Leaves the output
378
+ # string untouched. Note that the #text method automatically HTML-escapes
379
+ # its parameter, so be careful *not* to do something like text(h("2<4"))
380
+ # since that will double-escape the less-than sign (you'll get
381
+ # "2&amp;lt;4" instead of "2&lt;4").
352
382
  def h(content)
353
383
  content.html_escape
354
384
  end
@@ -358,20 +388,20 @@ module Erector
358
388
  indent_for_open_tag(tag_name)
359
389
  @indentation += SPACES_PER_INDENT
360
390
 
361
- output.concat "<#{tag_name}#{format_attributes(attributes)}>"
391
+ output << "<#{tag_name}#{format_attributes(attributes)}>"
362
392
  @at_start_of_line = false
363
393
  end
364
394
 
365
- # Emits text. If a string is passed in, it will be HTML-escaped.
366
- # If a widget or the result of calling methods such as raw
367
- # is passed in, the HTML will not be HTML-escaped again.
368
- # If another kind of object is passed in, the result of calling
369
- # its to_s method will be treated as a string would be.
395
+ # Emits text. If a string is passed in, it will be HTML-escaped. If a
396
+ # widget or the result of calling methods such as raw is passed in, the
397
+ # HTML will not be HTML-escaped again. If another kind of object is passed
398
+ # in, the result of calling its to_s method will be treated as a string
399
+ # would be.
370
400
  def text(value)
371
401
  if value.is_a? Widget
372
402
  widget value
373
403
  else
374
- output.concat(value.html_escape)
404
+ output <<(value.html_escape)
375
405
  end
376
406
  @at_start_of_line = false
377
407
  nil
@@ -410,12 +440,12 @@ module Erector
410
440
  end
411
441
  end
412
442
 
413
- # Emits a close tag, consisting of '<', tag name, and '>'
443
+ # Emits a close tag, consisting of '<', '/', tag name, and '>'
414
444
  def close_tag(tag_name)
415
445
  @indentation -= SPACES_PER_INDENT
416
446
  indent()
417
447
 
418
- output.concat("</#{tag_name}>")
448
+ output <<("</#{tag_name}>")
419
449
 
420
450
  if newliney(tag_name)
421
451
  _newline
@@ -438,12 +468,13 @@ module Erector
438
468
 
439
469
  # Emits an XML instruction, which looks like this: <?xml version=\"1.0\" encoding=\"UTF-8\"?>
440
470
  def instruct(attributes={:version => "1.0", :encoding => "UTF-8"})
441
- output.concat "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
471
+ output << "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
442
472
  end
443
473
 
444
- # Creates a whole new output string, executes the block, then converts the output string to a string and
445
- # emits it as raw text. If at all possible you should avoid this method since it hurts performance,
446
- # and use +content+ or +write_via+ instead.
474
+ # Creates a whole new output string, executes the block, then converts the
475
+ # output string to a string and emits it as raw text. If at all possible
476
+ # you should avoid this method since it hurts performance, and use
477
+ # +widget+ or +write_via+ instead.
447
478
  def capture(&block)
448
479
  begin
449
480
  original_output = output
@@ -475,7 +506,8 @@ module Erector
475
506
  )
476
507
  end
477
508
 
478
- # Emits a javascript block inside a +script+ tag, wrapped in CDATA doohickeys like all the cool JS kids do.
509
+ # Emits a javascript block inside a +script+ tag, wrapped in CDATA
510
+ # doohickeys like all the cool JS kids do.
479
511
  def javascript(*args, &block)
480
512
  if args.length > 2
481
513
  raise ArgumentError, "Cannot accept more than two arguments"
@@ -514,16 +546,17 @@ module Erector
514
546
  rawtext "\n"
515
547
  end
516
548
 
517
- # Convenience method to emit a css file link, which looks like this:
549
+ # Convenience method to emit a css file link, which looks like this:
518
550
  # <link href="erector.css" rel="stylesheet" type="text/css" />
519
- # The parameter is the full contents of the href attribute, including any ".css" extension.
551
+ # The parameter is the full contents of the href attribute, including any ".css" extension.
520
552
  #
521
553
  # If you want to emit raw CSS inline, use the #style method instead.
522
554
  def css(href)
523
555
  link :rel => 'stylesheet', :type => 'text/css', :href => href
524
556
  end
525
557
 
526
- # Convenience method to emit an anchor tag whose href and text are the same, e.g. <a href="http://example.com">http://example.com</a>
558
+ # Convenience method to emit an anchor tag whose href and text are the same,
559
+ # e.g. <a href="http://example.com">http://example.com</a>
527
560
  def url(href)
528
561
  a href, :href => href
529
562
  end
@@ -581,7 +614,7 @@ protected
581
614
  def __empty_element__(tag_name, attributes={})
582
615
  indent_for_open_tag(tag_name)
583
616
 
584
- output.concat "<#{tag_name}#{format_attributes(attributes)} />"
617
+ output << "<#{tag_name}#{format_attributes(attributes)} />"
585
618
 
586
619
  if newliney(tag_name)
587
620
  _newline
@@ -590,7 +623,7 @@ protected
590
623
 
591
624
  def _newline
592
625
  return unless @prettyprint
593
- output.concat "\n"
626
+ output << "\n"
594
627
  @at_start_of_line = true
595
628
  end
596
629
 
@@ -604,7 +637,7 @@ protected
604
637
 
605
638
  def indent()
606
639
  if @at_start_of_line
607
- output.concat " " * @indentation
640
+ output << " " * [@indentation, 0].max
608
641
  end
609
642
  end
610
643