hobo 0.5.3 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/bin/hobo +18 -4
  2. data/hobo_files/plugin/CHANGES.txt +511 -0
  3. data/hobo_files/plugin/README +8 -3
  4. data/hobo_files/plugin/Rakefile +81 -0
  5. data/hobo_files/plugin/generators/hobo/hobo_generator.rb +4 -4
  6. data/hobo_files/plugin/generators/hobo/templates/guest.rb +1 -1
  7. data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +1 -1
  8. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +16 -22
  9. data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +4 -6
  10. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +6 -5
  11. data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +4 -6
  12. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +237 -0
  13. data/hobo_files/plugin/generators/hobo_migration/templates/migration.rb +9 -0
  14. data/hobo_files/plugin/generators/hobo_model/USAGE +2 -3
  15. data/hobo_files/plugin/generators/hobo_model/hobo_model_generator.rb +1 -14
  16. data/hobo_files/plugin/generators/hobo_model/templates/fixtures.yml +1 -6
  17. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +10 -4
  18. data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +7 -6
  19. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_base.css +68 -0
  20. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.css +93 -0
  21. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +11 -6
  22. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/plus.png +0 -0
  23. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +24 -14
  24. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +28 -44
  25. data/hobo_files/plugin/generators/hobo_user_model/USAGE +2 -12
  26. data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +1 -14
  27. data/hobo_files/plugin/generators/hobo_user_model/templates/fixtures.yml +0 -6
  28. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +8 -1
  29. data/hobo_files/plugin/init.rb +6 -2
  30. data/hobo_files/plugin/lib/active_record/has_many_association.rb +23 -12
  31. data/hobo_files/plugin/lib/extensions.rb +134 -40
  32. data/hobo_files/plugin/lib/extensions/test_case.rb +0 -1
  33. data/hobo_files/plugin/lib/hobo.rb +77 -46
  34. data/hobo_files/plugin/lib/hobo/authenticated_user.rb +24 -2
  35. data/hobo_files/plugin/lib/hobo/authentication_support.rb +2 -1
  36. data/hobo_files/plugin/lib/hobo/controller.rb +35 -12
  37. data/hobo_files/plugin/lib/hobo/define_tags.rb +4 -4
  38. data/hobo_files/plugin/lib/hobo/dryml.rb +33 -51
  39. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +47 -34
  40. data/hobo_files/plugin/lib/hobo/dryml/scoped_variables.rb +37 -0
  41. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +27 -5
  42. data/hobo_files/plugin/lib/hobo/dryml/template.rb +545 -302
  43. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +305 -135
  44. data/hobo_files/plugin/lib/hobo/email_address.rb +5 -0
  45. data/hobo_files/plugin/lib/hobo/field_spec.rb +66 -0
  46. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +325 -0
  47. data/hobo_files/plugin/lib/hobo/html_string.rb +2 -0
  48. data/hobo_files/plugin/lib/hobo/lazy_hash.rb +13 -1
  49. data/hobo_files/plugin/lib/hobo/markdown_string.rb +3 -1
  50. data/hobo_files/plugin/lib/hobo/model.rb +185 -66
  51. data/hobo_files/plugin/lib/hobo/model_controller.rb +56 -49
  52. data/hobo_files/plugin/lib/hobo/password_string.rb +2 -0
  53. data/hobo_files/plugin/lib/hobo/plugins.rb +75 -0
  54. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +98 -0
  55. data/hobo_files/plugin/lib/hobo/static_tags +0 -3
  56. data/hobo_files/plugin/lib/hobo/textile_string.rb +11 -1
  57. data/hobo_files/plugin/lib/hobo/undefined.rb +1 -1
  58. data/hobo_files/plugin/lib/rexml.rb +166 -75
  59. data/hobo_files/plugin/spec/fixtures/users.yml +9 -0
  60. data/hobo_files/plugin/spec/spec.opts +6 -0
  61. data/hobo_files/plugin/spec/spec_helper.rb +28 -0
  62. data/hobo_files/plugin/spec/unit/hobo/dryml/template_spec.rb +650 -0
  63. data/hobo_files/plugin/tags/core.dryml +58 -4
  64. data/hobo_files/plugin/tags/rapid.dryml +289 -135
  65. data/hobo_files/plugin/tags/rapid_document_tags.dryml +49 -0
  66. data/hobo_files/plugin/tags/rapid_editing.dryml +92 -69
  67. data/hobo_files/plugin/tags/rapid_forms.dryml +242 -0
  68. data/hobo_files/plugin/tags/rapid_navigation.dryml +65 -65
  69. data/hobo_files/plugin/tags/rapid_pages.dryml +197 -124
  70. data/hobo_files/plugin/tags/rapid_support.dryml +23 -0
  71. metadata +29 -22
  72. data/hobo_files/plugin/generators/hobo_model/templates/migration.rb +0 -13
  73. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/default_mapping.rb +0 -11
  74. data/hobo_files/plugin/generators/hobo_user_model/templates/migration.rb +0 -15
  75. data/hobo_files/plugin/lib/hobo/HtmlString +0 -3
  76. data/hobo_files/plugin/lib/hobo/controller_helpers.rb +0 -135
  77. data/hobo_files/plugin/lib/hobo/core.rb +0 -475
  78. data/hobo_files/plugin/lib/hobo/rapid.rb +0 -447
  79. data/hobo_files/plugin/test/hobo_dryml_template_test.rb +0 -7
  80. data/hobo_files/plugin/test/hobo_test.rb +0 -7
