forme 1.11.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +54 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +235 -209
- data/Rakefile +1 -7
- data/lib/forme/bs3.rb +18 -4
- data/lib/forme/erb.rb +13 -25
- data/lib/forme/form.rb +144 -149
- data/lib/forme/input.rb +1 -1
- data/lib/forme/rails.rb +39 -83
- data/lib/forme/raw.rb +2 -2
- data/lib/forme/tag.rb +3 -12
- data/lib/forme/template.rb +110 -0
- data/lib/forme/transformers/formatter.rb +4 -1
- data/lib/forme/transformers/helper.rb +0 -1
- data/lib/forme/transformers/inputs_wrapper.rb +4 -4
- data/lib/forme/version.rb +2 -2
- data/lib/forme.rb +15 -2
- data/lib/roda/plugins/forme.rb +1 -1
- data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
- data/lib/roda/plugins/forme_route_csrf.rb +16 -34
- data/lib/roda/plugins/forme_set.rb +39 -76
- data/lib/sequel/plugins/forme.rb +40 -50
- data/lib/sequel/plugins/forme_i18n.rb +3 -1
- data/lib/sequel/plugins/forme_set.rb +3 -1
- data/spec/all.rb +1 -1
- data/spec/bs3_reference_spec.rb +18 -18
- data/spec/bs3_sequel_plugin_spec.rb +17 -17
- data/spec/bs3_spec.rb +23 -11
- data/spec/erb_helper.rb +69 -58
- data/spec/erubi_capture_helper.rb +198 -0
- data/spec/forme_spec.rb +21 -32
- data/spec/rails_integration_spec.rb +39 -25
- data/spec/roda_integration_spec.rb +118 -70
- data/spec/sequel_helper.rb +0 -1
- data/spec/sequel_i18n_helper.rb +1 -1
- data/spec/sequel_i18n_plugin_spec.rb +3 -2
- data/spec/sequel_plugin_spec.rb +29 -12
- data/spec/sequel_set_plugin_spec.rb +9 -2
- data/spec/shared_erb_specs.rb +71 -0
- data/spec/sinatra_integration_spec.rb +5 -6
- data/spec/spec_helper.rb +21 -8
- metadata +9 -7
- data/lib/forme/erb_form.rb +0 -74
- data/lib/forme/sinatra.rb +0 -17
@@ -1,8 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
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,39 @@ rescue LoadError
|
|
17
16
|
rescue LoadError
|
18
17
|
require 'tilt/erb'
|
19
18
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
38
|
+
|
39
|
+
def erb(s, opts={})
|
40
|
+
render(opts.merge(:inline=>s))
|
43
41
|
end
|
44
|
-
|
45
|
-
|
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 'csrf', :use do |use|
|
48
|
+
render :inline=>"<%= form({:method=>:post}, {:csrf=>#{use == '1'}}) %>"
|
49
|
+
end
|
50
|
+
instance_exec(r, &block)
|
46
51
|
end
|
47
|
-
instance_exec(r, &ERB_BLOCK)
|
48
52
|
end
|
49
53
|
end
|
50
54
|
|
@@ -54,7 +58,7 @@ rescue LoadError
|
|
54
58
|
warn "unable to load rack/csrf, skipping roda csrf plugin spec"
|
55
59
|
else
|
56
60
|
describe "Forme Roda ERB integration with roda forme and csrf plugins" do
|
57
|
-
app = FormeRodaCSRFTest =
|
61
|
+
app = FormeRodaCSRFTest = FormeRodaTest()
|
58
62
|
app.plugin :csrf
|
59
63
|
app.plugin :forme
|
60
64
|
|
@@ -68,64 +72,85 @@ describe "Forme Roda ERB integration with roda forme and csrf plugins" do
|
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
75
|
+
module FormeRouteCsrfSpecs
|
76
|
+
extend Minitest::Spec::DSL
|
77
|
+
include FormeErbSpecs
|
78
|
+
|
79
|
+
it "should have a valid CSRF tag" do
|
80
|
+
output = sin_get('/use_request_specific_token/1')
|
81
|
+
output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
|
82
|
+
secret = $1
|
83
|
+
token = $2
|
84
|
+
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
|
85
|
+
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
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should handle the :use_request_specific_token => true option" do
|
89
|
+
output = sin_get('/use_request_specific_token/1')
|
90
|
+
output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
|
91
|
+
secret = $1
|
92
|
+
token = $2
|
93
|
+
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
|
94
|
+
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
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should handle the :use_request_specific_token => false option" do
|
98
|
+
output = sin_get('/use_request_specific_token/0')
|
99
|
+
output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
|
100
|
+
secret = $1
|
101
|
+
token = $2
|
102
|
+
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)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should handle the :csrf option" do
|
106
|
+
sin_get('/csrf/1').must_include '<input name="_csrf" type="hidden" value="'
|
107
|
+
sin_get('/csrf/0').wont_include '<input name="_csrf" type="hidden" value="'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
71
111
|
begin
|
72
112
|
require 'roda/plugins/route_csrf'
|
113
|
+
require 'roda/plugins/capture_erb'
|
114
|
+
require 'roda/plugins/inject_erb'
|
73
115
|
rescue LoadError
|
74
|
-
warn "unable to load
|
116
|
+
warn "unable to load necessary Roda plugins, skipping forme_erubi_capture plugin spec"
|
75
117
|
else
|
118
|
+
describe "Forme Roda Erubi::CaptureEnd integration with roda forme_route_csrf" do
|
119
|
+
app = FormeRodaTest(ERUBI_CAPTURE_BLOCK)
|
120
|
+
app.plugin :forme_erubi_capture
|
121
|
+
app.plugin :render, :engine_opts=>{'erb'=>{:engine_class=>Erubi::CaptureEndEngine}}
|
122
|
+
|
123
|
+
define_method(:app){app}
|
124
|
+
define_method(:plugin_opts){{}}
|
125
|
+
define_method(:sin_get) do |path|
|
126
|
+
s = String.new
|
127
|
+
app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
|
128
|
+
s.gsub(/\s+/, ' ').strip
|
129
|
+
end
|
130
|
+
|
131
|
+
include FormeRouteCsrfSpecs
|
132
|
+
end if defined?(ERUBI_CAPTURE_BLOCK)
|
133
|
+
|
76
134
|
[{}, {:require_request_specific_tokens=>false}].each do |plugin_opts|
|
77
135
|
describe "Forme Roda ERB integration with roda forme_route_csrf and route_csrf plugin with #{plugin_opts}" do
|
78
|
-
app =
|
136
|
+
app = FormeRodaTest()
|
79
137
|
app.plugin :forme_route_csrf
|
80
138
|
app.plugin :route_csrf, plugin_opts
|
81
139
|
|
140
|
+
define_method(:app){app}
|
141
|
+
define_method(:plugin_opts){plugin_opts}
|
82
142
|
define_method(:sin_get) do |path|
|
83
143
|
s = String.new
|
84
144
|
app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
|
85
145
|
s.gsub(/\s+/, ' ').strip
|
86
146
|
end
|
87
147
|
|
88
|
-
include
|
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
|
148
|
+
include FormeRouteCsrfSpecs
|
124
149
|
end
|
125
150
|
|
126
151
|
describe "Forme Roda ERB Sequel integration with roda forme_set plugin and route_csrf plugin with #{plugin_opts}" do
|
127
152
|
before do
|
128
|
-
@app =
|
153
|
+
@app = FormeRodaTest()
|
129
154
|
@app.plugin :route_csrf, plugin_opts
|
130
155
|
@app.plugin(:forme_set, :secret=>'1'*64)
|
131
156
|
|
@@ -149,11 +174,15 @@ else
|
|
149
174
|
forme_set_block = orig_hash.delete(:forme_set_block)
|
150
175
|
orig_hash.each{|k,v| hash[k.to_s] = v}
|
151
176
|
album = @ab
|
152
|
-
ret,
|
177
|
+
ret, _, data, hmac = nil
|
153
178
|
|
154
179
|
@app.route do |r|
|
155
180
|
r.get do
|
156
|
-
|
181
|
+
if @block = env[:block]
|
182
|
+
render(:inline=>'<% form(*env[:args]) do |f| %><%= @block.call(f) %><% end %>')
|
183
|
+
else
|
184
|
+
form(*env[:args])
|
185
|
+
end
|
157
186
|
end
|
158
187
|
r.post do
|
159
188
|
r.params.replace(env[:params])
|
@@ -173,6 +202,25 @@ else
|
|
173
202
|
end
|
174
203
|
meth == :forme_parse ? ret : h
|
175
204
|
end
|
205
|
+
|
206
|
+
it "should have subform work correctly" do
|
207
|
+
@app.route do |r|
|
208
|
+
@album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
|
209
|
+
@album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
|
210
|
+
erb <<END
|
211
|
+
0
|
212
|
+
<% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
|
213
|
+
1
|
214
|
+
<%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
|
215
|
+
2
|
216
|
+
<% end %>
|
217
|
+
3
|
218
|
+
END
|
219
|
+
end
|
220
|
+
|
221
|
+
body = @app.call('REQUEST_METHOD'=>'GET')[2].join.gsub("\n", ' ').gsub(/ +/, ' ').chomp(' ')
|
222
|
+
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 <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><table><caption>Foo</caption><thead><tr><th>Name</th></tr></thead><tbody><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'
|
223
|
+
end
|
176
224
|
|
177
225
|
it "#forme_set should include HMAC values if form includes inputs for obj" do
|
178
226
|
h = forme_set(@ab, :name=>'Foo')
|
@@ -274,7 +322,7 @@ else
|
|
274
322
|
obj.must_be_same_as @ab
|
275
323
|
version.must_be_nil
|
276
324
|
|
277
|
-
|
325
|
+
forme_set(@ab, {:name=>'Bar', :forme_set_block=>forme_set_block}, {}, :form_version=>2){|f| f.input(:name)}
|
278
326
|
obj.must_be_same_as @ab
|
279
327
|
name.must_equal 'Bar'
|
280
328
|
version.must_equal 2
|
data/spec/sequel_helper.rb
CHANGED
data/spec/sequel_i18n_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
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_relative 'sequel_i18n_helper'
|
5
6
|
rescue LoadError
|
6
7
|
warn "unable to load i18n, skipping i18n Sequel plugin spec"
|
7
8
|
else
|
data/spec/sequel_plugin_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative 'sequel_helper'
|
3
3
|
|
4
4
|
describe "Forme Sequel::Model forms" do
|
5
5
|
before do
|
@@ -9,6 +9,15 @@ describe "Forme Sequel::Model forms" do
|
|
9
9
|
@c = Forme::Form.new(@ac)
|
10
10
|
end
|
11
11
|
|
12
|
+
it "should handle Forme::Form subclasses" do
|
13
|
+
c = Class.new(Forme::Form) do
|
14
|
+
def form(*)
|
15
|
+
super{|f| f.tag(:input, :type=>:hidden, :name=>'a', :value=>'b')}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
c.new(@ab).form.to_s.must_equal '<form class="forme album" method="post"><input name="a" type="hidden" value="b"/></form>'
|
19
|
+
end
|
20
|
+
|
12
21
|
it "should add appropriate attributes by default" do
|
13
22
|
@b.form.to_s.must_equal '<form class="forme album" method="post"></form>'
|
14
23
|
end
|
@@ -331,6 +340,11 @@ describe "Forme Sequel::Model forms" do
|
|
331
340
|
@b.input(:foo, :type=>:phone).to_s.must_equal '<label>Foo: <input id="album_foo" name="album[foo]" type="phone" value="bar"/></label>'
|
332
341
|
end
|
333
342
|
|
343
|
+
it "should not override an explicit :error setting" do
|
344
|
+
@ab.errors.add(:name, 'tis not valid')
|
345
|
+
@b.input(:name, :error=>nil).to_s.must_equal '<label>Name: <input id="album_name" maxlength="255" name="album[name]" type="text" value="b"/></label>'
|
346
|
+
end
|
347
|
+
|
334
348
|
it "should correctly show an error message if there is one" do
|
335
349
|
@ab.errors.add(:name, 'tis not valid')
|
336
350
|
@b.input(:name).to_s.must_equal '<label>Name: <input aria-describedby="album_name_error_message" aria-invalid="true" class="error" id="album_name" maxlength="255" name="album[name]" type="text" value="b"/></label><span class="error_message" id="album_name_error_message">tis not valid</span>'
|
@@ -400,19 +414,19 @@ describe "Forme Sequel::Model forms" do
|
|
400
414
|
end
|
401
415
|
|
402
416
|
it "should use allow nested forms with one_to_many associations" do
|
403
|
-
Forme.form(@ab){|f| f.subform(:tracks){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><
|
417
|
+
Forme.form(@ab){|f| f.subform(:tracks){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><fieldset class="inputs"><legend>Track #2</legend><label>Name: <input id="album_tracks_attributes_1_name" maxlength="255" name="album[tracks_attributes][1][name]" type="text" value="n"/></label></fieldset></form>'
|
404
418
|
end
|
405
419
|
|
406
420
|
it "should support :obj option for *_to_many associations" do
|
407
|
-
Forme.form(@ab){|f| f.subform(:tracks, :obj=>[Track.new(:name=>'x'), Track.load(:id=>5, :name=>'y')]){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="x"/></label></fieldset><
|
421
|
+
Forme.form(@ab){|f| f.subform(:tracks, :obj=>[Track.new(:name=>'x'), Track.load(:id=>5, :name=>'y')]){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="5"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="x"/></label></fieldset><fieldset class="inputs"><legend>Track #2</legend><label>Name: <input id="album_tracks_attributes_1_name" maxlength="255" name="album[tracks_attributes][1][name]" type="text" value="y"/></label></fieldset></form>'
|
408
422
|
end
|
409
423
|
|
410
424
|
it "should auto number legends when using subform with inputs for *_to_many associations" do
|
411
|
-
Forme.form(@ab){|f| f.subform(:tracks, :inputs=>[:name])}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><
|
425
|
+
Forme.form(@ab){|f| f.subform(:tracks, :inputs=>[:name])}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><fieldset class="inputs"><legend>Track #2</legend><label>Name: <input id="album_tracks_attributes_1_name" maxlength="255" name="album[tracks_attributes][1][name]" type="text" value="n"/></label></fieldset></form>'
|
412
426
|
end
|
413
427
|
|
414
428
|
it "should support callable :legend option when using subform with inputs for *_to_many associations" do
|
415
|
-
Forme.form(@ab){|f| f.subform(:tracks, :inputs=>[:name], :legend=>proc{|o, i| "Track #{i} (#{o.name})"})}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Track 0 (m)</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><
|
429
|
+
Forme.form(@ab){|f| f.subform(:tracks, :inputs=>[:name], :legend=>proc{|o, i| "Track #{i} (#{o.name})"})}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/><input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Track 0 (m)</legend><label>Name: <input id="album_tracks_attributes_0_name" maxlength="255" name="album[tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><fieldset class="inputs"><legend>Track 1 (n)</legend><label>Name: <input id="album_tracks_attributes_1_name" maxlength="255" name="album[tracks_attributes][1][name]" type="text" value="n"/></label></fieldset></form>'
|
416
430
|
end
|
417
431
|
|
418
432
|
it "should not add hidden primary key field for nested forms with one_to_many associations with new objects" do
|
@@ -421,7 +435,7 @@ describe "Forme Sequel::Model forms" do
|
|
421
435
|
end
|
422
436
|
|
423
437
|
it "should use allow nested forms with many_to_many associations" do
|
424
|
-
Forme.form(@ab){|f| f.subform(:tags){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tags_attributes_0_id" name="album[tags_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Tag #1</legend><label>Name: <input id="album_tags_attributes_0_name" maxlength="255" name="album[tags_attributes][0][name]" type="text" value="s"/></label></fieldset><
|
438
|
+
Forme.form(@ab){|f| f.subform(:tags){f.input(:name)}}.to_s.must_equal '<form class="forme album" method="post"><input id="album_tags_attributes_0_id" name="album[tags_attributes][0][id]" type="hidden" value="1"/><input id="album_tags_attributes_1_id" name="album[tags_attributes][1][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Tag #1</legend><label>Name: <input id="album_tags_attributes_0_name" maxlength="255" name="album[tags_attributes][0][name]" type="text" value="s"/></label></fieldset><fieldset class="inputs"><legend>Tag #2</legend><label>Name: <input id="album_tags_attributes_1_name" maxlength="255" name="album[tags_attributes][1][name]" type="text" value="t"/></label></fieldset></form>'
|
425
439
|
end
|
426
440
|
|
427
441
|
it "should not add hidden primary key field for nested forms with many_to_many associations with new objects" do
|
@@ -430,29 +444,32 @@ describe "Forme Sequel::Model forms" do
|
|
430
444
|
end
|
431
445
|
|
432
446
|
it "should handle multiple nested levels" do
|
433
|
-
Forme.form(Artist[1]){|f| f.subform(:albums){f.input(:name); f.subform(:tracks){f.input(:name)}}}.to_s.to_s.must_equal '<form class="forme artist" method="post"><input id="artist_albums_attributes_0_id" name="artist[albums_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Album #1</legend><label>Name: <input id="artist_albums_attributes_0_name" maxlength="255" name="artist[albums_attributes][0][name]" type="text" value="b"/></label><input id="artist_albums_attributes_0_tracks_attributes_0_id" name="artist[albums_attributes][0][tracks_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="artist_albums_attributes_0_tracks_attributes_0_name" maxlength="255" name="artist[albums_attributes][0][tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><
|
447
|
+
Forme.form(Artist[1]){|f| f.subform(:albums){f.input(:name); f.subform(:tracks){f.input(:name)}}}.to_s.to_s.must_equal '<form class="forme artist" method="post"><input id="artist_albums_attributes_0_id" name="artist[albums_attributes][0][id]" type="hidden" value="1"/><fieldset class="inputs"><legend>Album #1</legend><label>Name: <input id="artist_albums_attributes_0_name" maxlength="255" name="artist[albums_attributes][0][name]" type="text" value="b"/></label><input id="artist_albums_attributes_0_tracks_attributes_0_id" name="artist[albums_attributes][0][tracks_attributes][0][id]" type="hidden" value="1"/><input id="artist_albums_attributes_0_tracks_attributes_1_id" name="artist[albums_attributes][0][tracks_attributes][1][id]" type="hidden" value="2"/><fieldset class="inputs"><legend>Track #1</legend><label>Name: <input id="artist_albums_attributes_0_tracks_attributes_0_name" maxlength="255" name="artist[albums_attributes][0][tracks_attributes][0][name]" type="text" value="m"/></label></fieldset><fieldset class="inputs"><legend>Track #2</legend><label>Name: <input id="artist_albums_attributes_0_tracks_attributes_1_name" maxlength="255" name="artist[albums_attributes][0][tracks_attributes][1][name]" type="text" value="n"/></label></fieldset></fieldset></form>'
|
434
448
|
end
|
435
449
|
|
436
450
|
it "should have #subform :grid option create a grid" do
|
437
|
-
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true)}.to_s.must_equal '<form class="forme album" method="post"><
|
451
|
+
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true)}.to_s.must_equal '<form class="forme album" method="post"><input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/><table><caption>Artist</caption><thead><tr><th>Name</th></tr></thead><tbody><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></form>'
|
438
452
|
end
|
439
453
|
|
440
454
|
it "should have #subform :grid option respect :inputs_opts option to pass options to inputs" do
|
441
|
-
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :inputs_opts=>{:attr=>{:class=>'foo'}})}.to_s.must_equal '<form class="forme album" method="post"><
|
455
|
+
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :inputs_opts=>{:attr=>{:class=>'foo'}})}.to_s.must_equal '<form class="forme album" method="post"><input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/><table class="foo"><caption>Artist</caption><thead><tr><th>Name</th></tr></thead><tbody><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></form>'
|
442
456
|
end
|
443
457
|
|
444
458
|
it "should have #subform :grid option handle :legend and :labels options" do
|
445
|
-
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :legend=>'Foo', :labels=>%w'Bar')}.to_s.must_equal '<form class="forme album" method="post"><
|
459
|
+
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :legend=>'Foo', :labels=>%w'Bar')}.to_s.must_equal '<form class="forme album" method="post"><input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/><table><caption>Foo</caption><thead><tr><th>Bar</th></tr></thead><tbody><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></form>'
|
446
460
|
end
|
447
461
|
|
448
462
|
it "should have #subform :grid option handle :legend and :labels nil values" do
|
449
|
-
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :legend=>nil, :labels=>nil)}.to_s.must_equal '<form class="forme album" method="post"><
|
463
|
+
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :legend=>nil, :labels=>nil)}.to_s.must_equal '<form class="forme album" method="post"><input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/><table><tbody><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></form>'
|
450
464
|
end
|
451
465
|
|
452
466
|
it "should have #subform :grid option handle :skip_primary_key option" do
|
453
467
|
Forme.form(@ab){|f| f.subform(:artist, :inputs=>[:name], :grid=>true, :skip_primary_key=>true)}.to_s.must_equal '<form class="forme album" method="post"><table><caption>Artist</caption><thead><tr><th>Name</th></tr></thead><tbody><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></form>'
|
454
468
|
end
|
455
469
|
|
470
|
+
it "should handle non-Sequel forms with Sequel inputs" do
|
471
|
+
Forme.form{|f| f.input(:name, :obj=>@ab).to_s.must_equal '<label>Name: <input id="name" maxlength="255" name="name" type="text" value="b"/></label>'}
|
472
|
+
end
|
456
473
|
end
|
457
474
|
|
458
475
|
describe "Forme Sequel plugin default input types based on column names" do
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative 'sequel_helper'
|
3
3
|
|
4
4
|
describe "Sequel forme_set plugin" do
|
5
5
|
before do
|
@@ -222,4 +222,11 @@ describe "Sequel forme_set plugin" do
|
|
222
222
|
@ab.forme_validations[:name] = [:bar, []]
|
223
223
|
proc{@ab.valid?}.must_raise Sequel::Plugins::Forme::Error
|
224
224
|
end
|
225
|
+
|
226
|
+
it "should handle frozen instances as form inputs" do
|
227
|
+
@ab.freeze
|
228
|
+
@ab.forme_inputs.must_equal({})
|
229
|
+
@ab.forme_validations.must_equal({})
|
230
|
+
@f.input(:name).must_equal '<label>Name: <input id="album_name" maxlength="255" name="album[name]" type="text"/></label>'
|
231
|
+
end
|
225
232
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module FormeErbSpecs
|
2
|
+
extend Minitest::Spec::DSL
|
3
|
+
|
4
|
+
before do
|
5
|
+
o = Object.new
|
6
|
+
def o.puts(*) end
|
7
|
+
@rack = {'rack.input'=>'', 'REQUEST_METHOD'=>'GET', 'rack.errors'=>o, 'SCRIPT_NAME'=>''}
|
8
|
+
end
|
9
|
+
|
10
|
+
it "#form should add start and end tags and yield Forme::Form instance" do
|
11
|
+
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>'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "#form should have inputs work with a block" do
|
15
|
+
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>'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "#form should have inputs with fieldset_ol wrapper work with block" do
|
19
|
+
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>'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "#form should add start and end tags and yield Forme::Form instance" do
|
23
|
+
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>'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "#form should correctly handle situation where multiple templates are used with same form object" do
|
27
|
+
sin_get('/nest_sep').sub(/ 4\z/, '4').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'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "#form should correctly handle situation Sequel integration with subforms where multiple templates are used with same form object" do
|
31
|
+
sin_get('/nest_seq_simple').sub(/ 4\z/, '4').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 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 3 </form>4'
|
32
|
+
|
33
|
+
sin_get('/nest_seq').sub(/ 4\z/, '4').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'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#form should correctly handle subform with :grid option with block" do
|
37
|
+
sin_get('/grid-block').sub(/ 4\z/, '4').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"/><table><caption>Foo</caption><thead><tr><th>Name</th></tr></thead><tbody><tr><td class="string"><input id="album_artist_attributes_name" maxlength="255" name="album[artist_attributes][name]" type="text" value="A"/></td> 2 </tr></tbody></table> 3 <input type="submit" value="Sub"/></form>4'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#form should correctly handle subform with :grid option without block" do
|
41
|
+
sin_get('/grid-noblock').sub(/ 3\z/, '3').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"/><table><caption>Foo</caption><thead><tr><th>Name</th></tr></thead><tbody><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'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "#form should correctly handle subform with :grid option without block" do
|
45
|
+
sin_get('/grid-noblock-multiple').sub(/ 3\z/, '3').sub(%r{<input name="_csrf" type="hidden" value="([^"]+)"/>}, '<input name="_csrf" type="hidden" value="csrf"/>').must_equal '0 <form action="/baz" class="forme artist" method="post"><input name="_csrf" type="hidden" value="csrf"/> 1 <input id="artist_albums_attributes_0_id" name="artist[albums_attributes][0][id]" type="hidden" value="1"/><table><caption>Foo</caption><thead><tr><th>Name</th><th>Copies</th></tr></thead><tbody><tr><td class="string"><input id="artist_albums_attributes_0_name" maxlength="255" name="artist[albums_attributes][0][name]" type="text" value="N"/></td><td class="integer"><input id="artist_albums_attributes_0_copies_sold" name="artist[albums_attributes][0][copies_sold]" type="number" value="2"/></td></tr></tbody></table> 2 <input type="submit" value="Sub"/></form>3'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "#form should accept two hashes instead of requiring obj as first argument" do
|
49
|
+
sin_get('/hash').must_equal '<form action="/baz"> <input id="first" name="first" type="text" value="foo"/> </form>'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "#form should deal with emitted code" do
|
53
|
+
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>'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "#form should work with :inputs, :button, and :legend options" do
|
57
|
+
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>'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "#form should work without a block" do
|
61
|
+
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>'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "#form should work without a block and still have hidden tags emitted" do
|
65
|
+
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>'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "#form with an empty form should work" do
|
69
|
+
sin_get('/noblock_empty').must_equal '<form action="/baz"></form>'
|
70
|
+
end
|
71
|
+
end
|
@@ -1,8 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
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 'sinatra/base'
|
8
7
|
require 'rack/csrf'
|
@@ -19,9 +18,9 @@ rescue LoadError
|
|
19
18
|
require 'erb'
|
20
19
|
end
|
21
20
|
end
|
22
|
-
|
21
|
+
require_relative '../lib/forme/erb'
|
23
22
|
class FormeSinatraTest < Sinatra::Base
|
24
|
-
helpers(Forme::
|
23
|
+
helpers(Forme::ERB::Helper)
|
25
24
|
disable :show_exceptions
|
26
25
|
enable :raise_errors
|
27
26
|
enable :sessions
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,31 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'lib'))
|
2
2
|
|
3
|
-
if ENV['WARNING']
|
4
|
-
require 'warning'
|
5
|
-
Warning.ignore([:missing_ivar, :not_reached])
|
6
|
-
end
|
7
|
-
|
8
3
|
if ENV['COVERAGE']
|
9
|
-
|
4
|
+
require_relative 'forme_coverage'
|
10
5
|
SimpleCov.forme_coverage
|
11
6
|
end
|
12
7
|
|
13
|
-
|
8
|
+
require_relative '../lib/forme'
|
14
9
|
|
15
|
-
require 'rubygems'
|
16
10
|
ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
|
17
11
|
gem 'minitest'
|
18
12
|
require 'minitest/global_expectations/autorun'
|
13
|
+
|
14
|
+
module Minitest::Spec::DSL
|
15
|
+
def silence_warnings(name, &block)
|
16
|
+
it(name) do
|
17
|
+
silence_warnings do
|
18
|
+
instance_exec(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Minitest::Spec
|
25
|
+
def silence_warnings
|
26
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
27
|
+
yield
|
28
|
+
ensure
|
29
|
+
$VERBOSE = verbose
|
30
|
+
end
|
31
|
+
end
|