Permalink
Browse files

Merge remote branch 'origin/rails3'

This commit moves the main development branch back to master since
a rails 2.3.x and rails 3.0.x compatible version has been published.

The current rails3 branch will be deprecated shortly.
  • Loading branch information...
2 parents ab045a5 + 8054d6a commit 9ad994ab984df31272d246fe1393c649b9ac42f2 @yabawock yabawock committed with yabawock Sep 8, 2010
Showing with 1,531 additions and 552 deletions.
  1. +1 −0 .gitignore
  2. +2 −0 .rspec
  3. +21 −0 CHANGELOG
  4. +2 −2 README.textile
  5. +33 −8 Rakefile
  6. +1 −1 VERSION.yml
  7. +29 −19 formtastic.gemspec
  8. +3 −18 generators/formtastic/templates/formtastic.css
  9. +2 −1 generators/formtastic/templates/formtastic.rb
  10. +5 −0 init.rb
  11. +180 −82 lib/formtastic.rb
  12. +8 −9 lib/formtastic/i18n.rb
  13. +0 −1 lib/formtastic/layout_helper.rb
  14. +12 −0 lib/formtastic/railtie.rb
  15. +7 −0 lib/formtastic/util.rb
  16. +86 −0 lib/generators/formtastic/form/form_generator.rb
  17. +24 −0 lib/generators/formtastic/install/install_generator.rb
  18. +1 −6 rails/init.rb
  19. +25 −8 spec/buttons_spec.rb
  20. +67 −29 spec/commit_button_spec.rb
  21. +40 −4 spec/custom_builder_spec.rb
  22. +1 −1 spec/defaults_spec.rb
  23. +1 −1 spec/error_proc_spec.rb
  24. +3 −2 spec/errors_spec.rb
  25. +33 −17 spec/form_helper_spec.rb
  26. +21 −0 spec/helpers/layout_helper_spec.rb
  27. +13 −9 spec/i18n_spec.rb
  28. +9 −5 spec/include_blank_spec.rb
  29. +188 −48 spec/input_spec.rb
  30. +14 −7 spec/inputs/boolean_input_spec.rb
  31. +150 −20 spec/inputs/check_boxes_input_spec.rb
  32. +9 −5 spec/inputs/country_input_spec.rb
  33. +21 −9 spec/inputs/date_input_spec.rb
  34. +33 −14 spec/inputs/datetime_input_spec.rb
  35. +4 −3 spec/inputs/file_input_spec.rb
  36. +11 −4 spec/inputs/hidden_input_spec.rb
  37. +3 −3 spec/inputs/numeric_input_spec.rb
  38. +3 −3 spec/inputs/password_input_spec.rb
  39. +29 −10 spec/inputs/radio_input_spec.rb
  40. +66 −26 spec/inputs/select_input_spec.rb
  41. +5 −4 spec/inputs/string_input_spec.rb
  42. +4 −3 spec/inputs/text_input_spec.rb
  43. +26 −10 spec/inputs/time_input_spec.rb
  44. +11 −5 spec/inputs/time_zone_input_spec.rb
  45. +103 −39 spec/inputs_spec.rb
  46. +5 −3 spec/label_spec.rb
  47. +0 −29 spec/layout_helper_spec.rb
  48. +7 −7 spec/semantic_errors_spec.rb
  49. +5 −4 spec/semantic_fields_for_spec.rb
  50. +86 −38 spec/spec_helper.rb
  51. +69 −35 spec/{ → support}/custom_macros.rb
  52. +4 −0 spec/support/output_buffer.rb
  53. +45 −0 spec/support/test_environment.rb
