formtastic-rails3 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +558 -0
  3. data/Rakefile +103 -0
  4. data/generators/form/USAGE +16 -0
  5. data/generators/form/form_generator.rb +120 -0
  6. data/generators/form/templates/view__form.html.erb +5 -0
  7. data/generators/form/templates/view__form.html.haml +4 -0
  8. data/generators/formtastic/formtastic_generator.rb +24 -0
  9. data/generators/formtastic/templates/formtastic.css +144 -0
  10. data/generators/formtastic/templates/formtastic.rb +54 -0
  11. data/generators/formtastic/templates/formtastic_changes.css +10 -0
  12. data/generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb +16 -0
  13. data/lib/formtastic.rb +1724 -0
  14. data/lib/formtastic/i18n.rb +32 -0
  15. data/lib/formtastic/layout_helper.rb +10 -0
  16. data/lib/generators/formtastic/form/form_generator.rb +85 -0
  17. data/lib/generators/formtastic/form/templates/_form.html.erb +5 -0
  18. data/lib/generators/formtastic/form/templates/_form.html.haml +4 -0
  19. data/lib/generators/formtastic/install/install_generator.rb +23 -0
  20. data/lib/generators/formtastic/install/templates/formtastic.css +144 -0
  21. data/lib/generators/formtastic/install/templates/formtastic.rb +58 -0
  22. data/lib/generators/formtastic/install/templates/formtastic_changes.css +10 -0
  23. data/lib/locale/en.yml +8 -0
  24. data/spec/buttons_spec.rb +149 -0
  25. data/spec/commit_button_spec.rb +377 -0
  26. data/spec/custom_builder_spec.rb +62 -0
  27. data/spec/custom_macros.rb +460 -0
  28. data/spec/defaults_spec.rb +20 -0
  29. data/spec/error_proc_spec.rb +27 -0
  30. data/spec/errors_spec.rb +85 -0
  31. data/spec/form_helper_spec.rb +110 -0
  32. data/spec/i18n_spec.rb +131 -0
  33. data/spec/include_blank_spec.rb +70 -0
  34. data/spec/input_spec.rb +632 -0
  35. data/spec/inputs/boolean_input_spec.rb +93 -0
  36. data/spec/inputs/check_boxes_input_spec.rb +167 -0
  37. data/spec/inputs/country_input_spec.rb +80 -0
  38. data/spec/inputs/currency_input_spec.rb +80 -0
  39. data/spec/inputs/date_input_spec.rb +143 -0
  40. data/spec/inputs/datetime_input_spec.rb +259 -0
  41. data/spec/inputs/file_input_spec.rb +33 -0
  42. data/spec/inputs/hidden_input_spec.rb +52 -0
  43. data/spec/inputs/numeric_input_spec.rb +44 -0
  44. data/spec/inputs/password_input_spec.rb +46 -0
  45. data/spec/inputs/radio_input_spec.rb +152 -0
  46. data/spec/inputs/select_input_spec.rb +470 -0
  47. data/spec/inputs/string_input_spec.rb +47 -0
  48. data/spec/inputs/text_input_spec.rb +33 -0
  49. data/spec/inputs/time_input_spec.rb +128 -0
  50. data/spec/inputs/time_zone_input_spec.rb +102 -0
  51. data/spec/inputs_spec.rb +395 -0
  52. data/spec/label_spec.rb +48 -0
  53. data/spec/layout_helper_spec.rb +42 -0
  54. data/spec/semantic_errors_spec.rb +98 -0
  55. data/spec/semantic_fields_for_spec.rb +44 -0
  56. data/spec/spec.opts +2 -0
  57. data/spec/spec_helper.rb +238 -0
  58. metadata +205 -0
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), *%w[spec_helper])
3
+
4
+ describe 'Formtastic::SemanticFormBuilder-defaults' do
5
+
6
+ # Note: This spec might make better sense somewhere else. Just temporary.
7
+
8
+ describe "required string" do
9
+
10
+ it "should render proc with I18n correctly" do
11
+ ::I18n.backend.store_translations :en, :formtastic => {:required => 'Haha!'}
12
+
13
+ required_string = Formtastic::SemanticFormBuilder.required_string
14
+ required_string = required_string.is_a?(::Proc) ? required_string.call : required_string.to_s
15
+ required_string.should == %{<abbr title="Haha!">*</abbr>}
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'Rails field_error_proc' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+ end
12
+
13
+ it "should not be overridden globally for all form builders" do
14
+ current_field_error_proc = ::ActionView::Base.field_error_proc
15
+
16
+ semantic_form_for(@new_post) do |builder|
17
+ ::ActionView::Base.field_error_proc.should_not == current_field_error_proc
18
+ end
19
+
20
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
21
+
22
+ form_for(@new_post) do |builder|
23
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,85 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'SemanticFormBuilder#errors_on' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
12
+ @errors = mock('errors')
13
+ @new_post.stub!(:errors).and_return(@errors)
14
+ end
15
+
16
+ describe 'when there are errors' do
17
+ before do
18
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
19
+ end
20
+
21
+ it 'should render a paragraph with the errors joined into a sentence when inline_errors config is :sentence' do
22
+ ::Formtastic::SemanticFormBuilder.inline_errors = :sentence
23
+ semantic_form_for(@new_post) do |builder|
24
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.to_sentence)
25
+ end
26
+ end
27
+
28
+ it 'should render an unordered list with the class errors when inline_errors config is :list' do
29
+ ::Formtastic::SemanticFormBuilder.inline_errors = :list
30
+ semantic_form_for(@new_post) do |builder|
31
+ builder.errors_on(:title).should have_tag('ul.errors')
32
+ @title_errors.each do |error|
33
+ builder.errors_on(:title).should have_tag('ul.errors li', error)
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'should render a paragraph with the first error when inline_errors config is :first' do
39
+ ::Formtastic::SemanticFormBuilder.inline_errors = :first
40
+ semantic_form_for(@new_post) do |builder|
41
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.first)
42
+ end
43
+ end
44
+
45
+ it 'should return nil when inline_errors config is :none' do
46
+ ::Formtastic::SemanticFormBuilder.inline_errors = :none
47
+ semantic_form_for(@new_post) do |builder|
48
+ builder.errors_on(:title).should be_nil
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe 'when there are no errors (nil)' do
55
+ before do
56
+ @errors.stub!(:[]).with(:title).and_return(nil)
57
+ end
58
+
59
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
60
+ [:sentence, :list, :none].each do |config|
61
+ ::Formtastic::SemanticFormBuilder.inline_errors = config
62
+ semantic_form_for(@new_post) do |builder|
63
+ builder.errors_on(:title).should be_nil
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ describe 'when there are no errors (empty array)' do
70
+ before do
71
+ @errors.stub!(:[]).with(:title).and_return([])
72
+ end
73
+
74
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
75
+ [:sentence, :list, :none].each do |config|
76
+ ::Formtastic::SemanticFormBuilder.inline_errors = config
77
+ semantic_form_for(@new_post) do |builder|
78
+ builder.errors_on(:title).should be_nil
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,110 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'SemanticFormHelper' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+ end
12
+
13
+ describe '#semantic_form_for' do
14
+
15
+ it 'yields an instance of SemanticFormBuilder' do
16
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
17
+ builder.class.should == ::Formtastic::SemanticFormBuilder
18
+ end
19
+ end
20
+
21
+ it 'adds a class of "formtastic" to the generated form' do
22
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
23
+ end
24
+ output_buffer.should have_tag("form.formtastic")
25
+ end
26
+
27
+ it 'adds class matching the object name to the generated form when a symbol is provided' do
28
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
29
+ end
30
+ output_buffer.should have_tag("form.post")
31
+
32
+ semantic_form_for(:project, :url => '/hello') do |builder|
33
+ end
34
+ output_buffer.should have_tag("form.project")
35
+ end
36
+
37
+ it 'adds class matching the object\'s class to the generated form when an object is provided' do
38
+ semantic_form_for(@new_post) do |builder|
39
+ end
40
+ output_buffer.should have_tag("form.post")
41
+ end
42
+
43
+ it 'adds a namespaced class to the generated form' do
44
+ semantic_form_for(::Namespaced::Post.new, :url => '/hello') do |builder|
45
+ end
46
+ output_buffer.should have_tag("form.namespaced_post")
47
+ end
48
+
49
+ describe 'allows :html options' do
50
+ before(:each) do
51
+ semantic_form_for(:post, ::Post.new, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
52
+ end
53
+ end
54
+
55
+ it 'to add a id of "something-special" to generated form' do
56
+ output_buffer.should have_tag("form#something-special")
57
+ end
58
+
59
+ it 'to add a class of "something-extra" to generated form' do
60
+ output_buffer.should have_tag("form.something-extra")
61
+ end
62
+
63
+ it 'to add enctype="multipart/form-data"' do
64
+ output_buffer.should have_tag('form[@enctype="multipart/form-data"]')
65
+ end
66
+ end
67
+
68
+ it 'can be called with a resource-oriented style' do
69
+ semantic_form_for(@new_post) do |builder|
70
+ builder.object.class.should == ::Post
71
+ builder.object_name.should == "post"
72
+ end
73
+ end
74
+
75
+ it 'can be called with a generic style and instance variable' do
76
+ semantic_form_for(:post, @new_post, :url => new_post_path) do |builder|
77
+ builder.object.class.should == ::Post
78
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
79
+ end
80
+ end
81
+
82
+ it 'can be called with a generic style and inline object' do
83
+ semantic_form_for(:post, ::Post.new, :url => new_post_path) do |builder|
84
+ builder.object.class.should == ::Post
85
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
86
+ end
87
+ end
88
+
89
+ describe "with :builder option" do
90
+ it "yields an instance of the given builder" do
91
+ class MyAwesomeCustomBuilder < ::Formtastic::SemanticFormBuilder
92
+ end
93
+ semantic_form_for(:post, ::Post.new, :url => '/hello', :builder => MyAwesomeCustomBuilder) do |builder|
94
+ builder.class.should == MyAwesomeCustomBuilder
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ describe '#semantic_fields_for' do
102
+ it 'yields an instance of SemanticFormBuilder' do
103
+ semantic_fields_for(:post, ::Post.new, :url => '/hello') do |builder|
104
+ builder.class.should == ::Formtastic::SemanticFormBuilder
105
+ end
106
+ end
107
+ end
108
+
109
+ end
110
+
data/spec/i18n_spec.rb ADDED
@@ -0,0 +1,131 @@
1
+ # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), *%w[spec_helper])
3
+
4
+ describe 'Formtastic::I18n' do
5
+
6
+ FORMTASTIC_KEYS = [:required, :yes, :no, :create, :update].freeze
7
+
8
+ it "should be defined" do
9
+ lambda { ::Formtastic::I18n }.should_not raise_error(::NameError)
10
+ end
11
+
12
+ describe "default translations" do
13
+ it "should be defined" do
14
+ lambda { ::Formtastic::I18n::DEFAULT_VALUES }.should_not raise_error(::NameError)
15
+ ::Formtastic::I18n::DEFAULT_VALUES.is_a?(::Hash).should == true
16
+ end
17
+
18
+ it "should exists for the core I18n lookup keys" do
19
+ (::Formtastic::I18n::DEFAULT_VALUES.keys & FORMTASTIC_KEYS).size.should == FORMTASTIC_KEYS.size
20
+ end
21
+ end
22
+
23
+ describe "when I18n locales are available" do
24
+
25
+ before do
26
+ @formtastic_strings = {
27
+ :required => 'Default Required',
28
+ :yes => 'Default Yes',
29
+ :no => 'Default No',
30
+ :create => 'Default Create {{model}}',
31
+ :update => 'Default Update {{model}}',
32
+ :custom_scope => {
33
+ :duck => 'Duck',
34
+ :duck_pond => '{{ducks}} ducks in a pond'
35
+ }
36
+ }
37
+ ::I18n.backend.store_translations :en, :formtastic => @formtastic_strings
38
+ end
39
+
40
+ it "should translate core strings correctly" do
41
+ ::Formtastic::I18n.t(:required).should == "Default Required"
42
+ ::Formtastic::I18n.t(:yes).should == "Default Yes"
43
+ ::Formtastic::I18n.t(:no).should == "Default No"
44
+ ::Formtastic::I18n.t(:create, :model => 'Post').should == "Default Create Post"
45
+ ::Formtastic::I18n.t(:update, :model => 'Post').should == "Default Update Post"
46
+ end
47
+
48
+ it "should all belong to scope 'formtastic'" do
49
+ ::Formtastic::I18n.t(:duck, :scope => [:custom_scope]).should == 'Duck'
50
+ end
51
+
52
+ it "should override default I18n lookup args if these are specified" do
53
+ ::Formtastic::I18n.t(:duck_pond, :scope => [:custom_scope], :ducks => 15).should == '15 ducks in a pond'
54
+ end
55
+
56
+ it "should be possible to override default values" do
57
+ ::I18n.backend.store_translations :en, {:formtastic => {:required => nil}}
58
+ ::Formtastic::I18n.t(:required, :default => 'Nothing found!').should == 'Nothing found!'
59
+ end
60
+
61
+ end
62
+
63
+ describe "when no I18n locales are available" do
64
+
65
+ before do
66
+ ::I18n.backend.store_translations :en, :formtastic => {
67
+ :required => nil,
68
+ :yes => nil,
69
+ :no => nil,
70
+ :create => nil,
71
+ :update => nil
72
+ }
73
+ end
74
+
75
+ it "should use default strings" do
76
+ (::Formtastic::I18n::DEFAULT_VALUES.keys).each do |key|
77
+ ::Formtastic::I18n.t(key, :model => '{{model}}').should == ::Formtastic::I18n::DEFAULT_VALUES[key]
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ describe "I18n string lookups" do
84
+
85
+ include FormtasticSpecHelper
86
+
87
+ before do
88
+ @output_buffer = ActiveSupport::SafeBuffer.new
89
+ mock_everything
90
+
91
+ ::I18n.backend.store_translations :en, :formtastic => {
92
+ :labels => {
93
+ :title => "Hello world!",
94
+ :post => {:title => "Hello post!"},
95
+ :project => {:title => "Hello project!"}
96
+ }
97
+ }
98
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
99
+
100
+ @new_post.stub!(:title)
101
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :string, :limit => 255))
102
+ end
103
+
104
+ after do
105
+ ::I18n.backend.store_translations :en, :formtastic => nil
106
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
107
+ end
108
+
109
+ it "lookup scopes should be defined" do
110
+ lambda { ::Formtastic::I18n::SCOPES }.should_not raise_error(::NameError)
111
+ end
112
+
113
+ it "should be able to translate with namespaced object" do
114
+ semantic_form_for(@new_post) do |builder|
115
+ concat(builder.input(:title))
116
+ end
117
+ output_buffer.should have_tag("form label", /Hello post!/)
118
+ end
119
+
120
+ it "should be able to translate without form-object" do
121
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
122
+ concat(builder.input(:title))
123
+ end
124
+ output_buffer.should have_tag("form label", /Hello project!/)
125
+ end
126
+
127
+ # TODO: Add spec for namespaced models?
128
+
129
+ end
130
+
131
+ end
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe "*select: options[:include_blank]" do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+
12
+ @new_post.stub!(:author_id).and_return(nil)
13
+ @new_post.stub!(:publish_at).and_return(nil)
14
+
15
+ @select_input_types = {
16
+ :select => :author,
17
+ :datetime => :publish_at,
18
+ :date => :publish_at,
19
+ :time => :publish_at
20
+ }
21
+ end
22
+
23
+ describe 'when :include_blank is not set' do
24
+ it 'blank value should be included if the default value specified in config is true' do
25
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = true
26
+ @select_input_types.each do |as, attribute|
27
+ semantic_form_for(@new_post) do |builder|
28
+ concat(builder.input(attribute, :as => as))
29
+ end
30
+ output_buffer.should have_tag("form li select option[@value='']", "")
31
+ end
32
+ end
33
+
34
+ it 'blank value should not be included if the default value specified in config is false' do
35
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = false
36
+ @select_input_types.each do |as, attribute|
37
+ semantic_form_for(@new_post) do |builder|
38
+ concat(builder.input(attribute, :as => as))
39
+ end
40
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
41
+ end
42
+ end
43
+
44
+ after do
45
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = true
46
+ end
47
+ end
48
+
49
+ describe 'when :include_blank is set to false' do
50
+ it 'should not have a blank option' do
51
+ @select_input_types.each do |as, attribute|
52
+ semantic_form_for(@new_post) do |builder|
53
+ concat(builder.input(attribute, :as => as, :include_blank => false))
54
+ end
55
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
56
+ end
57
+ end
58
+ end
59
+
60
+ describe 'when :include_blank => true is set' do
61
+ it 'should have a blank select option' do
62
+ @select_input_types.each do |as, attribute|
63
+ semantic_form_for(@new_post) do |builder|
64
+ concat(builder.input(attribute, :as => as, :include_blank => true))
65
+ end
66
+ output_buffer.should have_tag("form li select option[@value='']", "")
67
+ end
68
+ end
69
+ end
70
+ end