forme 1.12.0 → 2.0.0

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.
@@ -0,0 +1,202 @@
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 'hidden_tags' do
188
+ erb "<%= form([:foo, :bar], {:action=>'/baz'}, :hidden_tags=>[{'a'=>'b'}]) %>"
189
+ end
190
+
191
+ r.get 'noblock' do
192
+ erb "<%= form([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
193
+ end
194
+
195
+ r.get 'noblock_post' do
196
+ erb "<%= form({:method=>:post}, :button=>'xyz') %>"
197
+ end
198
+
199
+ r.get 'noblock_empty' do
200
+ erb "<%= form(:action=>'/baz') %>"
201
+ end
202
+ 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)
@@ -631,13 +631,19 @@ describe "Forme plain forms" do
631
631
  @f.tag(:textarea, {:name=>:foo}, :bar).to_s.must_equal '<textarea name="foo">bar</textarea>'
632
632
  end
633
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
+
634
640
  it "#tag should accept children as procs" do
635
- @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>'
636
642
  end
637
643
 
638
644
  it "#tag should accept children as methods" do
639
645
  o = Object.new
640
- 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
641
647
  @f.tag(:div, {:class=>"foo"}, o.method(:foo)).to_s.must_equal '<div class="foo"><input class="foo"/></div>'
642
648
  end
643
649
 
@@ -645,6 +651,10 @@ describe "Forme plain forms" do
645
651
  @f.inputs([:textarea, :text]).to_s.must_equal '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
646
652
  end
647
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
+
648
658
  it "should have default #inputs method accept an :attr option" do
649
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>'
650
660
  end
@@ -805,41 +815,45 @@ describe "Forme plain forms" do
805
815
  proc{@f.input(:textarea, :wrapper=>Object.new).to_s}.must_raise(Forme::Error)
806
816
  proc{@f.input(:textarea, :formatter=>nil).to_s}.must_raise(Forme::Error)
807
817
  end
808
- end
809
818
 
810
- describe "Forme::Form :hidden_tags option " do
811
- before do
812
- @f = Forme::Form.new
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>'
813
821
  end
822
+ end
814
823
 
815
- it "should handle hash" do
824
+ describe "Forme::Form :hidden_tags option " do
825
+ silence_warnings "should handle hash" do
816
826
  Forme.form({}, :hidden_tags=>[{:a=>'b'}]).to_s.must_equal '<form><input name="a" type="hidden" value="b"/></form>'
817
827
  end
818
828
 
819
- it "should handle array" do
829
+ silence_warnings "should handle array" do
820
830
  Forme.form({}, :hidden_tags=>[["a ", "b"]]).to_s.must_equal '<form>a b</form>'
821
831
  end
822
832
 
823
- it "should handle string" do
833
+ silence_warnings "should handle string" do
824
834
  Forme.form({}, :hidden_tags=>["a "]).to_s.must_equal '<form>a </form>'
825
835
  end
826
836
 
827
- it "should handle proc return hash" do
837
+ silence_warnings "should handle proc return hash" do
828
838
  Forme.form({}, :hidden_tags=>[lambda{|tag| {:a=>'b'}}]).to_s.must_equal '<form><input name="a" type="hidden" value="b"/></form>'
829
839
  end
830
840
 
831
- it "should handle proc return tag" do
832
- Forme.form({:method=>'post'}, :hidden_tags=>[lambda{|tag| tag.form._tag(tag.attr[:method])}]).to_s.must_equal '<form method="post"><post></post></form>'
841
+ silence_warnings "should handle proc return hash when from takes a block" do
842
+ Forme.form({}, :hidden_tags=>[lambda{|tag| {:a=>'b'}}]){}.to_s.must_equal '<form><input name="a" type="hidden" value="b"/></form>'
843
+ end
844
+
845
+ silence_warnings "should handle proc return tag" do
846
+ Forme.form({:method=>'post'}, :hidden_tags=>[lambda{|tag| tag.tag(tag.attr[:method])}]).to_s.must_equal '<form method="post"><post></post></form>'
833
847
  end
834
848
 
835
- it "should raise error for unhandled object" do
849
+ silence_warnings "should raise error for unhandled object" do
836
850
  proc{Forme.form({}, :hidden_tags=>[Object.new])}.must_raise Forme::Error
837
851
  end
838
852
  end
839
853
 
840
854
  describe "Forme custom" do
841
855
  it "formatters can be specified as a proc" do
842
- 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>'
856
+ 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>'
843
857
  end
844
858
 
845
859
  it "serializers can be specified as a proc" do
@@ -1056,6 +1070,7 @@ describe "Forme built-in custom" do
1056
1070
  Forme::Form.new(:serializer=>:text).button().to_s.must_equal ""