@@ -1,51 +1,151 @@
1
1
  module Hobo::Dryml
2
2
 
3
3
  class TemplateEnvironment
4
-
4
+
5
5
  class << self
6
6
  def inherited(subclass)
7
7
  subclass.compiled_local_names = []
8
8
  end
9
9
  attr_accessor :load_time, :compiled_local_names
10
+
11
+ # --- Local Tags --- #
12
+
13
+ def start_redefine_block(method_names)
14
+ @_preserved_methods_for_redefine ||= []
15
+ @_redef_impl_names ||= []
16
+
17
+ methods = {}
18
+ method_names.each {|m| methods[m] = m.in?(self.methods) && instance_method(m) }
19
+ @_preserved_methods_for_redefine.push(methods)
20
+ @_redef_impl_names.push []
21
+ end
22
+
23
+
24
+ def end_redefine_block
25
+ methods = @_preserved_methods_for_redefine.pop
26
+ methods.each_pair do |name, method|
27
+ if method
28
+ define_method(name, method)
29
+ else
30
+ remove_method(name)
31
+ end
32
+ end
33
+ to_remove = @_redef_impl_names.pop
34
+ to_remove.each {|m| remove_method(m) }
35
+ end
36
+
37
+
38
+ def redefine_nesting
39
+ @_preserved_methods_for_redefine.length
40
+ end
41
+
42
+
43
+ def redefine_tag(name, proc)
44
+ impl_name = "#{name}_redefined_#{redefine_nesting}"
45
+ define_method(impl_name, proc)
46
+ class_eval "def #{name}(options={}, &b); #{impl_name}(options, b); end"
47
+ @_redef_impl_names.push(impl_name)
48
+ end
49
+
50
+ def redefine_template(name, proc)
51
+ impl_name = "#{name}_redefined_#{redefine_nesting}"
52
+ define_method(impl_name, proc)
53
+ class_eval "def #{name}(options={}, template_parameters={}, &b); " +
54
+ "#{impl_name}(options, template_parameters, b); end"
55
+ @_redef_impl_names.push(impl_name)
56
+ end
57
+
58
+ # --- end local tags --- #
59
+
60
+
61
+ def _register_tag_attrs(tag_name, attrs)
62
+ @tag_attrs ||= {}
63
+ @tag_attrs[tag_name] = attrs
64
+ end
65
+
66
+ def tag_attrs
67
+ @tag_attrs ||= {}
68
+ end
69
+
10
70
  end
11
71
 
12
72
  for mod in ActionView::Helpers.constants.grep(/Helper$/).map {|m| ActionView::Helpers.const_get(m)}
13
73
  include mod
14
74
  end
15
75
 
