pivotal-erector 0.5.1 → 0.6.0

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.
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