ehoch_simple_form 2.0.2.dev
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +257 -0
- data/MIT-LICENSE +20 -0
- data/README.md +797 -0
- data/lib/generators/simple_form/USAGE +3 -0
- data/lib/generators/simple_form/install_generator.rb +32 -0
- data/lib/generators/simple_form/templates/README +12 -0
- data/lib/generators/simple_form/templates/_form.html.erb +13 -0
- data/lib/generators/simple_form/templates/_form.html.haml +10 -0
- data/lib/generators/simple_form/templates/_form.html.slim +10 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb.tt +181 -0
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +26 -0
- data/lib/simple_form.rb +215 -0
- data/lib/simple_form/action_view_extensions/builder.rb +338 -0
- data/lib/simple_form/action_view_extensions/form_helper.rb +74 -0
- data/lib/simple_form/components.rb +20 -0
- data/lib/simple_form/components/errors.rb +35 -0
- data/lib/simple_form/components/hints.rb +18 -0
- data/lib/simple_form/components/html5.rb +26 -0
- data/lib/simple_form/components/label_input.rb +15 -0
- data/lib/simple_form/components/labels.rb +79 -0
- data/lib/simple_form/components/maxlength.rb +41 -0
- data/lib/simple_form/components/min_max.rb +50 -0
- data/lib/simple_form/components/pattern.rb +34 -0
- data/lib/simple_form/components/placeholders.rb +16 -0
- data/lib/simple_form/components/readonly.rb +22 -0
- data/lib/simple_form/core_ext/hash.rb +16 -0
- data/lib/simple_form/error_notification.rb +48 -0
- data/lib/simple_form/form_builder.rb +472 -0
- data/lib/simple_form/helpers.rb +12 -0
- data/lib/simple_form/helpers/autofocus.rb +11 -0
- data/lib/simple_form/helpers/disabled.rb +15 -0
- data/lib/simple_form/helpers/readonly.rb +15 -0
- data/lib/simple_form/helpers/required.rb +35 -0
- data/lib/simple_form/helpers/validators.rb +44 -0
- data/lib/simple_form/i18n_cache.rb +22 -0
- data/lib/simple_form/inputs.rb +21 -0
- data/lib/simple_form/inputs/base.rb +162 -0
- data/lib/simple_form/inputs/block_input.rb +14 -0
- data/lib/simple_form/inputs/boolean_input.rb +64 -0
- data/lib/simple_form/inputs/collection_check_boxes_input.rb +21 -0
- data/lib/simple_form/inputs/collection_input.rb +101 -0
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +63 -0
- data/lib/simple_form/inputs/collection_select_input.rb +14 -0
- data/lib/simple_form/inputs/date_time_input.rb +28 -0
- data/lib/simple_form/inputs/file_input.rb +9 -0
- data/lib/simple_form/inputs/grouped_collection_select_input.rb +41 -0
- data/lib/simple_form/inputs/hidden_input.rb +17 -0
- data/lib/simple_form/inputs/numeric_input.rb +24 -0
- data/lib/simple_form/inputs/password_input.rb +12 -0
- data/lib/simple_form/inputs/priority_input.rb +24 -0
- data/lib/simple_form/inputs/range_input.rb +14 -0
- data/lib/simple_form/inputs/string_input.rb +23 -0
- data/lib/simple_form/inputs/text_input.rb +11 -0
- data/lib/simple_form/map_type.rb +16 -0
- data/lib/simple_form/version.rb +3 -0
- data/lib/simple_form/wrappers.rb +8 -0
- data/lib/simple_form/wrappers/builder.rb +103 -0
- data/lib/simple_form/wrappers/many.rb +69 -0
- data/lib/simple_form/wrappers/root.rb +34 -0
- data/lib/simple_form/wrappers/single.rb +18 -0
- data/test/action_view_extensions/builder_test.rb +577 -0
- data/test/action_view_extensions/form_helper_test.rb +104 -0
- data/test/components/label_test.rb +310 -0
- data/test/form_builder/association_test.rb +177 -0
- data/test/form_builder/button_test.rb +47 -0
- data/test/form_builder/error_notification_test.rb +79 -0
- data/test/form_builder/error_test.rb +121 -0
- data/test/form_builder/general_test.rb +356 -0
- data/test/form_builder/hint_test.rb +139 -0
- data/test/form_builder/input_field_test.rb +63 -0
- data/test/form_builder/label_test.rb +71 -0
- data/test/form_builder/wrapper_test.rb +149 -0
- data/test/generators/simple_form_generator_test.rb +32 -0
- data/test/inputs/boolean_input_test.rb +108 -0
- data/test/inputs/collection_check_boxes_input_test.rb +224 -0
- data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
- data/test/inputs/collection_select_input_test.rb +241 -0
- data/test/inputs/datetime_input_test.rb +99 -0
- data/test/inputs/disabled_test.rb +38 -0
- data/test/inputs/discovery_test.rb +61 -0
- data/test/inputs/file_input_test.rb +16 -0
- data/test/inputs/general_test.rb +69 -0
- data/test/inputs/grouped_collection_select_input_test.rb +118 -0
- data/test/inputs/hidden_input_test.rb +30 -0
- data/test/inputs/numeric_input_test.rb +173 -0
- data/test/inputs/priority_input_test.rb +43 -0
- data/test/inputs/readonly_test.rb +61 -0
- data/test/inputs/required_test.rb +113 -0
- data/test/inputs/string_input_test.rb +140 -0
- data/test/inputs/text_input_test.rb +24 -0
- data/test/simple_form_test.rb +9 -0
- data/test/support/discovery_inputs.rb +21 -0
- data/test/support/misc_helpers.rb +102 -0
- data/test/support/mock_controller.rb +24 -0
- data/test/support/models.rb +210 -0
- data/test/test_helper.rb +90 -0
- metadata +210 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class CollectionInput < Base
|
4
|
+
# Default boolean collection for use with selects/radios when no
|
5
|
+
# collection is given. Always fallback to this boolean collection.
|
6
|
+
# Texts can be translated using i18n in "simple_form.yes" and
|
7
|
+
# "simple_form.no" keys. See the example locale file.
|
8
|
+
def self.boolean_collection
|
9
|
+
i18n_cache :boolean_collection do
|
10
|
+
[ [I18n.t(:"simple_form.yes", :default => 'Yes'), true],
|
11
|
+
[I18n.t(:"simple_form.no", :default => 'No'), false] ]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def input
|
16
|
+
raise NotImplementedError,
|
17
|
+
"input should be implemented by classes inheriting from CollectionInput"
|
18
|
+
end
|
19
|
+
|
20
|
+
def input_options
|
21
|
+
options = super
|
22
|
+
options[:include_blank] = true unless skip_include_blank?
|
23
|
+
options
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def collection
|
29
|
+
@collection ||= begin
|
30
|
+
collection = options.delete(:collection) || self.class.boolean_collection
|
31
|
+
collection.respond_to?(:call) ? collection.call : collection.to_a
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_required?
|
36
|
+
super && (input_options[:include_blank] || multiple?)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check if :include_blank must be included by default.
|
40
|
+
def skip_include_blank?
|
41
|
+
(options.keys & [:prompt, :include_blank, :default, :selected]).any? || multiple?
|
42
|
+
end
|
43
|
+
|
44
|
+
def multiple?
|
45
|
+
!!options[:input_html].try(:[], :multiple)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Detect the right method to find the label and value for a collection.
|
49
|
+
# If no label or value method are defined, will attempt to find them based
|
50
|
+
# on default label and value methods that can be configured through
|
51
|
+
# SimpleForm.collection_label_methods and
|
52
|
+
# SimpleForm.collection_value_methods.
|
53
|
+
def detect_collection_methods
|
54
|
+
label, value = options.delete(:label_method), options.delete(:value_method)
|
55
|
+
|
56
|
+
unless label && value
|
57
|
+
common_method_for = detect_common_display_methods
|
58
|
+
label ||= common_method_for[:label]
|
59
|
+
value ||= common_method_for[:value]
|
60
|
+
end
|
61
|
+
|
62
|
+
[label, value]
|
63
|
+
end
|
64
|
+
|
65
|
+
def detect_common_display_methods(collection_classes = detect_collection_classes)
|
66
|
+
collection_translated = translate_collection if collection_classes == [Symbol]
|
67
|
+
|
68
|
+
if collection_translated || collection_classes.include?(Array)
|
69
|
+
{ :label => :first, :value => :last }
|
70
|
+
elsif collection_includes_basic_objects?(collection_classes)
|
71
|
+
{ :label => :to_s, :value => :to_s }
|
72
|
+
else
|
73
|
+
sample = collection.first || collection.last
|
74
|
+
|
75
|
+
{ :label => SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
76
|
+
:value => SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def detect_collection_classes(some_collection = collection)
|
81
|
+
some_collection.map { |e| e.class }.uniq
|
82
|
+
end
|
83
|
+
|
84
|
+
def collection_includes_basic_objects?(collection_classes)
|
85
|
+
(collection_classes & [
|
86
|
+
String, Integer, Fixnum, Bignum, Float, NilClass, Symbol, TrueClass, FalseClass
|
87
|
+
]).any?
|
88
|
+
end
|
89
|
+
|
90
|
+
def translate_collection
|
91
|
+
if translated_collection = translate(:options)
|
92
|
+
@collection = collection.map do |key|
|
93
|
+
[translated_collection[key] || key, key]
|
94
|
+
end
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class CollectionRadioButtonsInput < CollectionInput
|
4
|
+
def input
|
5
|
+
label_method, value_method = detect_collection_methods
|
6
|
+
|
7
|
+
@builder.send("collection_#{input_type}",
|
8
|
+
attribute_name, collection, value_method, label_method,
|
9
|
+
input_options, input_html_options, &collection_block_for_nested_boolean_style
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def input_options
|
14
|
+
options = super
|
15
|
+
apply_default_collection_options!(options)
|
16
|
+
apply_nested_boolean_collection_options!(options) if nested_boolean_style?
|
17
|
+
options
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def apply_default_collection_options!(options)
|
23
|
+
options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag)
|
24
|
+
options[:item_wrapper_class] = [
|
25
|
+
item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class
|
26
|
+
].compact.presence
|
27
|
+
|
28
|
+
options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag)
|
29
|
+
options[:collection_wrapper_class] = [
|
30
|
+
options[:collection_wrapper_class], SimpleForm.collection_wrapper_class
|
31
|
+
].compact.presence
|
32
|
+
end
|
33
|
+
|
34
|
+
# Force item wrapper to be a label when using nested boolean, to support
|
35
|
+
# configuring classes through :item_wrapper_class, and to maintain
|
36
|
+
# compatibility with :inline style and default :item_wrapper_tag.
|
37
|
+
def apply_nested_boolean_collection_options!(options)
|
38
|
+
options[:item_wrapper_tag] = :label
|
39
|
+
end
|
40
|
+
|
41
|
+
def collection_block_for_nested_boolean_style
|
42
|
+
return unless nested_boolean_style?
|
43
|
+
|
44
|
+
proc { |builder| build_nested_boolean_style_item_tag(builder) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_nested_boolean_style_item_tag(collection_builder)
|
48
|
+
collection_builder.radio_button + collection_builder.text
|
49
|
+
end
|
50
|
+
|
51
|
+
def item_wrapper_class
|
52
|
+
"radio"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Do not attempt to generate label[for] attributes by default, unless an
|
56
|
+
# explicit html option is given. This avoids generating labels pointing to
|
57
|
+
# non existent fields.
|
58
|
+
def generate_label_for_attribute?
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class CollectionSelectInput < CollectionInput
|
4
|
+
def input
|
5
|
+
label_method, value_method = detect_collection_methods
|
6
|
+
|
7
|
+
@builder.collection_select(
|
8
|
+
attribute_name, collection, value_method, label_method,
|
9
|
+
input_options, input_html_options
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class DateTimeInput < Base
|
4
|
+
def input
|
5
|
+
@builder.send(:"#{input_type}_select", attribute_name, input_options, input_html_options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def has_required?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def label_target
|
15
|
+
position = case input_type
|
16
|
+
when :date, :datetime
|
17
|
+
date_order = input_options[:order] || I18n.t('date.order')
|
18
|
+
date_order.first
|
19
|
+
else
|
20
|
+
:hour
|
21
|
+
end
|
22
|
+
|
23
|
+
position = ActionView::Helpers::DateTimeSelector::POSITION[position]
|
24
|
+
"#{attribute_name}_#{position}i"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class GroupedCollectionSelectInput < CollectionInput
|
4
|
+
def input
|
5
|
+
label_method, value_method = detect_collection_methods
|
6
|
+
@builder.grouped_collection_select(attribute_name, grouped_collection,
|
7
|
+
group_method, group_label_method, value_method, label_method,
|
8
|
+
input_options, input_html_options)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def grouped_collection
|
14
|
+
@grouped_collection ||= begin
|
15
|
+
grouped_collection = options.delete(:collection)
|
16
|
+
grouped_collection.respond_to?(:call) ? grouped_collection.call : grouped_collection.to_a
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Sample collection
|
21
|
+
def collection
|
22
|
+
@collection ||= grouped_collection.first.try(:send, group_method) || []
|
23
|
+
end
|
24
|
+
|
25
|
+
def group_method
|
26
|
+
@group_method ||= options.delete(:group_method)
|
27
|
+
end
|
28
|
+
|
29
|
+
def group_label_method
|
30
|
+
label = options.delete(:group_label_method)
|
31
|
+
|
32
|
+
unless label
|
33
|
+
common_method_for = detect_common_display_methods(detect_collection_classes(grouped_collection))
|
34
|
+
label = common_method_for[:label]
|
35
|
+
end
|
36
|
+
|
37
|
+
label
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class HiddenInput < Base
|
4
|
+
disable :label, :errors, :hint, :required
|
5
|
+
|
6
|
+
def input
|
7
|
+
@builder.hidden_field(attribute_name, input_html_options)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def required_class
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class NumericInput < Base
|
4
|
+
enable :placeholder, :min_max
|
5
|
+
|
6
|
+
def input
|
7
|
+
add_size!
|
8
|
+
input_html_classes.unshift("numeric")
|
9
|
+
if html5?
|
10
|
+
input_html_options[:type] ||= "number"
|
11
|
+
input_html_options[:step] ||= integer? ? 1 : "any"
|
12
|
+
end
|
13
|
+
@builder.text_field(attribute_name, input_html_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Rails adds the size attr by default, if the :size key does not exist.
|
19
|
+
def add_size!
|
20
|
+
input_html_options[:size] ||= nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class PriorityInput < CollectionSelectInput
|
4
|
+
def input
|
5
|
+
@builder.send(:"#{input_type}_select", attribute_name, input_priority,
|
6
|
+
input_options, input_html_options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def input_priority
|
10
|
+
options[:priority] || SimpleForm.send(:"#{input_type}_priority")
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def has_required?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def skip_include_blank?
|
20
|
+
super || input_priority.present?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Inputs
|
3
|
+
class StringInput < Base
|
4
|
+
enable :placeholder, :maxlength, :pattern
|
5
|
+
|
6
|
+
def input
|
7
|
+
unless string?
|
8
|
+
input_html_classes.unshift("string")
|
9
|
+
input_html_options[:type] ||= input_type if html5?
|
10
|
+
end
|
11
|
+
|
12
|
+
add_size!
|
13
|
+
@builder.text_field(attribute_name, input_html_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def string?
|
19
|
+
input_type == :string
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
|
3
|
+
module SimpleForm
|
4
|
+
module MapType
|
5
|
+
def self.extended(base)
|
6
|
+
base.class_attribute :mappings
|
7
|
+
base.mappings = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def map_type(*types)
|
11
|
+
map_to = types.extract_options![:to]
|
12
|
+
raise ArgumentError, "You need to give :to as option to map_type" unless map_to
|
13
|
+
self.mappings = mappings.merge types.each_with_object({}) { |t, m| m[t] = map_to }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Wrappers
|
3
|
+
# Provides the builder syntax for components. The builder provides
|
4
|
+
# three methods `use`, `optional` and `wrapper` and they allow the following invocations:
|
5
|
+
#
|
6
|
+
# config.wrappers do |b|
|
7
|
+
# # Use a single component
|
8
|
+
# b.use :html5
|
9
|
+
#
|
10
|
+
# # Use the component, but do not automatically lookup. It will only be triggered when
|
11
|
+
# # :placeholder is explicitly set.
|
12
|
+
# b.optional :placeholder
|
13
|
+
#
|
14
|
+
# # Use a component with specific wrapper options
|
15
|
+
# b.use :error, :wrap_with => { :tag => "span", :class => "error" }
|
16
|
+
#
|
17
|
+
# # Use a set of components by wrapping them in a tag+class.
|
18
|
+
# b.wrapper :tag => "div", :class => "another" do |ba|
|
19
|
+
# ba.use :label
|
20
|
+
# ba.use :input
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # Use a set of components by wrapping them in a tag+class.
|
24
|
+
# # This wrapper is identified by :label_input, which means it can
|
25
|
+
# # be turned off on demand with `f.input :name, :label_input => false`
|
26
|
+
# b.wrapper :label_input, :tag => "div", :class => "another" do |ba|
|
27
|
+
# ba.use :label
|
28
|
+
# ba.use :input
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# The builder also accepts default options at the root level. This is usually
|
33
|
+
# used if you want a component to be disabled by default:
|
34
|
+
#
|
35
|
+
# config.wrappers :hint => false do |b|
|
36
|
+
# b.use :hint
|
37
|
+
# b.use :label_input
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# In the example above, hint defaults to false, which means it won't automatically
|
41
|
+
# do the lookup anymore. It will only be triggered when :hint is explicitly set.
|
42
|
+
class Builder
|
43
|
+
def initialize(options)
|
44
|
+
@options = options
|
45
|
+
@components = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def use(name, options=nil, &block)
|
49
|
+
if block_given?
|
50
|
+
ActiveSupport::Deprecation.warn "Passing a block to use is deprecated. " \
|
51
|
+
"Please use wrapper instead of use."
|
52
|
+
return wrapper(name, options, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
if options && options.keys != [:wrap_with]
|
56
|
+
ActiveSupport::Deprecation.warn "Passing :tag, :class and others to use is deprecated. " \
|
57
|
+
"Please invoke b.use #{name.inspect}, :wrap_with => #{options.inspect} instead."
|
58
|
+
options = { :wrap_with => options }
|
59
|
+
end
|
60
|
+
|
61
|
+
if options && wrapper = options[:wrap_with]
|
62
|
+
@components << Single.new(name, wrapper)
|
63
|
+
else
|
64
|
+
@components << name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def optional(name, options=nil, &block)
|
69
|
+
if block_given?
|
70
|
+
ActiveSupport::Deprecation.warn "Passing a block to optional is deprecated. " \
|
71
|
+
"Please use wrapper instead of optional."
|
72
|
+
return wrapper(name, options, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
if options && options.keys != [:wrap_with]
|
76
|
+
ActiveSupport::Deprecation.warn "Passing :tag, :class and others to optional is deprecated. " \
|
77
|
+
"Please invoke b.optional #{name.inspect}, :wrap_with => #{options.inspect} instead."
|
78
|
+
options = { :wrap_with => options }
|
79
|
+
end
|
80
|
+
|
81
|
+
@options[name] = false
|
82
|
+
use(name, options, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def wrapper(name, options=nil)
|
86
|
+
if block_given?
|
87
|
+
name, options = nil, name if name.is_a?(Hash)
|
88
|
+
builder = self.class.new(@options)
|
89
|
+
options ||= {}
|
90
|
+
options[:tag] = :div if options[:tag].nil?
|
91
|
+
yield builder
|
92
|
+
@components << Many.new(name, builder.to_a, options)
|
93
|
+
else
|
94
|
+
raise ArgumentError, "A block is required as argument to wrapper"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_a
|
99
|
+
@components
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|