16
- def initialize(view_name, view)
17
- @view = view
18
- @view_name = view_name
19
- @erb_binding = binding
20
- @part_contexts = {}
21
- @stack = [nil]
22
-
23
- # Make sure the "assigns" from the controller are available (instance variables)
24
- if view
25
- view.assigns.each do |key, value|
26
- instance_variable_set("@#{key}", value)
27
- end
28
-
29
- # copy view instance variables over
30
- view.instance_variables.each do |iv|
31
- instance_variable_set(iv, @view.instance_variable_get(iv))
76
+ def initialize(view_name=nil, view=nil)
77
+ unless view_name.nil? && view.nil?
78
+ @view = view
79
+ @_view_name = view_name
80
+ @_erb_binding = binding
81
+ @_part_contexts = {}
82
+ @_scoped_variables = ScopedVariables.new
83
+
84
+ # Make sure the "assigns" from the controller are available (instance variables)
85
+ if view
86
+ view.assigns.each do |key, value|
87
+ instance_variable_set("@#{key}", value)
88
+ end
89
+
90
+ # copy view instance variables over
91
+ view.instance_variables.each do |iv|
92
+ instance_variable_set(iv, view.instance_variable_get(iv))
93
+ end
32
94
  end
33
95
  end
34
96
  end
35
97
 
36
- attr_accessor :erb_binding, :part_contexts, :view_name
98
+ attr_accessor
99
+
100
+ for attr in [:erb_binding, :part_contexts, :view_name,
101
+ :this, :this_parent, :this_field, :this_type,
102
+ :form_field_path, :form_this, :form_field_names]
103
+ class_eval "def #{attr}; @_#{attr}; end"
104
+ end
105
+
106
+
107
+ def attrs_for(name)
108
+ self.class.tag_attrs[name.to_sym]
109
+ end
110
+
111
+
112
+ def add_classes!(attributes, *classes)
113
+ classes = classes.flatten.select{|x|x}.every(:to_s)
114
+ current = attributes[:class]
115
+ attributes[:class] = (current ? current.split + classes : classes).uniq.join(' ')
116
+ attributes
117
+ end
118
+
119
+
120
+ def add_classes(attributes, *classes)
121
+ add_classes!(HashWithIndifferentAccess.new(attributes), classes)
122
+ end
37
123
 
38
- attr_reader :this_parent, :this_field, :this_type, :form_field_path, :form_this, :form_field_names
39
124
 
40
- def this; @_this; end
125
+ def merge_attrs(attrs, overriding_attrs)
126
+ attrs = attrs.with_indifferent_access unless attrs.is_a?(HashWithIndifferentAccess)
127
+ classes = overriding_attrs[:class]
128
+ attrs = add_classes(attrs, *classes.split) if classes
129
+ attrs.update(overriding_attrs - [:class])
130
+ end
131
+
41
132
 
133
+ def scope
134
+ @_scoped_variables
135
+ end
136
+
137
+
42
138
  def attr_extension(s)
43
139
  AttributeExtensionString.new(s)
44
140
  end
45
-
141
+
46
142
 
47
143
  def this_field_dom_id
48
- Hobo.dom_id(this_parent, this_field)
144
+ if this_parent && this_field
145
+ Hobo.dom_id(this_parent, this_field)
146
+ else
147
+ Hobo.dom_id(this)
148
+ end
49
149
  end
50
150
 
51
151
 
@@ -66,36 +166,81 @@ module Hobo::Dryml
66
166
  res = ''
67
167
  if part_this
68
168
  new_object_context(part_this) do
69
- @part_contexts[dom_id] = [part_id, part_context_model_id]
169
+ @_part_contexts[dom_id] = [part_id, part_context_model_id]
70
170
  res = send("#{part_id}_part")
71
171
  end
72
172
  else
73
173
  new_context do
74
- @part_contexts[dom_id] = [part_id, part_context_model_id]
174
+ @_part_contexts[dom_id] = [part_id, part_context_model_id]
75
175
  res = send("#{part_id}_part")
76
176
  end
77
177
  end
78
178
  res
79
179
  end
180
+
181
+ def call_polymorphic_tag(*args, &b)
182
+ attributes = extract_options_from_args!(args)
183
+ name, type = args
184
+
185
+ tag = find_polymorphic_tag(name, type)
186
+ if tag != name
187
+ send(tag, attributes, &b)
188
+ else
189
+ nil
190
+ end
191
+ end
80
192
 
