Most of refactoring done.

This commit is contained in:
José Valim 2010-01-09 15:39:14 +01:00
parent 075e7b23b6
commit 42830967d7
13 changed files with 508 additions and 658 deletions

View File

@ -68,7 +68,7 @@ module SimpleForm
# * disabled => the value or values that should be disabled. Accepts a single
# item or an array of items.
#
def collection_check_box(attribute, collection, value_method, text_method, options={}, html_options={})
def collection_check_boxes(attribute, collection, value_method, text_method, options={}, html_options={})
collection.inject('') do |result, item|
value = item.send value_method
text = item.send text_method
@ -77,7 +77,7 @@ module SimpleForm
default_html_options[:multiple] = true
result << check_box(attribute, default_html_options, value, '') <<
label("#{attribute}_#{value}", text, :class => "collection_check_box")
label("#{attribute}_#{value}", text, :class => "collection_check_boxes")
end
end

View File

@ -1,10 +1,4 @@
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'
autoload :Wrapper, 'simple_form/components/wrapper'
end
end

View File

@ -1,117 +0,0 @@
module SimpleForm
module Components
# The component is the core of SimpleForm. SimpleForm can be customized simply
# with the addition of new components to the component stack. A component just
# need to be initialized with two values, the builder and the next component to
# be invoked and respond to call.
#
# The Base component is a raw component with some helpers and a default behavior
# of prepending the content available in the method content.
class Base
delegate :template, :object, :object_name, :attribute_name, :column,
:reflection, :input_type, :options, :to => :@builder
# When action is create or update, we still should use new and edit
ACTIONS = {
:create => :new,
:update => :edit
}
def __content
valid? ? content : ""
end
def self.basename
@basename ||= name.split("::").last.underscore.to_sym
end
def initialize(builder, component)
@builder = builder
@component = component
end
# Generate component content and call next component in the stack. When a
# component is invalid it will be skipped.
def call
return @component.call unless valid?
content + @component.call
end
def valid?
true
end
def hidden_input?
input_type == :hidden
end
def basename
self.class.basename
end
# Find reflection name when available, otherwise use attribute
def reflection_or_attribute_name
reflection ? reflection.name : attribute_name
end
# Default html options for a component. Passed as a parameter for simple
# form component using component name as follows:
#
# label_html => {}
# input_html => {}
# hint_html => {}
# error_html => {}
# wrapper_html => {}
#
def component_html_options
options[:"#{basename}_html"] || {}
end
# Renders default content tag for components, using default html class
# and user defined parameters.
# Default component tag can be configured in SimpleForm.component_tag.
def component_tag(content)
html_options = component_html_options
html_options[:class] = "#{basename} #{html_options[:class]}".strip
template.content_tag(SimpleForm.error_tag, content, html_options)
end
# Lookup translations for components using I18n, based on object name,
# actual action and attribute name. Lookup priority as follows:
#
# simple_form.{type}.{model}.{action}.{attribute}
# simple_form.{type}.{model}.{attribute}
# simple_form.{type}.{attribute}
#
# Type is used for :labels and :hints.
# Model is the actual object name, for a @user object you'll have :user.
# Action is the action being rendered, usually :new or :edit.
# And attribute is the attribute itself, :name for example.
# Example:
#
# simple_form:
# labels:
# user:
# new:
# email: 'E-mail para efetuar o sign in.'
# edit:
# email: 'E-mail.'
#
# Take a look at our locale example file.
def translate(default='')
lookups = []
lookups << :"#{object_name}.#{lookup_action}.#{reflection_or_attribute_name}"
lookups << :"#{object_name}.#{reflection_or_attribute_name}"
lookups << :"#{reflection_or_attribute_name}"
lookups << default
I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
end
# The action to be used in lookup.
def lookup_action
action = template.controller.action_name.to_sym
ACTIONS[action] || action
end
end
end
end

View File

@ -1,28 +0,0 @@
module SimpleForm
module Components
# General error component. Responsible for verifying whether an object
# exists and there are errors on the attribute being generated. If errors
# exists than the component will be rendered, otherwise will be skipped.
class Error < Base
def valid?
object && !hidden_input? && !errors.blank?
end
def errors
@errors ||= (errors_on_attribute + errors_on_association).compact
end
def errors_on_attribute
Array(object.errors[attribute_name])
end
def errors_on_association
reflection ? Array(object.errors[reflection.name]) : []
end
def content
component_tag errors.to_sentence
end
end
end
end

View File

