pivotal-erector 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/README.txt +5 -5
  2. data/VERSION.yml +2 -2
  3. data/bin/{erect → erector} +0 -0
  4. data/lib/erector/erect.rb +1 -1
  5. data/lib/erector/erected.rb +1 -1
  6. data/lib/erector/rails/extensions/action_controller.rb +25 -7
  7. data/lib/erector/rails/extensions/{widget.rb → rails_widget/helpers.rb} +2 -9
  8. data/lib/erector/rails/extensions/{widget/2.2.0/widget.rb → rails_widget.rb} +4 -2
  9. data/lib/erector/rails/rails_version.rb +6 -0
  10. data/lib/erector/rails/template_handlers/action_view_template_handler.rb +43 -11
  11. data/lib/erector/rails.rb +2 -1
  12. data/lib/erector/version.rb +1 -1
  13. data/lib/erector/widget.rb +213 -73
  14. data/lib/erector/widgets/table.rb +3 -3
  15. data/spec/erector/indentation_spec.rb +39 -24
  16. data/spec/erector/widget_spec.rb +197 -64
  17. data/spec/erector/widgets/table_spec.rb +3 -3
  18. data/spec/spec.opts +1 -0
  19. data/spec/spec_helper.rb +1 -4
  20. data/spec/spec_suite.rb +6 -12
  21. metadata +18 -30
  22. data/lib/erector/rails/extensions/action_controller/1.2.5/action_controller.rb +0 -17
  23. data/lib/erector/rails/extensions/action_controller/2.2.0/action_controller.rb +0 -26
  24. data/lib/erector/rails/extensions/widget/1.2.5/widget.rb +0 -18
  25. data/lib/erector/rails/supported_rails_versions.rb +0 -14
  26. data/lib/erector/rails/template_handlers/1.2.5/action_view_template_handler.rb +0 -32
  27. data/lib/erector/rails/template_handlers/2.0.0/action_view_template_handler.rb +0 -36
  28. data/lib/erector/rails/template_handlers/2.1.0/action_view_template_handler.rb +0 -31
  29. data/lib/erector/rails/template_handlers/2.2.0/action_view_template_handler.rb +0 -46
  30. data/spec/erect/erect_spec.rb +0 -145
  31. data/spec/erect/erected_spec.rb +0 -80
  32. data/spec/erect/rhtml_parser_spec.rb +0 -318
data/README.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  = Erector
2
2
 
3
3
  * http://erector.rubyforge.org
4
- * mailto:erector-devel@rubyforge.org
4
+ * mailto:erector@googlegroups.com
5
5
  * http://www.pivotaltracker.com/projects/482
6
6
 
7
7
  == DESCRIPTION
@@ -18,20 +18,20 @@ project site at http://erector.rubyforge.org for more documentation.
18
18
  require 'erector'
19
19
 
20
20
  class Hello < Erector::Widget
21
- def render
21
+ def content
22
22
  html do
23
23
  head do
24
24
  title "Hello"
25
25
  end
26
26
  body do
27
27
  text "Hello, "
28
- b "world!", :class => 'big'
28
+ b "#{target}!", :class => 'big'
29
29
  end
30
30
  end
31
31
  end
32
32
  end
33
33
 
34
- Hello.new.to_s
34
+ Hello.new(:target => 'world').to_s
35
35
  => "<html><head><title>Hello</title></head><body>Hello, <b class=\"big\">world!</b></body></html>"
36
36
 
37
37
  == REQUIREMENTS
@@ -59,7 +59,7 @@ When installing this way, erector is automatically available to your Rails code
59
59
 
60
60
  (The MIT License)
61
61
 
62
- Copyright (c) 2007-8 Pivotal Labs
62
+ Copyright (c) 2007-2009 Pivotal Labs
63
63
 
64
64
  Permission is hereby granted, free of charge, to any person obtaining
