forme 1.11.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +54 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +235 -209
  5. data/Rakefile +1 -7
  6. data/lib/forme/bs3.rb +18 -4
  7. data/lib/forme/erb.rb +13 -25
  8. data/lib/forme/form.rb +144 -149
  9. data/lib/forme/input.rb +1 -1
  10. data/lib/forme/rails.rb +39 -83
  11. data/lib/forme/raw.rb +2 -2
  12. data/lib/forme/tag.rb +3 -12
  13. data/lib/forme/template.rb +110 -0
  14. data/lib/forme/transformers/formatter.rb +4 -1
  15. data/lib/forme/transformers/helper.rb +0 -1
  16. data/lib/forme/transformers/inputs_wrapper.rb +4 -4
  17. data/lib/forme/version.rb +2 -2
  18. data/lib/forme.rb +15 -2
  19. data/lib/roda/plugins/forme.rb +1 -1
  20. data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
  21. data/lib/roda/plugins/forme_route_csrf.rb +16 -34
  22. data/lib/roda/plugins/forme_set.rb +39 -76
  23. data/lib/sequel/plugins/forme.rb +40 -50
  24. data/lib/sequel/plugins/forme_i18n.rb +3 -1
  25. data/lib/sequel/plugins/forme_set.rb +3 -1
  26. data/spec/all.rb +1 -1
  27. data/spec/bs3_reference_spec.rb +18 -18
  28. data/spec/bs3_sequel_plugin_spec.rb +17 -17
  29. data/spec/bs3_spec.rb +23 -11
  30. data/spec/erb_helper.rb +69 -58
  31. data/spec/erubi_capture_helper.rb +198 -0
  32. data/spec/forme_spec.rb +21 -32
  33. data/spec/rails_integration_spec.rb +39 -25
  34. data/spec/roda_integration_spec.rb +118 -70
  35. data/spec/sequel_helper.rb +0 -1
  36. data/spec/sequel_i18n_helper.rb +1 -1
  37. data/spec/sequel_i18n_plugin_spec.rb +3 -2
  38. data/spec/sequel_plugin_spec.rb +29 -12
  39. data/spec/sequel_set_plugin_spec.rb +9 -2
  40. data/spec/shared_erb_specs.rb +71 -0
  41. data/spec/sinatra_integration_spec.rb +5 -6
  42. data/spec/spec_helper.rb +21 -8
  43. metadata +9 -7
  44. data/lib/forme/erb_form.rb +0 -74
  45. data/lib/forme/sinatra.rb +0 -17
data/spec/bs3_spec.rb CHANGED
@@ -1,5 +1,5 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
- require 'forme/bs3'
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/forme/bs3'
3
3
 
4
4
  describe "Forme Bootstrap3 (BS3) forms" do
5
5
  def sel(opts, s)
@@ -99,6 +99,18 @@ describe "Forme Bootstrap3 (BS3) forms" do
99
99
  end
100
100
  end
101
101
 
102
+ it "should consider form's :errors hash based on the :key option" do
103
+ @f.opts[:errors] = { 'foo' => 'must be present' }
104
+ @f.input(:text, :key=>"foo").to_s.must_equal "<div class=\"form-group has-error\"><input aria-describedby=\"foo_error_message\" aria-invalid=\"true\" class=\"form-control\" id=\"foo\" name=\"foo\" type=\"text\"/><span class=\"help-block with-errors\">must be present</span></div>"
105
+ end
106
+
107
+ it "should consider form's :errors hash based on the :key option when using namespaces" do
108
+ @f.opts[:errors] = { 'bar' => { 'foo' => 'must be present' } }
109
+ @f.with_opts(:namespace=>['bar']) do
110
+ @f.input(:text, :key=>"foo").to_s.must_equal "<div class=\"form-group has-error\"><input aria-describedby=\"bar_foo_error_message\" aria-invalid=\"true\" class=\"form-control\" id=\"bar_foo\" name=\"bar[foo]\" type=\"text\"/><span class=\"help-block with-errors\">must be present</span></div>"
111
+ end
112
+ end
113
+
102
114
  it "should support a with_obj method that changes the object and namespace for the given block" do
103
115
  @f.with_obj([:a, :c], 'bar') do