1057
1071
  Forme::Form.new(:serializer=>:text).inputs([[:textarea, {:label=>"Foo", :value=>"Bar"}]], :legend=>'Baz').to_s.must_equal "Baz\n---\nFoo: Bar\n\n"
1058
1072
  Forme::Form.new(:serializer=>:text).tag(:p){|f| f.input(:textarea, :label=>"Foo", :value=>"Bar")}.to_s.must_equal "Foo: Bar\n\n"
1073
+ Forme::Form.new(:serializer=>:text).tag(:p, {}, ['a']).to_s.must_equal "a"
1059
1074
  end
1060
1075
  end
1061
1076
 
@@ -1,7 +1,6 @@
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
5
  require 'action_controller/railtie'
7
6
 
@@ -9,23 +8,22 @@ begin
9
8
  require 'active_pack/gem_version'
10
9
  rescue LoadError
11
10
  end
12
- require 'forme/rails'
11
+ require_relative '../lib/forme/rails'
13
12
 
14
13
  if Rails.respond_to?(:version) && Rails.version.start_with?('4')
15
14
  # Work around issue in backported openssl environments where
16
15
  # secret is 64 bytes intead of 32 bytes
17
16
  require 'active_support/message_encryptor'
18
- ActiveSupport::MessageEncryptor.send :prepend, Module.new {
19
- def initialize(secret, *signature_key_or_options)
20
- secret = secret[0, 32]
21
- super
22
- end
23
- }
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
21
+ end
24
22
  end
25
23
 
26
24
  class FormeRails < Rails::Application
27
25
  routes.append do
28
- %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|
26
+ %w'index inputs_block inputs_block_wrapper nest nest_sep nest_inputs nest_seq hash legend combined hidden_tags noblock noblock_post safe_buffer'.each do |action|
29
27
  get action, :controller=>'forme', :action=>action
30
28
  end
31
29
  end
@@ -194,6 +192,10 @@ END
194
192
  END
195
193
  end
196
194
 
195
+ def hidden_tags
196
+ render :inline => "<%= forme([:foo, :bar], {:action=>'/baz'}, :hidden_tags=>[{'a'=>'b'}]) %>"
197
+ end
198
+
197
199
  def noblock
198
200
  render :inline => "<%= forme([:foo, :bar], {:action=>'/baz'}, :inputs=>[:first], :button=>'xyz', :legend=>'123') %>"
199
201
  end
@@ -265,6 +267,10 @@ describe "Forme Rails integration" do
265
267
  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>'
266
268
  end
267
269
 
270
+ silence_warnings "#form should support :hidden_tags option" do
271
+ sin_get('/hidden_tags').must_equal '<form action="/baz"><input name="a" type="hidden" value="b"/></form>'
272
+ end
273
+
268
274
  it "#form should work without a block" do
269
275
  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>'
270
276
  end
@@ -1,8 +1,7 @@
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')
3
- require File.join(File.dirname(File.expand_path(__FILE__)), 'erb_helper.rb')
1
+ require_relative 'spec_helper'
2
+ require_relative 'sequel_helper'
3
+ require_relative 'erb_helper'
4
4
 
5
- require 'rubygems'
6
5
  begin
7
6
  require 'roda'
8
7
  require 'tilt'
@@ -17,34 +16,42 @@ rescue LoadError
17
16
  rescue LoadError
18
17
  require 'tilt/erb'
19
18
  end
20
- end
21
-
22
- class FormeRodaTest < Roda
23
- opts[:check_dynamic_arity] = opts[:check_arity] = :warn
24
-
25
- if defined?(Roda::RodaVersionNumber) && Roda::RodaVersionNumber >= 30100
26
- require 'roda/session_middleware'
27
- opts[:sessions_convert_symbols] = true
28
- use RodaSessionMiddleware, :secret=>SecureRandom.random_bytes(64), :key=>'rack.session'
29
- else
30
- use Rack::Session::Cookie, :secret => "__a_very_long_string__"
31
- end
32
-
33
- def erb(s, opts={})
34
- render(opts.merge(:inline=>s))
19
+ else
20
+ begin
21
+ require 'erubi/capture_end'
22
+ require_relative 'erubi_capture_helper'
23
+ rescue LoadError
35
24
  end
25
+ end
36
26
 
37
- route do |r|
38
- r.get 'use_request_specific_token', :use do |use|
39
- render :inline=>"[#{Base64.strict_encode64(send(:csrf_secret))}]<%= form({:method=>:post}, {:use_request_specific_token=>#{use == '1'}}) %>"
27
+ def FormeRodaTest(block=ERB_BLOCK)
28
+ Class.new(Roda) do
29
+ opts[:check_dynamic_arity] = opts[:check_arity] = :warn
30
+
31
+ if defined?(Roda::RodaVersionNumber) && Roda::RodaVersionNumber >= 30100
32
+ require 'roda/session_middleware'
33
+ opts[:sessions_convert_symbols] = true
34
+ use RodaSessionMiddleware, :secret=>SecureRandom.random_bytes(64), :key=>'rack.session'
35
+ else
36
+ use Rack::Session::Cookie, :secret => "__a_very_long_string__"
40
37
  end