65
65
  a copy of this software and associated documentation files (the
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 5
4
- :patch: 1
3
+ :minor: 6
4
+ :patch: 0
File without changes
data/lib/erector/erect.rb CHANGED
@@ -11,7 +11,7 @@ module Erector
11
11
  @output_dir = nil
12
12
 
13
13
  opts = OptionParser.new do |opts|
14
- opts.banner = "Usage: erect [options] [file|dir]*"
14
+ opts.banner = "Usage: erector [options] [file|dir]*"
15
15
 
16
16
  opts.separator "Converts from html/rhtml files to erector widgets, or from erector widgets to html files"
17
17
  opts.separator ""
@@ -37,7 +37,7 @@ module Erector
37
37
  else
38
38
  File.open(filename, "w") do |f|
39
39
  f.puts("class #{classname} < Erector::Widget")
40
- f.puts(" def render")
40
+ f.puts(" def content")
41
41
  f.puts(parsed.set_indent(2).convert)
42
42
  f.puts(" end")
43
43
  f.puts("end")
@@ -1,8 +1,26 @@
1
- dir = File.dirname(__FILE__)
2
- if (
3
- ActionController::Base.instance_methods + ActionController::Base.private_instance_methods).
4
- include?("add_variables_to_assigns")
5
- require File.expand_path("#{dir}/action_controller/1.2.5/action_controller")
6
- else
7
- require File.expand_path("#{dir}/action_controller/2.2.0/action_controller")
1
+ ActionController::Base.class_eval do
2
+ def render_widget(widget_class, assigns=nil)
3
+ @__widget_class = widget_class
4
+ if assigns
5
+ @__widget_assigns = assigns
6
+ else
7
+ @__widget_assigns = {}
8
+ variables = instance_variable_names
9
+ variables -= protected_instance_variables
10
+ variables.each do |name|
11
+ @__widget_assigns[name.sub('@', "")] = instance_variable_get(name)
12
+ end
13
+ end
14
+ response.template.send(:_evaluate_assigns_and_ivars)
15
+ render :inline => "<% @__widget_class.new(@__widget_assigns).to_s(:output => output_buffer, :helpers => self) %>"
16
+ end
17
+
18
+ def render_with_erector_widget(*options, &block)
19
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
20
+ render_widget widget, @assigns, &block
21
+ else
22
+ render_without_erector_widget *options, &block
23
+ end
24
+ end
25
+ alias_method_chain :render, :erector_widget
8
26
  end
@@ -1,5 +1,5 @@
1
1
  module Erector
2
- Widget.class_eval do
2
+ class RailsWidget < Widget
3
3
  include ActionController::UrlWriter
4
4
 
5
5
  # helpers returning raw text
@@ -105,13 +105,6 @@ module Erector
105
105
 
106
106
  def pluralize(*args)
107
107
  helpers.pluralize(*args)
108
- end
108
+ end
109
109
  end
110
110
  end
111
-
112
- dir = File.dirname(__FILE__)
113
- if ActionView::Base.instance_methods.include?("output_buffer")
114
- require "#{dir}/widget/2.2.0/widget"
115
- else
116
- require "#{dir}/widget/1.2.5/widget"
117
- end
@@ -1,5 +1,5 @@
1
1
  module Erector
2
- Widget.class_eval do
2
+ class RailsWidget < Widget
3
3
  def output
4
4
  process_output_buffer || @output
5
5
  end
@@ -7,7 +7,7 @@ module Erector
7
7
  def capture_with_helpers(&block)
8
8
  helpers ? helpers.capture(&block) : capture_without_helpers(&block)
9
9
  end
10
-
10
+
11
11
  alias_method_chain :capture, :helpers
12
12
 
13
13
  # This is here to force #helpers.capture to return the output
@@ -34,3 +34,5 @@ module Erector
34
34
  end
35
35
  end
36
36
  end
37
+
38
+ require "#{File.dirname(__FILE__)}/rails_widget/helpers"
@@ -0,0 +1,6 @@
1
+ module Erector
2
+ module Rails
3
+ RAILS_VERSION = "2.3.2"
4
+ RAILS_VERSION_TAG = "v2.3.2"
5
+ end
6
+ end
@@ -1,14 +1,46 @@
1
- dir = File.dirname(__FILE__)
2
- if ActionView.const_defined?(:TemplateHandlers)
3
- if ::ActionView::TemplateHandlers::const_defined?(:Compilable)
4
- if ActionView.const_defined?(:TemplateHandlers) && ::ActionView::TemplateHandlers::ERB.respond_to?(:erb_trim_mode)
5
- require File.expand_path("#{dir}/2.2.0/action_view_template_handler")
6
- else
7
- require File.expand_path("#{dir}/2.1.0/action_view_template_handler")
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector < TemplateHandler
4
+ include Compilable
5
+ def self.line_offset
6
+ 2
7
+ end
8
+
9
+ ActionView::Template.instance_eval do
10
+ register_template_handler :rb, ActionView::TemplateHandlers::Erector
11
+ end
12
+
13
+ def compile(template)
14
+ relative_path_parts = template.path.split('/')
15
+
16
+ is_partial = relative_path_parts.last =~ /^_/
17
+ require_dependency File.expand_path(template.filename)
18
+
19
+ widget_class_parts = relative_path_parts.inject(['Views']) do |class_parts, node|
20
+ class_parts << node.gsub(/^_/, "").gsub(/(\.html)?\.rb$/, '').camelize
21
+ class_parts
22
+ end
23
+ widget_class_name = widget_class_parts.join("::")
24
+ render_method = is_partial ? 'render_partial' : 'content'
25
+
26
+ erb_template = <<-ERB
27
+ <%
28
+ assigns = instance_variables.inject({}) do |hash, name|
29
+ hash[name.sub('@', "")] = instance_variable_get(name)
30
+ hash
31
+ end
32
+
33
+ widget = #{widget_class_name}.new(assigns)
34
+ widget.to_s(:output => output_buffer, :helpers => self, :content_method_name => :#{render_method})
35
+ %>
36
+ ERB
37
+ ::ERB.new(
38
+ erb_template,
39
+ nil,
40
+ ::ActionView::TemplateHandlers::ERB.erb_trim_mode,
41
+ "@output_buffer"
42
+ ).src
43
+ end
8
44
  end
9
- else
10
- require File.expand_path("#{dir}/2.0.0/action_view_template_handler")
11
45
  end
12
- else
13
- require File.expand_path("#{dir}/1.2.5/action_view_template_handler")
14
46
  end
data/lib/erector/rails.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  dir = File.dirname(__FILE__)
2
2
  require "action_controller"
3
- require "#{dir}/rails/extensions/widget"
3
+ require "#{dir}/rails/rails_version"
4
+ require "#{dir}/rails/extensions/rails_widget"
4
5
  require "#{dir}/rails/extensions/action_controller"
5
6
  require "#{dir}/rails/extensions/action_view"
6
7
  require "#{dir}/rails/template_handlers/action_view_template_handler"
@@ -4,7 +4,7 @@ module Erector
4
4
  if !Erector.const_defined?(:VERSION)
5
5
  dir = File.dirname(__FILE__)
6
6
  version = YAML.load_file(File.expand_path("#{dir}/../../VERSION.yml"))
7
- VERSION = "#{version['major']}.#{version['minor']}.#{version['patch']}"
7
+ VERSION = "#{version[:major]}.#{version[:minor]}.#{version[:patch]}"
8
8
  end
9
9
  end
10
10
 
@@ -3,17 +3,27 @@ module Erector
3
3
  # A Widget is the center of the Erector universe.
4
4
  #
5
5
  # To create a widget, extend Erector::Widget and implement
6
- # the +render+ method. Inside this method you may call any of the tag methods like +span+ or +p+ to emit HTML/XML
6
+ # the +content+ method. Inside this method you may call any of the tag methods like +span+ or +p+ to emit HTML/XML
7
7
  # tags.
8
8
  #
9
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
- # +render+ method is called.
10
+ # +content+ method is called.
11
11
  #
12
12
  # To render a widget from the outside, instantiate it and call its +to_s+ method.
13
+ #
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.
16
+ #
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.
13
22
  #
14
- # To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
15
- # its +render_to+ method, passing in +self+ (or self.output if you prefer). This assures that the same output
16
- # is used, which gives better performance than using +capture+ or +to_s+.
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.
17
27
  #
18
28
  # In this documentation we've tried to keep the distinction clear between methods that *emit* text and those that
19
29
  # *return* text. "Emit" means that it writes to the output stream; "return" means that it returns a string
@@ -64,13 +74,64 @@ module Erector
64
74
  raise ArgumentError, "You must provide either an instance or a block"
65
75
  end
66
76
  end
67
-
77
+
68
78
  protected
69
79
  def after_initialize_parts
70
80
  @after_initialize_parts ||= []
71
81
  end
72
82
  end
73
83
 
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.
90
+ #
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).
95
+ #
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).
102
+ #
103
+ # Usage:
104
+ # class FancyForm < Erector::Widget
105
+ # needs :title, :show_okay => true, :show_cancel => false
106
+ # ...
107
+ # end
108
+ #
109
+ # That means that
110
+ # FancyForm.new(:title => 'Login')
111
+ # will succeed, as will
112
+ # FancyForm.new(:title => 'Login', :show_cancel => true)
113
+ # but
114
+ # FancyForm.new(:name => 'Login')
115
+ # will fail.
116
+ #
117
+ def self.needs(*args)
118
+ args.each do |arg|
119
+ (@needs ||= []) << (arg.nil? ? nil : (arg.is_a? Hash) ? arg : arg.to_sym)
120
+ end
121
+ end
122
+
123
+ protected
124
+ def self.get_needs
125
+ @needs ||= []
126
+ parent = self.ancestors[1]
127
+ if parent.respond_to? :get_needs
128
+ parent.get_needs + @needs
129
+ else
130
+ @needs
131
+ end
132
+ end
133
+
134
+ public
74
135
  @@prettyprint_default = false