104
116
  @f.input(:first).to_s.must_equal '<div class="form-group"><input class="form-control" id="bar_first" name="bar[first]" type="text" value="a"/></div>'
@@ -481,19 +493,19 @@ describe "Forme Bootstrap3 (BS3) forms" do
481
493
  end
482
494
 
483
495
  it "should automatically note the input has errors if :error option is used" do
484
- @f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.must_equal '<div class="form-group has-error"><input class="form-control" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
496
+ @f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.must_equal '<div class="form-group has-error"><input aria-invalid="true" class="form-control" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
485
497
  end
486
498
 
487
499
  it "should add an error message after the label" do
488
- @f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :label=>"Foo").to_s.must_equal '<div class="form-group has-error"><label>Foo</label> <input class="form-control" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
500
+ @f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :label=>"Foo").to_s.must_equal '<div class="form-group has-error"><label>Foo</label> <input aria-invalid="true" class="form-control" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
489
501
  end
490
502
 
491
503
  it "should add to existing :class option if :error option is used" do
492
- @f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.must_equal '<div class="form-group has-error"><input class="form-control bar" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
504
+ @f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.must_equal '<div class="form-group has-error"><input aria-invalid="true" class="form-control bar" type="text" value="foo"/><span class="help-block with-errors">Bad Stuff!</span></div>'
493
505
  end
494
506
 
495
507
  it "should respect :error_attr option for setting the attributes for the error message span" do
496
- @f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :error_attr=>{:class=>'foo'}).to_s.must_equal '<div class="form-group has-error"><input class="form-control" type="text" value="foo"/><span class="foo help-block with-errors">Bad Stuff!</span></div>'
508
+ @f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :error_attr=>{:class=>'foo'}).to_s.must_equal '<div class="form-group has-error"><input aria-invalid="true" class="form-control" type="text" value="foo"/><span class="foo help-block with-errors">Bad Stuff!</span></div>'
497
509
  end
498
510
 
499
511
  it "#open should return an opening tag" do
@@ -527,12 +539,12 @@ describe "Forme Bootstrap3 (BS3) forms" do
527
539
  end
528
540
 
529
541
  it "#tag should accept children as procs" do
530
- @f.tag(:div, {:class=>"foo"}, lambda{|t| t.form.tag(:input, :class=>t.attr[:class])}).to_s.must_equal '<div class="foo"><input class="form-control foo" type="text"/></div>'
542
+ @f.tag(:div, {:class=>"foo"}, lambda{|t| t.tag(:input, :class=>t.attr[:class])}).to_s.must_equal '<div class="foo"><input class="form-control foo" type="text"/></div>'
531
543
  end
532
544
 
533
545
  it "#tag should accept children as methods" do
534
546
  o = Object.new
535
- def o.foo(t) t.form.tag(:input, :class=>t.attr[:class]) end
547
+ def o.foo(t) t.tag(:input, :class=>t.attr[:class]) end
536
548
  @f.tag(:div, {:class=>"foo"}, o.method(:foo)).to_s.must_equal '<div class="foo"><input class="form-control foo" type="text"/></div>'
537
549
  end
538
550
 
@@ -624,7 +636,7 @@ describe "Forme Bootstrap3 (BS3) forms" do
624
636
  end
625
637
 
626
638
  it "inputs should have helper displayed inside wrapper, after error" do
627
- @f.input(:text, :help=>"List type of foo", :error=>'bad', :wrapper=>:li).to_s.must_equal '<li class="has-error"><input class="form-control" type="text"/><span class="help-block with-errors">bad</span><span class="helper">List type of foo</span></li>'
639
+ @f.input(:text, :help=>"List type of foo", :error=>'bad', :wrapper=>:li).to_s.must_equal '<li class="has-error"><input aria-invalid="true" class="form-control" type="text"/><span class="help-block with-errors">bad</span><span class="helper">List type of foo</span></li>'
628
640
  end
629
641
 
630
642
  it "inputs should accept a :formatter option to use a custom formatter" do
@@ -661,7 +673,7 @@ describe "Forme Bootstrap3 (BS3) forms" do
661
673
  end
662
674
 
663
675
  it "inputs should accept a :error_handler option to use a custom error_handler" do