193
+
194
+ def find_polymorphic_tag(name, call_type=nil)
195
+ call_type ||= this_type
196
+ return name if call_type.is_a?(ActiveRecord::Reflection::AssociationReflection)
197
+ call_type = TrueClass if call_type == FalseClass
198
+
199
+ while true
200
+ if call_type == ActiveRecord::Base || call_type == Object
201
+ return name
202
+ elsif respond_to?(poly_name = "#{name}__for_#{call_type.name.to_s.underscore.gsub('/', '__')}")
203
+ return poly_name
204
+ else
205
+ call_type = call_type.superclass
206
+ end
207
+ end
208
+ end
209
+ alias_method :find_polymorphic_template, :find_polymorphic_tag
210
+
211
+
212
+ def repeat_attribute(array, &b)
213
+ res = array.map { |x| new_object_context(x, &b) }.join
214
+ Hobo::Dryml.last_if = !array.empty?
215
+ res
216
+ end
81
217
 
218
+
82
219
  def _erbout
83
- @output
220
+ @_erb_output
221
+ end
222
+
223
+
224
+ def _output(s)
225
+ @_erb_output.concat(s)
84
226
  end
85
227
 
86
228
 
87
229
  def new_context
88
- ctx = @output, @_this, @this_parent, @this_field, @this_type, @form_field_path
89
- @output = ""
230
+ ctx = [ @_erb_output,
231
+ @_this, @_this_parent, @_this_field, @_this_type,
232
+ @_form_field_path]
233
+ @_erb_output = ""
90
234
  res = yield
91
- @output, @_this, @this_parent, @this_field, @this_type, @form_field_path = ctx
235
+ @_erb_output, @_this, @_this_parent, @_this_field, @_this_type,
236
+ @_form_field_path = ctx
92
237
  res.to_s
93
238
  end
94
239
 
95
240
 
96
241
  def new_object_context(new_this)
97
242
  new_context do
98
- @this_parent,@this_field,@this_type = if new_this.respond_to?(:proxy_reflection)
243
+ @_this_parent,@_this_field,@_this_type = if new_this.respond_to?(:proxy_reflection)
99
244
  refl = new_this.proxy_reflection
100
245
  [new_this.proxy_owner, refl.name, refl]
101
246
  else
@@ -129,10 +274,9 @@ module Hobo::Dryml
129
274
  else
130
275
  obj.class
131
276
  end
132
-
133
277
 
134
- @_this, @this_parent, @this_field, @this_type = obj, parent, field, type
135
- @form_field_path += path if @form_field_path
278
+ @_this, @_this_parent, @_this_field, @_this_type = obj, parent, field, type
279
+ @_form_field_path += path if @_form_field_path
136
280
  yield
137
281
  end
138
282
  end
@@ -141,23 +285,25 @@ module Hobo::Dryml
141
285
  def _tag_context(options, tagbody_proc)
142
286
  tagbody = tagbody_proc && proc do |*args|
143
287
  res = ''
144
- block_options = args.length > 0 && args.first
145
- if block_options and block_options.has_key?(:obj)
146
- new_object_context(block_options[:obj]) { res = tagbody_proc.call }
147
- elsif block_options and block_options.has_key?(:attr)
148
- new_field_context(block_options[:attr]) { res = tagbody_proc.call }
288
+
289
+ block_options, default_tagbody = args
290
+ block_with = block_options && block_options[:with]
291
+ if block_options && block_options.has_key?(:field)
292
+ new_field_context(block_options[:field], block_with) { res = tagbody_proc.call(default_tagbody) }
293
+ elsif block_options && block_options.has_key?(:with)
294
+ new_object_context(block_with) { res = tagbody_proc.call(default_tagbody) }
149
295
  else
150
- new_context { res = tagbody_proc.call }
296
+ new_context { res = tagbody_proc.call(default_tagbody) }
151
297
  end
152
298
  res
153
299
  end
154
300
 
155
- obj = options[:obj] == "page" ? @this : options[:obj]
156
-
157
- if options.has_key?(:attr)
158
- new_field_context(options[:attr], obj) { yield tagbody }
159
- elsif options.has_key?(:obj)
160
- new_object_context(obj) { yield tagbody }
301
+ with = options[:with] == "page" ? @this : options[:with]
302
+
303
+ if options.has_key?(:field)
304
+ new_field_context(options[:field], with) { yield tagbody }
305
+ elsif options.has_key?(:with)
306
+ new_object_context(with) { yield tagbody }
161
307
  else
162
308
  new_context { yield tagbody }
163
309
  end
@@ -165,18 +311,18 @@ module Hobo::Dryml
165
311
 
166
312
 
167
313
  def with_form_context
168
- @form_this = this
169
- @form_field_path = []
170
- @form_field_names = []
314
+ @_form_this = this
315
+ @_form_field_path = []
316
+ @_form_field_names = []
171
317
  res = yield
