erector 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -13,6 +13,8 @@ modular decomposition, encapsulation) in views. See the rdoc for the
13
13
  Erector::Widget class to learn how to make your own widgets, and visit the
14
14
  project site at http://erector.rubyforge.org for more documentation.
15
15
 
16
+ No, seriously, we've got hella docs at http://erector.rubyforge.org
17
+
16
18
  == SYNOPSIS
17
19
 
18
20
  require 'erector'
@@ -25,7 +27,7 @@ project site at http://erector.rubyforge.org for more documentation.
25
27
  end
26
28
  body do
27
29
  text "Hello, "
28
- b target, :class => 'big'
30
+ b @target, :class => 'big'
29
31
  text "!"
30
32
  end
31
33
  end
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 7
4
- :patch: 0
4
+ :patch: 1
@@ -6,6 +6,7 @@ require "active_support/inflector"
6
6
  require "active_support/inflections"
7
7
  require "#{dir}/erector/extensions/object"
8
8
  require "#{dir}/erector/raw_string"
9
+ require "#{dir}/erector/externals"
9
10
  require "#{dir}/erector/widget"
10
11
  require "#{dir}/erector/inline"
11
12
  require "#{dir}/erector/unicode"
@@ -0,0 +1,29 @@
1
+ module Erector
2
+ module Externals
3
+ def externals(type, klass = nil)
4
+ type = type.to_sym
5
+ assure_externals_declared(type, klass)
6
+ x = @@externals[type].dup
7
+ if klass
8
+ x.select{|value| @@externals[klass].include?(value)}
9
+ else
10
+ x
11
+ end
12
+ end
13
+
14
+ def assure_externals_declared(type, klass)
15
+ @@externals ||= {}
16
+ @@externals[type] ||= []
17
+ @@externals[klass] ||= [] if klass
18
+ end
19
+
20
+ def external(type, value)
21
+ type = type.to_sym
22
+ klass = self # since it's a class method, self should be the class itself
23
+ assure_externals_declared(type, klass)
24
+ @@externals[type] << value unless @@externals[type].include?(value)
25
+ @@externals[klass] << value unless @@externals[klass].include?(value)
26
+ end
27
+ end
28
+
29
+ end
@@ -1,7 +1,10 @@
1
1
  dir = File.dirname(__FILE__)
2
2
  require "action_controller"
3
3
  require "#{dir}/rails/rails_version"
4
+ require "#{dir}/rails/rails_form_builder"
4
5
  require "#{dir}/rails/extensions/rails_widget"
5
6
  require "#{dir}/rails/extensions/action_controller"
6
7
  require "#{dir}/rails/extensions/action_view"
7
- require "#{dir}/rails/template_handlers/action_view_template_handler"
8
+ require "#{dir}/rails/extensions/rails_widget/rails_helpers"
9
+ require "#{dir}/rails/template_handlers/rb_handler"
10
+ require "#{dir}/rails/template_handlers/ert_handler"
@@ -12,7 +12,7 @@ ActionController::Base.class_eval do
12
12
  end
13
13
  end
14
14
  response.template.send(:_evaluate_assigns_and_ivars)
15
- render :inline => "<% @__widget_class.new(@__widget_assigns).to_s(:output => output_buffer, :helpers => self) %>"
15
+ render :inline => "<% @__widget_class.new(@__widget_assigns.merge(:parent => self)).to_s %>"
16
16
  end
17
17
 
18
18
  def render_with_erector_widget(*options, &block)
@@ -8,40 +8,37 @@ module Erector
8
8
  process_output_buffer || @output
9
9
  end
10
10
 
11
- def capture_with_helpers(&block)
12
- helpers ? helpers.capture(&block) : capture_without_helpers(&block)
11
+ def capture_with_parent(&block)
12
+ parent ? parent.capture(&block) : capture_without_parent(&block)
13
13
  end
14
14
 
15
- alias_method_chain :capture, :helpers
15
+ alias_method_chain :capture, :parent
16
16
 
17
- # This is here to force #helpers.capture to return the output
17
+ # This is here to force #parent.capture to return the output
18
18
  def __in_erb_template; end
19
19
 
20
20
  private
21
21
 
22
22
  def process_output_buffer
23
- if helpers.respond_to?(:output_buffer)
24
- buffer = helpers.output_buffer
25
- buffer.is_a?(String) ? buffer : handle_rjs_buffer
23
+ if parent.respond_to?(:output_buffer)
24
+ parent.output_buffer.is_a?(String) ? parent.output_buffer : handle_rjs_buffer
26
25
  else
27
26
  nil
28
27
  end
29
28
  end
30
29
 