75
136
  def prettyprint_default
76
137
  @@prettyprint_default
@@ -87,95 +148,163 @@ module Erector
87
148
 
88
149
  SPACES_PER_INDENT = 2
89
150
 
90
- attr_reader :helpers, :assigns, :block, :parent, :output
91
- attr_accessor :enable_prettyprint
151
+ attr_reader :helpers, :assigns, :block, :parent, :output, :prettyprint, :indentation
92
152
 
93
- def initialize(helpers=nil, assigns={}, output = "", &block)
153
+ def initialize(assigns={}, &block)
154
+ unless assigns.is_a? Hash
155
+ raise "Erector's API has changed. Now you should pass only an options hash into Widget.new; the rest come in via to_s, or by using #widget."
156
+ end
157
+ if (respond_to? :render) &&
158
+ !self.method(:render).to_s.include?("(RailsWidget)")
159
+ raise "Erector's API has changed. You should rename #{self.class}#render to #content."
160
+ end
94
161
  @assigns = assigns
95
162
  assign_locals(assigns)
96
- @helpers = helpers
97
163
  @parent = block ? eval("self", block.binding) : nil
98
- @output = output
99
164
  @block = block
100
- @at_start_of_line = true
101
- @indent = 0
102
- @enable_prettyprint = prettyprint_default
103
165
  self.class.after_initialize self
