forme 2.2.0 → 2.3.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.
@@ -1,541 +0,0 @@
1
- require_relative 'spec_helper'
2
- require_relative 'sequel_helper'
3
- require_relative 'erb_helper'
4
-
5
- begin
6
- require 'roda'
7
- require 'tilt'
8
- rescue LoadError
9
- warn "unable to load roda or tilt, skipping roda specs"
10
- else
11
- begin
12
- require 'tilt/erubi'
13
- rescue LoadError
14
- begin
15
- require 'tilt/erubis'
16
- rescue LoadError
17
- require 'tilt/erb'
18
- end
19
- else
20
- begin
21
- require 'erubi/capture_end'
22
- require_relative 'erubi_capture_helper'
23
- rescue LoadError
24
- end
25
- end
26
-
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__"
37
- end
38
-
39
- def erb(s, opts={})
40
- render(opts.merge(:inline=>s))
41
- end
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)
51
- end
52
- end
53
- end
54
-
55
- begin
56
- require 'rack/csrf'
57
- rescue LoadError
58
- warn "unable to load rack/csrf, skipping roda csrf plugin spec"
59
- else
60
- describe "Forme Roda ERB integration with roda forme and csrf plugins" do
61
- app = FormeRodaCSRFTest = FormeRodaTest()
62
- app.plugin :csrf
63
- app.plugin :forme
64
-
65
- def sin_get(path)
66
- s = String.new
67
- FormeRodaCSRFTest.app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
68
- s.gsub(/\s+/, ' ').strip
69
- end
70
-
71
- include FormeErbSpecs
72
- end
73
- end
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
-
111
- begin
112
- require 'roda/plugins/route_csrf'
113
- require 'roda/plugins/capture_erb'
114
- require 'roda/plugins/inject_erb'
115
- rescue LoadError
116
- warn "unable to load necessary Roda plugins, skipping forme_erubi_capture plugin spec"
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
-
134
- [{}, {:require_request_specific_tokens=>false}].each do |plugin_opts|
135
- describe "Forme Roda ERB integration with roda forme_route_csrf and route_csrf plugin with #{plugin_opts}" do
136
- app = FormeRodaTest()
137
- app.plugin :forme_route_csrf
138
- app.plugin :route_csrf, plugin_opts
139
-
140
- define_method(:app){app}
141
- define_method(:plugin_opts){plugin_opts}
142
- define_method(:sin_get) do |path|
143
- s = String.new
144
- app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
145
- s.gsub(/\s+/, ' ').strip
146
- end
147
-
148
- include FormeRouteCsrfSpecs
149
- end
150
-
151
- describe "Forme Roda ERB Sequel integration with roda forme_set plugin and route_csrf plugin with #{plugin_opts}" do
152
- before do
153
- @app = FormeRodaTest()
154
- @app.plugin :route_csrf, plugin_opts
155
- @app.plugin(:forme_set, :secret=>'1'*64)
156
-
157
- @ab = Album.new
158
- end
159
-
160
- def forme_parse(*args, &block)
161
- _forme_set(:forme_parse, *args, &block)
162
- end
163
-
164
- def forme_set(*args, &block)
165
- _forme_set(:forme_set, *args, &block)
166
- end
167
-
168
- def forme_call(params)
169
- @app.call('REQUEST_METHOD'=>'POST', 'rack.input'=>StringIO.new, :params=>params)
170
- end
171
-
172
- def _forme_set(meth, obj, orig_hash, *form_args, &block)
173
- hash = {}
174
- forme_set_block = orig_hash.delete(:forme_set_block)
175
- handle_params = hash.delete(:handle_params)
176
- orig_hash.each{|k,v| hash[k.to_s] = v}
177
- album = obj
178
- ret, _, data, hmac = nil
179
-
180
- @app.route do |r|
181
- r.get do
182
- if @block = env[:block]
183
- render(:inline=>'<% form(*env[:args]) do |f| %><%= @block.call(f) %><% end %>')
184
- else
185
- form(*env[:args])
186
- end
187
- end
188
- r.post do
189
- r.params.replace(env[:params])
190
- ret = send(meth, album, &forme_set_block)
191
- nil
192
- end
193
- end
194
- body = @app.call('REQUEST_METHOD'=>'GET', :args=>[album, *form_args], :block=>block)[2].join
195
- body =~ %r|<input name="_csrf" type="hidden" value="([^"]+)"/>.*<input name="_forme_set_data" type="hidden" value="([^"]+)"/><input name="_forme_set_data_hmac" type="hidden" value="([^"]+)"/>|n
196
- csrf = $1
197
- data = $2
198
- hmac = $3
199
- data.gsub!("&quot;", '"') if data
200
- h = {"album"=>hash, "_forme_set_data"=>data, "_forme_set_data_hmac"=>hmac, "_csrf"=>csrf, "body"=>body}
201
- if data && hmac
202
- h = handle_params.call(h) if handle_params
203
- forme_call(h)
204
- end
205
- meth == :forme_parse ? ret : h
206
- end
207
-
208
- it "should have subform work correctly" do
209
- @app.route do |r|
210
- @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
211
- @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
212
- erb <<END
213
- 0
214
- <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
215
- 1
216
- <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
217
- 2
218
- <% end %>
219
- 3
220
- END
221
- end
222
-
223
- body = @app.call('REQUEST_METHOD'=>'GET')[2].join.gsub("\n", ' ').gsub(/ +/, ' ').chomp(' ')
224
- 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'
225
- end
226
-
227
- it "#forme_set should include HMAC values if form includes inputs for obj" do
228
- h = forme_set(@ab, :name=>'Foo')
229
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
230
- @ab.name.must_be_nil
231
- @ab.copies_sold.must_be_nil
232
-
233
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
234
- hmac = h.delete("_forme_set_data_hmac")
235
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
236
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))}.must_raise Roda::RodaPlugins::FormeSet::Error
237
- data = h["_forme_set_data"]
238
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
239
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
240
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac))}.must_raise Roda::RodaPlugins::FormeSet::Error
241
- @ab.name.must_equal 'Foo'
242
- @ab.copies_sold.must_be_nil
243
-
244
- forme_set(@ab, :copies_sold=>100){|f| f.input(:name)}
245
- @ab.name.must_be_nil
246
- @ab.copies_sold.must_be_nil
247
- end
248
-
249
- it "#forme_set handle missing csrf" do
250
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
251
- @ab.name = nil
252
- data = JSON.parse(h["_forme_set_data"])
253
- data.delete('csrf')
254
- data = data.to_json
255
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
256
- forme_call(h.merge("_forme_set_data_hmac"=>hmac, "_forme_set_data"=>data))
257
- @ab.name.must_equal 'Foo'
258
- @ab.copies_sold.must_be_nil
259
- end
260
-
261
- it "#forme_set should handle custom form namespaces" do
262
- forme_set(@ab, {"album"=>{"name"=>'Foo', 'copies_sold'=>'100'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}
263
- @ab.name.must_equal 'Foo'
264
- @ab.copies_sold.must_equal 100
265
-
266
- proc{forme_set(@ab, {"a"=>{"name"=>'Foo'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}}.must_raise Roda::RodaPlugins::FormeSet::Error
267
- end
268
-
269
- it "#forme_set should call plugin block if there is an error with the form submission hmac not matching data" do
270
- @app.plugin :forme_set do |error_type, _|
271
- request.on{error_type.to_s}
272
- end
273
-
274
- h = forme_set(@ab, :name=>'Foo')
275
- forme_call(h)[2].must_equal ['missing_data']
276
-
277
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
278
- hmac = h.delete("_forme_set_data_hmac")
279
- forme_call(h)[2].must_equal ['missing_hmac']
280
-
281
- forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))[2].must_equal ['hmac_mismatch']
282
-
283
- data = h["_forme_set_data"]
284
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
285
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
286
- forme_call(h.merge("_forme_set_data_hmac"=>hmac))[2].must_equal ['csrf_mismatch']
287
-
288
- h = forme_set(@ab, :name=>'Foo')
289
- h.delete('album')
290
- forme_call(h)[2].must_equal ['missing_namespace']
291
- end
292
-
293
- it "#forme_set should raise if plugin block does not raise or throw" do
294
- @app.plugin :forme_set do |_, obj|
295
- obj
296
- end
297
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
298
- h.delete("_forme_set_data_hmac")
299
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
300
- end
301
-
302
- it "#forme_set should only set values in the form" do
303
- forme_set(@ab, :name=>'Foo')
304
- @ab.name.must_be_nil
305
-
306
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
307
- @ab.name.must_equal 'Foo'
308
-
309
- forme_set(@ab, 'copies_sold'=>'1'){|f| f.input(:name)}
310
- @ab.name.must_be_nil
311
- @ab.copies_sold.must_be_nil
312
-
313
- forme_set(@ab, 'name'=>'Bar', 'copies_sold'=>'1'){|f| f.input(:name); f.input(:copies_sold)}
314
- @ab.name.must_equal 'Bar'
315
- @ab.copies_sold.must_equal 1
316
- end
317
-
318
- it "#forme_set should handle form_versions" do
319
- h = forme_set(@ab, {:name=>'Foo'}){|f| f.input(:name)}
320
- @ab.name.must_equal 'Foo'
321
-
322
- obj = nil
323
- version = nil
324
- name = nil
325
- forme_set_block = proc do |v, o|
326
- obj = o
327
- name = o.name
328
- version = v
329
- end
330
- h2 = forme_set(@ab, {:name=>'Foo', :forme_set_block=>forme_set_block}, {}, :form_version=>1){|f| f.input(:name)}
331
- obj.must_be_same_as @ab
332
- name.must_equal 'Foo'
333
- version.must_equal 1
334
-
335
- forme_call(h)
336
- obj.must_be_same_as @ab
337
- version.must_be_nil
338
-
339
- forme_set(@ab, {:name=>'Bar', :forme_set_block=>forme_set_block}, {}, :form_version=>2){|f| f.input(:name)}
340
- obj.must_be_same_as @ab
341
- name.must_equal 'Bar'
342
- version.must_equal 2
343
-
344
- h['album']['name'] = 'Baz'
345
- forme_call(h)
346
- obj.must_be_same_as @ab
347
- name.must_equal 'Baz'
348
- version.must_be_nil
349
-
350
- forme_call(h2)
351
- obj.must_be_same_as @ab
352
- version.must_equal 1
353
- end
354
-
355
- it "#forme_set should work for forms without blocks" do
356
- forme_set(@ab, {:name=>'Foo'}, {}, :inputs=>[:name])
357
- @ab.name.must_equal 'Foo'
358
- end
359
-
360
- it "#forme_set should handle different ways to specify parameter names" do
361
- [{:attr=>{:name=>'foo'}}, {:attr=>{'name'=>:foo}}, {:name=>'foo'}, {:name=>'bar[foo]'}, {:key=>:foo}].each do |opts|
362
- forme_set(@ab, name=>'Foo'){|f| f.input(:name, opts)}
363
- @ab.name.must_be_nil
364
-
365
- forme_set(@ab, 'foo'=>'Foo'){|f| f.input(:name, opts)}
366
- @ab.name.must_equal 'Foo'
367
- end
368
- end
369
-
370
- it "#forme_set should ignore values where key is explicitly set to nil" do
371
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :key=>nil)}
372
- @ab.forme_set(:name=>'Foo')
373
- @ab.name.must_be_nil
374
- @ab.forme_set(nil=>'Foo')
375
- @ab.name.must_be_nil
376
- end
377
-
378
- it "#forme_set should skip inputs with disabled/readonly formatter set on input" do
379
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
380
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>formatter)}
381
- @ab.name.must_be_nil
382
- end
383
-
384
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>:default)}
385
- @ab.name.must_equal 'Foo'
386
- end
387
-
388
- it "#forme_set should skip inputs with disabled/readonly formatter set on Form" do
389
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
390
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:disabled){|f| f.input(:name)}
391
- @ab.name.must_be_nil
392
- end
393
-
394
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.input(:name)}
395
- @ab.name.must_equal 'Foo'
396
- end
397
-
398
- it "#forme_set should skip inputs with disabled/readonly formatter set using with_opts" do
399
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
400
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>formatter){f.input(:name)}}
401
- @ab.name.must_be_nil
402
- end
403
-
404
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
405
- @ab.name.must_equal 'Foo'
406
- end
407
-
408
- it "#forme_set should prefer input formatter to with_opts formatter" do
409
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name, :formatter=>:readonly)}}
410
- @ab.name.must_be_nil
411
-
412
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:readonly){f.input(:name, :formatter=>:default)}}
413
- @ab.name.must_equal 'Foo'
414
- end
415
-
416
- it "#forme_set should prefer with_opts formatter to form formatter" do
417
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.with_opts(:formatter=>:readonly){f.input(:name)}}
418
- @ab.name.must_be_nil
419
-
420
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:readonly){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
421
- @ab.name.must_equal 'Foo'
422
- end
423
-
424
- it "#forme_set should handle setting values for associated objects" do
425
- forme_set(@ab, :artist_id=>'1')
426
- @ab.artist_id.must_be_nil
427
-
428
- forme_set(@ab, :artist_id=>'1'){|f| f.input(:artist)}
429
- @ab.artist_id.must_equal 1
430
-
431
- forme_set(@ab, 'tag_pks'=>%w'1 2'){|f| f.input(:artist)}
432
- @ab.artist_id.must_be_nil
433
- @ab.tag_pks.must_equal []
434
-
435
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist); f.input(:tags)}
436
- @ab.artist_id.must_equal 1
437
- @ab.tag_pks.must_equal [1, 2]
438
- end
439
-
440
- it "#forme_set should handle validations for filtered associations" do
441
- [
442
- [{:dataset=>proc{|ds| ds.exclude(:id=>1)}},
443
- {:dataset=>proc{|ds| ds.exclude(:id=>1)}}],
444
- [{:options=>Artist.exclude(:id=>1).select_order_map([:name, :id])},
445
- {:options=>Tag.exclude(:id=>1).select_order_map(:id), :name=>'tag_pks[]'}],
446
- [{:options=>Artist.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id},
447
- {:options=>Tag.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id}],
448
- ].each do |artist_opts, tag_opts|
449
- @ab.forme_validations.clear
450
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
451
- @ab.artist_id.must_equal 1
452
- @ab.tag_pks.must_equal [1, 2]
453
- @ab.valid?.must_equal false
454
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
455
- @ab.errors[:tag_pks].must_equal ['invalid value submitted']
456
-
457
- @ab.forme_validations.clear
458
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
459
- @ab.forme_set('artist_id'=>'1', 'tag_pks'=>['2'])
460
- @ab.artist_id.must_equal 1
461
- @ab.tag_pks.must_equal [2]
462
- @ab.valid?.must_equal false
463
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
464
- @ab.errors[:tag_pks].must_be_nil
465
-
466
- @ab.forme_validations.clear
467
- forme_set(@ab, 'artist_id'=>'2', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
468
- @ab.valid?.must_equal true
469
- end
470
- end
471
-
472
- it "#forme_set should not require associated values for many_to_one association with select boxes" do
473
- forme_set(@ab, {}){|f| f.input(:artist)}
474
- @ab.valid?.must_equal true
475
-
476
- forme_set(@ab, {'artist_id'=>nil}){|f| f.input(:artist)}
477
- @ab.valid?.must_equal true
478
-
479
- forme_set(@ab, {'artist_id'=>''}){|f| f.input(:artist)}
480
- @ab.valid?.must_equal true
481
- end
482
-
483
- it "#forme_set should not require associated values for many_to_one association with radio buttons" do
484
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio)}
485
- @ab.valid?.must_equal true
486
- end
487
-
488
- it "#forme_set should require associated values for many_to_one association with select boxes when :required is used" do
489
- forme_set(@ab, {}){|f| f.input(:artist, :required=>true)}
490
- @ab.valid?.must_equal false
491
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
492
- end
493
-
494
- it "#forme_set should require associated values for many_to_one association with radio buttons when :required is used" do
495
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio, :required=>true)}
496
- @ab.valid?.must_equal false
497
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
498
- end
499
-
500
- it "#forme_set should handle cases where currently associated values is nil" do
501
- def @ab.tag_pks; nil; end
502
- forme_set(@ab, :tag_pks=>['1']){|f| f.input(:tags)}
503
- @ab.valid?.must_equal true
504
- end
505
-
506
- it "#forme_parse should return hash with values and validations" do
507
- forme_parse(@ab, :name=>'Foo'){|f| f.input(:name)}.must_equal(:values=>{:name=>'Foo'}, :validations=>{}, :form_version=>nil)
508
-
509
- hash = forme_parse(@ab, :name=>'Foo', 'artist_id'=>'1') do |f|
510
- f.input(:name)
511
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>1)})
512
- end
513
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, false]}, :form_version=>nil)
514
-
515
- @ab.set(hash[:values])
516
- @ab.valid?.must_equal true
517
-
518
- @ab.forme_validations.merge!(hash[:validations])
519
- @ab.valid?.must_equal false
520
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
521
-
522
- @ab = Album.new
523
- hash = forme_parse(@ab, {:name=>'Foo', 'artist_id'=>'1'}, {}, :form_version=>1) do |f|
524
- f.input(:name)
525
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>2)})
526
- end
527
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, true]}, :form_version=>1)
528
- @ab.set(hash[:values])
529
- @ab.valid?.must_equal true
530
-
531
- @ab.forme_validations.merge!(hash[:validations])
532
- @ab.valid?.must_equal true
533
- end
534
-
535
- it "should handle forms with objects that don't support forme_inputs" do
536
- forme_set(String, {:name=>'Foo'}, {}, :inputs=>[:name])['body'].must_equal '<form><fieldset class="inputs"><input id="name" name="name" type="text" value="String"/></fieldset></form>'
537
- end
538
- end
539
- end
540
- end
541
- end
@@ -1,103 +0,0 @@
1
- require 'sequel'
2
-
3
- db_url = RUBY_ENGINE == 'jruby' ? 'jdbc:sqlite::memory:' : 'sqlite:/'
4
- DB = Sequel.connect(db_url, :identifier_mangling=>false)
5
- DB.extension(:freeze_datasets)
6
- Sequel.default_timezone = :utc
7
- DB.create_table(:artists) do
8
- primary_key :id
9
- String :name
10
- end
11
- DB.create_table(:albums) do
12
- primary_key :id
13
- foreign_key :artist_id, :artists
14
- String :name
15
- TrueClass :gold
16
- TrueClass :platinum, :null=>false, :default=>false
17
- Date :release_date
18
- DateTime :created_at
19
- Integer :copies_sold
20
- Float :fl
21
- BigDecimal :bd
22
- end
23
- DB.create_table(:album_infos) do
24
- primary_key :id
25
- foreign_key :album_id, :albums
26
- String :info
27
- end
28
- DB.create_table(:tracks) do
29
- primary_key :id
30
- foreign_key :album_id, :albums
31
- String :name
32
- end
33
- DB.create_table(:tags) do
34
- primary_key :id
35
- String :name
36
- end
37
- DB.create_table(:albums_tags) do
38
- foreign_key :album_id, :albums
39
- foreign_key :tag_id, :tags
40
- end
41
-
42
- a = DB[:artists].insert(:name=>'a')
43
- d = DB[:artists].insert(:name=>'d')
44
- b = DB[:albums].insert(:name=>'b', :artist_id=>a, :gold=>false, :release_date=>Date.new(2011, 6, 5), :created_at=>Date.new(2011, 6, 5), :copies_sold=>10)
45
- DB[:tracks].insert(:name=>'m', :album_id=>b)
46
- DB[:tracks].insert(:name=>'n', :album_id=>b)
47
- c = DB[:albums].insert(:name=>'c', :artist_id=>d, :gold=>true, :platinum=>true)
48
- DB[:tracks].insert(:name=>'o', :album_id=>c)
49
- s = DB[:tags].insert(:name=>'s')
50
- t = DB[:tags].insert(:name=>'t')
51
- DB[:tags].insert(:name=>'u')
52
- [[b, s], [b, t], [c, t]].each{|k, v| DB[:albums_tags].insert(k, v)}
53
-
54
- # Allow loading of pg_array extension even when not on PostgreSQL
55
- def DB.add_conversion_proc(*)
56
- super if defined?(super)
57
- end
58
- def DB.conversion_procs_updated(*)
59
- super if defined?(super)
60
- end
61
- def DB.conversion_procs
62
- return super if defined?(super)
63
- {}
64
- end
65
-
66
- Sequel::Model.plugin :forme
67
- class Album < Sequel::Model
68
- plugin :association_pks
69
- plugin :forme_set
70
-
71
- many_to_one :artist, :order=>:name
72
- one_to_one :album_info
73
- one_to_many :tracks
74
- many_to_many :tags, :delay_pks=>:always
75
-
76
- plugin :pg_array_associations
77
- pg_array_to_many :atags, :class=>:Tag
78
-
79
- def atag_ids
80
- @atag_ids ||= [1,2]
81
- end
82
-
83
- def artist_name
84
- artist.name if artist
85
- end
86
-
87
- alias foo= name=
88
-
89
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
90
- # Add workaround for no boolean handling in jdbc-sqlite3
91
- plugin :typecast_on_load, :gold, :platinum, :release_date, :created_at
92
- end
93
- end
94
- class Artist < Sequel::Model
95
- one_to_many :albums
96
- def idname() "#{id}#{name}" end
97
- def name2() "#{name}2" end
98
- def name3() "#{name}3" end
99
- end
100
- class Track < Sequel::Model; end
101
- class Tag < Sequel::Model; end
102
- class AlbumInfo < Sequel::Model; end
103
-
@@ -1,40 +0,0 @@
1
- require_relative 'sequel_helper'
2
-
3
- gem 'i18n', '>= 0.7.0'
4
- require 'i18n'
5
- I18n.load_path = [File.join(File.dirname(File.expand_path(__FILE__)), 'i18n_helper.yml')]
6
-
7
- DB.create_table(:firms) do
8
- primary_key :id
9
- String :name
10
- end
11
- DB.create_table(:invoices) do
12
- primary_key :id
13
- foreign_key :firm_id, :firms
14
- String :name
15
- String :summary
16
- end
17
- DB.create_table(:clients) do
18
- primary_key :id
19
- foreign_key :firm_id, :firms
20
- String :name
21
- end
22
-
23
- a = DB[:firms].insert(:name=>'a')
24
- DB[:invoices].insert(:name=>'b', :firm_id=>a, :summary=>'a brief summary')
25
- DB[:clients].insert(:name=>'a great client', :firm_id=>a)
26
-
27
- class Firm < Sequel::Model
28
- one_to_many :invoices
29
- one_to_many :clients
30
- end
31
-
32
- class Invoice < Sequel::Model
33
- many_to_one :firm
34
- end
35
-
36
- class Client < Sequel::Model
37
- many_to_one :firm
38
- end
39
-
40
- [Firm, Invoice, Client].each{|c| c.plugin :forme_i18n }