@ -1,122 +0,0 @@
module SimpleForm
module Components
# Default input component, responsible for mapping column attributes from
# database to inputs to be rendered.
class Input < Base
include RequiredHelpers
extend I18nCache
extend MapType
map_type :boolean, :to => :check_box
map_type :string, :to => :text_field
map_type :password, :to => :password_field
map_type :text, :to => :text_area
map_type :file, :to => :file_field
map_type :hidden, :to => :hidden_field
# Numeric types
map_type :integer, :float, :decimal, :to => :text_field
# Date/time types
map_type :datetime, :to => :datetime_select, :options => true
map_type :date, :to => :date_select, :options => true
map_type :time, :to => :time_select, :options => true
# Collection types
map_type :select, :to => :collection_select, :options => true, :collection => true
map_type :radio, :to => :collection_radio, :options => true, :collection => true
map_type :check_boxes, :to => :collection_check_box, :options => true, :collection => true
# With priority zones
map_type :country, :to => :country_select, :options => true, :with_priority => true
map_type :time_zone, :to => :time_zone_select, :options => true, :with_priority => true
# Default boolean collection for use with selects/radios when no
# collection is given. Always fallback to this boolean collection.
# Texts can be translated using i18n in "simple_form.true" and
# "simple_form.false" keys. See the example locale file.
def self.boolean_collection
i18n_cache :boolean_collection do
[ [I18n.t(:"simple_form.yes", :default => 'Yes'), true],
[I18n.t(:"simple_form.no", :default => 'No'), false] ]
end
end
# Generate the input through the mapped option. Apply correct behaviors
# for collections and add options whenever the input requires it.
def content
mapping = self.class.mappings[input_type]
raise "Invalid input type #{input_type.inspect}" unless mapping
args = [ attribute_name ]
apply_with_priority_behavior(args) if mapping.with_priority
apply_collection_behavior(args) if mapping.collection
apply_options_behavior(args) if mapping.options
apply_html_options(args)
@builder.send(mapping.method, *args)
end
protected
# Applies priority behavior to configured types.
def apply_with_priority_behavior(args)
priorities = options[:priority] || SimpleForm.send(:"#{input_type}_priority")
args.push(priorities)
end
# Applies default collection behavior, mapping the default collection to
# boolean collection if it was not set, and defining default include_blank
# option
def apply_collection_behavior(args)
collection = (options[:collection] || self.class.boolean_collection).to_a
detect_collection_methods(collection, options)
args.push(collection, options[:value_method], options[:label_method])
end
# Apply default behavior for inputs that need extra options, such as date
# and time selects.
def apply_options_behavior(args)
options[:include_blank] = true unless skip_include_blank?
args << options
end
# Adds default html options to the input based on db column information.
def apply_html_options(args)
html_options = component_html_options
if column && [:string, :password, :decimal, :float].include?(input_type)
html_options[:maxlength] ||= column.limit
end
args << html_options
end
# Check if :include_blank must be included by default.
def skip_include_blank?
options.key?(:prompt) || options.key?(:include_blank) || options[:input_html].try(:[], :multiple)
end
# Detect the right method to find the label and value for a collection.
# If no label or value method are defined, will attempt to find them based
# on default label and value methods that can be configured through
# SimpleForm.collection_label_methods and
# SimpleForm.collection_value_methods.
def detect_collection_methods(collection, options)
sample = collection.first || collection.last
case sample
when Array
label, value = :first, :last
when Integer
label, value = :to_s, :to_i
when String, NilClass
label, value = :to_s, :to_s
end
options[:label_method] ||= label || SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) }
options[:value_method] ||= value || SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) }
end
end
end
end

View File

@ -1,19 +0,0 @@
module SimpleForm
module Components
# Wrapper component. The last the will be executed by default, responsible
# for wrapping the entire stack in a wrapper tag if it is configured.
class Wrapper < Base
include RequiredHelpers
def call
tag = options[:wrapper] || SimpleForm.wrapper_tag
if tag
template.content_tag(tag, @component.call, component_html_options)
else
@component.call
end
end
end
end
end

View File