104
166
  end
105
167
 
106
168
  #-- methods for other classes to call, left public for ease of testing and documentation
107
169
  #++
108
170
 
171
+ protected
172
+ def context(output, prettyprint = false, indentation = 0, helpers = nil)
173
+ #TODO: pass in options hash, maybe, instead of parameters
174
+ original_output = @output
175
+ original_indendation = @indentation
176
+ original_helpers = @helpers
177
+ original_prettyprint = @prettyprint
178
+ @output = output
179
+ @at_start_of_line = true
180
+ raise "indentation must be a number, not #{indentation.inspect}" unless indentation.is_a? Fixnum
181
+ @indentation = indentation
182
+ @helpers = helpers
183
+ @prettyprint = prettyprint
184
+ yield
185
+ ensure
186
+ @output = original_output
187
+ @indentation = original_indendation
188
+ @helpers = original_helpers
189
+ @prettyprint = original_prettyprint
190
+ end
191
+
192
+ public
109
193
  def assign_locals(local_assigns)
110
- local_assigns.each do |name, value|
111
- instance_variable_set("@#{name}", value)
194
+ needed = self.class.get_needs.map{|need| need.is_a?(Hash) ? need.keys : need}.flatten
195
+ assigned = []
196
+ local_assigns.each do |name, value|
197
+ unless needed.empty? || needed.include?(name)
198
+ raise "Unknown parameter '#{name}'. #{self.class.name} only accepts #{needed.join(', ')}"
199
+ end
200
+ assign_local(name, value)
201
+ assigned << name
202
+ end
203
+
204
+ # set variables with default values
205
+ self.class.get_needs.select{|var| var.is_a? Hash}.each do |hash|
206
+ hash.each_pair do |name, value|
207
+ unless assigned.include?(name)
208
+ assign_local(name, value)
209
+ assigned << name
210
+ end
211
+ end
212
+ end
213
+
214
+ missing = needed - assigned
215
+ unless missing.empty? || missing == [nil]
216
+ raise "Missing parameter#{missing.size == 1 ? '' : 's'}: #{missing.join(', ')}"
217
+ end
218
+ end
219
+
220
+ def assign_local(name, value)
221
+ instance_variable_set("@#{name}", value)
222
+ if any_are_needed?
112
223
  metaclass.module_eval do
113
224
  attr_reader name
114
225
  end
115
226
  end
116
227
  end
117
228
 