172
- field_names = @form_field_names
173
- @form_this = @form_field_path = @form_field_names = nil
318
+ field_names = @_form_field_names
319
+ @_form_this = @_form_field_path = @_form_field_names = nil
174
320
  [res, field_names]
175
321
  end
176
322
 
177
323
 
178
324
  def register_form_field(name)
179
- @form_field_names << name
325
+ @_form_field_names << name
180
326
  end
181
327
 
182
328
 
@@ -192,107 +338,131 @@ module Hobo::Dryml
192
338
  end
193
339
 
194
340
 
195
- def _tag_locals(options, attrs, inner_tag_names)
196
- options = Hobo::Dryml.hashify_options(options)
197
- options.symbolize_keys!
198
- #ensure obj and attr are not in options
199
- options.delete(:obj)
200
- options.delete(:attr)
341
+ def _tag_locals(attributes, locals)
342
+ attributes.symbolize_keys!
343
+ #ensure with and field are not in attributes
344
+ attributes.delete(:with)
345
+ attributes.delete(:field)
201
346
 
202
- inner_tag_options, options = options.partition_hash(inner_tag_names.omap{to_sym})
203
-
204
- # positional arguments never appear in the options hash
205
- stripped_options = {}.update(options)
206
- attrs.each {|a| stripped_options.delete(a.to_sym) }
207
- attrs.map {|a| options[a.to_sym]} + [stripped_options, inner_tag_options]
347
+ # positional arguments never appear in the attributes hash
348
+ stripped_attributes = HashWithIndifferentAccess.new.update(attributes)
349
+ locals.each {|a| stripped_attributes.delete(a.to_sym) }
350
+
351
+ # Return locals declared as local variables (attrs="...")
352
+ locals.map {|a| attributes[a.to_sym]} + [stripped_attributes]
208
353
  end
209
354
 
210
355
 
211
- def call_replaceable_tag(name, options, external_param, &b)
212
- options.delete(:replace_option)
213
-
214
- if external_param.is_a? Hash
215
- before = external_param.delete(:before_content)
216
- after = external_param.delete(:after_content)
217
- top = external_param.delete(:top_content)
218
- bottom = external_param.delete(:bottom_content)
219
- content = external_param.delete(:content)
220
- options = Hobo::Dryml.merge_tag_options(options, external_param)
221
- elsif !external_param.nil?
222
- return external_param.to_s
223
- end
224
-
225
- tag = if respond_to?(name)
226
- body = if content
227
- proc { content }
228
- elsif b && (top || bottom)
229
- proc { top.to_s + b.call + bottom.to_s }
230
- else
231
- b
232
- end
233
- send(name, options, &body)
356
+ def do_tagbody(tagbody, attributes, default_tagbody)
357
+ res = if tagbody
358
+ tagbody.call(attributes, default_tagbody)
234
359
  else
235
- body = if content
236
- content
237
- elsif b
238
- top.to_s + new_context { b.call } + bottom.to_s
239
- else
240
- top.to_s + bottom.to_s
241
- end
242
- content_tag(name, body, options)
360
+ default_tagbody ? new_context { default_tagbody.call } : ""
243
361
  end
244
- before.to_s + tag.to_s + after.to_s
362
+ Hobo::Dryml.last_if = !!tagbody
363
+ res
245
364
  end
246
365
 
247
366
 
248
- def call_replaceable_content_tag(name, options, external_param, &b)
249
- options.delete(:content_option)
250
-
251
- if external_param.is_a? Hash
252
- content = external_param.delete(:content)
253
- top = external_param.delete(:top_content)
254
- bottom = external_param.delete(:bottom_content)
255
- external_param.delete(:before_content)
256
- external_param.delete(:after_content)
257
- options = Hobo::Dryml.merge_tag_options(options, external_param)
258
- elsif !external_param.nil?
259
- content = external_param.to_s
260
- end
367
+ def call_block_tag_parameter(the_tag, attributes, overriding_proc, &b)
368
+ if overriding_proc && overriding_proc.arity == 1
369
+ # This is a 'replace' parameter
370
+
371
+ template_default = proc do |attrs, body_block|
372
+ tagbody_proc = body_block && proc {|_| new_context { body_block.call(b) } }
373
+ call_block_tag_parameter(the_tag, attributes, proc { attrs.update(:tagbody => tagbody_proc) }, &b)
374
+ end
375
+ overriding_proc.call(template_default)
376
+ else
377
+ if overriding_proc
378
+ overriding_attributes = overriding_proc.call
379
+ tagbody = overriding_attributes.delete(:tagbody)
380
+ attributes = merge_attrs(attributes, overriding_attributes)
381
+ end
261
382
 