31
30
  def handle_rjs_buffer
32
- returning buffer = helpers.output_buffer.dup.to_s do
33
- helpers.output_buffer.clear
34
- helpers.with_output_buffer(buffer) do
35
- buffer << helpers.output_buffer.to_s
31
+ returning buffer = parent.output_buffer.dup.to_s do
32
+ parent.output_buffer.clear
33
+ parent.with_output_buffer(buffer) do
34
+ buffer << parent.output_buffer.to_s
36
35
  end
37
36
  end
38
37
  end
39
38
  end
40
-
39
+
41
40
  class InlineRailsWidget < RailsWidget
42
41
  include Inline
43
42
  end
44
-
45
- end
46
43
 
47
- require "#{File.dirname(__FILE__)}/rails_widget/helpers"
44
+ end
@@ -0,0 +1,136 @@
1
+ module Erector
2
+ class RailsWidget < Widget
3
+ module RailsHelpers
4
+ include ActionController::UrlWriter
5
+
6
+ # parent returning raw text whose first parameter is HTML escaped
7
+ ESCAPED_HELPERS = [
8
+ :link_to,
9
+ :link_to_remote,
10
+ :mail_to,
11
+ :button_to,
12
+ :submit_tag,
13
+ ]
14
+ ESCAPED_HELPERS.each do |method_name|
15
+ start_line = __LINE__ + 2
16
+ method_def =<<-METHOD_DEF
17
+ def #{method_name}(link_text, *args, &block)
18
+ rawtext(parent.#{method_name}(h(link_text), *args, &block))
19
+ end
20
+ METHOD_DEF
21
+ eval(method_def, binding, __FILE__, start_line)
22
+ end
23
+
24
+ # return text, take block
25
+ RAW_HELPERS = [
26
+ :link_to_function,
27
+ :text_field_tag,
28
+ :password_field_tag,
29
+ :check_box_tag,
30
+ :error_messages_for,
31
+ :submit_tag,
32
+ :file_field,
33
+ :image_tag,
34
+ :javascript_include_tag,
35
+ :stylesheet_link_tag,
36
+ :sortable_element,
37
+ :sortable_element_js,
38
+ :text_field_with_auto_complete
39
+ ]
40
+ RAW_HELPERS.each do |method_name|
41
+ start_line = __LINE__ + 2
42
+ method_def =<<-METHOD_DEF
43
+ def #{method_name}(*args, &block)
44
+ rawtext parent.#{method_name}(*args, &block)
45
+ end
46
+ METHOD_DEF
47
+ eval(method_def, binding, __FILE__, start_line)
48
+ end
49
+
50
+ CAPTURED_HELPERS_WITHOUT_CONCAT = [
51
+ :render
52
+ ]
53
+ CAPTURED_HELPERS_WITHOUT_CONCAT.each do |method_name|
54
+ start_line = __LINE__ + 2
55
+ method_def =<<-METHOD_DEF
56
+ def #{method_name}(*args, &block)
57
+ captured = parent.capture do
58
+ parent.concat(parent.#{method_name}(*args, &block))
59
+ parent.output_buffer.to_s
60
+ end
61
+ rawtext(captured)
62
+ end
63
+ METHOD_DEF
64
+ eval(method_def, binding, __FILE__, start_line)
65
+ end
66
+
67
+ CAPTURED_HELPERS_WITH_CONCAT = [
68
+ :form_tag
69
+ ]
70
+ CAPTURED_HELPERS_WITH_CONCAT.each do |method_name|
71
+ start_line = __LINE__ + 2
72
+ method_def =<<-METHOD_DEF
73
+ def #{method_name}(*args, &block)
74
+ captured = parent.capture do
75
+ parent.#{method_name}(*args, &block)
76
+ parent.output_buffer.to_s
77
+ end
78
+ rawtext(captured)
79
+ end
80
+ METHOD_DEF
81
+ eval(method_def, binding, __FILE__, start_line)
82
+ end
83
+
84
+ def form_for(record_or_name_or_array, *args, &proc)
85
+ options = args.extract_options!
86
+ options[:builder] ||= ::Erector::RailsFormBuilder
87
+ args.push(options)
88
+ parent.form_for(record_or_name_or_array, *args, &proc)
89
+ end
90
+
91
+ def fields_for(record_or_name_or_array, *args, &proc)
92
+ options = args.extract_options!
93
+ options[:builder] ||= ::Erector::RailsFormBuilder
94
+ args.push(options)
95
+ parent.fields_for(record_or_name_or_array, *args, &proc)
96
+ end
97
+
98
+ def javascript_include_merged(key)
99
+ parent.javascript_include_merged(key)
100
+ end
101
+
102
+ def stylesheet_link_merged(key)
103
+ parent.stylesheet_link_merged(key)
104
+ end
105
+
106
+ def flash
107
+ parent.controller.send(:flash)
108
+ end
109
+
110
+ def session
111
+ parent.controller.session
112
+ end
113
+
114
+ def controller
115
+ parent.controller
116
+ end
117
+
118
+ def cycle(*args)
119
+ parent.cycle(*args)
120
+ end
121
+
122
+ def simple_format(string)
123
+ p raw(string.to_s.html_escape.gsub(/\r\n?/, "\n").gsub(/\n/, "<br/>\n"))
124
+ end
125
+
126
+ def time_ago_in_words(*args)
127
+ parent.time_ago_in_words(*args)
128
+ end
129
+
130
+ def pluralize(*args)
131
+ parent.pluralize(*args)
132
+ end
133
+ end
134
+ include RailsHelpers
135
+ end
136
+ end
@@ -0,0 +1,20 @@
1
+ module Erector
2
+ class RailsFormBuilder
3
+ attr_reader :parent, :template
4
+
5
+ def initialize(object_name, object, template, options, proc)
6
+ @template = template
7
+ @parent = ActionView::Helpers::FormBuilder.new(object_name, object, template, options, proc)
8
+ end
9
+
10
+ def method_missing(method_name, *args, &block)
11
+ if parent.respond_to?(method_name)
12
+ return_value = parent.send(method_name, *args, &block)
13
+ template.concat(return_value) if return_value.is_a?(String)
14
+ return_value
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,6 @@
1
1
  module Erector
2
2
  module Rails
3
- RAILS_VERSION = "2.3.2"
4
- RAILS_VERSION_TAG = "v2.3.2"
3
+ RAILS_VERSION = "2.3.4"
4
+ RAILS_VERSION_TAG = "v2.3.4"
5
5
  end
6
6
  end
@@ -0,0 +1,32 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class ErtTemplate < TemplateHandler
4
+ include Compilable
5
+ def self.line_offset
6
+ 2
7
+ end
8
+
9
+ ActionView::Template.instance_eval do
10
+ register_template_handler :ert, ActionView::TemplateHandlers::ErtTemplate
11
+ end
12
+
13
+ def compile(template)
14
+ [
15
+ "extend ::Erector::Mixin",
16
+ "@output_buffer = ''",
17
+ "memoized_instance_variables = instance_variables.inject({}) do |all, instance_variable|",
18
+ " all[instance_variable] = instance_variable_get(instance_variable)",
19
+ " all",
20
+ "end",
21
+ "r =::Erector::RailsWidget.inline do",
22
+ " memoized_instance_variables.each do |instance_variable, value|",
23
+ " instance_variable_set(instance_variable, value)",
24
+ " end",
25
+ template.source,
26
+ "end",
27
+ "r.to_s",
28
+ ].join("; ")
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,13 +1,13 @@
1
1
  module ActionView #:nodoc:
2
2
  module TemplateHandlers #:nodoc:
3
- class Erector < TemplateHandler
3
+ class RbHandler < TemplateHandler
4
4
  include Compilable
5
5
  def self.line_offset
6
6
  2
7
7
  end
8
8
 
9
9
  ActionView::Template.instance_eval do
10
- register_template_handler :rb, ActionView::TemplateHandlers::Erector
10
+ register_template_handler :rb, ActionView::TemplateHandlers::RbHandler
11
11
  end
12
12
 
13
13
  def compile(template)
@@ -33,6 +33,8 @@ module Erector
33
33
  # like a normal method and leaves it up to the caller to emit that string if
34
34
  # it wants.
35
35
  class Widget
36
+ extend Erector::Externals # 'extend'ing since they're class methods, not instance methods
37
+
36
38
  class << self
37
39
  def all_tags
38
40
  Erector::Widget.full_tags + Erector::Widget.empty_tags
@@ -84,6 +86,7 @@ module Erector
84
86
  def after_initialize_parts
85
87
  @after_initialize_parts ||= []
86
88
  end
89
+
87
90
  end
88
91
 
89
92
  # Class method by which widget classes can declare that they need certain
@@ -153,21 +156,20 @@ module Erector
153
156
 
154
157
  SPACES_PER_INDENT = 2
155
158
 
156
- RESERVED_INSTANCE_VARS = [:helpers, :assigns, :block, :parent, :output, :prettyprint, :indentation, :at_start_of_line]
159
+ RESERVED_INSTANCE_VARS = [:helpers, :assigns, :block, :output, :prettyprint, :indentation, :at_start_of_line]
157
160
 
158
161
  attr_reader *RESERVED_INSTANCE_VARS
162
+ attr_reader :parent
159
163
 
160
164
  def initialize(assigns={}, &block)
161
165
  unless assigns.is_a? Hash
162
166
  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."
163
167
  end
164
- if (respond_to? :render) &&
165
- !self.method(:render).to_s.include?("(RailsWidget)")
166
- raise "Erector's API has changed. You should rename #{self.class}#render to #content."
167
- end
168
168
  @assigns = assigns
169
- assign_locals(assigns)
170
- @parent = block ? eval("self", block.binding) : nil
169
+ assign_instance_variables(assigns)
170
+ unless @parent
171
+ @parent = block ? eval("self", block.binding) : nil
172
+ end
171
173
  @block = block
172
174
  self.class.after_initialize self
173
175
  end
@@ -197,14 +199,14 @@ module Erector
197
199
  end
198
200
 
199
201
  public
200
- def assign_locals(local_assigns)
202
+ def assign_instance_variables (instance_variables)
201
203
  needed = self.class.get_needs.map{|need| need.is_a?(Hash) ? need.keys : need}.flatten
202
204
  assigned = []
203
- local_assigns.each do |name, value|
205
+ instance_variables.each do |name, value|
204
206
  unless needed.empty? || needed.include?(name)
205
207
  raise "Unknown parameter '#{name}'. #{self.class.name} only accepts #{needed.join(', ')}"
206
208
  end
207
- assign_local(name, value)
209
+ assign_instance_variable(name, value)
208
210
  assigned << name
209
211
  end
210
212
 
@@ -212,7 +214,7 @@ module Erector
212
214
  self.class.get_needs.select{|var| var.is_a? Hash}.each do |hash|
213
215
  hash.each_pair do |name, value|
214
216
  unless assigned.include?(name)
215
- assign_local(name, value)
217
+ assign_instance_variable(name, value)
216
218
  assigned << name
217
219
  end
218
220
  end
@@ -224,9 +226,11 @@ module Erector
224
226
  end
225
227
  end
226
228
 
227
- def assign_local(name, value)
229
+ def assign_instance_variable (name, value)
228
230
  raise ArgumentError, "Sorry, #{name} is a reserved variable name for Erector. Please choose a different name." if RESERVED_INSTANCE_VARS.include?(name)
229
- instance_variable_set("@#{name}", value)
231
+ name = name.to_s
232
+ ivar_name = (name[0..0] == '@' ? name : "@#{name}")
233
+ instance_variable_set(ivar_name, value)
230
234
  end
231
235
 
232
236
  # Render (like to_s) but adding newlines and indentation.
@@ -279,14 +283,12 @@ module Erector
279
283
  end
280
284
  end
281
285
 
282
- alias_method :inspect, :to_s
283
-
284
286
  # Template method which must be overridden by all widget subclasses.
285
287
  # Inside this method you call the magic #element methods which emit HTML
286
288
  # and text to the output string. If you call "super" (or don't override
287
289
  # +content+) then your widget will render any block that was passed into
288
290
  # its constructor. If you want this block to have access to Erector methods
289
- # then see Erector::Inline#content.
291
+ # then see Erector::Inline#content or Erector#inline.
290
292
  def content
291
293
  if @block
292
294
  @block.call
@@ -465,6 +467,15 @@ module Erector
465
467
  output << "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
466
468
  end
467
469
 
470
+ # Emits an HTML comment, which looks like this: &lt;!--foo--&gt;
471
+ # see http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4
472
+ # Since "Authors should avoid putting two or more adjacent hyphens inside comments,"
473
+ # we emit a warning if you do that.
474
+ def comment(text)
475
+ puts "Warning: Authors should avoid putting two or more adjacent hyphens inside comments." if text =~ /--/
476
+ output << "<!--#{text}-->"
477
+ end
478
+
468
479
  # Creates a whole new output string, executes the block, then converts the
469
480
  # output string to a string and emits it as raw text. If at all possible
470
481
  # you should avoid this method since it hurts performance, and use
@@ -562,6 +573,21 @@ module Erector
562
573
  false
563
574
  end
564
575
  end
576
+
577
+ # emits a jQuery script that is to be run on document ready
578
+ def jquery(txt)
579
+ javascript do
580
+ jquery_ready txt
581
+ end
582
+ end
583
+
584
+ protected
585
+ def jquery_ready(txt)
586
+ rawtext "\n"
587
+ rawtext "$(document).ready(function(){\n"
588
+ rawtext txt
589
+ rawtext "\n});"
590
+ end
565
591
 
566
592
  ### internal utility methods
567
593