664
- @f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.must_equal '<div class="form-group"><textarea class="form-control" id="foo"></textarea>!!! bar</div>'
676
+ @f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.must_equal '<div class="form-group"><textarea aria-describedby="foo_error_message" aria-invalid="true" class="form-control" id="foo"></textarea>!!! bar</div>'
665
677
  end
666
678
 
667
679
  it "#inputs should accept a :inputs_wrapper option to use a custom inputs_wrapper" do
@@ -679,7 +691,7 @@ describe "Forme Bootstrap3 (BS3) forms" do
679
691
  end
680
692
 
681
693
  it "inputs should accept a :error_handler=>nil option to not use an error_handler" do
682
- @f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.must_equal '<div class="form-group"><textarea class="form-control" id="foo"></textarea></div>'
694
+ @f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.must_equal '<div class="form-group"><textarea aria-invalid="true" class="form-control" id="foo"></textarea></div>'
683
695
  end
684
696
 
685
697
  it "#inputs should accept a :inputs_wrapper=>nil option to not use an inputs_wrapper" do
data/spec/erb_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative 'shared_erb_specs'
2
+
1
3
  ERB_BLOCK = lambda do |r|
2
4
  r.get '' do
3
5
  erb <<END
@@ -65,6 +67,29 @@ END
65
67
  END
66
68
  end
67
69
 
70
+ r.get 'nest_seq_simple' do
71
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
72
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
73
+ @nest = <<END
74
+ n1
75
+ <% f.subform(:artist) do %>
76
+ n2
77
+ <%= f.input(:name2) %>
78
+ n3
79
+ <% end %>
80
+ n4
81
+ END
82
+ erb <<END
83
+ 0
84
+ <% form(@album, :action=>'/baz') do |f| %>
85
+ 1
86
+ <%= erb(@nest, :locals=>{:f=>f}) %>
87
+ 3
88
+ <% end %>
89
+ 4
90
+ END
91
+ end
92
+
68
93
  r.get 'nest_seq' do
69
94
  @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
70
95
  @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
@@ -92,6 +117,50 @@ END
92
117
  END
93
118
  end
94
119
 
120
+ r.get 'grid-block' do
121
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
122
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
123
+ erb <<END
124
+ 0
125
+ <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
126
+ 1
127
+ <% f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') do %>
128
+ 2
129
+ <% end %>
130
+ 3
131
+ <% end %>
132
+ 4
133
+ END
134
+ end
135
+
136
+ r.get 'grid-noblock' do
137
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
138
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
139
+ erb <<END
140
+ 0
141
+ <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
142
+ 1
143
+ <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
144
+ 2
145
+ <% end %>
146
+ 3
147
+ END
148
+ end
149
+
150
+ r.get 'grid-noblock-multiple' do
151
+ @artist = Artist.load(:name=>'A', :id=>2)
152
+ @artist.associations[:albums] = [Album.load(:name=>'N', :copies_sold=>2, :id=>1)]
153
+ erb <<END
154
+ 0
155
+ <% form(@artist, {:action=>'/baz'}, :button=>'Sub') do |f| %>
156
+ 1
157
+ <%= f.subform(:albums, :inputs=>[:name, :copies_sold], :legend=>'Foo', :grid=>true, :labels=>%w'Name Copies') %>
158
+ 2
159
+ <% end %>
160
+ 3
161
+ END
162
+ end
163
+
95
164
  r.get 'hash' do
96
165
  erb "<% form({:action=>'/baz'}, :obj=>[:foo]) do |f| %> <%= f.input(:first) %> <% end %>"
97
166
  end
@@ -127,61 +196,3 @@ END
127
196
  erb "<%= form(:action=>'/baz') %>"
128
197
  end
129
198
  end