@ -3,8 +3,6 @@ module SimpleForm
attr_reader :template, :object_name, :object, :attribute_name, :column,
:reflection, :input_type, :options
TERMINATOR = lambda { "" }
# Basic input helper, combines all components in the stack to generate
# input html based on options the user define and some guesses through
# database column information. By default a call to input will generate
@ -76,8 +74,6 @@ module SimpleForm
end
module ClassMethods #:nodoc:
include I18nCache
def translate_required_html
i18n_cache :translate_required_html do
I18n.t(:"simple_form.required.html", :default =>
@ -102,20 +98,11 @@ module SimpleForm
def label_text
SimpleForm.label_text.call(raw_label_text, required_label_text)
end
# TODO Fix me
def label_target
case input_type
when :date, :datetime
"#{attribute_name}_1i"
when :time
"#{attribute_name}_4i"
else
attribute_name
end
attribute_name
end
# TODO Why default_css_options only in labels?
def label_html_options
label_options = html_options_for(:label, input_type, required_class)
label_options[:for] = options[:input_html][:id] if options.key?(:input_html)
@ -196,7 +183,9 @@ module SimpleForm
end
end
class Input
class Base
extend I18nCache
include Errors
include Hints
include Labels
@ -209,13 +198,38 @@ module SimpleForm
end
def input
SimpleForm::Components::Input.new(@builder, TERMINATOR).__content
raise NotImplemented
end
def input_options
options[:include_blank] = true unless skip_include_blank?
options
end
def input_html_options
html_options_for(:input, input_type, required_class)
end
def render
pieces = SimpleForm.components.select { |n| n unless @builder.options[n] == false }
terminator = lambda { pieces.map!{ |p| send(p).to_s }.join }
SimpleForm::Components::Wrapper.new(@builder, terminator).call
content = pieces.map!{ |p| send(p).to_s }.join
wrap(content)
end
def wrap(content)
if wrapper_tag && options[:wrapper] != false
template.content_tag(wrapper_tag, content, wrapper_html_options)
else
content
end
end
def wrapper_tag
options[:wrapper_tag] || SimpleForm.wrapper_tag
end
def wrapper_html_options
html_options_for(:wrapper, input_type, required_class)
end
protected
@ -239,6 +253,11 @@ module SimpleForm
reflection ? reflection.name : attribute_name
end
# Check if :include_blank must be included by default.
def skip_include_blank?
options.key?(:prompt) || options.key?(:include_blank)
end
# Retrieve options for the given namespace from the options hash
def html_options_for(namespace, *extra)
html_options = options[:"#{namespace}_html"] || {}
@ -286,9 +305,136 @@ module SimpleForm
end
end
# Uses MapType to handle basic input types.
class MappingInput < Base
extend MapType
map_type :boolean, :to => :check_box
map_type :password, :to => :password_field
map_type :text, :to => :text_area
map_type :file, :to => :file_field
def input
@builder.send(input_method, attribute_name, input_html_options)
end
def input_method
method = self.class.mappings[input_type]
raise "Could not find method for #{input_type.inspect}" unless method
method
end
end
# Handles common text field inputs, as String, Numeric, Float and Decimal.
class TextFieldInput < Base
def input
@builder.text_field(attribute_name, input_html_options)
end
def input_html_options
input_options = super
input_options[:max_length] ||= column.limit if column
input_options
end
end
class DateTimeInput < Base
def input
@builder.send(:"#{input_type}_select", attribute_name, input_options, input_html_options)
end
def label_target
case input_type
when :date, :datetime
"#{attribute_name}_1i"
when :time
"#{attribute_name}_4i"
end
end
end
class CollectionInput < Base
# Default boolean collection for use with selects/radios when no
# collection is given. Always fallback to this boolean collection.
# Texts can be translated using i18n in "simple_form.true" and
# "simple_form.false" keys. See the example locale file.
def self.boolean_collection
i18n_cache :boolean_collection do
[ [I18n.t(:"simple_form.yes", :default => 'Yes'), true],
[I18n.t(:"simple_form.no", :default => 'No'), false] ]
end
end
def input
collection = (options[:collection] || self.class.boolean_collection).to_a
detect_collection_methods(collection, options)
@builder.send(:"collection_#{input_type}", attribute_name, collection, options[:value_method],
options[:label_method], input_options, input_html_options)
end
protected
def skip_include_blank?
super || options[:input_html].try(:[], :multiple)
end
# Detect the right method to find the label and value for a collection.
# If no label or value method are defined, will attempt to find them based
# on default label and value methods that can be configured through
# SimpleForm.collection_label_methods and
# SimpleForm.collection_value_methods.
def detect_collection_methods(collection, options)
sample = collection.first || collection.last
case sample
when Array
label, value = :first, :last
when Integer
label, value = :to_s, :to_i
when String, NilClass
label, value = :to_s, :to_s
end
options[:label_method] ||= label || SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) }
options[:value_method] ||= value || SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) }
end
end
# Handles hidden input.
class HiddenInput < Base
def render
@builder.hidden_field(attribute_name, input_html_options)
end
end
class PriorityInput < Base
def input
@builder.send(:"#{input_type}_select", attribute_name, input_priority,
input_options, input_html_options)
end
def input_priority
options[:priority] || SimpleForm.send(:"#{input_type}_priority")
end
end
extend MapType
map_type :boolean, :password, :text, :file, :to => MappingInput
map_type :hidden, :to => HiddenInput # TODO This should be automatic
map_type :string, :integer, :decimal, :float, :to => TextFieldInput
map_type :select, :radio, :check_boxes, :to => CollectionInput
map_type :date, :time, :datetime, :to => DateTimeInput
map_type :country, :time_zone, :to => PriorityInput
def input(attribute_name, options={})
define_simple_form_attributes(attribute_name, options)
Input.new(self).render
if klass = self.class.mappings[input_type]
klass.new(self).render
else
const_get(:"#{input_type.to_s.camelize}Input").new(self).render
end
end
alias :attribute :input
@ -420,7 +566,7 @@ module SimpleForm
#
def error(attribute_name, options={})
define_simple_form_attributes(attribute_name, :error_html => options)
SimpleForm::Components::Error.new(self, TERMINATOR).call
Base.new(self).error
end
# Creates a hint tag for the given attribute. Accepts a symbol indicating
@ -436,7 +582,7 @@ module SimpleForm
def hint(attribute_name, options={})
attribute_name, options[:hint] = nil, attribute_name if attribute_name.is_a?(String)
define_simple_form_attributes(attribute_name, :hint => options.delete(:hint), :hint_html => options)
SimpleForm::Components::Hint.new(self, TERMINATOR).call
Base.new(self).hint
end
# Creates a default label tag for the given attribute. You can give a label
@ -457,7 +603,7 @@ module SimpleForm
options = args.extract_options!
define_simple_form_attributes(attribute_name, :label => options.delete(:label),
:label_html => options, :required => options.delete(:required))
SimpleForm::Components::Label.new(self, TERMINATOR).call
Base.new(self).label
end
private

View File

@ -1,6 +1,4 @@
module SimpleForm
Mapping = Struct.new(:method, :collection, :options, :with_priority)
module MapType
def mappings
@mappings ||= {}
@ -9,9 +7,7 @@ module SimpleForm
def map_type(*types)
options = types.extract_options!
raise ArgumentError, "You need to give :to as option to map_type" unless options[:to]
mapping = Mapping.new(options[:to], options[:collection] || false,
options[:options] || false, options[:with_priority] || false)
types.each { |t| mappings[t] = mapping }
types.each { |t| mappings[t] = options[:to] }
end
end
end

