forme 1.2.0 → 1.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +37 -18
- data/Rakefile +6 -5
- data/lib/forme.rb +6 -1348
- data/lib/forme/form.rb +387 -0
- data/lib/forme/input.rb +48 -0
- data/lib/forme/raw.rb +12 -0
- data/lib/forme/tag.rb +60 -0
- data/lib/forme/transformers/error_handler.rb +18 -0
- data/lib/forme/transformers/formatter.rb +511 -0
- data/lib/forme/transformers/helper.rb +17 -0
- data/lib/forme/transformers/inputs_wrapper.rb +95 -0
- data/lib/forme/transformers/labeler.rb +78 -0
- data/lib/forme/transformers/serializer.rb +171 -0
- data/lib/forme/transformers/wrapper.rb +52 -0
- data/lib/forme/version.rb +1 -1
- data/lib/sequel/plugins/forme.rb +7 -4
- data/spec/forme_spec.rb +65 -5
- data/spec/sequel_plugin_spec.rb +18 -3
- metadata +15 -4
data/lib/forme/form.rb
ADDED
@@ -0,0 +1,387 @@
|
|
1
|
+
module Forme
|
2
|
+
# The +Form+ class is the main entry point to the library.
|
3
|
+
# Using the +form+, +input+, +tag+, and +inputs+ methods, one can easily build
|
4
|
+
# an abstract syntax tree of +Tag+ and +Input+ instances, which can be serialized
|
5
|
+
# to a string using +to_s+.
|
6
|
+
class Form
|
7
|
+
# A hash of options for the form.
|
8
|
+
attr_reader :opts
|
9
|
+
|
10
|
+
# Set the default options for inputs by type. This should be a hash with
|
11
|
+
# input type keys and values that are hashes of input options.
|
12
|
+
attr_reader :input_defaults
|
13
|
+
|
14
|
+
# The hidden tags to automatically add to the form.
|
15
|
+
attr_reader :hidden_tags
|
16
|
+
|
17
|
+
# The namespaces if any for the receiver's inputs. This can be used to
|
18
|
+
# automatically setup namespaced class and id attributes.
|
19
|
+
attr_accessor :namespaces
|
20
|
+
|
21
|
+
# The +serializer+ determines how +Tag+ objects are transformed into strings.
|
22
|
+
# Must respond to +call+ or be a registered symbol.
|
23
|
+
attr_reader :serializer
|
24
|
+
|
25
|
+
# Use appropriate Form subclass for object based on the current class, if the
|
26
|
+
# object responds to +forme_form_class+.
|
27
|
+
def self.new(obj=nil, opts={})
|
28
|
+
if obj && obj.respond_to?(:forme_form_class) && !opts[:_forme_form_class_set]
|
29
|
+
obj.forme_form_class(self).new(obj, opts.merge(:_forme_form_class_set=>true))
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create a +Form+ instance and yield it to the block,
|
36
|
+
# injecting the opening form tag before yielding and
|
37
|
+
# the closing form tag after yielding.
|
38
|
+
#
|
39
|
+
# Argument Handling:
|
40
|
+
# No args :: Creates a +Form+ object with no options and not associated
|
41
|
+
# to an +obj+, and with no attributes in the opening tag.
|
42
|
+
# 1 hash arg :: Treated as opening form tag attributes, creating a
|
43
|
+
# +Form+ object with no options.
|
44
|
+
# 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
|
45
|
+
# and no attributes in the opening tag.
|
46
|
+
# 2 hash args :: First hash is opening attributes, second hash is +Form+
|
47
|
+
# options.
|
48
|
+
# 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
|
49
|
+
# opening attributes, third if provided is
|
50
|
+
# +Form+'s options.
|
51
|
+
def self.form(obj=nil, attr={}, opts={}, &block)
|
52
|
+
f = if obj.is_a?(Hash)
|
53
|
+
raise Error, "Can't provide 3 hash arguments to form" unless opts.empty?
|
54
|
+
opts = attr
|
55
|
+
attr = obj
|
56
|
+
new(opts)
|
57
|
+
else
|
58
|
+
new(obj, opts)
|
59
|
+
end
|
60
|
+
|
61
|
+
ins = opts[:inputs]
|
62
|
+
button = opts[:button]
|
63
|
+
if ins || button
|
64
|
+
block = Proc.new do |form|
|
65
|
+
form._inputs(ins, opts) if ins
|
66
|
+
yield form if block_given?
|
67
|
+
form.emit(form.button(button)) if button
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
f.form(attr, &block)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Creates a +Form+ object. Arguments:
|
75
|
+
# obj :: Sets the obj for the form. If a hash, is merged with the +opts+ argument
|
76
|
+
# to set the opts.
|
77
|
+
# opts :: A hash of options for the form
|
78
|
+
def initialize(obj=nil, opts={})
|
79
|
+
@opts = opts.merge(obj.is_a?(Hash) ? obj : {:obj=>obj})
|
80
|
+
@opts[:namespace] = Array(@opts[:namespace])
|
81
|
+
|
82
|
+
if obj && obj.respond_to?(:forme_config)
|
83
|
+
obj.forme_config(self)
|
84
|
+
end
|
85
|
+
|
86
|
+
config = CONFIGURATIONS[@opts[:config]||Forme.default_config]
|
87
|
+
copy_inputs_wrapper_from_wrapper(@opts)
|
88
|
+
|
89
|
+
TRANSFORMER_TYPES.each do |t|
|
90
|
+
case @opts[t]
|
91
|
+
when Symbol
|
92
|
+
@opts[t] = Forme.transformer(t, @opts[t], @opts)
|
93
|
+
when nil
|
94
|
+
unless @opts.has_key?(t)
|
95
|
+
@opts[t] = Forme.transformer(t, config, @opts)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
@serializer = @opts[:serializer]
|
101
|
+
@input_defaults = @opts[:input_defaults] || {}
|
102
|
+
@hidden_tags = @opts[:hidden_tags]
|
103
|
+
@nesting = []
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create a form tag with the given attributes.
|
107
|
+
def form(attr={}, &block)
|
108
|
+
tag(:form, attr, method(:hidden_form_tags), &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Empty method designed to ease integration with other libraries where
|
112
|
+
# Forme is used in template code and some output implicitly
|
113
|
+
# created by Forme needs to be injected into the template output.
|
114
|
+
def emit(tag)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Creates an +Input+ with the given +field+ and +opts+ associated with
|
118
|
+
# the receiver, and add it to the list of children to the currently
|
119
|
+
# open tag.
|
120
|
+
#
|
121
|
+
# If the form is associated with an +obj+, or the :obj key exists in
|
122
|
+
# the +opts+ argument, treats the +field+ as a call to the +obj+. If
|
123
|
+
# +obj+ responds to +forme_input+, that method is called with the +field+
|
124
|
+
# and a copy of +opts+. Otherwise, the field is used as a method call
|
125
|
+
# on the +obj+ and a text input is created with the result.
|
126
|
+
#
|
127
|
+
# If no +obj+ is associated with the receiver, +field+ represents an input
|
128
|
+
# type (e.g. <tt>:text</tt>, <tt>:textarea</tt>, <tt>:select</tt>), and
|
129
|
+
# an input is created directly with the +field+ and +opts+.
|
130
|
+
def input(field, opts={})
|
131
|
+
if opts.has_key?(:obj)
|
132
|
+
opts = opts.dup
|
133
|
+
obj = opts.delete(:obj)
|
134
|
+
else
|
135
|
+
obj = self.obj
|
136
|
+
end
|
137
|
+
input = if obj
|
138
|
+
if obj.respond_to?(:forme_input)
|
139
|
+
obj.forme_input(self, field, opts.dup)
|
140
|
+
else
|
141
|
+
opts = opts.dup
|
142
|
+
opts[:key] = field unless opts.has_key?(:key)
|
143
|
+
unless opts.has_key?(:value)
|
144
|
+
opts[:value] = if obj.is_a?(Hash)
|
145
|
+
obj[field]
|
146
|
+
else
|
147
|
+
obj.send(field)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
_input(:text, opts)
|
151
|
+
end
|
152
|
+
else
|
153
|
+
_input(field, opts)
|
154
|
+
end
|
155
|
+
self << input
|
156
|
+
input
|
157
|
+
end
|
158
|
+
|
159
|
+
# Create a new +Input+ associated with the receiver with the given
|
160
|
+
# arguments, doing no other processing.
|
161
|
+
def _input(*a)
|
162
|
+
Input.new(self, *a)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Creates a tag using the +inputs_wrapper+ (a fieldset by default), calls
|
166
|
+
# input on each element of +inputs+, and yields if given a block.
|
167
|
+
# You can use array arguments if you want inputs to be created with specific
|
168
|
+
# options:
|
169
|
+
#
|
170
|
+
# f.inputs([:field1, :field2])
|
171
|
+
# f.inputs([[:field1, {:name=>'foo'}], :field2])
|
172
|
+
#
|
173
|
+
# The given +opts+ are passed to the +inputs_wrapper+, and the default
|
174
|
+
# +inputs_wrapper+ supports a <tt>:legend</tt> option that is used to
|
175
|
+
# set the legend for the fieldset.
|
176
|
+
#
|
177
|
+
# +opts+ can also include transformer options itself (e.g. :wrapper), which
|
178
|
+
# override the form's current transformer options for the duration of the block.
|
179
|
+
# The exception is the :inputs_wrapper transformer option, which affects the
|
180
|
+
# wrapper to use for this inputs call. You can use the :nested_inputs_wrapper
|
181
|
+
# option to set the default :inputs_wrapper option for the duration of the block.
|
182
|
+
#
|
183
|
+
# This can also be called with a single hash argument to just use an options hash:
|
184
|
+
#
|
185
|
+
# f.inputs(:legend=>'Foo') do
|
186
|
+
# # ...
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
# or even without any arguments:
|
190
|
+
#
|
191
|
+
# f.inputs do
|
192
|
+
# # ...
|
193
|
+
# end
|
194
|
+
def inputs(inputs=[], opts={}, &block)
|
195
|
+
_inputs(inputs, opts, &block)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Internals of #inputs, should be used internally by the library, where #inputs
|
199
|
+
# is designed for external use.
|
200
|
+
def _inputs(inputs=[], opts={}) # :nodoc:
|
201
|
+
if inputs.is_a?(Hash)
|
202
|
+
opts = inputs.merge(opts)
|
203
|
+
inputs = []
|
204
|
+
end
|
205
|
+
|
206
|
+
form_opts = {}
|
207
|
+
form_opts[:inputs_wrapper] = opts[:nested_inputs_wrapper] if opts[:nested_inputs_wrapper]
|
208
|
+
TRANSFORMER_TYPES.each do |t|
|
209
|
+
if opts.has_key?(t) && t != :inputs_wrapper
|
210
|
+
form_opts[t] = opts[t]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
Forme.transform(:inputs_wrapper, opts, @opts, self, opts) do
|
215
|
+
with_opts(form_opts) do
|
216
|
+
inputs.each do |i|
|
217
|
+
emit(input(*i))
|
218
|
+
end
|
219
|
+
yield if block_given?
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Returns a string representing the opening of the form tag for serializers
|
225
|
+
# that support opening tags.
|
226
|
+
def open(attr)
|
227
|
+
serializer.serialize_open(_tag(:form, attr)) if serializer.respond_to?(:serialize_open)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Returns a string representing the closing of the form tag, for serializers
|
231
|
+
# that support closing tags.
|
232
|
+
def close
|
233
|
+
serializer.serialize_close(_tag(:form)) if serializer.respond_to?(:serialize_close)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Create a +Tag+ associated to the receiver with the given arguments and block,
|
237
|
+
# doing no other processing.
|
238
|
+
def _tag(*a, &block)
|
239
|
+
tag = Tag.new(self, *a, &block)
|
240
|
+
end
|
241
|
+
|
242
|
+
# The object associated with this form, if any. If the +Form+ has an associated
|
243
|
+
# obj, then calls to +input+ are assumed to be accessing fields of the object
|
244
|
+
# instead to directly representing input types.
|
245
|
+
def obj
|
246
|
+
@opts[:obj]
|
247
|
+
end
|
248
|
+
|
249
|
+
# The current namespaces for the form, if any.
|
250
|
+
def namespaces
|
251
|
+
@opts[:namespace]
|
252
|
+
end
|
253
|
+
|
254
|
+
# Creates a +Tag+ associated to the receiver with the given arguments.
|
255
|
+
# Add the tag to the the list of children for the currently open tag.
|
256
|
+
# If a block is given, make this tag the currently open tag while inside
|
257
|
+
# the block.
|
258
|
+
def tag(*a, &block)
|
259
|
+
tag = _tag(*a)
|
260
|
+
self << tag
|
261
|
+
nest(tag, &block) if block
|
262
|
+
tag
|
263
|
+
end
|
264
|
+
|
265
|
+
# Aliased for tag. Workaround for issue with rails plugin.
|
266
|
+
def tag_(*a, &block) # :nodoc:
|
267
|
+
tag(*a, &block)
|
268
|
+
end
|
269
|
+
|
270
|
+
# Creates a :submit +Input+ with the given opts, adding it to the list
|
271
|
+
# of children for the currently open tag.
|
272
|
+
def button(opts={})
|
273
|
+
opts = {:value=>opts} if opts.is_a?(String)
|
274
|
+
input = _input(:submit, opts)
|
275
|
+
self << input
|
276
|
+
input
|
277
|
+
end
|
278
|
+
|
279
|
+
# Add the +Input+/+Tag+ instance given to the currently open tag.
|
280
|
+
def <<(tag)
|
281
|
+
if n = @nesting.last
|
282
|
+
n << tag
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# Calls the block for each object in objs, using with_obj with the given namespace
|
287
|
+
# and an index namespace (starting at 0).
|
288
|
+
def each_obj(objs, namespace=nil)
|
289
|
+
objs.each_with_index do |obj, i|
|
290
|
+
with_obj(obj, Array(namespace) + [i]) do
|
291
|
+
yield obj, i
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Return a new string that will not be html escaped by the default serializer.
|
297
|
+
def raw(s)
|
298
|
+
Forme.raw(s)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Marks the string as containing already escaped output. Returns string given
|
302
|
+
# by default, but subclasses for specific web frameworks can handle automatic
|
303
|
+
# html escaping by overriding this.
|
304
|
+
def raw_output(s)
|
305
|
+
s
|
306
|
+
end
|
307
|
+
|
308
|
+
# Temporarily override the given object and namespace for the form. Any given
|
309
|
+
# namespaces are appended to the form's current namespace.
|
310
|
+
def with_obj(obj, namespace=nil)
|
311
|
+
with_opts(:obj=>obj, :namespace=>@opts[:namespace]+Array(namespace)) do
|
312
|
+
yield obj
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# Temporarily override the opts for the form for the duration of the block.
|
317
|
+
# This merges the given opts with the form's current opts, restoring
|
318
|
+
# the previous opts before returning.
|
319
|
+
def with_opts(opts)
|
320
|
+
orig_opts = @opts
|
321
|
+
@opts = orig_opts.merge(opts)
|
322
|
+
copy_inputs_wrapper_from_wrapper(opts, @opts)
|
323
|
+
yield
|
324
|
+
ensure
|
325
|
+
@opts = orig_opts if orig_opts
|
326
|
+
end
|
327
|
+
|
328
|
+
private
|
329
|
+
|
330
|
+
# Copy the :wrapper option to :inputs_wrapper in output_opts if only :wrapper
|
331
|
+
# is present in input_opts and the :wrapper option value is a shared wrapper.
|
332
|
+
def copy_inputs_wrapper_from_wrapper(input_opts, output_opts=input_opts)
|
333
|
+
if input_opts[:wrapper] && !input_opts[:inputs_wrapper] && SHARED_WRAPPERS.include?(input_opts[:wrapper])
|
334
|
+
output_opts[:inputs_wrapper] = output_opts[:wrapper]
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# Return array of hidden tags to use for this form,
|
339
|
+
# or nil if the form does not have hidden tags added automatically.
|
340
|
+
def hidden_form_tags(form_tag)
|
341
|
+
if hidden_tags
|
342
|
+
tags = []
|
343
|
+
hidden_tags.each do |hidden_tag|
|
344
|
+
hidden_tag = hidden_tag.call(form_tag) if hidden_tag.respond_to?(:call)
|
345
|
+
tags.concat(parse_hidden_tags(hidden_tag))
|
346
|
+
end
|
347
|
+
tags
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# Handle various types of hidden tags for the form.
|
352
|
+
def parse_hidden_tags(hidden_tag)
|
353
|
+
case hidden_tag
|
354
|
+
when Array
|
355
|
+
hidden_tag
|
356
|
+
when Tag, String
|
357
|
+
[hidden_tag]
|
358
|
+
when Hash
|
359
|
+
hidden_tag.map{|k,v| _tag(:input, :type=>:hidden, :name=>k, :value=>v)}
|
360
|
+
when nil
|
361
|
+
[]
|
362
|
+
else
|
363
|
+
raise Error, "unhandled hidden_tag response: #{hidden_tag.inspect}"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# Make the given tag the currently open tag, and yield. After the
|
368
|
+
# block returns, make the previously open tag the currently open
|
369
|
+
# tag.
|
370
|
+
def nest(tag)
|
371
|
+
@nesting << tag
|
372
|
+
yield self
|
373
|
+
ensure
|
374
|
+
@nesting.pop
|
375
|
+
end
|
376
|
+
|
377
|
+
# Return a serialized opening tag for the given tag.
|
378
|
+
def serialize_open(tag)
|
379
|
+
raw_output(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
|
380
|
+
end
|
381
|
+
|
382
|
+
# Return a serialized closing tag for the given tag.
|
383
|
+
def serialize_close(tag)
|
384
|
+
raw_output(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
data/lib/forme/input.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Forme
|
2
|
+
# High level abstract tag form, transformed by formatters into the lower
|
3
|
+
# level +Tag+ form (or an array of them).
|
4
|
+
class Input
|
5
|
+
# The +Form+ object related to the receiver.
|
6
|
+
attr_reader :form
|
7
|
+
|
8
|
+
# The type of input, should be a symbol (e.g. :submit, :text, :select).
|
9
|
+
attr_reader :type
|
10
|
+
|
11
|
+
# The options hash for the Input.
|
12
|
+
attr_reader :opts
|
13
|
+
|
14
|
+
# The options hash in use by the form at the time of the Input's instantiation.
|
15
|
+
attr_reader :form_opts
|
16
|
+
|
17
|
+
# Set the +form+, +type+, and +opts+.
|
18
|
+
def initialize(form, type, opts={})
|
19
|
+
@form, @type = form, type
|
20
|
+
defaults = form.input_defaults
|
21
|
+
@opts = (defaults.fetch(type){defaults[type.to_s]} || {}).merge(opts)
|
22
|
+
@form_opts = form.opts
|
23
|
+
end
|
24
|
+
|
25
|
+
# Replace the +opts+ by merging the given +hash+ into +opts+,
|
26
|
+
# without modifying +opts+.
|
27
|
+
def merge_opts(hash)
|
28
|
+
@opts = @opts.merge(hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a new +Tag+ instance with the given arguments and block
|
32
|
+
# related to the receiver's +form+.
|
33
|
+
def tag(*a, &block)
|
34
|
+
form._tag(*a, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return a string containing the serialized content of the receiver.
|
38
|
+
def to_s
|
39
|
+
form.raw_output(Forme.transform(:serializer, @opts, @form_opts, self))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Transform the receiver into a lower level +Tag+ form (or an array
|
43
|
+
# of them).
|
44
|
+
def format
|
45
|
+
Forme.transform(:formatter, @opts, @form_opts, self)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/forme/raw.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Forme
|
2
|
+
# Empty module for marking objects as "raw", where they will no longer
|
3
|
+
# html escaped by the default serializer.
|
4
|
+
module Raw
|
5
|
+
end
|
6
|
+
|
7
|
+
# A String subclass that includes Raw, which will cause the default
|
8
|
+
# serializer to no longer html escape the string.
|
9
|
+
class RawString < ::String
|
10
|
+
include Raw
|
11
|
+
end
|
12
|
+
end
|
data/lib/forme/tag.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Forme
|
2
|
+
# Low level abstract tag form, where each instance represents a
|
3
|
+
# html tag with attributes and children.
|
4
|
+
class Tag
|
5
|
+
# The +Form+ object related to the receiver.
|
6
|
+
attr_reader :form
|
7
|
+
|
8
|
+
# The type of tag, should be a symbol (e.g. :input, :select).
|
9
|
+
attr_reader :type
|
10
|
+
|
11
|
+
# The attributes hash of this receiver.
|
12
|
+
attr_reader :attr
|
13
|
+
|
14
|
+
# An array instance representing the children of the receiver,
|
15
|
+
# or possibly +nil+ if the receiver has no children.
|
16
|
+
attr_reader :children
|
17
|
+
|
18
|
+
# Set the +form+, +type+, +attr+, and +children+.
|
19
|
+
def initialize(form, type, attr={}, children=nil)
|
20
|
+
@form, @type, @attr = form, type, (attr||{})
|
21
|
+
@children = parse_children(children)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Adds a child to the array of receiver's children.
|
25
|
+
def <<(child)
|
26
|
+
if children
|
27
|
+
children << child
|
28
|
+
else
|
29
|
+
@children = [child]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create a new +Tag+ instance with the given arguments and block
|
34
|
+
# related to the receiver's +form+.
|
35
|
+
def tag(*a, &block)
|
36
|
+
form._tag(*a, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return a string containing the serialized content of the receiver.
|
40
|
+
def to_s
|
41
|
+
form.raw_output(Forme.transform(:serializer, @opts, @form.opts, self))
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Convert children constructor argument into the children to use for the tag.
|
47
|
+
def parse_children(children)
|
48
|
+
case children
|
49
|
+
when Array
|
50
|
+
children
|
51
|
+
when Proc, Method
|
52
|
+
parse_children(children.call(self))
|
53
|
+
when nil
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
[children]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|