130
-
131
- module FormeErbSpecs
132
- extend Minitest::Spec::DSL
133
-
134
- before do
135
- o = Object.new
136
- def o.puts(*) end
137
- @rack = {'rack.input'=>'', 'REQUEST_METHOD'=>'GET', 'rack.errors'=>o, 'SCRIPT_NAME'=>''}
138
- end
139
-
140
- it "#form should add start and end tags and yield Forme::Form instance" do
141
- sin_get('/').must_equal '<form action="/baz"> <p>FBB</p> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="Save"/> </form>'
142
- end
143
-
144
- it "#form should have inputs work with a block" do
145
- sin_get('/inputs_block').must_equal '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend> <input id="last" name="last" type="text" value="bar"/> </fieldset></form>'
146
- end
147
-
148
- it "#form should have inputs with fieldset_ol wrapper work with block" do
149
- sin_get('/inputs_block_wrapper').must_equal '<form action="/baz"><fieldset class="inputs"><legend>FBB</legend><ol> <input id="last" name="last" type="text" value="bar"/> </ol></fieldset></form>'
150
- end
151
-
152
- it "#form should add start and end tags and yield Forme::Form instance" do
153
- sin_get('/nest').must_equal '<form action="/baz"> <p>FBB</p> <div> <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> </div> </form>'
154
- end
155
-
156
- it "#form should correctly handle situation where multiple templates are used with same form object" do
157
- sin_get('/nest_sep').must_equal '0 <form action="/baz"> 1 <p>FBB</p> 2 n1 <div> n2 <input id="first" name="first" type="text" value="foo"/> <input id="last" name="last" type="text" value="bar"/> n3 </div> n4 <fieldset class="inputs"><legend>Foo</legend><input id="first" name="first" type="text" value="foo"/><input id="last" name="last" type="text" value="bar"/></fieldset> n5 3 </form>4'
158
- end
159
-
160
- it "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
161
- sin_get('/nest_seq').sub(%r{<input name="_csrf" type="hidden" value="([^"]+)"/>}, '<input name="_csrf" type="hidden" value="csrf"/>').must_equal '0 <form action="/baz" class="forme album" method="post"><input name="_csrf" type="hidden" value="csrf"/> 1 <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Foo</legend><label>Name: <input id="album_artist_attributes_name" maxlength="255" name="album[artist_attributes][name]" type="text" value="A"/></label></fieldset> 2 n1 <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Artist</legend> n2 <label>Name2: <input id="album_artist_attributes_name2" name="album[artist_attributes][name2]" type="text" value="A2"/></label> n3 </fieldset> n4 <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Bar</legend><label>Name3: <input id="album_artist_attributes_name3" name="album[artist_attributes][name3]" type="text" value="A3"/></label></fieldset> n5 3 </form>4'
162
- end
163
-
164
- it "#form should accept two hashes instead of requiring obj as first argument" do
165
- sin_get('/hash').must_equal '<form action="/baz"> <input id="first" name="first" type="text" value="foo"/> </form>'
166
- end
167
-
168
- it "#form should deal with emitted code" do
169
- sin_get('/legend').must_equal '<form action="/baz"> <p>FBB</p> <fieldset class="inputs"><legend>Foo</legend><input id="first" name="first" type="text" value="foo"/><input id="last" name="last" type="text" value="bar"/></fieldset> <p>FBB2</p> </form>'
170
- end
171
-
172
- it "#form should work with :inputs, :button, and :legend options" do
173
- sin_get('/combined').must_equal '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset> <p>FBB</p> <input id="last" name="last" type="text" value="bar"/> <input type="submit" value="xyz"/></form>'
174
- end
175
-
176
- it "#form should work without a block" do
177
- sin_get('/noblock').must_equal '<form action="/baz"><fieldset class="inputs"><legend>123</legend><input id="first" name="first" type="text" value="foo"/></fieldset><input type="submit" value="xyz"/></form>'
178
- end
179
-
180
- it "#form should work without a block and still have hidden tags emitted" do
181
- sin_get('/noblock_post').sub(%r{<input name=\"_csrf\" type=\"hidden\" value=\"([^\"]+)\"/>}, "<input name=\"_csrf\" type=\"hidden\" value=\"csrf\"/>").must_equal '<form method="post"><input name="_csrf" type="hidden" value="csrf"/><input type="submit" value="xyz"/></form>'
182
- end
183
-
184
- it "#form with an empty form should work" do
185
- sin_get('/noblock_empty').must_equal '<form action="/baz"></form>'
186
- end
187
- end
@@ -0,0 +1,198 @@
1
+ require_relative 'shared_erb_specs'
2
+
3
+ ERUBI_CAPTURE_BLOCK = lambda do |r|
4
+ r.get '' do
5
+ erb <<END
6
+ <%|= form([:foo, :bar], :action=>'/baz') do |f| %>
7
+ <p>FBB</p>
8
+ <%= f.input(:first) %>
9
+ <%= f.input(:last) %>
10
+ <%= f.button('Save') %>
11
+ <%| end %>
12
+ END
13
+ end
14
+
15
+ r.get 'inputs_block' do
16
+ erb <<END
17
+ <%|= form([:foo, :bar], :action=>'/baz') do |f| %><%|= f.inputs(:legend=>'FBB') do %>
18
+ <%= f.input(:last) %>
19
+ <%| end %><%| end %>
20
+ END
21
+ end
22
+
23
+ r.get 'inputs_block_wrapper' do
24
+ erb <<END
25
+ <%|= form([:foo, :bar], {:action=>'/baz'}, :inputs_wrapper=>:fieldset_ol) do |f| %><%|= f.inputs(:legend=>'FBB') do %>
26
+ <%= f.input(:last) %>
27
+ <%| end %><%| end %>
28
+ END
29
+ end
30
+
31
+ r.get 'nest' do
32
+ erb <<END
33
+ <%|= form([:foo, :bar], :action=>'/baz') do |f| %>
34
+ <%= f.tag(:p, {}, 'FBB') %>
35
+ <%|= f.tag(:div) do %>
36
+ <%= f.input(:first) %>
37
+ <%= f.input(:last) %>
38
+ <%| end %>
39
+
40
+ <%| end %>
41
+ END
42
+ end
43
+
44
+ r.get 'nest_sep' do
45
+ @nest = <<END
46
+ n1
47
+ <%|= f.tag(:div) do %>
48
+ n2
49
+ <%= f.input(:first) %>
50
+ <%= f.input(:last) %>
51
+ n3
52
+ <%| end %>
53
+ n4
54
+ <%= f.inputs([:first, :last], :legend=>'Foo') %>
55
+ n5
56
+ END
57
+ erb <<END
58
+ 0
59
+ <%|= form([:foo, :bar], :action=>'/baz') do |f| %>
60
+ 1
61
+ <%= f.tag(:p, {}, 'FBB') %>
62
+ 2
63
+ <%= erb(@nest, :locals=>{:f=>f}) %>
64
+ 3
65
+ <%| end %>
66
+ 4
67
+ END
68
+ end
69
+
70
+ r.get 'nest_seq_simple' do
71
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
72
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
73
+ @nest = <<END
74
+ n1
75
+ <%|= f.subform(:artist) do %>
76
+ n2
77
+ <%= f.input(:name2) %>
78
+ n3
79
+ <%| end %>
80
+ n4
81
+ END
82
+ erb <<END
83
+ 0
84
+ <%|= form(@album, :action=>'/baz') do |f| %>
85
+ 1
86
+ <%= erb(@nest, :locals=>{:f=>f}) %>
87
+ 3
88
+ <%| end %>
89
+ 4
90
+ END
91
+ end
92
+
93
+ r.get 'nest_seq' do
94
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
95
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
96
+ @nest = <<END
97
+ n1
98
+ <%|= f.subform(:artist) do %>
99
+ n2
100
+ <%= f.input(:name2) %>
101
+ n3
102
+ <%| end %>
103
+ n4
104
+ <%= f.subform(:artist, :inputs=>[:name3], :legend=>'Bar') %>
105
+ n5
106
+ END
107
+ erb <<END
108
+ 0
109
+ <%|= form(@album, :action=>'/baz') do |f| %>
110
+ 1
111
+ <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo') %>
112
+ 2
113
+ <%= erb(@nest, :locals=>{:f=>f}) %>
114
+ 3
115
+ <%| end %>
116
+ 4
117
+ END
118
+ end
119
+
120
+ r.get 'grid-block' do
121
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
122
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
123
+ erb <<END
124
+ 0
125
+ <%|= form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
126
+ 1
127
+ <%|= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') do %>
128
+ 2
129
+ <%| end %>
130
+ 3
131
+ <%| end %>
132
+ 4
133
+ END
134
+ end
135
+
136
+ r.get 'grid-noblock' do
137
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
138
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
139
+ erb <<END
140
+ 0
141
+ <%|= form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
142
+ 1
143
+ <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
144
+ 2
145
+ <%| end %>
146
+ 3
147
+ END
148
+ end
149
+
150
+ r.get 'grid-noblock-multiple' do
151
+ @artist = Artist.load(:name=>'A', :id=>2)
152
+ @artist.associations[:albums] = [Album.load(:name=>'N', :copies_sold=>2, :id=>1)]
153
+ erb <<END
154
+ 0
155
+ <%|= form(@artist, {:action=>'/baz'}, :button=>'Sub') do |f| %>
156
+ 1
157
+ <%= f.subform(:albums, :inputs=>[:name, :copies_sold], :legend=>'Foo', :grid=>true, :labels=>%w'Name Copies') %>
158
+ 2
159
+ <%| end %>
160
+ 3
161
+ END
162
+ end
163
+
164
+ r.get 'hash' do
165
+ erb "<%|= form({:action=>'/baz'}, :obj=>[:foo]) do |f| %> <%= f.input(:first) %> <%| end %>"
166
+ end
167
+
168
+ r.get 'legend' do
169
+ erb <<END
170
+ <%|= form([:foo, :bar], :action=>'/baz') do |f| %>
171
+ <p>FBB</p>
172
+ <%= f.inputs([:first, :last], :legend=>'Foo') %>
173
+ <p>FBB2</p>
174
+ <%| end %>
175
+ END
176
+ end
177
+
178
+ r.get 'combined' do
179
+ erb <<END
180
+ <%|= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') do |f| %>
181
+ <p>FBB</p>
182
+ <%= f.input(:last) %>
183
+ <%| end %>
184
+ END
185
+ end
186
+
187
+ r.get 'noblock' do
188
+ erb "<%= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
189
+ end
190
+
191
+ r.get 'noblock_post' do
192
+ erb "<%= form({:method=>:post}, :button=>'xyz') %>"
193
+ end
194
+
195
+ r.get 'noblock_empty' do
196
+ erb "<%= form(:action=>'/baz') %>"
197
+ end
198
+ end
data/spec/forme_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe "Forme plain forms" do
4
4
  def sel(opts, s)
@@ -317,6 +317,10 @@ describe "Forme plain forms" do
317
317
  @f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :select_options=>{:year=>1970..2020}).to_s.must_equal %{<select id="bar" name="foo[year]">#{sel(1970..2020, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>}
318
318
  end
319
319
 
320
+ it "should support :select_options with both values and text for dates when :as=>:select is given" do
321
+ @f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :select_options=>{:year=>[[2011, 'A'], [2012, 'B']]}).to_s.must_equal %{<select id="bar" name="foo[year]"><option selected="selected" value="2011">A</option><option value="2012">B</option></select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>}
322
+ end
323
+
320
324
  it "should have explicit labeler and trtd wrapper work with multiple select boxes for dates" do