118
- # Set whether Erector should add newlines and indentation in to_s.
119
- # This is an experimental feature and is subject to change
120
- # (either in terms of how it is enabled, or in terms of
121
- # what decisions Erector makes about where to add whitespace).
122
- # This flag should be set prior to any rendering being done
123
- # (for example, calls to to_s or to_pretty).
124
- def enable_prettyprint(enable)
125
- self.enable_prettyprint = enable
126
- self
229
+ def any_are_needed?
230
+ !self.class.get_needs.empty?
127
231
  end
128
-
232
+
129
233
  # Render (like to_s) but adding newlines and indentation.
234
+ # This is a convenience method; you may just want to call to_s(:prettyprint => true)
235
+ # so you can pass in other rendering options as well.
130
236
  def to_pretty
131
- enable_prettyprint(true).to_s
237
+ to_s(:prettyprint => true)
132
238
  end
133
239
 
134
- # Entry point for rendering a widget (and all its children). This method creates a new output string,
135
- # calls this widget's #render method and returns the string.
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.
242
+ #
243
+ # Options:
244
+ # 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.
136
249
  #
137
- # If it's called again later
138
- # then it returns the earlier rendered string, which may lead to higher performance, but may have confusing
139
- # effects if some underlying state has changed. In general we recommend you create a new instance of every
140
- # widget for each render, unless you know what you're doing.
141
- def to_s(render_method_name=:render, &blk)
142
- # The @__to_s variable is used as a cache.
143
- # If it's useful we should add a test for it. -ac
144
- return @__to_s if @__to_s
145
- send(render_method_name, &blk)
146
- @__to_s = output.to_s
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).
253
+ def to_s(options = {}, &blk)
254
+
255
+ 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
+
257
+ options = {
258
+ :output => "",
259
+ :prettyprint => prettyprint_default,
260
+ :indentation => 0,
261
+ :helpers => nil,
262
+ :content_method_name => :content,
263
+ }.merge(options)
264
+ context(options[:output], options[:prettyprint], options[:indentation], options[:helpers]) do
265
+ send(options[:content_method_name], &blk)
266
+ output.to_s
267
+ end
147
268
  end
148
269
 
149
270
  alias_method :inspect, :to_s
150
-
271
+
151
272
  # Template method which must be overridden by all widget subclasses. Inside this method you call the magic
152
273
  # #element methods which emit HTML and text to the output string.
153
- def render
274
+ def content
154
275
  if @block
155
276
  instance_eval(&@block)
156
277
  end
157
278
  end
158
279
 
159
- # To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
160
- # its +render_to+ method, passing in +self+ (or self.output if you prefer). This assures that the same output string
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
161
282
  # is used, which gives better performance than using +capture+ or +to_s+.
162
- def render_to(output_or_widget)
163
- if output_or_widget.is_a?(Widget)
164
- @parent = output_or_widget
165
- @output = @parent.output
166
- else
167
- @output = output_or_widget
283
+ # You can also use the +widget+ method.
284
+ def write_via(parent)
285
+ @parent = parent
286
+ context(parent.output, parent.prettyprint, parent.indentation, parent.helpers) do
287
+ content
168
288
  end
169
- render
170
289
  end
171
290
 
172
- # Convenience method for on-the-fly widgets. This is a way of making
173
- # a sub-widget which still has access to the methods of the parent class.
174
- # This is an experimental erector feature which may disappear in future
175
- # versions of erector (see #widget in widget_spec in the Erector tests).
176
- def widget(widget_class, assigns={}, &block)
177
- child = widget_class.new(helpers, assigns, output, &block)
178
- child.render
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).
295
+ #
296
+ # The sub-widget will have access to the methods of the parent class, via some method_missing
297
+ # magic and a "parent" pointer.
298
+ def widget(target, assigns={}, &block)
299
+ child = if target.is_a? Class
300
+ target.new(assigns, &block)
301
+ else
302
+ unless assigns.empty?
303
+ raise "Unexpected second parameter. Did you mean to pass in variables when you instantiated the #{target.class.to_s}?"
304
+ end
305
+ target
306
+ end
307
+ child.write_via(self)
179
308
  end
180
309
 
181
310
  # (Should we make this hidden?)
@@ -227,7 +356,7 @@ module Erector
227
356
  # Emits an open tag, comprising '<', tag name, optional attributes, and '>'
228
357
  def open_tag(tag_name, attributes={})
229
358
  indent_for_open_tag(tag_name)