View
1 .gitignore
@@ -5,3 +5,4 @@ pkg
*~
*watchr.rb
log/*
+.rvmrc
View
2 .rspec
@@ -0,0 +1,2 @@
+--color
+--format=progress
View
21 CHANGELOG
@@ -1,3 +1,24 @@
+1.1.0
+
+* documentation changes only
+
+1.1.0.beta [Specs passed against Rails 2.3.8, 3.0.0.rc & 3.0.0]
+
+* Changed semantic_remote_form_for to allow for unobstrusive javascript / :remote option (rails3)
+* Changed spec_helper to support Rails 2 with RSpec or Rails 3 with RSpec 2 environments
+* Changed Rakefile to initalize the correct testing framework for the enviroment
+* Changed i18n dependency to >= 0.4
+* Fixed use of model_name.human instead of model_name.human_name (rails3)
+* Fixed use of deprecated Errors#on_base
+* Fixed use of ActionController::RecordIdentifier#singular_class_name (rails3)
+* Added railtie to perform initialization tasks after the rails framework is available (rails3)
+* Added compatible install and form helpers (rails3)
+* Added support for ActiveModel Validations, thanks to Guillaume Belleguic (rails3)
+
+1.0.1
+
+* fixed "already initialised constant" warnings on boot
+
1.0.0
* nothing changed from rc2
View
4 README.textile
@@ -357,7 +357,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the
title: "Choose a good title for you post."
body: "Write something inspiring here."
actions:
- create: "Create my {{model}}"
+ create: "Create my %{model}"
update: "Save changes"
dummie: "Launch!"
</pre>
@@ -374,7 +374,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the
<%= form.input :section %> # => :label => I18n.t('activerecord.attributes.user.section') or 'Section'
<% end %>
<% form.buttons do %>
- <%= form.commit_button %> # => "Create my {{model}}"
+ <%= form.commit_button %> # => "Create my %{model}"
<% end %>
<% end %>
</pre>
View
41 Rakefile
@@ -1,13 +1,17 @@
# coding: utf-8
+require 'rubygems'
require 'rake'
require 'rake/rdoctask'
begin
+ gem 'rspec', '>= 1.2.6'
+ gem 'rspec-rails', '>= 1.2.6'
+ require 'spec'
require 'spec/rake/spectask'
rescue LoadError
begin
- gem 'rspec-rails', '>= 1.0.0'
- require 'spec/rake/spectask'
+ require 'rspec/core/rake_task.rb'
+ require 'rspec/core/version'
rescue LoadError
puts "[formtastic:] RSpec - or one of it's dependencies - is not available. Install it with: sudo gem install rspec-rails"
end
@@ -25,10 +29,12 @@ begin
------------------------------------------------------------------------
You can now (optionally) run the generator to copy some stylesheets and
a config initializer into your application:
- ./script/generate formtastic
+ rails generator formastic:install # Rails 3
+ ./script/generate formtastic # Rails 2
To generate some semantic form markup for your existing models, just run:
- ./script/generate form MODEL_NAME
+ rails generate formtastic:form MODEL_NAME # Rails 3
+ ./script/generate form MODEL_NAME # Rails 2
Find out more and get involved:
http://github.com/justinfrench/formtastic
@@ -49,13 +55,13 @@ begin
s.post_install_message = INSTALL_MESSAGE
s.require_path = 'lib'
- s.files = %w(MIT-LICENSE README.textile Rakefile) + Dir.glob("{rails,lib,generators,spec}/**/*")
+ s.files = %w(MIT-LICENSE README.textile Rakefile init.rb) + Dir.glob("{rails,lib,generators,spec}/**/*")
# Runtime dependencies: When installing Formtastic these will be checked if they are installed.
# Will be offered to install these if they are not already installed.
- s.add_dependency 'activesupport', '>= 2.3.0', '< 3.0.0'
- s.add_dependency 'actionpack', '>= 2.3.0', '< 3.0.0'
- s.add_dependency 'i18n', '< 0.4'
+ s.add_dependency 'activesupport', '>= 2.3.0'
+ s.add_dependency 'actionpack', '>= 2.3.0'
+ s.add_dependency 'i18n', '>= 0.4.0'
# Development dependencies. Not installed by default.
# Install with: sudo gem install formtastic --development
@@ -100,3 +106,22 @@ if defined?(Spec)
t.rcov_opts = ['--exclude', 'spec,Library']
end
end
+
+if defined?(RSpec)
+ desc 'Test the formtastic plugin.'
+ RSpec::Core::RakeTask.new('spec') do |t|
+ t.pattern = FileList['spec/**/*_spec.rb']
+ end
+
+ desc 'Test the formtastic plugin with specdoc formatting and colors'
+ RSpec::Core::RakeTask.new('specdoc') do |t|
+ t.pattern = FileList['spec/**/*_spec.rb']
+ end
+
+ desc "Run all examples with RCov"
+ RSpec::Core::RakeTask.new('examples_with_rcov') do |t|
+ t.pattern = FileList['spec/**/*_spec.rb']
+ t.rcov = true
+ t.rcov_opts = ['--exclude', 'spec,Library']
+ end
+end
View
2 VERSION.yml
@@ -1,5 +1,5 @@
---
:major: 1
-:minor: 0
+:minor: 1
:patch: 0
:build:
View
48 formtastic.gemspec
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{formtastic}
- s.version = "1.0.0"
+ s.version = "1.1.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Justin French"]
- s.date = %q{2010-08-12}
+ s.date = %q{2010-09-08}
s.description = %q{A Rails form builder plugin/gem with semantically rich and accessible markup}
s.email = %q{justin@indent.com.au}
s.extra_rdoc_files = [
@@ -28,20 +28,24 @@ Gem::Specification.new do |s|
"generators/formtastic/templates/formtastic.rb",
"generators/formtastic/templates/formtastic_changes.css",
"generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb",
+ "init.rb",
"lib/formtastic.rb",
"lib/formtastic/i18n.rb",
"lib/formtastic/layout_helper.rb",
+ "lib/formtastic/railtie.rb",
"lib/formtastic/util.rb",
+ "lib/generators/formtastic/form/form_generator.rb",
+ "lib/generators/formtastic/install/install_generator.rb",
"lib/locale/en.yml",
"rails/init.rb",
"spec/buttons_spec.rb",
"spec/commit_button_spec.rb",
"spec/custom_builder_spec.rb",
- "spec/custom_macros.rb",
"spec/defaults_spec.rb",
"spec/error_proc_spec.rb",
"spec/errors_spec.rb",
"spec/form_helper_spec.rb",
+ "spec/helpers/layout_helper_spec.rb",
"spec/i18n_spec.rb",
"spec/include_blank_spec.rb",
"spec/input_spec.rb",
@@ -62,11 +66,13 @@ Gem::Specification.new do |s|
"spec/inputs/time_zone_input_spec.rb",
"spec/inputs_spec.rb",
"spec/label_spec.rb",
- "spec/layout_helper_spec.rb",
"spec/semantic_errors_spec.rb",
"spec/semantic_fields_for_spec.rb",
"spec/spec.opts",
- "spec/spec_helper.rb"
+ "spec/spec_helper.rb",
+ "spec/support/custom_macros.rb",
+ "spec/support/output_buffer.rb",
+ "spec/support/test_environment.rb"
]
s.homepage = %q{http://github.com/justinfrench/formtastic/tree/master}
s.post_install_message = %q{
@@ -75,10 +81,12 @@ Gem::Specification.new do |s|
------------------------------------------------------------------------
You can now (optionally) run the generator to copy some stylesheets and
a config initializer into your application:
- ./script/generate formtastic
+ rails generator formastic:install # Rails 3
+ ./script/generate formtastic # Rails 2
To generate some semantic form markup for your existing models, just run:
- ./script/generate form MODEL_NAME
+ rails generate formtastic:form MODEL_NAME # Rails 3
+ ./script/generate form MODEL_NAME # Rails 2
Find out more and get involved:
http://github.com/justinfrench/formtastic
@@ -93,11 +101,11 @@ Gem::Specification.new do |s|
"spec/buttons_spec.rb",
"spec/commit_button_spec.rb",
"spec/custom_builder_spec.rb",
- "spec/custom_macros.rb",
"spec/defaults_spec.rb",
"spec/error_proc_spec.rb",
"spec/errors_spec.rb",
"spec/form_helper_spec.rb",
+ "spec/helpers/layout_helper_spec.rb",
"spec/i18n_spec.rb",
"spec/include_blank_spec.rb",
"spec/input_spec.rb",
@@ -118,33 +126,35 @@ Gem::Specification.new do |s|
"spec/inputs/time_zone_input_spec.rb",
"spec/inputs_spec.rb",
"spec/label_spec.rb",
- "spec/layout_helper_spec.rb",
"spec/semantic_errors_spec.rb",
"spec/semantic_fields_for_spec.rb",
- "spec/spec_helper.rb"
+ "spec/spec_helper.rb",
+ "spec/support/custom_macros.rb",
+ "spec/support/output_buffer.rb",
+ "spec/support/test_environment.rb"
]
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.0", "< 3.0.0"])
- s.add_runtime_dependency(%q<actionpack>, [">= 2.3.0", "< 3.0.0"])
- s.add_runtime_dependency(%q<i18n>, ["< 0.4"])
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.0"])
+ s.add_runtime_dependency(%q<actionpack>, [">= 2.3.0"])
+ s.add_runtime_dependency(%q<i18n>, [">= 0.4.0"])
s.add_development_dependency(%q<rspec-rails>, [">= 1.2.6"])
s.add_development_dependency(%q<rspec_tag_matchers>, [">= 1.0.0"])
else
- s.add_dependency(%q<activesupport>, [">= 2.3.0", "< 3.0.0"])
- s.add_dependency(%q<actionpack>, [">= 2.3.0", "< 3.0.0"])
- s.add_dependency(%q<i18n>, ["< 0.4"])
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
+ s.add_dependency(%q<actionpack>, [">= 2.3.0"])
+ s.add_dependency(%q<i18n>, [">= 0.4.0"])
s.add_dependency(%q<rspec-rails>, [">= 1.2.6"])
s.add_dependency(%q<rspec_tag_matchers>, [">= 1.0.0"])
end
else
- s.add_dependency(%q<activesupport>, [">= 2.3.0", "< 3.0.0"])
- s.add_dependency(%q<actionpack>, [">= 2.3.0", "< 3.0.0"])
- s.add_dependency(%q<i18n>, ["< 0.4"])
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
+ s.add_dependency(%q<actionpack>, [">= 2.3.0"])
+ s.add_dependency(%q<i18n>, [">= 0.4.0"])
s.add_dependency(%q<rspec-rails>, [">= 1.2.6"])
s.add_dependency(%q<rspec_tag_matchers>, [">= 1.0.0"])
end
View
21 generators/formtastic/templates/formtastic.css
@@ -30,28 +30,16 @@ form.formtastic ul.errors li { padding:0; border:none; display:list-item; }
/* FIELDSETS & LISTS
--------------------------------------------------------------------------------------------------*/
-form.formtastic fieldset { }
+form.formtastic fieldset { overflow:auto; } /* clearing contained floats */
form.formtastic fieldset.inputs { }
form.formtastic fieldset.buttons { padding-left:25%; }
form.formtastic fieldset ol { }
form.formtastic fieldset.buttons li { float:left; padding-right:0.5em; }
-/* clearfixing the fieldsets */
-form.formtastic fieldset { display: inline-block; }
-form.formtastic fieldset:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-html[xmlns] form.formtastic fieldset { display: block; }
-* html form.formtastic fieldset { height: 1%; }
-
-
/* INPUT LIs
--------------------------------------------------------------------------------------------------*/
form.formtastic fieldset > ol > li { margin-bottom:1.5em; }
-
-/* clearfixing the li's */
-form.formtastic fieldset > ol > li { display: inline-block; }
-form.formtastic fieldset > ol > li:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-html[xmlns] form.formtastic fieldset > ol > li { display: block; }
-* html form.formtastic fieldset > ol > li { height: 1%; }
+form.formtastic fieldset > ol > li { overflow:auto; } /* clearing contained floats */
form.formtastic fieldset > ol > li.required { }
form.formtastic fieldset > ol > li.optional { }
@@ -100,11 +88,8 @@ form.formtastic fieldset > ol > li.text textarea { width:74%; }
/* HIDDEN OVERRIDES
-The dual declarations are required because of our clearfix display hack on the LIs, which is more
-specific than the more general rule below. TODO: Revist the clearing hack and this rule.
--------------------------------------------------------------------------------------------------*/
-form.formtastic fieldset ol li.hidden,
-html[xmlns] form.formtastic fieldset ol li.hidden { display:none; }
+form.formtastic fieldset ol li.hidden { display:none; }
/* BOOLEAN OVERRIDES
--------------------------------------------------------------------------------------------------*/
View
3 generators/formtastic/templates/formtastic.rb
@@ -5,7 +5,8 @@
# Formtastic::SemanticFormBuilder.default_text_area_height = 5
# Should all fields be considered "required" by default?
-# Defaults to true, see ValidationReflection notes below.
+# Rails 2 only, ignored by Rails 3 because it will never fall back to this default.
+# Defaults to true.
# Formtastic::SemanticFormBuilder.all_fields_required_by_default = true
# Should select fields have a blank option/prompt by default?
View
5 init.rb
@@ -0,0 +1,5 @@
+# coding: utf-8
+require 'formtastic'
+require 'formtastic/layout_helper'
+ActionView::Base.send :include, Formtastic::SemanticFormHelper
+ActionView::Base.send :include, Formtastic::LayoutHelper
View
262 lib/formtastic.rb
@@ -1,30 +1,32 @@
# coding: utf-8
require File.join(File.dirname(__FILE__), *%w[formtastic i18n])
require File.join(File.dirname(__FILE__), *%w[formtastic util])
+require File.join(File.dirname(__FILE__), *%w[formtastic railtie]) if defined?(::Rails::Railtie)
module Formtastic #:nodoc:
class SemanticFormBuilder < ActionView::Helpers::FormBuilder
-
- @@default_text_field_size = 50
- @@default_text_area_height = 20
- @@all_fields_required_by_default = true
- @@include_blank_for_select_by_default = true
- @@required_string = proc { ::Formtastic::Util.html_safe(%{<abbr title="#{::Formtastic::I18n.t(:required)}">*</abbr>}) }
- @@optional_string = ''
- @@inline_errors = :sentence
- @@label_str_method = :humanize
- @@collection_label_methods = %w[to_label display_name full_name name title username login value to_s]
- @@inline_order = [ :input, :hints, :errors ]
- @@file_methods = [ :file?, :public_filename, :filename ]
- @@priority_countries = ["Australia", "Canada", "United Kingdom", "United States"]
- @@i18n_lookups_by_default = false
- @@escape_html_entities_in_hints_and_labels = true
- @@default_commit_button_accesskey = nil
-
- cattr_accessor :default_text_field_size, :default_text_area_height, :all_fields_required_by_default, :include_blank_for_select_by_default,
- :required_string, :optional_string, :inline_errors, :label_str_method, :collection_label_methods,
- :inline_order, :file_methods, :priority_countries, :i18n_lookups_by_default, :escape_html_entities_in_hints_and_labels, :default_commit_button_accesskey
+ class_inheritable_accessor :default_text_field_size, :default_text_area_height, :all_fields_required_by_default, :include_blank_for_select_by_default,
+ :required_string, :optional_string, :inline_errors, :label_str_method, :collection_value_methods, :collection_label_methods,
+ :inline_order, :file_methods, :priority_countries, :i18n_lookups_by_default, :escape_html_entities_in_hints_and_labels, :default_commit_button_accesskey,
+ :instance_reader => false
+
+ self.default_text_field_size = 50
+ self.default_text_area_height = 20
+ self.all_fields_required_by_default = true
+ self.include_blank_for_select_by_default = true
+ self.required_string = proc { ::Formtastic::Util.html_safe(%{<abbr title="#{::Formtastic::I18n.t(:required)}">*</abbr>}) }
+ self.optional_string = ''
+ self.inline_errors = :sentence
+ self.label_str_method = :humanize
+ self.collection_label_methods = %w[to_label display_name full_name name title username login value to_s]
+ self.collection_value_methods = %w[id to_s]
+ self.inline_order = [ :input, :hints, :errors ]
+ self.file_methods = [ :file?, :public_filename, :filename ]
+ self.priority_countries = ["Australia", "Canada", "United Kingdom", "United States"]
+ self.i18n_lookups_by_default = false
+ self.escape_html_entities_in_hints_and_labels = true
+ self.default_commit_button_accesskey = nil
RESERVED_COLUMNS = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
@@ -100,7 +102,7 @@ def input(method, options = {})
options[:label_html][:for] ||= options[:input_html][:id]
end
- input_parts = @@inline_order.dup
+ input_parts = self.class.inline_order.dup
input_parts = input_parts - [:errors, :hints] if options[:as] == :hidden
list_item_content = input_parts.map do |type|
@@ -327,13 +329,17 @@ def commit_button(*args)
# ActiveRecord::Base.human_name falls back to ActiveRecord::Base.name.humanize ("Userpost")
# if there's no i18n, which is pretty crappy. In this circumstance we want to detect this
# fall back (human_name == name.humanize) and do our own thing name.underscore.humanize ("User Post")
- object_human_name = @object.class.human_name # default is UserPost => "Userpost", but i18n may do better ("User post")
- crappy_human_name = @object.class.name.humanize # UserPost => "Userpost"
- decent_human_name = @object.class.name.underscore.humanize # UserPost => "User post"
- object_name = (object_human_name == crappy_human_name) ? decent_human_name : object_human_name
+ if @object.class.model_name.respond_to?(:human)
+ object_name = @object.class.model_name.human
+ else
+ object_human_name = @object.class.human_name # default is UserPost => "Userpost", but i18n may do better ("User post")
+ crappy_human_name = @object.class.name.humanize # UserPost => "Userpost"
+ decent_human_name = @object.class.name.underscore.humanize # UserPost => "User post"
+ object_name = (object_human_name == crappy_human_name) ? decent_human_name : object_human_name
+ end
else
key = :submit
- object_name = @object_name.to_s.send(@@label_str_method)
+ object_name = @object_name.to_s.send(self.class.label_str_method)
end
text = (self.localized_string(key, text, :action, :model => object_name) ||
@@ -342,8 +348,8 @@ def commit_button(*args)
button_html = options.delete(:button_html) || {}
button_html.merge!(:class => [button_html[:class], key].compact.join(' '))
element_class = ['commit', options.delete(:class)].compact.join(' ') # TODO: Add class reflecting on form action.
- accesskey = (options.delete(:accesskey) || @@default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
- button_html = button_html.merge(:accesskey => accesskey) if accesskey
+ accesskey = (options.delete(:accesskey) || self.class.default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
+ button_html = button_html.merge(:accesskey => accesskey) if accesskey
template.content_tag(:li, Formtastic::Util.html_safe(self.submit(text, button_html)), :class => element_class)
end
@@ -368,7 +374,7 @@ def commit_button(*args)
#
def semantic_fields_for(record_or_name_or_array, *args, &block)
opts = args.extract_options!
- opts[:builder] ||= Formtastic::SemanticFormHelper.builder
+ opts[:builder] ||= self.class
args.push(opts)
fields_for(record_or_name_or_array, *args, &block)
end
@@ -431,7 +437,7 @@ def inline_errors_for(method, options = nil) #:nodoc:
errors = [@object.errors[method.to_sym]]
errors << [@object.errors[association_primary_key(method)]] if association_macro_for_method(method) == :belongs_to
errors = errors.flatten.compact.uniq
- send(:"error_#{@@inline_errors}", [*errors]) if errors.any?
+ send(:"error_#{self.class.inline_errors}", [*errors]) if errors.any?
else
nil
end
@@ -454,7 +460,7 @@ def semantic_errors(*args)
errors = Array(@object.errors[method.to_sym]).to_sentence
errors.present? ? array << [attribute, errors].join(" ") : array ||= []
end
- full_errors << @object.errors.on_base
+ full_errors << @object.errors[:base]
full_errors.flatten!
full_errors.compact!
return nil if full_errors.blank?
@@ -467,7 +473,7 @@ def semantic_errors(*args)
protected
def render_inline_errors?
- @object && @object.respond_to?(:errors) && INLINE_ERROR_TYPES.include?(@@inline_errors)
+ @object && @object.respond_to?(:errors) && INLINE_ERROR_TYPES.include?(self.class.inline_errors)
end
# Collects content columns (non-relation columns) for the current form object class.
@@ -524,9 +530,17 @@ def inputs_for_nested_attributes(*args, &block) #:nodoc:
raise ArgumentError, 'You gave :for option with a block to inputs method, ' <<
'but the block does not accept any argument.' if block.arity <= 0
- lambda { |f| f.inputs(*args){ block.call(f) } }
+ lambda do |f|
+ contents = f.inputs(*args){ block.call(f) }
+ template.concat(contents) if ::Formtastic::Util.rails3?
+ contents
+ end
else
- lambda { |f| f.inputs(*args) }
+ lambda do |f|
+ contents = f.inputs(*args)
+ template.concat(contents) if ::Formtastic::Util.rails3?
+ contents
+ end
end
fields_for_args = [options.delete(:for), options.delete(:for_options) || {}].flatten
@@ -546,12 +560,13 @@ def strip_formtastic_options(options) #:nodoc:
# returned immediately, allowing the view to override any guesswork that follows:
#
# * if the :required option isn't provided in the options hash, and the ValidationReflection
- # plugin is installed (http://github.com/redinger/validation_reflection), true is returned
+ # plugin is installed (http://github.com/redinger/validation_reflection), or the object is
+ # an ActiveModel, true is returned
# if the validates_presence_of macro has been used in the class for this attribute, or false
# otherwise.
#
- # * if the :required option isn't provided, and the plugin isn't available, the value of the
- # configuration option @@all_fields_required_by_default is used.
+ # * if the :required option isn't provided, and validates_presence_of can't be determined, the
+ # configuration option all_fields_required_by_default is used.
#
def method_required?(attribute) #:nodoc:
if @object && @object.class.respond_to?(:reflect_on_validations_for)
@@ -563,7 +578,12 @@ def method_required?(attribute) #:nodoc:
(validation.options.present? ? options_require_validation?(validation.options) : true)
end
else
- @@all_fields_required_by_default
+ if @object && @object.class.respond_to?(:validators_on)
+ attribute_sym = attribute.to_s.sub(/_id$/, '').to_sym
+ !@object.class.validators_on(attribute_sym).find{|validator| (validator.kind == :presence) && (validator.options.present? ? options_require_validation?(validator.options) : true)}.nil?
+ else
+ self.class.all_fields_required_by_default
+ end
end
end
@@ -1115,6 +1135,15 @@ def date_or_datetime_input(method, options)
# f.input :authors, :as => :check_boxes, :selected => Author.most_popular.collect(&:id)
# f.input :authors, :as => :check_boxes, :selected => nil # override any defaults: select none
#
+ #
+ # Formtastic works around a bug in rails handling of check box collections by
+ # not generating the hidden fields for state checking of the checkboxes
+ # The :hidden_fields option provides a way to re-enable these hidden inputs by
+ # setting it to true.
+ #
+ # f.input :authors, :as => :check_boxes, :hidden_fields => false
+ # f.input :authors, :as => :check_boxes, :hidden_fields => true
+ #
# Finally, you can set :value_as_class => true if you want the li wrapper around each checkbox / label
# combination to contain a class with the value of the radio button (useful for applying specific
# CSS or Javascript to a particular checkbox).
@@ -1124,30 +1153,30 @@ def check_boxes_input(method, options)
html_options = options.delete(:input_html) || {}
input_name = generate_association_input_name(method)
+ hidden_fields = options.delete(:hidden_fields)
value_as_class = options.delete(:value_as_class)
unchecked_value = options.delete(:unchecked_value) || ''
html_options = { :name => "#{@object_name}[#{input_name}][]" }.merge(html_options)
input_ids = []
- selected_option_is_present = [:selected, :checked].any? { |k| options.key?(k) }
- selected_values = (options.key?(:checked) ? options[:checked] : options[:selected]) if selected_option_is_present
- selected_values = [*selected_values].compact
-
+ selected_values = find_selected_values_for_column(method, options)
disabled_option_is_present = options.key?(:disabled)
disabled_values = [*options[:disabled]] if disabled_option_is_present
+ li_options = value_as_class ? { :class => [method.to_s.singularize, 'default'].join('_') } : {}
+
list_item_content = collection.map do |c|
label = c.is_a?(Array) ? c.first : c
value = c.is_a?(Array) ? c.last : c
input_id = generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
input_ids << input_id
- html_options[:checked] = selected_values.include?(value) if selected_option_is_present
+ html_options[:checked] = selected_values.include?(value)
html_options[:disabled] = disabled_values.include?(value) if disabled_option_is_present
html_options[:id] = input_id
li_content = template.content_tag(:label,
- Formtastic::Util.html_safe("#{self.check_box(input_name, html_options, value, unchecked_value)} #{escape_html_entities(label)}"),
+ Formtastic::Util.html_safe("#{self.create_check_boxes(input_name, html_options, value, unchecked_value, hidden_fields)} #{escape_html_entities(label)}"),
:for => input_id
)
@@ -1156,10 +1185,46 @@ def check_boxes_input(method, options)
end
fieldset_content = legend_tag(method, options)
+ fieldset_content << self.create_hidden_field_for_check_boxes(input_name, value_as_class) unless hidden_fields
fieldset_content << template.content_tag(:ol, Formtastic::Util.html_safe(list_item_content.join))
template.content_tag(:fieldset, fieldset_content)
end
+ # Used by check_boxes input. The selected values will be set either by:
+ #
+ # * Explicitly provided through :selected or :checked
+ # * Values retrieved through an association
+ #
+ # If the collection is not a hash or an array of strings, fixnums or symbols,
+ # we use value_method to retrieve an array with the values
+ #
+ def find_selected_values_for_column(method, options)
+ selected_option_is_present = [:selected, :checked].any? { |k| options.key?(k) }
+ if selected_option_is_present
+ selected_values = (options.key?(:checked) ? options[:checked] : options[:selected])
+ elsif object.respond_to?(method)
+ collection = [object.send(method)].compact.flatten
+ label, value = detect_label_and_value_method!(collection, options)
+ selected_values = collection.map { |o| send_or_call(value, o) }
+ end
+ selected_values = [*selected_values].compact
+ selected_values
+ end
+
+ # Outputs a custom hidden field for check_boxes
+ def create_hidden_field_for_check_boxes(method, value_as_class) #:nodoc:
+ options = value_as_class ? { :class => [method.to_s.singularize, 'default'].join('_') } : {}
+ input_name = "#{object_name}[#{method.to_s}][]"
+ template.hidden_field_tag(input_name, '', options)
+ end
+
+ # Outputs a checkbox tag. If called with no_hidden_input = true a plain check_box_tag is returned,
+ # otherwise the helper uses the output generated by the rails check_box method.
+ def create_check_boxes(input_name, html_options = {}, checked_value = "1", unchecked_value = "0", hidden_fields = false) #:nodoc:
+ return template.check_box_tag(input_name, checked_value, html_options[:checked], html_options) unless hidden_fields == true
+ self.check_box(input_name, html_options, checked_value, unchecked_value)
+ end
+
# Outputs a country select input, wrapping around a regular country_select helper.
# Rails doesn't come with a country_select helper by default any more, so you'll need to install
# the "official" plugin, or, if you wish, any other country_select plugin that behaves in the
@@ -1176,9 +1241,9 @@ def check_boxes_input(method, options)
#
def country_input(method, options)
raise "To use the :country input, please install a country_select plugin, like this one: http://github.com/rails/iso-3166-country-select" unless self.respond_to?(:country_select)
-
+
html_options = options.delete(:input_html) || {}
- priority_countries = options.delete(:priority_countries) || @@priority_countries
+ priority_countries = options.delete(:priority_countries) || self.class.priority_countries
self.label(method, options_for_label(options)) <<
self.country_select(method, priority_countries, strip_formtastic_options(options), html_options)
@@ -1252,9 +1317,9 @@ def error_first(errors) #:nodoc:
def required_or_optional_string(required) #:nodoc:
string_or_proc = case required
when true
- @@required_string
+ self.class.required_string
when false
- @@optional_string
+ self.class.optional_string
else
required
end
@@ -1307,7 +1372,7 @@ def field_set_and_list_wrapping(*args, &block) #:nodoc:
html_options.except(:builder, :parent)
)
- template.concat(fieldset) if block_given? && (!defined?(Rails::VERSION) || Rails::VERSION::MAJOR == 2)
+ template.concat(fieldset) if block_given? && !Formtastic::Util.rails3?
fieldset
end
@@ -1380,7 +1445,7 @@ def default_input_type(method, options = {}) #:nodoc:
return :select if self.reflection_for(method)
file = @object.send(method) if @object.respond_to?(method)
- return :file if file && @@file_methods.any? { |m| file.respond_to?(m) }
+ return :file if file && self.class.file_methods.any? { |m| file.respond_to?(m) }
end
return :select if options.key?(:collection)
@@ -1421,10 +1486,15 @@ def find_raw_collection_for_column(column, options) #:nodoc:
options[:find_options] ||= {}
if conditions = reflection.options[:conditions]
- options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
+ if reflection.klass.respond_to?(:merge_conditions)
+ options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
+ reflection.klass.all(options[:find_options])
+ else
+ reflection.klass.where(conditions).where(options[:find_options][:conditions])
+ end
+ else
+ reflection.klass.all(options[:find_options])
end
-
- reflection.klass.find(:all, options[:find_options])
else
create_boolean_collection(options)
end
@@ -1433,21 +1503,35 @@ def find_raw_collection_for_column(column, options) #:nodoc:
collection
end
- # Detects the label and value methods from a collection values set in
- # @@collection_label_methods. It will use and delete
- # the options :label_method and :value_methods when present
+ # Detects the label and value methods from a collection using methods set in
+ # collection_label_methods and collection_value_methods. For some ruby core
+ # classes sensible defaults have been defined. It will use and delete the options
+ # :label_method and :value_methods when present.
#
- def detect_label_and_value_method!(collection_or_instance, options = {}) #:nodoc
- label = options.delete(:label_method) || detect_label_method(collection_or_instance)
- value = options.delete(:value_method) || :id
+ def detect_label_and_value_method!(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
+
+ # Order of preference: user supplied method, class defaults, auto-detect
+ label = options[:label_method] || label || self.class.collection_label_methods.find { |m| sample.respond_to?(m) }
+ value = options[:value_method] || value || self.class.collection_value_methods.find { |m| sample.respond_to?(m) }
+
[label, value]
end
- # Detected the label collection method when none is supplied using the
- # values set in @@collection_label_methods.
+ # Return the label collection method when none is supplied using the
+ # values set in collection_label_methods.
#
def detect_label_method(collection) #:nodoc:
- @@collection_label_methods.detect { |m| collection.first.respond_to?(m) }
+ detect_label_and_value_method!(collection).first
end
# Detects the method to call for fetching group members from the groups when grouping select options
@@ -1542,12 +1626,12 @@ def default_string_options(method, type) #:nodoc:
column = self.column_for(method)
if type == :text
- { :cols => @@default_text_field_size, :rows => @@default_text_area_height }
+ { :cols => self.class.default_text_field_size, :rows => self.class.default_text_area_height }
elsif type == :numeric || column.nil? || column.limit.nil?
- { :size => @@default_text_field_size }
+ { :size => self.class.default_text_field_size }
else
- { :maxlength => column.limit,
- :size => @@default_text_field_size && [column.limit, @@default_text_field_size].min }
+ { :maxlength => column.limit,
+ :size => self.class.default_text_field_size && [column.limit, self.class.default_text_field_size].min }
end
end
@@ -1593,27 +1677,27 @@ def humanized_attribute_name(method) #:nodoc:
if @object && @object.class.respond_to?(:human_attribute_name)
humanized_name = @object.class.human_attribute_name(method.to_s)
if humanized_name == method.to_s.send(:humanize)
- method.to_s.send(@@label_str_method)
+ method.to_s.send(self.class.label_str_method)
else
humanized_name
end
else
- method.to_s.send(@@label_str_method)
+ method.to_s.send(self.class.label_str_method)
end
end
# Internal generic method for looking up localized values within Formtastic
# using I18n, if no explicit value is set and I18n-lookups are enabled.
- #
+ #
# Enabled/Disable this by setting:
#
# Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true/false
#
# Lookup priority:
#
- # 'formtastic.{{type}}.{{model}}.{{action}}.{{attribute}}'
- # 'formtastic.{{type}}.{{model}}.{{attribute}}'
- # 'formtastic.{{type}}.{{attribute}}'
+ # 'formtastic.%{type}.%{model}.%{action}.%{attribute}'
+ # 'formtastic.%{type}.%{model}.%{attribute}'
+ # 'formtastic.%{type}.%{attribute}'
#
# Example:
#
@@ -1629,7 +1713,7 @@ def localized_string(key, value, type, options = {}) #:nodoc:
if value.is_a?(::String)
escape_html_entities(value)
else
- use_i18n = value.nil? ? @@i18n_lookups_by_default : (value != false)
+ use_i18n = value.nil? ? self.class.i18n_lookups_by_default : (value != false)
if use_i18n
model_name, nested_model_name = normalize_model_name(self.model_name.underscore)
@@ -1638,10 +1722,10 @@ def localized_string(key, value, type, options = {}) #:nodoc:
defaults = ::Formtastic::I18n::SCOPES.collect do |i18n_scope|
i18n_path = i18n_scope.dup
- i18n_path.gsub!('{{action}}', action_name)
- i18n_path.gsub!('{{model}}', model_name)
- i18n_path.gsub!('{{nested_model}}', nested_model_name) unless nested_model_name.nil?
- i18n_path.gsub!('{{attribute}}', attribute_name)
+ i18n_path.gsub!('%{action}', action_name)
+ i18n_path.gsub!('%{model}', model_name)
+ i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil?
+ i18n_path.gsub!('%{attribute}', attribute_name)
i18n_path.gsub!('..', '.')
i18n_path.to_sym
end
@@ -1677,13 +1761,13 @@ def send_or_call(duck, object)
def set_include_blank(options)
unless options.key?(:include_blank) || options.key?(:prompt)
- options[:include_blank] = @@include_blank_for_select_by_default
+ options[:include_blank] = self.class.include_blank_for_select_by_default
end
options
end
def escape_html_entities(string) #:nodoc:
- if @@escape_html_entities_in_hints_and_labels
+ if self.class.escape_html_entities_in_hints_and_labels
# Acceppt html_safe flag as indicator to skip escaping
string = template.escape_once(string) unless string.respond_to?(:html_safe?) && string.html_safe? == true
end
@@ -1743,20 +1827,32 @@ def with_custom_field_error_proc(&block)
ensure
::ActionView::Base.field_error_proc = default_field_error_proc
end
-
+
+ def semantic_remote_form_for_wrapper(record_or_name_or_array, *args, &proc)
+ options = args.extract_options!
+ if self.respond_to? :remote_form_for
+ semantic_remote_form_for_real(record_or_name_or_array, *(args << options), &proc)
+ else
+ options[:remote] = true
+ semantic_form_for(record_or_name_or_array, *(args << options), &proc)
+ end
+ end
+
[:form_for, :fields_for, :remote_form_for].each do |meth|
module_eval <<-END_SRC, __FILE__, __LINE__ + 1
def semantic_#{meth}(record_or_name_or_array, *args, &proc)
options = args.extract_options!
options[:builder] ||= @@builder
options[:html] ||= {}
+ singularizer = defined?(ActiveModel::Naming.singular) ? ActiveModel::Naming.method(:singular) : ActionController::RecordIdentifier.method(:singular_class_name)
+
class_names = options[:html][:class] ? options[:html][:class].split(" ") : []
class_names << "formtastic"
class_names << case record_or_name_or_array
when String, Symbol then record_or_name_or_array.to_s # :post => "post"
- when Array then ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array.last.class) # [@post, @comment] # => "comment"
- else ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array.class) # @post => "post"
+ when Array then singularizer.call(record_or_name_or_array.last.class) # [@post, @comment] # => "comment"
+ else singularizer.call(record_or_name_or_array.class) # @post => "post"
end
options[:html][:class] = class_names.join(" ")
@@ -1766,6 +1862,8 @@ def semantic_#{meth}(record_or_name_or_array, *args, &proc)
end
END_SRC
end
+ alias :semantic_remote_form_for_real :semantic_remote_form_for
+ alias :semantic_remote_form_for :semantic_remote_form_for_wrapper
alias :semantic_form_remote_for :semantic_remote_form_for
end
View
17 lib/formtastic/i18n.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
module Formtastic
module I18n
@@ -7,16 +6,16 @@ module I18n
:required => 'required',
:yes => 'Yes',
:no => 'No',
- :create => 'Create {{model}}',
- :update => 'Update {{model}}'
+ :create => 'Create %{model}',
+ :update => 'Update %{model}'
}.freeze
SCOPES = [
- '{{model}}.{{nested_model}}.{{action}}.{{attribute}}',
- '{{model}}.{{action}}.{{attribute}}',
- '{{model}}.{{nested_model}}.{{attribute}}',
- '{{model}}.{{attribute}}',
- '{{nested_model}}.{{attribute}}',
- '{{attribute}}'
+ '%{model}.%{nested_model}.%{action}.%{attribute}',
+ '%{model}.%{action}.%{attribute}',
+ '%{model}.%{nested_model}.%{attribute}',
+ '%{model}.%{attribute}',
+ '%{nested_model}.%{attribute}',
+ '%{attribute}'
]
class << self
View
1 lib/formtastic/layout_helper.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
module Formtastic
module LayoutHelper
View
12 lib/formtastic/railtie.rb
@@ -0,0 +1,12 @@
+require 'formtastic'
+require 'formtastic/layout_helper'
+require 'rails'
+
+module Formtastic
+ class Railtie < Rails::Railtie
+ initializer 'formtastic.initialize', :after => :after_initialize do
+ ActionView::Base.send :include, Formtastic::SemanticFormHelper
+ ActionView::Base.send(:include, Formtastic::LayoutHelper)
+ end
+ end
+end
View
7 lib/formtastic/util.rb
@@ -25,5 +25,12 @@ def rails_safe_buffer_class
return ActionView::SafeBuffer
end
+ def rails3?
+ version=
+ if defined?(ActionPack::VERSION::MAJOR)
+ ActionPack::VERSION::MAJOR
+ end
+ !version.blank? && version >= 3
+ end
end
end
View
86 lib/generators/formtastic/form/form_generator.rb
@@ -0,0 +1,86 @@
+# coding: utf-8
+module Formtastic
+ class FormGenerator < Rails::Generators::NamedBase
+ desc "Generates formtastic form code based on an existing model. By default the " <<
+ "generated code will be printed out directly in the terminal, and also copied " <<
+ "to clipboard. Can optionally be saved into partial directly."
+
+ argument :name, :type => :string, :required => true, :banner => 'ExistingModelName'
+ argument :attributes, :type => :array, :default => [], :banner => 'field:type field:type'
+
+ class_option :haml, :type => :boolean, :default => false, :group => :formtastic,
+ :desc => "Generate HAML instead of ERB"
+
+ class_option :partial, :type => :boolean, :default => false, :group => :formtastic,
+ :desc => 'Generate a form partial in the model views path, i.e. "_form.html.erb" or "_form.html.haml"'
+
+ class_option :controller, :type => :string, :default => false, :group => :formtastic,
+ :desc => 'Generate for custom controller/view path - in case model and controller namespace is different, i.e. "admin/posts"'
+
+ def self.source_root
+ # Set source directory for the templates to the rails2 generator template directory
+ @source_root ||= File.expand_path(File.join('..', '..', '..', '..', 'generators', 'form', 'templates'), File.dirname(__FILE__))
+ end
+
+ def create_or_show
+ @attributes = self.columns if @attributes.empty?
+ if options[:partial]
+ empty_directory "app/views/#{controller_path}"
+ template "view__form.html.#{template_type}", "app/views/#{controller_path}/_form.html.#{template_type}"
+ else
+ template = File.read("#{self.class.source_root}/view__form.html.#{template_type}")
+ erb = ERB.new(template, nil, '-')
+ generated_code = erb.result(binding).strip rescue nil
+
+ puts "# ---------------------------------------------------------"
+ puts "# GENERATED FORMTASTIC CODE"
+ puts "# ---------------------------------------------------------"
+ puts
+ puts generated_code || "Nothing could be generated - model exists?"
+ puts
+ puts "# ---------------------------------------------------------"
+ puts "Copied to clipboard - just paste it!" if save_to_clipboard(generated_code)
+ end
+ end
+
+ protected
+
+ IGNORED_COLUMNS = [:updated_at, :created_at].freeze
+
+ def template_type
+ @template_type ||= options[:haml] ? :haml : :erb
+ end
+
+ def controller_path
+ @controller_path ||= if options[:controller]
+ options[:controller].underscore
+ else
+ name.underscore.pluralize
+ end
+ end
+
+ def columns
+ @columns ||= self.name.camelize.constantize.content_columns.reject { |column| IGNORED_COLUMNS.include?(column.name.to_sym) }
+ end
+
+ def save_to_clipboard(data)
+ return unless data
+
+ begin
+ case RUBY_PLATFORM
+ when /win32/
+ require 'win32/clipboard'
+ ::Win32::Clipboard.data = data
+ when /darwin/ # mac
+ `echo "#{data}" | pbcopy`
+ else # linux/unix
+ `echo "#{data}" | xsel --clipboard` || `echo "#{data}" | xclip`
+ end
+ rescue LoadError
+ false
+ else
+ true
+ end
+ end
+ end
+end
View
24 lib/generators/formtastic/install/install_generator.rb
@@ -0,0 +1,24 @@
+# coding: utf-8
+module Formtastic
+ class InstallGenerator < Rails::Generators::Base
+ desc "Copies formtastic.css and formtastic_changes.css to public/stylesheets/ and a config initializer to config/initializers/formtastic_config.rb"
+
+ def self.source_root
+ # Set source directory for the templates to the rails2 generator template directory
+ @source_root ||= File.expand_path(File.join('..', '..', '..', '..', 'generators', 'formtastic', 'templates'), File.dirname(__FILE__))
+ end
+
+ def self.banner
+ "rails generate formtastic:install [options]"
+ end
+
+ def copy_files
+ empty_directory 'config/initializers'
+ template 'formtastic.rb', 'config/initializers/formtastic.rb'
+
+ empty_directory 'public/stylesheets'
+ template 'formtastic.css', 'public/stylesheets/formtastic.css'
+ template 'formtastic_changes.css', 'public/stylesheets/formtastic_changes.css'
+ end
+ end
+end
View
7 rails/init.rb
@@ -1,7 +1,2 @@
# coding: utf-8
-require 'formtastic'
-require 'formtastic/layout_helper'
-
-ActionView::Base.send :include, Formtastic::SemanticFormHelper
-ActionView::Base.send :include, Formtastic::LayoutHelper
-
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "init"))
View
33 spec/buttons_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'SemanticFormBuilder#buttons' do
@@ -13,26 +13,31 @@
describe 'with a block' do
describe 'when no options are provided' do
before do
- semantic_form_for(@new_post) do |builder|
- builder.buttons do
+ @form = semantic_form_for(@new_post) do |builder|
+ buttons = builder.buttons do
concat('hello')
end
+ concat(buttons)
end
end
it 'should render a fieldset inside the form, with a class of "inputs"' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form fieldset.buttons")
end
it 'should render an ol inside the fieldset' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form fieldset.buttons ol")
end
it 'should render the contents of the block inside the ol' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form fieldset.buttons ol", /hello/)
end
it 'should not render a legend inside the fieldset' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should_not have_tag("form fieldset.buttons legend")
end
end
@@ -41,12 +46,13 @@
before do
@legend_text = "Advanced options"
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
builder.buttons :name => @legend_text do
end
end
end
it 'should render a fieldset inside the form' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form fieldset legend", /#{@legend_text}/)
end
end
@@ -56,12 +62,13 @@
@id_option = 'advanced'
@class_option = 'wide'
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
builder.buttons :id => @id_option, :class => @class_option do
end
end
end
it 'should pass the options into the fieldset tag as attributes' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form fieldset##{@id_option}")
output_buffer.should have_tag("form fieldset.#{@class_option}")
end
@@ -74,32 +81,38 @@
describe 'with no args (default buttons)' do
before do
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.buttons)
end
end
it 'should render a form' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form')
end
it 'should render a buttons fieldset inside the form' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form fieldset.buttons')
end
it 'should not render a legend in the fieldset' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should_not have_tag('form fieldset.buttons legend')
end
it 'should render an ol in the fieldset' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form fieldset.buttons ol')
end
it 'should render a list item in the ol for each default button' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form fieldset.buttons ol li', :count => 1)
end
it 'should render a commit list item for the commit button' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form fieldset.buttons ol li.commit')
end
@@ -108,12 +121,13 @@
describe 'with button names as args' do
before do
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.buttons(:commit))
end
end
it 'should render a form with a fieldset containing a list item for each button arg' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form > fieldset.buttons > ol > li', :count => 1)
output_buffer.should have_tag('form > fieldset.buttons > ol > li.commit')
end
@@ -123,21 +137,24 @@
describe 'with button names as args and an options hash' do
before do
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.buttons(:commit, :name => "Now click a button", :id => "my-id"))
end
end
it 'should render a form with a fieldset containing a list item for each button arg' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form > fieldset.buttons > ol > li', :count => 1)
output_buffer.should have_tag('form > fieldset.buttons > ol > li.commit', :count => 1)
end
it 'should pass the options down to the fieldset' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form > fieldset#my-id.buttons')
end
it 'should use the special :name option as a text for the legend tag' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form > fieldset#my-id.buttons > legend', /Now click a button/)
end
View
96 spec/commit_button_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'SemanticFormBuilder#commit_button' do
@@ -14,29 +14,33 @@
before do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
end
it 'should render a commit li' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit')
end
it 'should render an input with a type attribute of "submit"' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@type="submit"]')
end
it 'should render an input with a name attribute of "commit"' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@name="commit"]')
end
it 'should pass options given in :button_html to the button' do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button('text', :button_html => {:class => 'my_class', :id => 'my_id'}))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input#my_id')
output_buffer.should have_tag('li.commit input.my_class')
end
@@ -54,19 +58,21 @@
it 'should use the default if set' do
with_config :default_commit_button_accesskey, 's' do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button('text', :button_html => {}))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@accesskey="s"]')
end
end
it 'should use the value set in options over the default' do
with_config :default_commit_button_accesskey, 's' do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button('text', :accesskey => 'o'))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
output_buffer.should have_tag('li.commit input[@accesskey="o"]')
end
@@ -75,9 +81,10 @@
it 'should use the value set in button_html over options' do
with_config :default_commit_button_accesskey, 's' do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button('text', :accesskey => 'o', :button_html => {:accesskey => 't'}))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
output_buffer.should_not have_tag('li.commit input[@accesskey="o"]')
output_buffer.should have_tag('li.commit input[@accesskey="t"]')
@@ -90,16 +97,18 @@
before do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
end
end
it "should render the string as the value of the button" do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li input[@value="a string"]')
end
it "should deal with the options hash" do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li input.pretty')
end
@@ -109,12 +118,13 @@
before do
@new_post.stub!(:new_record?).and_return(false)
- semantic_form_for(@new_post) do |builder|
+ @form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button(:button_html => { :class => "pretty"}))
end
end
it "should deal with the options hash" do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li input.pretty')
end
@@ -126,27 +136,29 @@
describe 'when used without object' do
describe 'when explicit label is provided' do
it 'should render an input with the explicitly specified label' do
- semantic_form_for(:post, :url => 'http://example.com') do |builder|
+ form = semantic_form_for(:post, :url => 'http://example.com') do |builder|
concat(builder.commit_button("Click!"))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="submit"]')
end
end
describe 'when no explicit label is provided' do
describe 'when no I18n-localized label is provided' do
before do
- ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit {{model}}'}
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit %{model}'}
end
after do
::I18n.backend.reload!
end
it 'should render an input with default I18n-localized label (fallback)' do
- semantic_form_for(:post, :url => 'http://example.com') do |builder|
+ form = semantic_form_for(:post, :url => 'http://example.com') do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Submit Post"][@class~="submit"]')
end
end
@@ -171,20 +183,22 @@
:formtastic => {
:actions => {
:post => {
- :submit => 'Custom Submit {{model}}'
+ :submit => 'Custom Submit %{model}'
}
}
}
- semantic_form_for(:post, :url => 'http://example.com') do |builder|
+ form = semantic_form_for(:post, :url => 'http://example.com') do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit Post"][@class~="submit"]})
end
it 'should render an input with anoptional localized label (I18n) - if first is not set' do
- semantic_form_for(:post, :url => 'http://example.com') do |builder|
+ form = semantic_form_for(:post, :url => 'http://example.com') do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit"][@class~="submit"]})
end
@@ -200,27 +214,29 @@
describe 'when explicit label is provided' do
it 'should render an input with the explicitly specified label' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button("Click!"))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="create"]')
end
end
describe 'when no explicit label is provided' do
describe 'when no I18n-localized label is provided' do
before do
- ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create {{model}}'}
+ ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create %{model}'}
end
after do
::I18n.backend.reload!
end
it 'should render an input with default I18n-localized label (fallback)' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Create Post"][@class~="create"]')
end
end
@@ -245,21 +261,23 @@
:formtastic => {
:actions => {
:post => {
- :create => 'Custom Create {{model}}'
+ :create => 'Custom Create %{model}'
}
}
}
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create Post"][@class~="create"]})
end
it 'should render an input with anoptional localized label (I18n) - if first is not set' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
- output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
+ output_buffer.concat(form) if Formtastic::Util.rails3?
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
end
end
@@ -274,33 +292,36 @@
describe 'when explicit label is provided' do
it 'should render an input with the explicitly specified label' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button("Click!"))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="update"]')
end
end
describe 'when no explicit label is provided' do
describe 'when no I18n-localized label is provided' do
before do
- ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save {{model}}'}
+ ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save %{model}'}
end
after do
::I18n.backend.reload!
end
it 'should render an input with default I18n-localized label (fallback)' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li.commit input[@value="Save Post"][@class~="update"]')
end
end
describe 'when I18n-localized label is provided' do
before do
+ ::I18n.backend.reload!
::I18n.backend.store_translations :en,
:formtastic => {
:actions => {
@@ -319,20 +340,22 @@
:formtastic => {
:actions => {
:post => {
- :update => 'Custom Save {{model}}'
+ :update => 'Custom Save %{model}'
}
}
}
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save Post"][@class~="update"]})
end
it 'should render an input with anoptional localized label (I18n) - if first is not set' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.commit_button)
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save"][@class~="update"]})
::I18n.backend.store_translations :en, :formtastic => {}
end
@@ -345,16 +368,31 @@
describe 'when the model is two words' do
before do
output_buffer = ''
- class ::UserPost; def id; end; def self.human_name; "Userpost"; end; end # Rails does crappy human_name
+ class ::UserPost
+ extend ActiveModel::Naming if defined?(ActiveModel::Naming)
+ include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
+
+ def id
+ end
+
+ def persisted?
+ end
+
+ # Rails does crappy human_name
+ def self.human_name
+ "User post"
+ end
+ end
@new_user_post = ::UserPost.new
@new_user_post.stub!(:new_record?).and_return(true)
- semantic_form_for(@new_user_post, :url => '') do |builder|
+ @form = semantic_form_for(@new_user_post, :url => '') do |builder|
concat(builder.commit_button())
end
end
it "should render the string as the value of the button" do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('li input[@value="Create User post"]')
end
View
44 spec/custom_builder_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'Formtastic::SemanticFormHelper.builder' do
@@ -29,7 +29,16 @@ def awesome_input(method, options)
::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
end
-
+
+ it 'should allow custom settings per form builder subclass' do
+ with_config(:all_fields_required_by_default, true) do
+ MyCustomFormBuilder.all_fields_required_by_default = false
+
+ MyCustomFormBuilder.all_fields_required_by_default.should be_false
+ ::Formtastic::SemanticFormBuilder.all_fields_required_by_default.should be_true
+ end
+ end
+
describe "when using a custom builder" do
before do
@@ -43,7 +52,7 @@ def awesome_input(method, options)
describe "semantic_form_for" do
- it "should yeild and instance of the custom builder" do
+ it "should yield an instance of the custom builder" do
semantic_form_for(@new_post) do |builder|
builder.class.should == MyCustomFormBuilder
end
@@ -56,7 +65,34 @@ def awesome_input(method, options)
end
end
+
+ describe "semantic_fields_for" do
+
+ it "should yield an instance of the parent form builder" do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_fields_for(:author) do |nested_builder|
+ nested_builder.class.should == MyCustomFormBuilder
+ end
+ end
+ end
+
+ end
end
-end
+ describe "when using a builder passed to form options" do
+
+ describe "semantic_fields_for" do
+
+ it "should yield an instance of the parent form builder" do
+ semantic_form_for(@new_post, :builder => MyCustomFormBuilder) do |builder|
+ builder.semantic_fields_for(:author) do |nested_builder|
+ nested_builder.class.should == MyCustomFormBuilder
+ end
+ end
+ end
+
+ end
+
+ end
+end
View
2 spec/defaults_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.join(File.dirname(__FILE__), *%w[spec_helper])
+require 'spec_helper'
describe 'Formtastic::SemanticFormBuilder-defaults' do
View
2 spec/error_proc_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'Rails field_error_proc' do
View
5 spec/errors_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'SemanticFormBuilder#errors_on' do
@@ -91,9 +91,10 @@
@errors.stub!(:[]).with(:author).and_return(['must not be blank'])
@errors.stub!(:[]).with(:author_id).and_return(['is already taken', 'must not be blank']) # note the duplicate of association
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
concat(builder.input(:author))
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("ul.errors li", /must not be blank/, :count => 1)
output_buffer.should have_tag("ul.errors li", /is already taken/, :count => 1)
end
View
50 spec/form_helper_spec.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-require File.dirname(__FILE__) + '/spec_helper'
+require 'spec_helper'
describe 'SemanticFormHelper' do
@@ -13,54 +13,62 @@
describe '#semantic_form_for' do
it 'yields an instance of SemanticFormBuilder' do
- semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
+ semantic_form_for(@new_post, :url => '/hello') do |builder|
builder.class.should == ::Formtastic::SemanticFormBuilder
end
end
it 'adds a class of "formtastic" to the generated form' do
- semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
+ form = semantic_form_for(@new_post, :url => '/hello') do |builder|
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.formtastic")
end
it 'adds class matching the object name to the generated form when a symbol is provided' do
- semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
+ form = semantic_form_for(@new_post, :url => '/hello') do |builder|
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.post")
- semantic_form_for(:project, :url => '/hello') do |builder|
+ form = semantic_form_for(:project, :url => '/hello') do |builder|
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.project")
end
it 'adds class matching the object\'s class to the generated form when an object is provided' do
- semantic_form_for(@new_post) do |builder|
+ form = semantic_form_for(@new_post) do |builder|
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.post")
end
it 'adds a namespaced class to the generated form' do
- semantic_form_for(::Namespaced::Post.new, :url => '/hello') do |builder|
+ form = semantic_form_for(::Namespaced::Post.new, :url => '/hello') do |builder|
end
+ output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.namespaced_post")
end
describe 'allows :html options' do
before(:each) do
- semantic_form_for(:post, ::Post.new, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
+ @form = semantic_form_for(@new_post, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
end
end
it 'to add a id of "something-special" to generated form' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form#something-special")
end
it 'to add a class of "something-extra" to generated form' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form.something-extra")
end
it 'to add enctype="multipart/form-data"' do
+ output_buffer.concat(@form) if Formtastic::Util.rails3?
output_buffer.should have_tag('form[@enctype="multipart/form-data"]')
end
end
@@ -71,16 +79,24 @@
builder.object_name.should == "post"
end
end
-
+
it 'can be called with a generic style and instance variable' do
- semantic_form_for(:post, @new_post, :url => new_post_path) do |builder|
- builder.object.class.should == ::Post
- builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
+ if rails3?
+ semantic_form_for(@new_post, :as => :post, :url => new_post_path) do |builder|
+ builder.object.class.should == ::Post
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
+ end
+ end
+ if rails2?
+ semantic_form_for(:post, @new_post, :url => new_post_path) do |builder|
+ builder.object.class.should == ::Post
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
+ end
end
end
it 'can be called with a generic style and inline object' do
- semantic_form_for(:post, ::Post.new, :url => new_post_path) do |builder|
+ semantic_form_for(@new_post, :url => new_post_path) do |builder|
builder.object.class.should == ::Post
builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
end
@@ -90,7 +106,7 @@
it "yields an instance of the given builder" do
class MyAwesomeCustomBuilder < ::Formtastic::SemanticFormBuilder
end
- semantic_form_for(:post, ::Post.new, :url => '/hello', :builder => MyAwesomeCustomBuilder) do |builder|
+ semantic_form_for(@new_post, :url => '/hello', :builder => MyAwesomeCustomBuilder) do |builder|
builder.class.should == MyAwesomeCustomBuilder
end
end
@@ -100,23 +116,23 @@ class MyAwesomeCustomBuilder < ::Formtastic::SemanticFormBuilder
describe '#semantic_fields_for' do
it 'yields an instance of SemanticFormBuilder' do
- semantic_fields_for(:post, ::Post.new, :url => '/hello') do |builder|
+ semantic_fields_for(@new_post, :url => '/hello') do |builder|
builder.class.should == ::Formtastic::SemanticFormBuilder
end
end
end
describe '#semantic_form_remote_for' do
it 'yields an instance of SemanticFormBuilder' do
- semantic_form_remote_for(:post, ::Post.new, :url => '/hello') do |builder|
+ semantic_form_remote_for(@new_post, :url => '/hello') do |builder|
builder.class.should == ::Formtastic::SemanticFormBuilder
end
end
end
describe '#semantic_form_for_remote' do
it 'yields an instance of SemanticFormBuilder' do
- semantic_remote_form_for(:post, ::Post.new, :url => '/hello') do |builder|
+ semantic_remote_form_for(@new_post, :url => '/hello') do |builder|
builder.class.should == ::Formtastic::SemanticFormBuilder
end
end
View
21 spec/helpers/layout_helper_spec.rb
@@ -0,0 +1,21 @@
+# coding: utf-8
+require 'spec_helper'
+
+describe Formtastic::LayoutHelper do
+
+ include FormtasticSpecHelper
+ include Formtastic::LayoutHelper
+
+ describe '#formtastic_stylesheet_link_tag' do
+
+ it 'should render a link to formtastic.css' do
+ formtastic_stylesheet_link_tag.should have_tag("link[@href='/stylesheets/formtastic.css']")
+ end