321
325
  @f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :wrapper=>:trtd, :labeler=>:explicit, :label=>'Baz').to_s.must_equal %{<tr><td><label class="label-before" for="bar">Baz</label></td><td><select id="bar" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select></td></tr>}
322
326
  end
@@ -627,13 +631,19 @@ describe "Forme plain forms" do
627
631
  @f.tag(:textarea, {:name=>:foo}, :bar).to_s.must_equal '<textarea name="foo">bar</textarea>'
628
632
  end
629
633
 
634
+ it "#tag should accept a block" do
635
+ @f.tag(:div){@f.tag(:textarea)}.to_s.must_equal '<div><textarea></textarea></div>'
636
+ @f.tag(:div, :name=>'a'){@f.tag(:textarea)}.to_s.must_equal '<div name="a"><textarea></textarea></div>'
637
+ @f.tag(:div, {:name=>'a'}, ["text"]){@f.tag(:textarea)}.to_s.must_equal '<div name="a">text<textarea></textarea></div>'
638
+ end
639
+
630
640
  it "#tag should accept children as procs" do
631
- @f.tag(:div, {:class=>"foo"}, lambda{|t| t.form.tag(:input, :class=>t.attr[:class])}).to_s.must_equal '<div class="foo"><input class="foo"/></div>'
641
+ @f.tag(:div, {:class=>"foo"}, lambda{|t| t.tag(:input, :class=>t.attr[:class])}).to_s.must_equal '<div class="foo"><input class="foo"/></div>'
632
642
  end