41
- r.get 'hidden_tags' do |use|
42
- render :inline=>"<%= form({:method=>:post}, {:hidden_tags=>[{:foo=>'bar'}]}) %>"
38
+
39
+ def erb(s, opts={})
40
+ render(opts.merge(:inline=>s))
43
41
  end
44
- r.get 'csrf', :use do |use|
45
- render :inline=>"<%= form({:method=>:post}, {:csrf=>#{use == '1'}}) %>"
42
+
43
+ route do |r|
44
+ r.get 'use_request_specific_token', :use do |use|
45
+ render :inline=>"[#{Base64.strict_encode64(send(:csrf_secret))}]<%= form({:method=>:post}, {:use_request_specific_token=>#{use == '1'}}) %>"
46
+ end
47
+ r.get 'hidden_tags2' do |use|
48
+ render :inline=>"<%= form({:method=>:post}, {:hidden_tags=>[{:foo=>'bar'}]}) %>"
49
+ end
50
+ r.get 'csrf', :use do |use|
51
+ render :inline=>"<%= form({:method=>:post}, {:csrf=>#{use == '1'}}) %>"
52
+ end
53
+ instance_exec(r, &block)
46
54
  end
47
- instance_exec(r, &ERB_BLOCK)
48
55
  end
49
56
  end
50
57
 
@@ -54,7 +61,7 @@ rescue LoadError
54
61
  warn "unable to load rack/csrf, skipping roda csrf plugin spec"
55
62
  else
56
63
  describe "Forme Roda ERB integration with roda forme and csrf plugins" do
57
- app = FormeRodaCSRFTest = Class.new(FormeRodaTest)
64
+ app = FormeRodaCSRFTest = FormeRodaTest()
58
65
  app.plugin :csrf
59
66
  app.plugin :forme
60
67
 
@@ -68,64 +75,89 @@ describe "Forme Roda ERB integration with roda forme and csrf plugins" do
68
75
  end
69
76
  end
70
77
 
78
+ module FormeRouteCsrfSpecs
79
+ extend Minitest::Spec::DSL
80
+ include FormeErbSpecs
81
+
82
+ it "should have a valid CSRF tag" do
83
+ output = sin_get('/use_request_specific_token/1')
84
+ output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
85
+ secret = $1
86
+ token = $2
87
+ app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
88
+ app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
89
+ end
90
+
91
+ it "should handle the :use_request_specific_token => true option" do
92
+ output = sin_get('/use_request_specific_token/1')
93
+ output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
94
+ secret = $1
95
+ token = $2
96
+ app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
97
+ app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
98
+ end
99
+
100
+ it "should handle the :use_request_specific_token => false option" do
101
+ output = sin_get('/use_request_specific_token/0')
102
+ output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
103
+ secret = $1
104
+ token = $2
105
+ app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/0', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal(plugin_opts.empty? ? false : true)
106
+ end
107
+
108
+ silence_warnings "should include :hidden_tags option" do
109
+ sin_get('/hidden_tags2').must_include 'name="foo" type="hidden" value="bar"'
110
+ end
111
+
112
+ it "should handle the :csrf option" do
113
+ sin_get('/csrf/1').must_include '<input name="_csrf" type="hidden" value="'
114
+ sin_get('/csrf/0').wont_include '<input name="_csrf" type="hidden" value="'
115
+ end
116
+ end
117
+
71
118
  begin
72
119
  require 'roda/plugins/route_csrf'
120
+ require 'roda/plugins/capture_erb'
121
+ require 'roda/plugins/inject_erb'
73
122
  rescue LoadError
74
- warn "unable to load roda/plugins/route_csrf, skipping forme_route_csrf plugin spec"
123
+ warn "unable to load necessary Roda plugins, skipping forme_erubi_capture plugin spec"
75
124
  else
125
+ describe "Forme Roda Erubi::CaptureEnd integration with roda forme_route_csrf" do
126
+ app = FormeRodaTest(ERUBI_CAPTURE_BLOCK)
127
+ app.plugin :forme_erubi_capture
128
+ app.plugin :render, :engine_opts=>{'erb'=>{:engine_class=>Erubi::CaptureEndEngine}}
129
+
130
+ define_method(:app){app}
131
+ define_method(:plugin_opts){{}}
132
+ define_method(:sin_get) do |path|
133
+ s = String.new
134
+ app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
135
+ s.gsub(/\s+/, ' ').strip
136
+ end
137
+
138
+ include FormeRouteCsrfSpecs
139
+ end if defined?(ERUBI_CAPTURE_BLOCK)
140
+
76
141
  [{}, {:require_request_specific_tokens=>false}].each do |plugin_opts|
