erector 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
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