633
643
 
634
644
  it "#tag should accept children as methods" do
635
645
  o = Object.new
636
- def o.foo(t) t.form.tag(:input, :class=>t.attr[:class]) end
646
+ def o.foo(t) t.tag(:input, :class=>t.attr[:class]) end
637
647
  @f.tag(:div, {:class=>"foo"}, o.method(:foo)).to_s.must_equal '<div class="foo"><input class="foo"/></div>'
638
648
  end
639
649
 
@@ -641,6 +651,10 @@ describe "Forme plain forms" do
641
651
  @f.inputs([:textarea, :text]).to_s.must_equal '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
642
652
  end
643
653
 
654
+ it "should have an #inputs method for multiple inputs wrapped in a fieldset when using an empty block" do
655
+ @f.inputs([:textarea, :text]){}.to_s.must_equal '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
656
+ end
657
+
644
658
  it "should have default #inputs method accept an :attr option" do
645
659
  @f.inputs([:textarea, :text], :legend=>'Inputs', :attr=>{:class=>'foo', :bar=>'baz'}).to_s.must_equal '<fieldset bar="baz" class="foo inputs"><legend>Inputs</legend><textarea></textarea><input type="text"/></fieldset>'
646
660
  end
@@ -801,41 +815,15 @@ describe "Forme plain forms" do
801
815
  proc{@f.input(:textarea, :wrapper=>Object.new).to_s}.must_raise(Forme::Error)
