diff --git a/lib/simple_form.rb b/lib/simple_form.rb
index 16d470b8..39bce42a 100644
--- a/lib/simple_form.rb
+++ b/lib/simple_form.rb
@@ -2,7 +2,9 @@ require 'simple_form/action_view_extensions/form_helper'
require 'simple_form/action_view_extensions/builder'
module SimpleForm
+ autoload :Components, 'simple_form/components'
autoload :FormBuilder, 'simple_form/form_builder'
autoload :I18nCache, 'simple_form/i18n_cache'
autoload :MapType, 'simple_form/map_type'
+ autoload :RequiredComponent, 'simple_form/required_component'
end
\ No newline at end of file
diff --git a/lib/simple_form/abstract_component.rb b/lib/simple_form/abstract_component.rb
deleted file mode 100644
index 4333e03c..00000000
--- a/lib/simple_form/abstract_component.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-module SimpleForm
- class AbstractComponent
- attr_reader :builder, :attribute, :input_type, :options
-
- def self.basename
- @basename ||= name.split("::").last.underscore.to_sym
- end
-
- def initialize(builder, attribute, input_type, options)
- @builder = builder
- @attribute = attribute
- @input_type = input_type
- @options = options
- end
-
- def generate
- return "" unless valid?
- component_tag(content).to_s
- end
-
- def valid?
- true
- end
-
- def template
- @builder.template
- end
-
- def object
- @builder.object
- end
-
- def hidden_input?
- @input_type == :hidden
- end
-
- def basename
- self.class.basename
- end
-
- def component_tag(content)
- template.content_tag(:span, content, :class => basename)
- end
-
- def translate(default='')
- lookups = [ :"#{@builder.object_name}.#{@attribute}", :"#{@attribute}", default ]
- I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
- end
- end
-end
\ No newline at end of file
diff --git a/lib/simple_form/components.rb b/lib/simple_form/components.rb
new file mode 100644
index 00000000..94a3f21c
--- /dev/null
+++ b/lib/simple_form/components.rb
@@ -0,0 +1,9 @@
+module SimpleForm
+ module Components
+ autoload :Base, 'simple_form/components/base'
+ autoload :Error, 'simple_form/components/error'
+ autoload :Hint, 'simple_form/components/hint'
+ autoload :Input, 'simple_form/components/input'
+ autoload :Label, 'simple_form/components/label'
+ end
+end
\ No newline at end of file
diff --git a/lib/simple_form/components/base.rb b/lib/simple_form/components/base.rb
new file mode 100644
index 00000000..dc9328a9
--- /dev/null
+++ b/lib/simple_form/components/base.rb
@@ -0,0 +1,52 @@
+module SimpleForm
+ module Components
+ class Base
+ attr_reader :builder, :attribute, :input_type, :options
+
+ def self.basename
+ @basename ||= name.split("::").last.underscore.to_sym
+ end
+
+ def initialize(builder, attribute, input_type, options)
+ @builder = builder
+ @attribute = attribute
+ @input_type = input_type
+ @options = options
+ end
+
+ def generate
+ return "" unless valid?
+ component_tag(content).to_s
+ end
+
+ def valid?
+ true
+ end
+
+ def template
+ @builder.template
+ end
+
+ def object
+ @builder.object
+ end
+
+ def hidden_input?
+ @input_type == :hidden
+ end
+
+ def basename
+ self.class.basename
+ end
+
+ def component_tag(content)
+ template.content_tag(:span, content, :class => basename)
+ end
+
+ def translate(default='')
+ lookups = [ :"#{@builder.object_name}.#{@attribute}", :"#{@attribute}", default ]
+ I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/simple_form/components/error.rb b/lib/simple_form/components/error.rb
new file mode 100644
index 00000000..990bb2f3
--- /dev/null
+++ b/lib/simple_form/components/error.rb
@@ -0,0 +1,17 @@
+module SimpleForm
+ module Components
+ class Error < Base
+ def valid?
+ !hidden_input? && !errors.blank?
+ end
+
+ def errors
+ @errors ||= object.errors[@attribute]
+ end
+
+ def content
+ Array(errors).to_sentence
+ end
+ end
+ end
+end
diff --git a/lib/simple_form/components/hint.rb b/lib/simple_form/components/hint.rb
new file mode 100644
index 00000000..74ba4b72
--- /dev/null
+++ b/lib/simple_form/components/hint.rb
@@ -0,0 +1,13 @@
+module SimpleForm
+ module Components
+ class Hint < Base
+ def valid?
+ !hidden_input? && !content.blank?
+ end
+
+ def content
+ @content ||= @options[:hint] || translate
+ end
+ end
+ end
+end
diff --git a/lib/simple_form/components/input.rb b/lib/simple_form/components/input.rb
new file mode 100644
index 00000000..e30b51a8
--- /dev/null
+++ b/lib/simple_form/components/input.rb
@@ -0,0 +1,68 @@
+module SimpleForm
+ module Components
+ class Input < Base
+ extend I18nCache
+ extend MapType
+ include RequiredComponent
+
+ map_type :boolean, :to => :check_box
+ map_type :text, :to => :text_area
+ map_type :datetime, :to => :datetime_select, :options => true
+ map_type :date, :to => :date_select, :options => true
+ map_type :time, :to => :time_select, :options => true
+ map_type :password, :to => :password_field
+ map_type :hidden, :to => :hidden_field
+ map_type :select, :to => :collection_select, :options => true, :collection => true
+ map_type :radio, :to => :collection_radio, :collection => true
+ map_type :numeric, :to => :text_field
+ map_type :string, :to => :text_field
+
+ def self.boolean_collection
+ i18n_cache :boolean_collection do
+ [ [I18n.t(:"simple_form.true", :default => 'Yes'), true],
+ [I18n.t(:"simple_form.false", :default => 'No'), false] ]
+ end
+ end
+
+ def generate
+ html_options = @options[:html] || {}
+ html_options[:class] = default_css_classes(html_options[:class])
+ @options[:options] ||= {}
+
+ mapping = self.class.mappings[@input_type]
+ raise "Invalid input type #{@input_type.inspect}" unless mapping
+
+ args = [ @attribute ]
+
+ if mapping.collection
+ collection = @options[:collection] || self.class.boolean_collection
+ detect_collection_methods(collection, @options)
+ args.push(collection, @options[:value_method], @options[:label_method])
+ end
+
+ args << @options[:options] if mapping.options
+ args << html_options
+
+ @builder.send(mapping.method, *args)
+ end
+
+ def detect_collection_methods(collection, options)
+ sample = collection.first
+
+ if sample.is_a?(Array) # TODO Test me
+ options[:label_method] ||= :first
+ options[:value_method] ||= :last
+ elsif sample.is_a?(String) # TODO Test me
+ options[:label_method] ||= :to_s
+ options[:value_method] ||= :to_s
+ elsif sample.is_a?(Numeric) # TODO Test me (including selected)
+ options[:label_method] ||= :to_s
+ options[:value_method] ||= :to_i
+ else # TODO Implement collection label methods or something similar
+ options[:label_method] ||= :to_s
+ options[:value_method] ||= :to_s
+ end
+ end
+ end
+ end
+end
diff --git a/lib/simple_form/components/label.rb b/lib/simple_form/components/label.rb
new file mode 100644
index 00000000..7823639e
--- /dev/null
+++ b/lib/simple_form/components/label.rb
@@ -0,0 +1,48 @@
+module SimpleForm
+ module Components
+ class Label < Base
+ extend I18nCache
+ include RequiredComponent
+
+ def self.translate_required_string
+ i18n_cache :translate_required_string do
+ I18n.t(:"simple_form.required.string", :default =>
+ %[#{translate_required_mark} ]
+ )
+ end
+ end
+
+ def self.translate_required_text
+ I18n.t(:"simple_form.required.text", :default => 'required')
+ end
+
+ def self.translate_required_mark
+ I18n.t(:"simple_form.required.mark", :default => '*')
+ end
+
+ def valid?
+ !hidden_input?
+ end
+
+ def generate
+ return '' unless valid?
+ html_options = { :class => default_css_classes }
+ html_options[:for] = @options[:html][:id] if @options.key?(:html)
+ @builder.label(@attribute, label_text, html_options)
+ end
+
+ def label_text
+ required_text << (@options[:label] || translate_label)
+ end
+
+ def required_text
+ attribute_required? ? self.class.translate_required_string.dup : ''
+ end
+
+ def translate_label
+ default = object.try(:human_attribute_name, @attribute.to_s) || @attribute.to_s.humanize
+ translate(default)
+ end
+ end
+ end
+end
diff --git a/lib/simple_form/error.rb b/lib/simple_form/error.rb
deleted file mode 100644
index 0e530c49..00000000
--- a/lib/simple_form/error.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module SimpleForm
- class Error < AbstractComponent
- def valid?
- !hidden_input? && !errors.blank?
- end
-
- def errors
- @errors ||= object.errors[@attribute]
- end
-
- def content
- Array(errors).to_sentence
- end
- end
-end
diff --git a/lib/simple_form/form_builder.rb b/lib/simple_form/form_builder.rb
index 0f7c1d01..f29d0b53 100644
--- a/lib/simple_form/form_builder.rb
+++ b/lib/simple_form/form_builder.rb
@@ -1,24 +1,17 @@
-require 'simple_form/abstract_component'
-require 'simple_form/label'
-require 'simple_form/input'
-require 'simple_form/hint'
-require 'simple_form/error'
-
module SimpleForm
class FormBuilder < ActionView::Helpers::FormBuilder
- # Components used by the folder builder. By default is:
- # [SimpleForm::Label, SimpleForm::Input, SimpleForm::Hint, SimpleForm::Error]
+ # Components used by the folder builder.
+ # By default is [:label, :input, :hint, :error].
cattr_accessor :components, :instance_writer => false
- @@components = [SimpleForm::Label, SimpleForm::Input, SimpleForm::Hint, SimpleForm::Error]
+ @@components = [
+ SimpleForm::Components::Label, SimpleForm::Components::Input,
+ SimpleForm::Components::Hint, SimpleForm::Components::Error
+ ]
# Make the template accessible for components
attr_reader :template
def input(attribute, options={})
- # TODO Do this makes sense since we are delegating to components?
- options.assert_valid_keys(:as, :label, :required, :hint, :options, :html,
- :collection, :label_method, :value_method)
-
input_type = (options[:as] || default_input_type(attribute, options)).to_sym
pieces = self.components.collect do |klass|
diff --git a/lib/simple_form/hint.rb b/lib/simple_form/hint.rb
deleted file mode 100644
index a2c3210b..00000000
--- a/lib/simple_form/hint.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module SimpleForm
- class Hint < AbstractComponent
- def valid?
- !hidden_input? && !content.blank?
- end
-
- def content
- @content ||= @options[:hint] || translate
- end
- end
-end
diff --git a/lib/simple_form/input.rb b/lib/simple_form/input.rb
deleted file mode 100644
index 63207e4d..00000000
--- a/lib/simple_form/input.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require 'simple_form/required_component'
-require 'simple_form/i18n_cache'
-require 'simple_form/map_type'
-
-module SimpleForm
- class Input < AbstractComponent
- extend I18nCache
- extend MapType
- include RequiredComponent
-
- map_type :boolean, :to => :check_box
- map_type :text, :to => :text_area
- map_type :datetime, :to => :datetime_select, :options => true
- map_type :date, :to => :date_select, :options => true
- map_type :time, :to => :time_select, :options => true
- map_type :password, :to => :password_field
- map_type :hidden, :to => :hidden_field
- map_type :select, :to => :collection_select, :options => true, :collection => true
- map_type :radio, :to => :collection_radio, :collection => true
- map_type :numeric, :to => :text_field
- map_type :string, :to => :text_field
-
- def self.boolean_collection
- i18n_cache :boolean_collection do
- [ [I18n.t(:"simple_form.true", :default => 'Yes'), true],
- [I18n.t(:"simple_form.false", :default => 'No'), false] ]
- end
- end
-
- def generate
- html_options = @options[:html] || {}
- html_options[:class] = default_css_classes(html_options[:class])
- @options[:options] ||= {}
-
- mapping = self.class.mappings[@input_type]
- raise "Invalid input type #{@input_type.inspect}" unless mapping
-
- args = [ @attribute ]
-
- if mapping.collection
- collection = @options[:collection] || self.class.boolean_collection
- detect_collection_methods(collection, @options)
- args.push(collection, @options[:value_method], @options[:label_method])
- end
-
- args << @options[:options] if mapping.options
- args << html_options
-
- @builder.send(mapping.method, *args)
- end
-
- def detect_collection_methods(collection, options)
- sample = collection.first
-
- if sample.is_a?(Array) # TODO Test me
- options[:label_method] ||= :first
- options[:value_method] ||= :last
- elsif sample.is_a?(String) # TODO Test me
- options[:label_method] ||= :to_s
- options[:value_method] ||= :to_s
- elsif sample.is_a?(Numeric) # TODO Test me (including selected)
- options[:label_method] ||= :to_s
- options[:value_method] ||= :to_i
- else # TODO Implement collection label methods or something similar
- options[:label_method] ||= :to_s
- options[:value_method] ||= :to_s
- end
- end
-
- end
-end
diff --git a/lib/simple_form/label.rb b/lib/simple_form/label.rb
deleted file mode 100644
index 579f878e..00000000
--- a/lib/simple_form/label.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require 'simple_form/required_component'
-require 'simple_form/i18n_cache'
-
-module SimpleForm
- class Label < AbstractComponent
- extend SimpleForm::I18nCache
- include RequiredComponent
-
- def self.translate_required_string
- i18n_cache :translate_required_string do
- I18n.t(:"simple_form.required.string", :default =>
- %[#{translate_required_mark} ]
- )
- end
- end
-
- def self.translate_required_text
- I18n.t(:"simple_form.required.text", :default => 'required')
- end
-
- def self.translate_required_mark
- I18n.t(:"simple_form.required.mark", :default => '*')
- end
-
- def valid?
- !hidden_input?
- end
-
- def generate
- return '' unless valid?
- html_options = { :class => default_css_classes }
- html_options[:for] = @options[:html][:id] if @options.key?(:html)
- @builder.label(@attribute, label_text, html_options)
- end
-
- def label_text
- required_text << (@options[:label] || translate_label)
- end
-
- def required_text
- attribute_required? ? self.class.translate_required_string.dup : ''
- end
-
- def translate_label
- default = object.try(:human_attribute_name, @attribute.to_s) || @attribute.to_s.humanize
- translate(default)
- end
- end
-end
diff --git a/test/input_test.rb b/test/input_test.rb
index 8abdd525..e40f0d89 100644
--- a/test/input_test.rb
+++ b/test/input_test.rb
@@ -3,15 +3,7 @@ require 'test_helper'
class InputTest < ActionView::TestCase
setup do
- SimpleForm::Input.reset_i18n_cache :boolean_collection
- end
-
- test 'input should verify options hash' do
- assert_raise ArgumentError do
- simple_form_for @user do |f|
- concat f.input :name, :invalid_param => true
- end
- end
+ SimpleForm::Components::Input.reset_i18n_cache :boolean_collection
end
test 'input should generate a default text field' do
diff --git a/test/label_test.rb b/test/label_test.rb
index c404ccf7..6ee9dd7f 100644
--- a/test/label_test.rb
+++ b/test/label_test.rb
@@ -3,7 +3,7 @@ require 'test_helper'
class LabelTest < ActionView::TestCase
setup do
- SimpleForm::Label.reset_i18n_cache :translate_required_string
+ SimpleForm::Components::Label.reset_i18n_cache :translate_required_string
end
test 'input should generate a label with the text field' do