262
- # If there's no body, and no content provided externally, remove
263
- # the tag altogether
264
- return if b.nil? and content.nil?
265
-
266
- tag = if respond_to?(name)
267
- body = if content
268
- proc { content }
269
- elsif b && (top || bottom)
270
- proc { top.to_s + b.call + bottom.to_s }
271
- else
272
- b
273
- end
274
- send(name, options, &body)
275
- else
276
- body = if content
277
- content
278
- elsif b
279
- top.to_s + new_context { b.call } + bottom.to_s
280
- else
281
- top.to_s + bottom.to_s
282
- end
283
- content_tag(name, body, options)
383
+ if the_tag.is_a?(String, Symbol) && the_tag.to_s.in?(Hobo.static_tags)
384
+ body = if tagbody
385
+ new_context { tagbody.call(proc {b.call(nil)}) }
386
+ elsif b
387
+ new_context { b.call(nil) }
388
+ else
389
+ nil
390
+ end
391
+ if body.blank?
392
+ tag(the_tag, attributes)
393
+ else
394
+ content_tag(the_tag, body, attributes)
395
+ end
396
+ else
397
+ if the_tag.is_a?(String, Symbol)
398
+ body = proc do |default|
399
+ if tagbody
400
+ tagbody.call(proc { b ? b.call(default) : "" })
401
+ else
402
+ b ? b.call(default) : ""
403
+ end
284
404
  end
285
- tag.to_s
405
+
406
+ send(the_tag, attributes, &body)
407
+ else
408
+ # It's a proc - a template default
409
+ the_tag.call(attributes, tagbody || b)
410
+ end
411
+ end
412
+ end
286
413
  end
287
414
 
288
-
289
- def render_tag(tag_name, options)
290
- (send(tag_name, options) + part_contexts_js).strip
415
+ def call_template_parameter(the_template, attributes, template_procs, overriding_proc)
416
+ if overriding_proc && overriding_proc.arity == 1
417
+ # It's a replace parameter
418
+
419
+ template_default = proc do |attributes, parameters|
420
+ call_template_parameter(the_template, attributes, template_procs, proc { [attributes, parameters] })
421
+ end
422
+ overriding_proc.call(template_default)
423
+ else
424
+ if overriding_proc
425
+ overriding_attributes, overriding_template_procs = overriding_proc.call
426
+
427
+ attributes = merge_attrs(attributes, overriding_attributes)
428
+ template_procs = template_procs.merge(overriding_template_procs)
429
+ end
430
+
431
+ send(the_template, attributes, template_procs)
432
+ end
433
+ end
434
+
435
+ # Takes two procs that each returh hashes and returns a single
436
+ # proc that calls these in turn and merges the results into a
437
+ # single hash
438
+ def merge_option_procs(general_proc, overriding_proc)
439
+ if overriding_proc
440
+ proc { general_proc.call.merge(overriding_proc.call) }
441
+ else
442
+ general_proc
443
+ end
444
+ end
445
+
446
+ # Same as merge_option_procs, except these procs return a pair of
447
+ # hashes rather than a single hash. The first hash is the tag
448
+ # attributes, the second is a hash of procs -- the template
449
+ # parameters.
450
+ def merge_template_parameter_procs(general_proc, overriding_proc)
451
+ proc do
452
+ general_attributes, general_template_procs = general_proc.call
453
+ overriding_attributes, overriding_template_procs = overriding_proc.call
454
+ [merge_attrs(general_attributes, overriding_attributes), general_template_procs.merge(overriding_template_procs)]
455
+ end
291
456
  end
292
457
 
293
458
 
294
- def method_missing(name, *args)
295
- @view.send(name, *args)
459
+ def render_tag(tag_name, attributes)
460
+ (send(tag_name, attributes) + part_contexts_js).strip
461
+ end
462
+
463
+
464
+ def method_missing(name, *args, &b)
465
+ @view.send(name, *args, &b)
296
466
  end
297
467
 
298
468