formtastic 2.0.2 → 2.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.gitignore +4 -1
  2. data/Appraisals +11 -0
  3. data/CHANGELOG +2 -2
  4. data/Gemfile +0 -2
  5. data/README.textile +183 -151
  6. data/Rakefile +9 -5
  7. data/app/assets/stylesheets/formtastic.css +16 -3
  8. data/formtastic.gemspec +6 -2
  9. data/gemfiles/rails-3.0.gemfile +7 -0
  10. data/gemfiles/rails-3.1.gemfile +7 -0
  11. data/gemfiles/rails-3.2.gemfile +7 -0
  12. data/lib/formtastic.rb +10 -2
  13. data/lib/formtastic/actions.rb +11 -0
  14. data/lib/formtastic/actions/base.rb +156 -0
  15. data/lib/formtastic/actions/button_action.rb +72 -0
  16. data/lib/formtastic/actions/buttonish.rb +17 -0
  17. data/lib/formtastic/actions/input_action.rb +68 -0
  18. data/lib/formtastic/actions/link_action.rb +87 -0
  19. data/lib/formtastic/engine.rb +5 -1
  20. data/lib/formtastic/form_builder.rb +3 -0
  21. data/lib/formtastic/helpers.rb +2 -1
  22. data/lib/formtastic/helpers/action_helper.rb +109 -0
  23. data/lib/formtastic/helpers/actions_helper.rb +168 -0
  24. data/lib/formtastic/helpers/buttons_helper.rb +22 -9
  25. data/lib/formtastic/helpers/errors_helper.rb +0 -54
  26. data/lib/formtastic/helpers/fieldset_wrapper.rb +10 -5
  27. data/lib/formtastic/helpers/form_helper.rb +2 -2
  28. data/lib/formtastic/helpers/input_helper.rb +1 -10
  29. data/lib/formtastic/helpers/inputs_helper.rb +6 -3
  30. data/lib/formtastic/i18n.rb +3 -2
  31. data/lib/formtastic/inputs/base.rb +11 -3
  32. data/lib/formtastic/inputs/base/choices.rb +6 -1
  33. data/lib/formtastic/inputs/base/collections.rb +36 -13
  34. data/lib/formtastic/inputs/base/grouped_collections.rb +1 -1
  35. data/lib/formtastic/inputs/base/numeric.rb +50 -0
  36. data/lib/formtastic/inputs/base/options.rb +1 -1
  37. data/lib/formtastic/inputs/base/placeholder.rb +17 -0
  38. data/lib/formtastic/inputs/base/stringish.rb +2 -7
  39. data/lib/formtastic/inputs/base/timeish.rb +21 -5
  40. data/lib/formtastic/inputs/base/validations.rb +1 -1
  41. data/lib/formtastic/inputs/base/wrapping.rb +10 -3
  42. data/lib/formtastic/inputs/boolean_input.rb +10 -2
  43. data/lib/formtastic/inputs/check_boxes_input.rb +18 -9
  44. data/lib/formtastic/inputs/country_input.rb +2 -2
  45. data/lib/formtastic/inputs/date_input.rb +19 -1
  46. data/lib/formtastic/inputs/datetime_input.rb +1 -1
  47. data/lib/formtastic/inputs/email_input.rb +2 -1
  48. data/lib/formtastic/inputs/file_input.rb +1 -1
  49. data/lib/formtastic/inputs/hidden_input.rb +1 -1
  50. data/lib/formtastic/inputs/number_input.rb +6 -36
  51. data/lib/formtastic/inputs/password_input.rb +2 -1
  52. data/lib/formtastic/inputs/phone_input.rb +3 -2
  53. data/lib/formtastic/inputs/radio_input.rb +1 -1
  54. data/lib/formtastic/inputs/range_input.rb +8 -32
  55. data/lib/formtastic/inputs/search_input.rb +2 -1
  56. data/lib/formtastic/inputs/select_input.rb +56 -28
  57. data/lib/formtastic/inputs/string_input.rb +3 -1
  58. data/lib/formtastic/inputs/text_input.rb +5 -4
  59. data/lib/formtastic/inputs/time_input.rb +4 -8
  60. data/lib/formtastic/inputs/time_zone_input.rb +1 -1
  61. data/lib/formtastic/inputs/url_input.rb +2 -1
  62. data/lib/formtastic/localized_string.rb +6 -94
  63. data/lib/formtastic/localizer.rb +110 -0
  64. data/lib/formtastic/version.rb +1 -1
  65. data/lib/generators/formtastic/form/form_generator.rb +105 -0
  66. data/lib/generators/templates/_form.html.erb +2 -2
  67. data/lib/generators/templates/_form.html.haml +4 -4
  68. data/lib/generators/templates/_form.html.slim +2 -2
  69. data/lib/generators/templates/formtastic.rb +4 -0
  70. data/lib/locale/en.yml +2 -0
  71. data/sample/basic_inputs.html +22 -0
  72. data/spec/actions/button_action_spec.rb +63 -0
  73. data/spec/actions/generic_action_spec.rb +484 -0
  74. data/spec/actions/input_action_spec.rb +59 -0
  75. data/spec/actions/link_action_spec.rb +92 -0
  76. data/spec/builder/semantic_fields_for_spec.rb +14 -0
  77. data/spec/generators/formtastic/form/form_generator_spec.rb +118 -0
  78. data/spec/generators/formtastic/install/install_generator_spec.rb +47 -0
  79. data/spec/helpers/action_helper_spec.rb +365 -0
  80. data/spec/helpers/actions_helper_spec.rb +143 -0
  81. data/spec/helpers/buttons_helper_spec.rb +39 -23
  82. data/spec/helpers/commit_button_helper_spec.rb +153 -93
  83. data/spec/helpers/inputs_helper_spec.rb +14 -0
  84. data/spec/i18n_spec.rb +11 -0
  85. data/spec/inputs/boolean_input_spec.rb +31 -2
  86. data/spec/inputs/check_boxes_input_spec.rb +29 -1
  87. data/spec/inputs/date_input_spec.rb +95 -0
  88. data/spec/inputs/datetime_input_spec.rb +49 -0
  89. data/spec/inputs/email_input_spec.rb +28 -0
  90. data/spec/inputs/file_input_spec.rb +28 -0
  91. data/spec/inputs/hidden_input_spec.rb +28 -0
  92. data/spec/inputs/include_blank_spec.rb +53 -45
  93. data/spec/inputs/number_input_spec.rb +34 -4
  94. data/spec/inputs/password_input_spec.rb +28 -0
  95. data/spec/inputs/phone_input_spec.rb +28 -0
  96. data/spec/inputs/placeholder_spec.rb +10 -10
  97. data/spec/inputs/radio_input_spec.rb +51 -6
  98. data/spec/inputs/range_input_spec.rb +30 -2
  99. data/spec/inputs/search_input_spec.rb +27 -0
  100. data/spec/inputs/select_input_spec.rb +52 -6
  101. data/spec/inputs/string_input_spec.rb +28 -0
  102. data/spec/inputs/text_input_spec.rb +27 -0
  103. data/spec/inputs/time_input_spec.rb +67 -1
  104. data/spec/inputs/time_zone_input_spec.rb +28 -0
  105. data/spec/inputs/url_input_spec.rb +28 -0
  106. data/spec/inputs/with_options_spec.rb +43 -0
  107. data/spec/spec_helper.rb +22 -6
  108. data/spec/support/custom_macros.rb +6 -134
  109. data/spec/support/test_environment.rb +0 -1
  110. metadata +104 -17
  111. data/lib/formtastic/helpers/semantic_form_helper.rb +0 -11
  112. data/lib/formtastic/inputs/numeric_input.rb +0 -21
  113. data/lib/formtastic/railtie.rb +0 -12
  114. data/lib/formtastic/semantic_form_builder.rb +0 -11
  115. data/spec/builder/errors_spec.rb +0 -203
  116. data/spec/inputs/numeric_input_spec.rb +0 -41
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'InputAction', 'when submitting' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ concat(semantic_form_for(@new_post) do |builder|
13
+ concat(builder.action(:submit, :as => :input))
14
+ end)
15
+ end
16
+
17
+ it 'should render a submit type of input' do
18
+ output_buffer.should have_tag('li.action.input_action input[@type="submit"]')
19
+ end
20
+
21
+ end
22
+
23
+ describe 'InputAction', 'when resetting' do
24
+
25
+ include FormtasticSpecHelper
26
+
27
+ before do
28
+ @output_buffer = ''
29
+ mock_everything
30
+
31
+ concat(semantic_form_for(@new_post) do |builder|
32
+ concat(builder.action(:reset, :as => :input))
33
+ end)
34
+ end
35
+
36
+ it 'should render a reset type of input' do
37
+ output_buffer.should have_tag('li.action.input_action input[@type="reset"]')
38
+ end
39
+
40
+ end
41
+
42
+ describe 'InputAction', 'when cancelling' do
43
+
44
+ include FormtasticSpecHelper
45
+
46
+ before do
47
+ @output_buffer = ''
48
+ mock_everything
49
+ end
50
+
51
+ it 'should raise an error' do
52
+ lambda {
53
+ concat(semantic_form_for(@new_post) do |builder|
54
+ concat(builder.action(:cancel, :as => :input))
55
+ end)
56
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
57
+ end
58
+
59
+ end
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'LinkAction', 'when cancelling' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ context 'without a :url' do
14
+ before do
15
+ concat(semantic_form_for(@new_post) do |builder|
16
+ concat(builder.action(:cancel, :as => :link))
17
+ end)
18
+ end
19
+
20
+ it 'should render a submit type of input' do
21
+ output_buffer.should have_tag('li.action.link_action a[@href="javascript:history.back()"]')
22
+ end
23
+
24
+ end
25
+
26
+ context 'with a :url as String' do
27
+
28
+ before do
29
+ concat(semantic_form_for(@new_post) do |builder|
30
+ concat(builder.action(:cancel, :as => :link, :url => "http://foo.bah/baz"))
31
+ end)
32
+ end
33
+
34
+ it 'should render a submit type of input' do
35
+ output_buffer.should have_tag('li.action.link_action a[@href="http://foo.bah/baz"]')
36
+ end
37
+
38
+ end
39
+
40
+ context 'with a :url as Hash' do
41
+
42
+ before do
43
+ concat(semantic_form_for(@new_post) do |builder|
44
+ concat(builder.action(:cancel, :as => :link, :url => { :action => "foo" }))
45
+ end)
46
+ end
47
+
48
+ it 'should render a submit type of input' do
49
+ output_buffer.should have_tag('li.action.link_action a[@href="/mock/path"]')
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ describe 'LinkAction', 'when submitting' do
57
+
58
+ include FormtasticSpecHelper
59
+
60
+ before do
61
+ @output_buffer = ''
62
+ mock_everything
63
+ end
64
+
65
+ it 'should raise an error' do
66
+ lambda {
67
+ concat(semantic_form_for(@new_post) do |builder|
68
+ concat(builder.action(:submit, :as => :link))
69
+ end)
70
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
71
+ end
72
+
73
+ end
74
+
75
+ describe 'LinkAction', 'when submitting' do
76
+
77
+ include FormtasticSpecHelper
78
+
79
+ before do
80
+ @output_buffer = ''
81
+ mock_everything
82
+ end
83
+
84
+ it 'should raise an error' do
85
+ lambda {
86
+ concat(semantic_form_for(@new_post) do |builder|
87
+ concat(builder.action(:reset, :as => :link))
88
+ end)
89
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
90
+ end
91
+
92
+ end
@@ -98,6 +98,20 @@ describe 'Formtastic::FormBuilder#fields_for' do
98
98
  end)
99
99
  output_buffer.should have_tag('form fieldset.inputs #context2_post_author_1_login_input')
100
100
  end
101
+
102
+ it 'should render errors on the nested inputs' do
103
+ @errors = mock('errors')
104
+ @errors.stub!(:[]).with(:login).and_return(['oh noes'])
105
+ @bob.stub!(:errors).and_return(@errors)
106
+
107
+ concat(semantic_form_for(@new_post, :namespace => 'context2') do |builder|
108
+ concat(builder.semantic_fields_for(@bob) do |nested_builder|
109
+ concat(nested_builder.inputs(:login))
110
+ end)
111
+ end)
112
+ output_buffer.should =~ /oh noes/
113
+ end
114
+
101
115
  end
102
116
 
103
117
  context "when I rendered my own hidden id input" do
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ # Generators are not automatically loaded by Rails
4
+ require 'generators/formtastic/form/form_generator'
5
+
6
+ describe Formtastic::FormGenerator do
7
+
8
+ include FormtasticSpecHelper
9
+
10
+ # Tell the generator where to put its output (what it thinks of as Rails.root)
11
+ destination File.expand_path("../../../../../tmp", __FILE__)
12
+
13
+ before do
14
+ @output_buffer = ''
15
+ prepare_destination
16
+ mock_everything
17
+ ::Post.stub!(:reflect_on_all_associations).with(:belongs_to).and_return([
18
+ mock('reflection', :name => :author, :options => {}, :klass => ::Author, :macro => :belongs_to),
19
+ mock('reflection', :name => :reviewer, :options => {:class_name => 'Author'}, :klass => ::Author, :macro => :belongs_to),
20
+ mock('reflection', :name => :main_post, :options => {}, :klass => ::Post, :macro => :belongs_to),
21
+ mock('reflection', :name => :attachment, :options => {:polymorphic => true}, :macro => :belongs_to),
22
+ ])
23
+ end
24
+
25
+ describe 'without model' do
26
+ it 'should raise Thor::RequiredArgumentMissingError' do
27
+ lambda { run_generator }.should raise_error(Thor::RequiredArgumentMissingError)
28
+ end
29
+ end
30
+
31
+ describe 'with existing model' do
32
+ it 'should not raise an exception' do
33
+ lambda { run_generator %w(Post) }.should_not raise_error(Thor::RequiredArgumentMissingError)
34
+ end
35
+ end
36
+
37
+ describe 'with attributes' do
38
+ before { run_generator %w(Post title:string author:references) }
39
+
40
+ describe 'render only the specified attributes' do
41
+ subject { file('app/views/posts/_form.html.erb') }
42
+ it { should exist }
43
+ it { should contain "<%= f.input :title %>" }
44
+ it { should contain "<%= f.input :author %>" }
45
+ it { should_not contain "<%= f.input :main_post %>" }
46
+ end
47
+ end
48
+
49
+ describe 'without attributes' do
50
+ before { run_generator %w(Post) }
51
+
52
+ subject { file('app/views/posts/_form.html.erb') }
53
+
54
+ describe 'content_columns' do
55
+ it { should contain "<%= f.input :title %>" }
56
+ it { should contain "<%= f.input :body %>" }
57
+ it { should_not contain "<%= f.input :created_at %>" }
58
+ it { should_not contain "<%= f.input :updated_at %>" }
59
+ end
60
+
61
+ describe 'reflection_on_association' do
62
+ it { should contain "<%= f.input :author %>" }
63
+ it { should contain "<%= f.input :reviewer %>" }
64
+ it { should contain "<%= f.input :main_post %>" }
65
+ it { should_not contain "<%= f.input :attachment %>" }
66
+ end
67
+ end
68
+
69
+ describe 'with template engine option' do
70
+ describe 'erb' do
71
+ before { run_generator %w(Post --template-engine erb) }
72
+
73
+ describe 'app/views/posts/_form.html.erb' do
74
+ subject { file('app/views/posts/_form.html.erb') }
75
+ it { should exist }
76
+ it { should contain "<%= semantic_form_for @post do |f| %>" }
77
+ end
78
+ end
79
+
80
+ describe 'haml' do
81
+ before { run_generator %w(Post --template-engine haml) }
82
+
83
+ describe 'app/views/posts/_form.html.haml' do
84
+ subject { file('app/views/posts/_form.html.haml') }
85
+ it { should exist }
86
+ it { should contain "= semantic_form_for @post do |f|" }
87
+ end
88
+ end
89
+
90
+ describe 'slim' do
91
+ before { run_generator %w(Post --template-engine slim) }
92
+
93
+ describe 'app/views/posts/_form.html.slim' do
94
+ subject { file('app/views/posts/_form.html.slim') }
95
+ it { should exist }
96
+ it { should contain "= semantic_form_for @post do |f|" }
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'with copy option' do
102
+ before { run_generator %w(Post --copy) }
103
+
104
+ describe 'app/views/posts/_form.html.erb' do
105
+ subject { file('app/views/posts/_form.html.erb') }
106
+ it { should_not exist }
107
+ end
108
+ end
109
+
110
+ describe 'with controller option' do
111
+ before { run_generator %w(Post --controller admin/posts) }
112
+
113
+ describe 'app/views/admin/posts/_form.html.erb' do
114
+ subject { file('app/views/admin/posts/_form.html.erb') }
115
+ it { should exist }
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ # Generators are not automatically loaded by Rails
4
+ require 'generators/formtastic/install/install_generator'
5
+
6
+ describe Formtastic::InstallGenerator do
7
+ # Tell the generator where to put its output (what it thinks of as Rails.root)
8
+ destination File.expand_path("../../../../../tmp", __FILE__)
9
+
10
+ before { prepare_destination }
11
+
12
+ describe 'no arguments' do
13
+ before { run_generator }
14
+
15
+ describe 'config/initializers/formtastic.rb' do
16
+ subject { file('config/initializers/formtastic.rb') }
17
+ it { should exist }
18
+ it { should contain "# Please note: If you're subclassing Formtastic::FormBuilder" }
19
+ end
20
+
21
+ describe 'lib/templates/erb/scaffold/_form.html.erb' do
22
+ subject { file('lib/templates/erb/scaffold/_form.html.erb') }
23
+ it { should exist }
24
+ it { should contain "<%%= semantic_form_for @<%= singular_name %> do |f| %>" }
25
+ end
26
+ end
27
+
28
+ describe 'haml' do
29
+ before { run_generator %w(--template-engine haml) }
30
+
31
+ describe 'lib/templates/erb/scaffold/_form.html.haml' do
32
+ subject { file('lib/templates/haml/scaffold/_form.html.haml') }
33
+ it { should exist }
34
+ it { should contain "= semantic_form_for @<%= singular_name %> do |f|" }
35
+ end
36
+ end
37
+
38
+ describe 'slim' do
39
+ before { run_generator %w(--template-engine slim) }
40
+
41
+ describe 'lib/templates/erb/scaffold/_form.html.slim' do
42
+ subject { file('lib/templates/slim/scaffold/_form.html.slim') }
43
+ it { should exist }
44
+ it { should contain "= semantic_form_for @<%= singular_name %> do |f|" }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,365 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Formtastic::FormBuilder#action' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ after do
14
+ ::I18n.backend.reload!
15
+ end
16
+
17
+ describe 'arguments and options' do
18
+
19
+ it 'should require the first argument (the action method)' do
20
+ lambda {
21
+ concat(semantic_form_for(@new_post) do |builder|
22
+ concat(builder.action()) # no args passed in at all
23
+ end)
24
+ }.should raise_error(ArgumentError)
25
+ end
26
+
27
+ describe ':as option' do
28
+
29
+ describe 'when not provided' do
30
+
31
+ it 'should default to a commit for commit' do
32
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
33
+ concat(builder.action(:submit))
34
+ end)
35
+ output_buffer.should have_tag('form li.action.input_action', :count => 1)
36
+ end
37
+
38
+ it 'should default to a button for reset' do
39
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
40
+ concat(builder.action(:reset))
41
+ end)
42
+ output_buffer.should have_tag('form li.action.input_action', :count => 1)
43
+ end
44
+
45
+ it 'should default to a link for cancel' do
46
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
47
+ concat(builder.action(:cancel))
48
+ end)
49
+ output_buffer.should have_tag('form li.action.link_action', :count => 1)
50
+ end
51
+ end
52
+
53
+ it 'should call the corresponding action class with .to_html' do
54
+ [:input, :button, :link].each do |action_style|
55
+ semantic_form_for(:project, :url => "http://test.host") do |builder|
56
+ action_instance = mock('Action instance')
57
+ action_class = "#{action_style.to_s}_action".classify
58
+ action_constant = "Formtastic::Actions::#{action_class}".constantize
59
+
60
+ action_constant.should_receive(:new).and_return(action_instance)
61
+ action_instance.should_receive(:to_html).and_return("some HTML")
62
+
63
+ concat(builder.action(:submit, :as => action_style))
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ #describe ':label option' do
71
+ #
72
+ # describe 'when provided' do
73
+ # it 'should be passed down to the label tag' do
74
+ # concat(semantic_form_for(@new_post) do |builder|
75
+ # concat(builder.input(:title, :label => "Kustom"))
76
+ # end)
77
+ # output_buffer.should have_tag("form li label", /Kustom/)
78
+ # end
79
+ #
80
+ # it 'should not generate a label if false' do
81
+ # concat(semantic_form_for(@new_post) do |builder|
82
+ # concat(builder.input(:title, :label => false))
83
+ # end)
84
+ # output_buffer.should_not have_tag("form li label")
85
+ # end
86
+ #
87
+ # it 'should be dupped if frozen' do
88
+ # concat(semantic_form_for(@new_post) do |builder|
89
+ # concat(builder.input(:title, :label => "Kustom".freeze))
90
+ # end)
91
+ # output_buffer.should have_tag("form li label", /Kustom/)
92
+ # end
93
+ # end
94
+ #
95
+ # describe 'when not provided' do
96
+ # describe 'when localized label is provided' do
97
+ # describe 'and object is given' do
98
+ # describe 'and label_str_method not :humanize' do
99
+ # it 'should render a label with localized text and not apply the label_str_method' do
100
+ # with_config :label_str_method, :reverse do
101
+ # @localized_label_text = 'Localized title'
102
+ # @new_post.stub!(:meta_description)
103
+ # ::I18n.backend.store_translations :en,
104
+ # :formtastic => {
105
+ # :labels => {
106
+ # :meta_description => @localized_label_text
107
+ # }
108
+ # }
109
+ #
110
+ # concat(semantic_form_for(@new_post) do |builder|
111
+ # concat(builder.input(:meta_description))
112
+ # end)
113
+ # output_buffer.should have_tag('form li label', /Localized title/)
114
+ # end
115
+ # end
116
+ # end
117
+ # end
118
+ # end
119
+ #
120
+ # describe 'when localized label is NOT provided' do
121
+ # describe 'and object is not given' do
122
+ # it 'should default the humanized method name, passing it down to the label tag' do
123
+ # ::I18n.backend.store_translations :en, :formtastic => {}
124
+ # with_config :label_str_method, :humanize do
125
+ # concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
126
+ # concat(builder.input(:meta_description))
127
+ # end)
128
+ # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
129
+ # end
130
+ # end
131
+ # end
132
+ #
133
+ # describe 'and object is given' do
134
+ # it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
135
+ # @new_post.stub!(:meta_description) # a two word method name
136
+ # @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
137
+ #
138
+ # concat(semantic_form_for(@new_post) do |builder|
139
+ # concat(builder.input(:meta_description))
140
+ # end)
141
+ # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
142
+ # end
143
+ # end
144
+ #
145
+ # describe 'and object is given with label_str_method set to :capitalize' do
146
+ # it 'should capitalize method name, passing it down to the label tag' do
147
+ # with_config :label_str_method, :capitalize do
148
+ # @new_post.stub!(:meta_description)
149
+ #
150
+ # concat(semantic_form_for(@new_post) do |builder|
151
+ # concat(builder.input(:meta_description))
152
+ # end)
153
+ # output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/)
154
+ # end
155
+ # end
156
+ # end
157
+ # end
158
+ #
159
+ # describe 'when localized label is provided' do
160
+ # before do
161
+ # @localized_label_text = 'Localized title'
162
+ # @default_localized_label_text = 'Default localized title'
163
+ # ::I18n.backend.store_translations :en,
164
+ # :formtastic => {
165
+ # :labels => {
166
+ # :title => @default_localized_label_text,
167
+ # :published => @default_localized_label_text,
168
+ # :post => {
169
+ # :title => @localized_label_text,
170
+ # :published => @default_localized_label_text
171
+ # }
172
+ # }
173
+ # }
174
+ # end
175
+ #
176
+ # it 'should render a label with localized label (I18n)' do
177
+ # with_config :i18n_lookups_by_default, false do
178
+ # concat(semantic_form_for(@new_post) do |builder|
179
+ # concat(builder.input(:title, :label => true))
180
+ # concat(builder.input(:published, :as => :boolean, :label => true))
181
+ # end)
182
+ # output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text))
183
+ # end
184
+ # end
185
+ #
186
+ # it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
187
+ # with_config :i18n_lookups_by_default, false do
188
+ # ::I18n.backend.store_translations :en,
189
+ # :formtastic => {
190
+ # :labels => {
191
+ # :post => {
192
+ # :title => nil,
193
+ # :published => nil
194
+ # }
195
+ # }
196
+ # }
197
+ # concat(semantic_form_for(@new_post) do |builder|
198
+ # concat(builder.input(:title, :label => true))
199
+ # concat(builder.input(:published, :as => :boolean, :label => true))
200
+ # end)
201
+ # output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text))
202
+ # end
203
+ # end
204
+ # end
205
+ # end
206
+ #
207
+ #end
208
+ #
209
+ describe ':wrapper_html option' do
210
+
211
+ describe 'when provided' do
212
+ it 'should be passed down to the li tag' do
213
+ concat(semantic_form_for(@new_post) do |builder|
214
+ concat(builder.action(:submit, :wrapper_html => {:id => :another_id}))
215
+ end)
216
+ output_buffer.should have_tag("form li#another_id")
217
+ end
218
+
219
+ it 'should append given classes to li default classes' do
220
+ concat(semantic_form_for(@new_post) do |builder|
221
+ concat(builder.action(:submit, :wrapper_html => {:class => :another_class}))
222
+ end)
223
+ output_buffer.should have_tag("form li.action")
224
+ output_buffer.should have_tag("form li.input_action")
225
+ output_buffer.should have_tag("form li.another_class")
226
+ end
227
+
228
+ it 'should allow classes to be an array' do
229
+ concat(semantic_form_for(@new_post) do |builder|
230
+ concat(builder.action(:submit, :wrapper_html => {:class => [ :my_class, :another_class ]}))
231
+ end)
232
+ output_buffer.should have_tag("form li.action")
233
+ output_buffer.should have_tag("form li.input_action")
234
+ output_buffer.should have_tag("form li.my_class")
235
+ output_buffer.should have_tag("form li.another_class")
236
+ end
237
+ end
238
+
239
+ describe 'when not provided' do
240
+ it 'should use default id and class' do
241
+ concat(semantic_form_for(@new_post) do |builder|
242
+ concat(builder.action(:submit))
243
+ end)
244
+ output_buffer.should have_tag("form li#post_submit_action")
245
+ output_buffer.should have_tag("form li.action")
246
+ output_buffer.should have_tag("form li.input_action")
247
+ end
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ describe 'instantiating an action class' do
255
+
256
+ context 'when a class does not exist' do
257
+ it "should raise an error" do
258
+ lambda {
259
+ concat(semantic_form_for(@new_post) do |builder|
260
+ builder.action(:submit, :as => :non_existant)
261
+ end)
262
+ }.should raise_error(Formtastic::UnknownActionError)
263
+ end
264
+ end
265
+
266
+ context 'when a customized top-level class does not exist' do
267
+
268
+ it 'should instantiate the Formtastic action' do
269
+ action = mock('action', :to_html => 'some HTML')
270
+ Formtastic::Actions::ButtonAction.should_receive(:new).and_return(action)
271
+ concat(semantic_form_for(@new_post) do |builder|
272
+ builder.action(:commit, :as => :button)
273
+ end)
274
+ end
275
+
276
+ end
277
+
278
+ describe 'when a top-level (custom) action class exists' do
279
+ it "should instantiate the top-level action instead of the Formtastic one" do
280
+ class ::ButtonAction < Formtastic::Actions::ButtonAction
281
+ end
282
+
283
+ action = mock('action', :to_html => 'some HTML')
284
+ Formtastic::Actions::ButtonAction.should_not_receive(:new).and_return(action)
285
+ ::ButtonAction.should_receive(:new).and_return(action)
286
+
287
+ concat(semantic_form_for(@new_post) do |builder|
288
+ builder.action(:commit, :as => :button)
289
+ end)
290
+ end
291
+ end
292
+
293
+ describe 'when instantiated multiple times with the same action type' do
294
+
295
+ it "should be cached (not calling the internal methods)" do
296
+ # TODO this is really tied to the underlying implementation
297
+ concat(semantic_form_for(@new_post) do |builder|
298
+ builder.should_receive(:custom_action_class_name).with(:button).once.and_return(::Formtastic::Actions::ButtonAction)
299
+ builder.action(:submit, :as => :button)
300
+ builder.action(:submit, :as => :button)
301
+ end)
302
+ end
303
+
304
+ end
305
+
306
+ describe 'support for :as on each action' do
307
+
308
+ it "should raise an error when the action does not support the :as" do
309
+ lambda {
310
+ concat(semantic_form_for(@new_post) do |builder|
311
+ concat(builder.action(:submit, :as => :link))
312
+ end)
313
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
314
+
315
+ lambda {
316
+ concat(semantic_form_for(@new_post) do |builder|
317
+ concat(builder.action(:cancel, :as => :input))
318
+ end)
319
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
320
+
321
+ lambda {
322
+ concat(semantic_form_for(@new_post) do |builder|
323
+ concat(builder.action(:cancel, :as => :button))
324
+ end)
325
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
326
+ end
327
+
328
+ it "should not raise an error when the action does not support the :as" do
329
+ lambda {
330
+ concat(semantic_form_for(@new_post) do |builder|
331
+ concat(builder.action(:cancel, :as => :link))
332
+ end)
333
+ }.should_not raise_error(Formtastic::UnsupportedMethodForAction)
334
+
335
+ lambda {
336
+ concat(semantic_form_for(@new_post) do |builder|
337
+ concat(builder.action(:submit, :as => :input))
338
+ end)
339
+ }.should_not raise_error(Formtastic::UnsupportedMethodForAction)
340
+
341
+ lambda {
342
+ concat(semantic_form_for(@new_post) do |builder|
343
+ concat(builder.action(:submit, :as => :button))
344
+ end)
345
+ }.should_not raise_error(Formtastic::UnsupportedMethodForAction)
346
+
347
+ lambda {
348
+ concat(semantic_form_for(@new_post) do |builder|
349
+ concat(builder.action(:reset, :as => :input))
350
+ end)
351
+ }.should_not raise_error(Formtastic::UnsupportedMethodForAction)
352
+
353
+ lambda {
354
+ concat(semantic_form_for(@new_post) do |builder|
355
+ concat(builder.action(:reset, :as => :button))
356
+ end)
357
+ }.should_not raise_error(Formtastic::UnsupportedMethodForAction)
358
+ end
359
+
360
+ end
361
+
362
+ end
363
+
364
+ end
365
+