802
816
  proc{@f.input(:textarea, :formatter=>nil).to_s}.must_raise(Forme::Error)
803
817
  end
804
- end
805
-
806
- describe "Forme::Form :hidden_tags option " do
807
- before do
808
- @f = Forme::Form.new
809
- end
810
-
811
- it "should handle hash" do
812
- Forme.form({}, :hidden_tags=>[{:a=>'b'}]).to_s.must_equal '<form><input name="a" type="hidden" value="b"/></form>'
813
- end
814
-
815
- it "should handle array" do
816
- Forme.form({}, :hidden_tags=>[["a ", "b"]]).to_s.must_equal '<form>a b</form>'
817
- end
818
-
819
- it "should handle string" do
820
- Forme.form({}, :hidden_tags=>["a "]).to_s.must_equal '<form>a </form>'
821
- end
822
-
823
- it "should handle proc return hash" do
824
- Forme.form({}, :hidden_tags=>[lambda{|tag| {:a=>'b'}}]).to_s.must_equal '<form><input name="a" type="hidden" value="b"/></form>'
825
- end
826
-
827
- it "should handle proc return tag" do
828
- Forme.form({:method=>'post'}, :hidden_tags=>[lambda{|tag| tag.form._tag(tag.attr[:method])}]).to_s.must_equal '<form method="post"><post></post></form>'
829
- end
830
818
 
831
- it "should raise error for unhandled object" do
832
- proc{Forme.form({}, :hidden_tags=>[Object.new])}.must_raise Forme::Error
819
+ it "should handle :before and :after hook options" do
820
+ Forme.form({}, :before=>lambda{|f| f.tag(:input, :type=>:hidden, :name=>:a, :value=>'b')}, :after=>lambda{|f| f.tag(:input, :type=>:hidden, :name=>:c, :value=>'d')}){|f| f.tag(:input)}.to_s.must_equal '<form><input name="a" type="hidden" value="b"/><input/><input name="c" type="hidden" value="d"/></form>'
833
821
  end
834
822
  end
835
823
 
836
824
  describe "Forme custom" do
837
825
  it "formatters can be specified as a proc" do
838
- Forme::Form.new(:formatter=>proc{|i| i.form._tag(:textarea, i.opts[:name]=>:name)}).input(:text, :name=>'foo').to_s.must_equal '<textarea foo="name"></textarea>'
826
+ Forme::Form.new(:formatter=>proc{|i| i.tag(:textarea, i.opts[:name]=>:name)}).input(:text, :name=>'foo').to_s.must_equal '<textarea foo="name"></textarea>'
839
827
  end