230
- @indent += SPACES_PER_INDENT
359
+ @indentation += SPACES_PER_INDENT
231
360
 
232
361
  output.concat "<#{tag_name}#{format_attributes(attributes)}>"
233
362
  @at_start_of_line = false
@@ -239,7 +368,11 @@ module Erector
239
368
  # If another kind of object is passed in, the result of calling
240
369
  # its to_s method will be treated as a string would be.
241
370
  def text(value)
242
- output.concat(value.html_escape)
371
+ if value.is_a? Widget
372
+ widget value
373
+ else
374
+ output.concat(value.html_escape)
375
+ end
243
376
  @at_start_of_line = false
244
377
  nil
245
378
  end
@@ -279,20 +412,19 @@ module Erector
279
412
 
280
413
  # Emits a close tag, consisting of '<', tag name, and '>'
281
414
  def close_tag(tag_name)
282
- @indent -= SPACES_PER_INDENT
415
+ @indentation -= SPACES_PER_INDENT
283
416
  indent()
284
417
 
285
418
  output.concat("</#{tag_name}>")
286
419
 
287
420
  if newliney(tag_name)
288
- output.concat "\n"
289
- @at_start_of_line = true
421
+ _newline
290
422
  end
291
423
  end
292
424
 
293
425
  # Emits the result of joining the elements in array with the separator.
294
426
  # The array elements and separator can be Erector::Widget objects,
295
- # which are rendered, or strings, which are quoted and output.
427
+ # which are rendered, or strings, which are html-escaped and output.
296
428
  def join(array, separator)
297
429
  first = true
298
430
  array.each do |widget_or_text|
@@ -311,7 +443,7 @@ module Erector
311
443
 
312
444
  # Creates a whole new output string, executes the block, then converts the output string to a string and
313
445
  # emits it as raw text. If at all possible you should avoid this method since it hurts performance,
314
- # and use #render_to instead.
446
+ # and use +content+ or +write_via+ instead.
315
447
  def capture(&block)
316
448
  begin
317
449
  original_output = output
@@ -382,10 +514,11 @@ module Erector
382
514
  rawtext "\n"
383
515
  end
384
516
 
385
- # Convenience method to emit a css file link, which looks like this: <link href="erector.css" rel="stylesheet" type="text/css" />
517
+ # Convenience method to emit a css file link, which looks like this:
518
+ # <link href="erector.css" rel="stylesheet" type="text/css" />
386
519
  # The parameter is the full contents of the href attribute, including any ".css" extension.
387
520
  #
388
- # If you want to emit raw CSS inline, use the #script method instead.
521
+ # If you want to emit raw CSS inline, use the #style method instead.
389
522
  def css(href)
390
523
  link :rel => 'stylesheet', :type => 'text/css', :href => href
391
524
  end
@@ -396,7 +529,7 @@ module Erector
396
529
  end
397
530
 
398
531
  def newliney(tag_name)
399
- if @enable_prettyprint
532
+ if @prettyprint
400
533
  !NON_NEWLINEY.include?(tag_name)
401
534
  else
402
535
  false
@@ -434,6 +567,9 @@ protected
434
567
  end
435
568
  attributes ||= {}
436
569
  open_tag tag_name, attributes
570
+ if block && value
571
+ raise ArgumentError, "You can't pass both a block and a value to #{tag_name} -- please choose one."
572
+ end
437
573
  if block
438
574
  instance_eval(&block)
439
575
  else
@@ -448,23 +584,27 @@ protected
448
584
  output.concat "<#{tag_name}#{format_attributes(attributes)} />"
449
585
 
450
586
  if newliney(tag_name)
451
- output.concat "\n"
452
- @at_start_of_line = true
587
+ _newline
453
588
  end
454
589
  end
590
+
591
+ def _newline
592
+ return unless @prettyprint
593
+ output.concat "\n"
594
+ @at_start_of_line = true
595
+ end
455
596
 
456
597
  def indent_for_open_tag(tag_name)
598
+ return unless @prettyprint
457
599
  if !@at_start_of_line && newliney(tag_name)
458
- output.concat "\n"
459
- @at_start_of_line = true
600
+ _newline
460
601
  end
461
-
462
602
  indent()
463
603
  end
464
604
 
465
605
  def indent()
466
606
  if @at_start_of_line
467
- output.concat " " * @indent
607
+ output.concat " " * @indentation
468
608
  end
469
609
  end
470
610