View File

@ -63,7 +63,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts a collection and generate a serie of checkboxes for value method' do
collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :id, :name
concat f.collection_check_boxes :tag_ids, collection, :id, :name
end
assert_select "form input[type=hidden][name='user[tag_ids][]'][value=]"
@ -74,7 +74,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts a collection and generate a serie of checkboxes with labels for label method' do
collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :id, :name
concat f.collection_check_boxes :tag_ids, collection, :id, :name
end
assert_select 'form label.collection_check_box[for=user_tag_ids_1]', 'Tag 1'
@ -84,7 +84,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts selected values as :checked option' do
collection = (1..3).map{|i| [i, "Tag #{i}"] }
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, :checked => [1, 3]
concat f.collection_check_boxes :tag_ids, collection, :first, :last, :checked => [1, 3]
end
assert_select 'form input[type=checkbox][value=1][checked=checked]'
@ -95,7 +95,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts a single checked value' do
collection = (1..3).map{|i| [i, "Tag #{i}"] }
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, :checked => 3
concat f.collection_check_boxes :tag_ids, collection, :first, :last, :checked => 3
end
assert_select 'form input[type=checkbox][value=3][checked=checked]'
@ -106,7 +106,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts multiple disabled items' do
collection = (1..3).map{|i| [i, "Tag #{i}"] }
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, :disabled => [1, 3]
concat f.collection_check_boxes :tag_ids, collection, :first, :last, :disabled => [1, 3]
end
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
@ -117,7 +117,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts single disable item' do
collection = (1..3).map{|i| [i, "Tag #{i}"] }
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, :disabled => 1
concat f.collection_check_boxes :tag_ids, collection, :first, :last, :disabled => 1
end
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
@ -128,7 +128,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts a proc to disabled items' do
collection = (1..3).map{|i| [i, "Tag #{i}"] }
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 }
concat f.collection_check_boxes :tag_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 }
end
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
@ -139,7 +139,7 @@ class BuilderTest < ActionView::TestCase
test 'collection check box accepts html options' do
collection = [[1, 'Tag 1'], [2, 'Tag 2']]
form_for @user do |f|
concat f.collection_check_box :tag_ids, collection, :first, :last, {}, :class => 'check'
concat f.collection_check_boxes :tag_ids, collection, :first, :last, {}, :class => 'check'
end
assert_select 'form input.check[type=checkbox][value=1]'

View File

@ -9,7 +9,7 @@ class ErrorTest < ActionView::TestCase
f.input_type = type
f.options = options
concat(SimpleForm::FormBuilder::Input.new(f).error)
concat(SimpleForm::FormBuilder::Base.new(f).error)
end
end

View File

@ -9,7 +9,7 @@ class HintTest < ActionView::TestCase
f.input_type = type
f.options = options
concat(SimpleForm::FormBuilder::Input.new(f).hint)
concat(SimpleForm::FormBuilder::Base.new(f).hint)
end
end

View File