840
828
 
841
829
  it "serializers can be specified as a proc" do
@@ -1052,6 +1040,7 @@ describe "Forme built-in custom" do
1052
1040
  Forme::Form.new(:serializer=>:text).button().to_s.must_equal ""
1053
1041
  Forme::Form.new(:serializer=>:text).inputs([[:textarea, {:label=>"Foo", :value=>"Bar"}]], :legend=>'Baz').to_s.must_equal "Baz\n---\nFoo: Bar\n\n"
1054
1042
  Forme::Form.new(:serializer=>:text).tag(:p){|f| f.input(:textarea, :label=>"Foo", :value=>"Bar")}.to_s.must_equal "Foo: Bar\n\n"
1043
+ Forme::Form.new(:serializer=>:text).tag(:p, {}, ['a']).to_s.must_equal "a"
1055
1044
  end
1056
1045
  end
1057
1046
 
@@ -1,34 +1,48 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
- require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_helper.rb')
1
+ require_relative 'spec_helper'
2
+ require_relative 'sequel_helper'
3
3
 
4
- require 'rubygems'
5
4
  begin
6
- require 'action_controller/railtie'
7
- rescue LoadError
8
- warn "unable to load rails, skipping rails spec"
9
- else
10
- begin
11
- require 'active_pack/gem_version'
12
- rescue LoadError
13
- end
14
- require 'forme/rails'
5
+ require 'action_controller/railtie'
6
+
7
+ begin
8
+ require 'active_pack/gem_version'
9
+ rescue LoadError
10
+ end
11
+ require_relative '../lib/forme/rails'
15
12
 
16
- class FormeRails < Rails::Application
17
- routes.append do
18
- %w'index inputs_block inputs_block_wrapper nest nest_sep nest_inputs nest_seq hash legend combined noblock noblock_post safe_buffer'.each do |action|
19
- get action, :controller=>'forme', :action=>action
13
+ if Rails.respond_to?(:version) && Rails.version.start_with?('4')
14
+ # Work around issue in backported openssl environments where
15
+ # secret is 64 bytes intead of 32 bytes
16
+ require 'active_support/message_encryptor'
17
+ def (ActiveSupport::MessageEncryptor).new(secret, *signature_key_or_options)
18
+ obj = allocate
19
+ obj.send(:initialize, secret[0, 32], *signature_key_or_options)
20
+ obj
20
21
  end
21
22
  end
22
- config.active_support.deprecation = :stderr
23
- config.middleware.delete(ActionDispatch::HostAuthorization) if defined?(ActionDispatch::HostAuthorization)
24
- config.middleware.delete(ActionDispatch::ShowExceptions)
25
- config.middleware.delete(Rack::Lock)
26
- config.secret_key_base = 'foo'*15
27
- config.secret_token = 'secret token'*15 if Rails.respond_to?(:version) && Rails.version < '5.2'
28
- config.eager_load = true
29
- initialize!
30
- end
31
23
 
24
+ class FormeRails < Rails::Application
25
+ routes.append do
26
+ %w'index inputs_block inputs_block_wrapper nest nest_sep nest_inputs nest_seq hash legend combined noblock noblock_post safe_buffer'.each do |action|
27
+ get action, :controller=>'forme', :action=>action
28
+ end
29
+ end
30
+ config.active_support.deprecation = :stderr
31
+ config.middleware.delete(ActionDispatch::HostAuthorization) if defined?(ActionDispatch::HostAuthorization)
32
+ config.middleware.delete(ActionDispatch::ShowExceptions)
33
+ config.middleware.delete(Rack::Lock)
34
+ config.secret_key_base = 'foo'*15
35
+ config.secret_token = 'secret token'*15 if Rails.respond_to?(:version) && Rails.version < '5.2'
36
+ config.eager_load = true
37
+ begin
38
+ initialize!
39
+ rescue NoMethodError
40
+ raise LoadError
41
+ end
42
+ end
43
+ rescue LoadError
44
+ warn "unable to load or setup rails, skipping rails spec"
45
+ else
32
46
  class FormeController < ActionController::Base
33
47
  helper Forme::Rails::ERB
34
48