77
142
  describe "Forme Roda ERB integration with roda forme_route_csrf and route_csrf plugin with #{plugin_opts}" do
78
- app = Class.new(FormeRodaTest)
143
+ app = FormeRodaTest()
79
144
  app.plugin :forme_route_csrf
80
145
  app.plugin :route_csrf, plugin_opts
81
146
 
147
+ define_method(:app){app}
148
+ define_method(:plugin_opts){plugin_opts}
82
149
  define_method(:sin_get) do |path|
83
150
  s = String.new
84
151
  app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
85
152
  s.gsub(/\s+/, ' ').strip
86
153
  end
87
154
 
88
- include FormeErbSpecs
89
-
90
- it "should handle the :hidden_tags option" do
91
- output = sin_get('/use_request_specific_token/1')
92
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
93
- secret = $1
94
- token = $2
95
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
96
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
97
- end
98
-
99
- it "should handle the :use_request_specific_token => true option" do
100
- output = sin_get('/use_request_specific_token/1')
101
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
102
- secret = $1
103
- token = $2
104
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
105
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
106
- end
107
-
108
- it "should handle the :use_request_specific_token => false option" do
109
- output = sin_get('/use_request_specific_token/0')
110
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
111
- secret = $1
112
- token = $2
113
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/0', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal(plugin_opts.empty? ? false : true)
114
- end
115
-
116
- it "should handle the :hidden_tags option" do
117
- sin_get('/hidden_tags').must_include 'name="foo" type="hidden" value="bar"'
118
- end
119
-
120
- it "should handle the :csrf option" do
121
- sin_get('/csrf/1').must_include '<input name="_csrf" type="hidden" value="'
122
- sin_get('/csrf/0').wont_include '<input name="_csrf" type="hidden" value="'
123
- end
155
+ include FormeRouteCsrfSpecs
124
156
  end
125
157
 
126
158
  describe "Forme Roda ERB Sequel integration with roda forme_set plugin and route_csrf plugin with #{plugin_opts}" do
127
159
  before do
128
- @app = Class.new(FormeRodaTest)
160
+ @app = FormeRodaTest()
129
161
  @app.plugin :route_csrf, plugin_opts
130
162
  @app.plugin(:forme_set, :secret=>'1'*64)
131
163
 
@@ -153,7 +185,11 @@ else
153
185
 
154
186
  @app.route do |r|
155
187
  r.get do
156
- form(*env[:args], &env[:block]).to_s
188
+ if @block = env[:block]
189
+ render(:inline=>'<% form(*env[:args]) do |f| %><%= @block.call(f) %><% end %>')
190
+ else
191
+ form(*env[:args])
192
+ end
157
193
  end
158
194
  r.post do
159
195
  r.params.replace(env[:params])
@@ -173,6 +209,25 @@ else
173
209
  end
174
210
  meth == :forme_parse ? ret : h
175
211
  end
212
+
213
+ it "should have subform work correctly" do
214
+ @app.route do |r|
215
+ @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
216
+ @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
217
+ erb <<END
218
+ 0
219
+ <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
220
+ 1
221
+ <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
222
+ 2
223
+ <% end %>
224
+ 3
225
+ END
226
+ end
227
+
228
+ body = @app.call('REQUEST_METHOD'=>'GET')[2].join.gsub("\n", ' ').gsub(/ +/, ' ').chomp(' ')
229
+ body.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 <table><caption>Foo</caption><thead><tr><th>Name</th></tr></thead><tbody><input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><tr><td class="string"><input id="album_artist_attributes_name" maxlength="255" name="album[artist_attributes][name]" type="text" value="A"/></td></tr></tbody></table> 2 <input type="submit" value="Sub"/></form>3'
230
+ end
176
231
 
177
232
  it "#forme_set should include HMAC values if form includes inputs for obj" do
178
233
  h = forme_set(@ab, :name=>'Foo')
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'sequel'
3
2
 
4
3
  db_url = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' ? 'jdbc:sqlite::memory:' : 'sqlite:/'
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_helper.rb')
1
+ require_relative 'sequel_helper'
2
2
 
3
3
  gem 'i18n', '>= 0.7.0'
4
4
  require 'i18n'
@@ -1,8 +1,8 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
1
+ require_relative 'spec_helper'
2
2
 
3
3
  begin
4
4
  raise LoadError if defined?(JRUBY_VERSION) && /\A9\.2\./.match(JRUBY_VERSION)
5
- require File.join(File.dirname(File.expand_path(__FILE__)), 'sequel_i18n_helper.rb')
5
+ require_relative 'sequel_i18n_helper'
6
6
  rescue LoadError
7
7
  warn "unable to load i18n, skipping i18n Sequel plugin spec"
8
8
  else