@ -5,327 +5,327 @@ class InputTest < ActionView::TestCase
setup do
SimpleForm::Components::Input.reset_i18n_cache :boolean_collection
end
def with_input_for(object, attribute_name, type, options={})
simple_form_for object do |f|
f.attribute_name = attribute_name
f.column = object.column_for_attribute(attribute_name) if object.respond_to?(:column_for_attribute)
f.input_type = type
f.options = options
input = SimpleForm::Components::Input.new(f, SimpleForm::FormBuilder::TERMINATOR)
concat(input.call)
yield input if block_given?
end
end
test 'input should map text field to string attribute' do
with_input_for @user, :name, :string
assert_select 'input[name=\'user[name]\'][id=user_name][value=New in Simple Form!]'
end
test 'input should generate css class based on default input type' do
with_input_for @user, :name, :string
assert_select 'input.string'
with_input_for @user, :description, :text
assert_select 'textarea.text'
with_input_for @user, :age, :integer
assert_select 'input.integer'
with_input_for @user, :born_at, :date
assert_select 'select.date'
with_input_for @user, :created_at, :datetime
assert_select 'select.datetime'
end
test 'input should allow passing options to text field' do
with_input_for @user, :name, :string, :input_html => { :class => 'my_input', :id => 'my_input' }
assert_select 'input#my_input.my_input'
end
test 'input should generate a text area for text attributes' do
with_input_for @user, :description, :text
assert_select 'textarea.text#user_description'
end
test 'input should generate an integer text field for integer attributes ' do
with_input_for @user, :age, :integer
assert_select 'input.integer#user_age'
end
test 'input should generate a float text field for float attributes ' do
with_input_for @user, :age, :float
assert_select 'input.float#user_age'
end
test 'input should generate a decimal text field for decimal attributes ' do
with_input_for @user, :age, :decimal
assert_select 'input.decimal#user_age'
end
test 'input should generate a checkbox by default for boolean attributes' do
with_input_for @user, :active, :boolean
assert_select 'input[type=checkbox].boolean#user_active'
end
test 'input should generate a password field for password attributes' do
with_input_for @user, :password, :password
assert_select 'input[type=password].password#user_password'
end
test 'input should generate a hidden field' do
with_input_for @user, :name, :hidden
assert_no_select 'input[type=text]'
assert_select 'input#user_name[type=hidden]'
end
test 'input should generate a file field' do
with_input_for @user, :name, :file
assert_select 'input#user_name[type=file]'
end
test 'input should generate a country select field' do
with_input_for @user, :country, :country
assert_select 'select#user_country'
assert_select 'select option[value=Brazil]', 'Brazil'
assert_no_select 'select option[value=][disabled=disabled]'
end
test 'input should generate a country select with simple form default' do
swap SimpleForm, :country_priority => [ 'Brazil' ] do
with_input_for @user, :country, :country
assert_select 'select option[value=][disabled=disabled]'
end
end
test 'input should generate a time zone select field' do
with_input_for @user, :time_zone, :time_zone
assert_select 'select#user_time_zone'
assert_select 'select option[value=Brasilia]', '(GMT-03:00) Brasilia'
assert_no_select 'select option[value=][disabled=disabled]'
end
test 'input should generate a time zone select field with default' do
with_input_for @user, :time_zone, :time_zone, :default => 'Brasilia'
assert_select 'select option[value=Brasilia][selected=selected]'
end
test 'input should generate a time zone select using options priority' do
with_input_for @user, :time_zone, :time_zone, :priority => /Brasilia/
assert_select 'select option[value=][disabled=disabled]'
end
test 'input should generate a datetime select by default for datetime attributes' do
with_input_for @user, :created_at, :datetime
1.upto(5) do |i|
assert_select "form select.datetime#user_created_at_#{i}i"
end
end
test 'input should be able to pass options to datetime select' do
with_input_for @user, :created_at, :datetime,
:disabled => true, :prompt => { :year => 'ano', :month => 'mês', :day => 'dia' }
assert_select 'select.datetime[disabled=disabled]'
assert_select 'select.datetime option', 'ano'
assert_select 'select.datetime option', 'mês'
assert_select 'select.datetime option', 'dia'
end
test 'input should generate a date select for date attributes' do
with_input_for @user, :born_at, :date
assert_select 'select.date#user_born_at_1i'
assert_select 'select.date#user_born_at_2i'
assert_select 'select.date#user_born_at_3i'
assert_no_select 'select.date#user_born_at_4i'
end
test 'input should be able to pass options to date select' do
with_input_for @user, :born_at, :date, :as => :date,
:disabled => true, :prompt => { :year => 'ano', :month => 'mês', :day => 'dia' }
assert_select 'select.date[disabled=disabled]'
assert_select 'select.date option', 'ano'
assert_select 'select.date option', 'mês'
assert_select 'select.date option', 'dia'
end
test 'input should generate a time select for time attributes' do
with_input_for @user, :delivery_time, :time
assert_select 'input[type=hidden]#user_delivery_time_1i'
assert_select 'input[type=hidden]#user_delivery_time_2i'
assert_select 'input[type=hidden]#user_delivery_time_3i'
assert_select 'select.time#user_delivery_time_4i'
assert_select 'select.time#user_delivery_time_5i'
end
test 'input should be able to pass options to time select' do
with_input_for @user, :delivery_time, :time, :required => true,
:disabled => true, :prompt => { :hour => 'hora', :minute => 'minuto' }
assert_select 'select.time[disabled=disabled]'
assert_select 'select.time option', 'hora'
assert_select 'select.time option', 'minuto'
end
test 'input should generate boolean radio buttons by default for radio types' do
with_input_for @user, :active, :radio
assert_select 'input[type=radio][value=true].radio#user_active_true'
assert_select 'input[type=radio][value=false].radio#user_active_false'
end
test 'input as radio should generate internal labels by default' do
with_input_for @user, :active, :radio
assert_select 'label[for=user_active_true]', 'Yes'
assert_select 'label[for=user_active_false]', 'No'
end
test 'input as radio should use i18n to translate internal labels' do
store_translations(:en, :simple_form => { :yes => 'Sim', :no => 'Não' }) do
with_input_for @user, :active, :radio
assert_select 'label[for=user_active_true]', 'Sim'
assert_select 'label[for=user_active_false]', 'Não'
end
end
test 'input should generate a boolean select with options by default for select types' do
with_input_for @user, :active, :select
assert_select 'select.select#user_active'
assert_select 'select option[value=true]', 'Yes'
assert_select 'select option[value=false]', 'No'
end
test 'input as select should use i18n to translate select boolean options' do
store_translations(:en, :simple_form => { :yes => 'Sim', :no => 'Não' }) do
with_input_for @user, :active, :select
assert_select 'select option[value=true]', 'Sim'
assert_select 'select option[value=false]', 'Não'
end
end
test 'input should allow overriding collection for select types' do
with_input_for @user, :name, :select, :collection => ['Jose', 'Carlos']
assert_select 'select.select#user_name'
assert_select 'select option', 'Jose'
assert_select 'select option', 'Carlos'
end
test 'input should mark the selected value by default' do
@user.name = "Carlos"
with_input_for @user, :name, :select, :collection => ['Jose', 'Carlos']
assert_select 'select option[selected=selected]', 'Carlos'
end
test 'input should mark the selected value also when using integers' do
@user.age = 18
with_input_for @user, :age, :select, :collection => 18..60
assert_select 'select option[selected=selected]', '18'
end
test 'input should automatically set include blank' do
with_input_for @user, :age, :select, :collection => 18..30
assert_select 'select option[value=]', ''
end
test 'input should not set include blank if otherwise is told' do
with_input_for @user, :age, :select, :collection => 18..30, :include_blank => false
assert_no_select 'select option[value=]', ''
end
test 'input should not set include blank if prompt is given' do
with_input_for @user, :age, :select, :collection => 18..30, :prompt => "Please select foo"
assert_no_select 'select option[value=]', ''
end
test 'input should not set include blank if multiple is given' do
with_input_for @user, :age, :select, :collection => 18..30, :input_html => { :multiple => true }
assert_no_select 'select option[value=]', ''
end
test 'input should detect label and value on collections' do
users = [ setup_new_user(:id => 1, :name => "Jose"), setup_new_user(:id => 2, :name => "Carlos") ]
with_input_for @user, :description, :select, :collection => users
assert_select 'select option[value=1]', 'Jose'
assert_select 'select option[value=2]', 'Carlos'
end
test 'input should allow overriding collection for radio types' do
with_input_for @user, :name, :radio, :collection => ['Jose', 'Carlos']
assert_select 'input[type=radio][value=Jose]'
assert_select 'input[type=radio][value=Carlos]'
assert_select 'label.collection_radio', 'Jose'
assert_select 'label.collection_radio', 'Carlos'
end
test 'input should mark the current radio value by default' do
@user.name = "Carlos"
with_input_for @user, :name, :radio, :collection => ['Jose', 'Carlos']
assert_select 'input[type=radio][value=Carlos][checked=checked]'
end
test 'input should allow using a collection with text/value arrays' do
with_input_for @user, :name, :radio, :collection => [['Jose', 'jose'], ['Carlos', 'carlos']]
assert_select 'input[type=radio][value=jose]'
assert_select 'input[type=radio][value=carlos]'
assert_select 'label.collection_radio', 'Jose'
assert_select 'label.collection_radio', 'Carlos'
end
test 'input should allow overriding label and value method for collections' do
with_input_for @user, :name, :radio,
:collection => ['Jose' , 'Carlos'],
:label_method => :upcase,
:value_method => :downcase
assert_select 'input[type=radio][value=jose]'
assert_select 'input[type=radio][value=carlos]'
assert_select 'label.collection_radio', 'JOSE'
assert_select 'label.collection_radio', 'CARLOS'
end
test 'input should be required by default' do
with_input_for @user, :name, :string
assert_select 'input.required#user_name'
end
test 'input should allow disabling required' do
with_input_for @user, :name, :string, :required => false
assert_no_select 'input.required'
assert_select 'input.optional#user_name'
end
test 'input should get options from column definition for string attributes' do
with_input_for @user, :name, :string
assert_select 'input.string[maxlength=100]'
end
test 'input should get options from column definition for decimal attributes' do
with_input_for @user, :credit_limit, :decimal
assert_select 'input.decimal[maxlength=15]'
end
test 'input should get options from column definition for password attributes' do
with_input_for @user, :password, :password
assert_select 'input.password[maxlength=100]'
end
test 'input should not generate options for different attributes' do
with_input_for @user, :description, :text
assert_select 'textarea'
assert_no_select 'textarea[maxlength]'
end
test 'input should be generated properly when object is not present' do
with_input_for :project, :name, :string
assert_select 'input.string.required#project_name'
end
test 'input as radio should be generated properly when object is not present ' do
with_input_for :project, :name, :radio
assert_select 'input.radio#project_name_true'
assert_select 'input.radio#project_name_false'
end
test 'input as select with collection should be generated properly when object is not present' do
with_input_for :project, :name, :select, :collection => ['Jose', 'Carlos']
assert_select 'select.select#project_name'
end
#
# def with_input_for(object, attribute_name, type, options={})
# simple_form_for object do |f|
# f.attribute_name = attribute_name
# f.column = object.column_for_attribute(attribute_name) if object.respond_to?(:column_for_attribute)
# f.input_type = type
# f.options = options
#
# input = SimpleForm::Components::Input.new(f, SimpleForm::FormBuilder::TERMINATOR)
# concat(input.call)
# yield input if block_given?
# end
# end
#
# test 'input should map text field to string attribute' do
# with_input_for @user, :name, :string
# assert_select 'input[name=\'user[name]\'][id=user_name][value=New in Simple Form!]'
# end
#
# test 'input should generate css class based on default input type' do
# with_input_for @user, :name, :string
# assert_select 'input.string'
# with_input_for @user, :description, :text
# assert_select 'textarea.text'
# with_input_for @user, :age, :integer
# assert_select 'input.integer'
# with_input_for @user, :born_at, :date
# assert_select 'select.date'
# with_input_for @user, :created_at, :datetime
# assert_select 'select.datetime'
# end
#
# test 'input should allow passing options to text field' do
# with_input_for @user, :name, :string, :input_html => { :class => 'my_input', :id => 'my_input' }
# assert_select 'input#my_input.my_input'
# end
#
# test 'input should generate a text area for text attributes' do
# with_input_for @user, :description, :text
# assert_select 'textarea.text#user_description'
# end
#
# test 'input should generate an integer text field for integer attributes ' do
# with_input_for @user, :age, :integer
# assert_select 'input.integer#user_age'
# end
#
# test 'input should generate a float text field for float attributes ' do
# with_input_for @user, :age, :float
# assert_select 'input.float#user_age'
# end
#
# test 'input should generate a decimal text field for decimal attributes ' do
# with_input_for @user, :age, :decimal
# assert_select 'input.decimal#user_age'
# end
#
# test 'input should generate a checkbox by default for boolean attributes' do
# with_input_for @user, :active, :boolean
# assert_select 'input[type=checkbox].boolean#user_active'
# end
#
# test 'input should generate a password field for password attributes' do
# with_input_for @user, :password, :password
# assert_select 'input[type=password].password#user_password'
# end
#
# test 'input should generate a hidden field' do
# with_input_for @user, :name, :hidden
# assert_no_select 'input[type=text]'
# assert_select 'input#user_name[type=hidden]'
# end
#
# test 'input should generate a file field' do
# with_input_for @user, :name, :file
# assert_select 'input#user_name[type=file]'
# end
#
# test 'input should generate a country select field' do
# with_input_for @user, :country, :country
# assert_select 'select#user_country'
# assert_select 'select option[value=Brazil]', 'Brazil'
# assert_no_select 'select option[value=][disabled=disabled]'
# end
#
# test 'input should generate a country select with simple form default' do
# swap SimpleForm, :country_priority => [ 'Brazil' ] do
# with_input_for @user, :country, :country
# assert_select 'select option[value=][disabled=disabled]'
# end
# end
#
# test 'input should generate a time zone select field' do
# with_input_for @user, :time_zone, :time_zone
# assert_select 'select#user_time_zone'
# assert_select 'select option[value=Brasilia]', '(GMT-03:00) Brasilia'
# assert_no_select 'select option[value=][disabled=disabled]'
# end
#
# test 'input should generate a time zone select field with default' do
# with_input_for @user, :time_zone, :time_zone, :default => 'Brasilia'
# assert_select 'select option[value=Brasilia][selected=selected]'
# end
#
# test 'input should generate a time zone select using options priority' do
# with_input_for @user, :time_zone, :time_zone, :priority => /Brasilia/
# assert_select 'select option[value=][disabled=disabled]'
# end
#
# test 'input should generate a datetime select by default for datetime attributes' do
# with_input_for @user, :created_at, :datetime
# 1.upto(5) do |i|
# assert_select "form select.datetime#user_created_at_#{i}i"
# end
# end
#
# test 'input should be able to pass options to datetime select' do
# with_input_for @user, :created_at, :datetime,
# :disabled => true, :prompt => { :year => 'ano', :month => 'mês', :day => 'dia' }
#
# assert_select 'select.datetime[disabled=disabled]'
# assert_select 'select.datetime option', 'ano'
# assert_select 'select.datetime option', 'mês'
# assert_select 'select.datetime option', 'dia'
# end
#
# test 'input should generate a date select for date attributes' do
# with_input_for @user, :born_at, :date
# assert_select 'select.date#user_born_at_1i'
# assert_select 'select.date#user_born_at_2i'
# assert_select 'select.date#user_born_at_3i'
# assert_no_select 'select.date#user_born_at_4i'
# end
#
# test 'input should be able to pass options to date select' do
# with_input_for @user, :born_at, :date, :as => :date,
# :disabled => true, :prompt => { :year => 'ano', :month => 'mês', :day => 'dia' }
#
# assert_select 'select.date[disabled=disabled]'
# assert_select 'select.date option', 'ano'
# assert_select 'select.date option', 'mês'
# assert_select 'select.date option', 'dia'
# end
#
# test 'input should generate a time select for time attributes' do
# with_input_for @user, :delivery_time, :time
# assert_select 'input[type=hidden]#user_delivery_time_1i'
# assert_select 'input[type=hidden]#user_delivery_time_2i'
# assert_select 'input[type=hidden]#user_delivery_time_3i'
# assert_select 'select.time#user_delivery_time_4i'
# assert_select 'select.time#user_delivery_time_5i'
# end
#
# test 'input should be able to pass options to time select' do
# with_input_for @user, :delivery_time, :time, :required => true,
# :disabled => true, :prompt => { :hour => 'hora', :minute => 'minuto' }
#
# assert_select 'select.time[disabled=disabled]'
# assert_select 'select.time option', 'hora'
# assert_select 'select.time option', 'minuto'
# end
#
# test 'input should generate boolean radio buttons by default for radio types' do
# with_input_for @user, :active, :radio
# assert_select 'input[type=radio][value=true].radio#user_active_true'
# assert_select 'input[type=radio][value=false].radio#user_active_false'
# end
#
# test 'input as radio should generate internal labels by default' do
# with_input_for @user, :active, :radio
# assert_select 'label[for=user_active_true]', 'Yes'
# assert_select 'label[for=user_active_false]', 'No'
# end
#
# test 'input as radio should use i18n to translate internal labels' do
# store_translations(:en, :simple_form => { :yes => 'Sim', :no => 'Não' }) do
# with_input_for @user, :active, :radio
# assert_select 'label[for=user_active_true]', 'Sim'
# assert_select 'label[for=user_active_false]', 'Não'
# end
# end
#
# test 'input should generate a boolean select with options by default for select types' do
# with_input_for @user, :active, :select
# assert_select 'select.select#user_active'
# assert_select 'select option[value=true]', 'Yes'
# assert_select 'select option[value=false]', 'No'
# end
#
# test 'input as select should use i18n to translate select boolean options' do
# store_translations(:en, :simple_form => { :yes => 'Sim', :no => 'Não' }) do
# with_input_for @user, :active, :select
# assert_select 'select option[value=true]', 'Sim'
# assert_select 'select option[value=false]', 'Não'
# end
# end
#
# test 'input should allow overriding collection for select types' do
# with_input_for @user, :name, :select, :collection => ['Jose', 'Carlos']
# assert_select 'select.select#user_name'
# assert_select 'select option', 'Jose'
# assert_select 'select option', 'Carlos'
# end
#
# test 'input should mark the selected value by default' do
# @user.name = "Carlos"
# with_input_for @user, :name, :select, :collection => ['Jose', 'Carlos']
# assert_select 'select option[selected=selected]', 'Carlos'
# end
#
# test 'input should mark the selected value also when using integers' do
# @user.age = 18
# with_input_for @user, :age, :select, :collection => 18..60
# assert_select 'select option[selected=selected]', '18'
# end
#
# test 'input should automatically set include blank' do
# with_input_for @user, :age, :select, :collection => 18..30
# assert_select 'select option[value=]', ''
# end
#
# test 'input should not set include blank if otherwise is told' do
# with_input_for @user, :age, :select, :collection => 18..30, :include_blank => false
# assert_no_select 'select option[value=]', ''
# end
#
# test 'input should not set include blank if prompt is given' do
# with_input_for @user, :age, :select, :collection => 18..30, :prompt => "Please select foo"
# assert_no_select 'select option[value=]', ''
# end
#
# test 'input should not set include blank if multiple is given' do
# with_input_for @user, :age, :select, :collection => 18..30, :input_html => { :multiple => true }
# assert_no_select 'select option[value=]', ''
# end
#
# test 'input should detect label and value on collections' do
# users = [ setup_new_user(:id => 1, :name => "Jose"), setup_new_user(:id => 2, :name => "Carlos") ]
# with_input_for @user, :description, :select, :collection => users
# assert_select 'select option[value=1]', 'Jose'
# assert_select 'select option[value=2]', 'Carlos'
# end
#
# test 'input should allow overriding collection for radio types' do
# with_input_for @user, :name, :radio, :collection => ['Jose', 'Carlos']
# assert_select 'input[type=radio][value=Jose]'
# assert_select 'input[type=radio][value=Carlos]'
# assert_select 'label.collection_radio', 'Jose'
# assert_select 'label.collection_radio', 'Carlos'
# end
#
# test 'input should mark the current radio value by default' do
# @user.name = "Carlos"
# with_input_for @user, :name, :radio, :collection => ['Jose', 'Carlos']
# assert_select 'input[type=radio][value=Carlos][checked=checked]'
# end
#
# test 'input should allow using a collection with text/value arrays' do
# with_input_for @user, :name, :radio, :collection => [['Jose', 'jose'], ['Carlos', 'carlos']]
# assert_select 'input[type=radio][value=jose]'
# assert_select 'input[type=radio][value=carlos]'
# assert_select 'label.collection_radio', 'Jose'
# assert_select 'label.collection_radio', 'Carlos'
# end
#
# test 'input should allow overriding label and value method for collections' do
# with_input_for @user, :name, :radio,
# :collection => ['Jose' , 'Carlos'],
# :label_method => :upcase,
# :value_method => :downcase
# assert_select 'input[type=radio][value=jose]'
# assert_select 'input[type=radio][value=carlos]'
# assert_select 'label.collection_radio', 'JOSE'
# assert_select 'label.collection_radio', 'CARLOS'
# end
#
# test 'input should be required by default' do
# with_input_for @user, :name, :string
# assert_select 'input.required#user_name'
# end
#
# test 'input should allow disabling required' do
# with_input_for @user, :name, :string, :required => false
# assert_no_select 'input.required'
# assert_select 'input.optional#user_name'
# end
#
# test 'input should get options from column definition for string attributes' do
# with_input_for @user, :name, :string
# assert_select 'input.string[maxlength=100]'
# end
#
# test 'input should get options from column definition for decimal attributes' do
# with_input_for @user, :credit_limit, :decimal
# assert_select 'input.decimal[maxlength=15]'
# end
#
# test 'input should get options from column definition for password attributes' do
# with_input_for @user, :password, :password
# assert_select 'input.password[maxlength=100]'
# end
#
# test 'input should not generate options for different attributes' do
# with_input_for @user, :description, :text
# assert_select 'textarea'
# assert_no_select 'textarea[maxlength]'
# end
#
# test 'input should be generated properly when object is not present' do
# with_input_for :project, :name, :string
# assert_select 'input.string.required#project_name'
# end
#
# test 'input as radio should be generated properly when object is not present ' do
# with_input_for :project, :name, :radio
# assert_select 'input.radio#project_name_true'
# assert_select 'input.radio#project_name_false'
# end
#
# test 'input as select with collection should be generated properly when object is not present' do
# with_input_for :project, :name, :select, :collection => ['Jose', 'Carlos']
# assert_select 'select.select#project_name'
# end
end

View File

@ -3,7 +3,7 @@ require 'test_helper'
class LabelTest < ActionView::TestCase
setup do
SimpleForm::FormBuilder::Input.reset_i18n_cache :translate_required_html
SimpleForm::FormBuilder::Base.reset_i18n_cache :translate_required_html
end
def with_label_for(object, attribute_name, type, options={})
@ -13,7 +13,7 @@ class LabelTest < ActionView::TestCase
f.input_type = type
f.options = options
concat(SimpleForm::FormBuilder::Input.new(f).label)
concat(SimpleForm::FormBuilder::Base.new(f).label)
end
end