forme 1.12.0 → 2.2.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +54 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +228 -206
  5. data/Rakefile +1 -7
  6. data/lib/forme/bs3.rb +23 -9
  7. data/lib/forme/erb.rb +13 -25
  8. data/lib/forme/form.rb +146 -149
  9. data/lib/forme/input.rb +1 -1
  10. data/lib/forme/rails.rb +39 -83
  11. data/lib/forme/raw.rb +2 -2
  12. data/lib/forme/tag.rb +3 -12
  13. data/lib/forme/template.rb +110 -0
  14. data/lib/forme/transformers/error_handler.rb +10 -10
  15. data/lib/forme/transformers/formatter.rb +32 -34
  16. data/lib/forme/transformers/helper.rb +0 -1
  17. data/lib/forme/transformers/inputs_wrapper.rb +4 -4
  18. data/lib/forme/version.rb +2 -2
  19. data/lib/forme.rb +13 -2
  20. data/lib/roda/plugins/forme.rb +1 -1
  21. data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
  22. data/lib/roda/plugins/forme_route_csrf.rb +16 -34
  23. data/lib/roda/plugins/forme_set.rb +39 -76
  24. data/lib/sequel/plugins/forme.rb +45 -54
  25. data/lib/sequel/plugins/forme_i18n.rb +3 -1
  26. data/lib/sequel/plugins/forme_set.rb +2 -4
  27. data/spec/all.rb +1 -1
  28. data/spec/bs3_reference_spec.rb +291 -314
  29. data/spec/bs3_sequel_plugin_spec.rb +155 -155
  30. data/spec/bs3_spec.rb +247 -206
  31. data/spec/erb_helper.rb +69 -58
  32. data/spec/erubi_capture_helper.rb +198 -0
  33. data/spec/forme_coverage.rb +1 -0
  34. data/spec/forme_spec.rb +438 -377
  35. data/spec/rails_integration_spec.rb +21 -11
  36. data/spec/roda_integration_spec.rb +136 -70
  37. data/spec/sequel_helper.rb +3 -2
  38. data/spec/sequel_i18n_helper.rb +1 -1
  39. data/spec/sequel_i18n_plugin_spec.rb +6 -6
  40. data/spec/sequel_plugin_spec.rb +262 -150
  41. data/spec/sequel_set_plugin_spec.rb +9 -3
  42. data/spec/shared_erb_specs.rb +71 -0
  43. data/spec/sinatra_integration_spec.rb +31 -6
  44. data/spec/spec_helper.rb +21 -8
  45. metadata +8 -6
  46. data/lib/forme/erb_form.rb +0 -74
  47. data/lib/forme/sinatra.rb +0 -17
@@ -1,5 +1,5 @@
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
4
  describe "Sequel forme_set plugin" do
5
5
  before do
@@ -170,6 +170,12 @@ describe "Sequel forme_set plugin" do
170
170
  end
171
171
  end
172
172
 
173
+ it "#forme_set should not add validations for inputs with no options" do
174
+ @f.input(:artist, :options=>nil)
175
+ @ab.forme_set('artist_id'=>'1')
176
+ @ab.valid?.must_equal true
177
+ end
178
+
173
179
  it "#forme_set should not require associated values for many_to_one association with select boxes" do
174
180
  @f.input(:artist)
175
181
  @ab.forme_set({})
@@ -227,6 +233,6 @@ describe "Sequel forme_set plugin" do
227
233
  @ab.freeze
228
234
  @ab.forme_inputs.must_equal({})
229
235
  @ab.forme_validations.must_equal({})
230
- @f.input(:name).must_be_kind_of(Forme::Input)
236
+ @f.input(:name).must_equal '<label>Name: <input id="album_name" maxlength="255" name="album[name]" type="text"/></label>'
231
237
  end
232
238
  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" inputmode="numeric" name="artist[albums_attributes][0][copies_sold]" pattern="-?[0-9]*" type="text" 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
- 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 'sinatra/base'
8
7
  require 'rack/csrf'
@@ -19,9 +18,9 @@ rescue LoadError
19
18
  require 'erb'
20
19
  end
21
20
  end
22
- require 'forme/sinatra'
21
+ require_relative '../lib/forme/erb'
23
22
  class FormeSinatraTest < Sinatra::Base
24
- helpers(Forme::Sinatra::ERB)
23
+ helpers(Forme::ERB::Helper)
25
24
  disable :show_exceptions
26
25
  enable :raise_errors
27
26
  enable :sessions
@@ -32,6 +31,24 @@ class FormeSinatraTest < Sinatra::Base
32
31
  end
33
32
 
34
33
  instance_exec(self, &ERB_BLOCK)
34
+
35
+ get 'no-session' do
36
+ session = env.delete('rack.session')
37
+ body = erb <<END
38
+ <% form(:method=>'POST') do %>
39
+ <% end %>
40
+ END
41
+ env['rack.session'] = session
42
+ body
43
+ end
44
+
45
+ get 'no-out_buf' do
46
+ erb(<<END, :outvar=>'@_foo')
47
+ <% form(:method=>'POST') do |f| %>
48
+ <%= f.input(:text) %>
49
+ <% end %>
50
+ END
51
+ end
35
52
  end
36
53
 
37
54
  describe "Forme Sinatra ERB integration" do
@@ -42,5 +59,13 @@ describe "Forme Sinatra ERB integration" do
42
59
  end
43
60
 
44
61
  include FormeErbSpecs
62
+
63
+ it "should handle missing rack.session when using Rack::Csrf" do
64
+ sin_get('/no-session').must_equal '<form method="POST"></form>'
65
+ end
66
+
67
+ it "should handle non-standard outvar, but without emitting into template" do
68
+ sin_get('/no-out_buf').must_equal '<input type="text"/>'
69
+ end
45
70
  end
46
71
  end
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, :method_redefined])
6
- end
7
-
8
3
  if ENV['COVERAGE']
9
- require File.join(File.dirname(File.expand_path(__FILE__)), "forme_coverage")
4
+ require_relative 'forme_coverage'
10
5
  SimpleCov.forme_coverage
11
6
  end
12
7
 
13
- require 'forme'
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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-25 00:00:00.000000000 Z
11
+ date: 2022-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -172,13 +172,12 @@ files:
172
172
  - lib/forme.rb
173
173
  - lib/forme/bs3.rb
174
174
  - lib/forme/erb.rb
175
- - lib/forme/erb_form.rb
176
175
  - lib/forme/form.rb
177
176
  - lib/forme/input.rb
178
177
  - lib/forme/rails.rb
179
178
  - lib/forme/raw.rb
180
- - lib/forme/sinatra.rb
181
179
  - lib/forme/tag.rb
180
+ - lib/forme/template.rb
182
181
  - lib/forme/transformers/error_handler.rb
183
182
  - lib/forme/transformers/formatter.rb
184
183
  - lib/forme/transformers/helper.rb
@@ -188,6 +187,7 @@ files:
188
187
  - lib/forme/transformers/wrapper.rb
189
188
  - lib/forme/version.rb
190
189
  - lib/roda/plugins/forme.rb
190
+ - lib/roda/plugins/forme_erubi_capture.rb
191
191
  - lib/roda/plugins/forme_route_csrf.rb
192
192
  - lib/roda/plugins/forme_set.rb
193
193
  - lib/sequel/plugins/forme.rb
@@ -198,6 +198,7 @@ files:
198
198
  - spec/bs3_sequel_plugin_spec.rb
199
199
  - spec/bs3_spec.rb
200
200
  - spec/erb_helper.rb
201
+ - spec/erubi_capture_helper.rb
201
202
  - spec/forme_coverage.rb
202
203
  - spec/forme_spec.rb
203
204
  - spec/rails_integration_spec.rb
@@ -207,6 +208,7 @@ files:
207
208
  - spec/sequel_i18n_plugin_spec.rb
208
209
  - spec/sequel_plugin_spec.rb
209
210
  - spec/sequel_set_plugin_spec.rb
211
+ - spec/shared_erb_specs.rb
210
212
  - spec/sinatra_integration_spec.rb
211
213
  - spec/spec_helper.rb
212
214
  homepage: http://github.com/jeremyevans/forme
@@ -233,14 +235,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
235
  requirements:
234
236
  - - ">="
235
237
  - !ruby/object:Gem::Version
236
- version: '0'
238
+ version: 1.9.2
237
239
  required_rubygems_version: !ruby/object:Gem::Requirement
238
240
  requirements:
239
241
  - - ">="
240
242
  - !ruby/object:Gem::Version
241
243
  version: '0'
242
244
  requirements: []
243
- rubygems_version: 3.2.22
245
+ rubygems_version: 3.3.7
244
246
  signing_key:
245
247
  specification_version: 4
246
248
  summary: HTML forms library
@@ -1,74 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require 'forme'
4
-
5
- module Forme
6
- module ERB
7
- # Subclass used when using Forme ERB integration.
8
- # Handles integrating into the view template so that
9
- # methods with blocks can inject strings into the output.
10
- class Form < ::Forme::Form
11
- # Template output object, where serialized output gets
12
- # injected.
13
- attr_reader :output
14
-
15
- # Set the template output object when initializing.
16
- def initialize(*)
17
- super
18
- @output = @opts[:output] ? @opts[:output] : String.new
19
- end
20
-
21
- # Serialize the tag and inject it into the output.
22
- def emit(tag)
23
- output << tag.to_s
24
- end
25
-
26
- # Capture the inside of the inputs, injecting it into the template
27
- # if a block is given, or returning it as a string if not.
28
- def inputs(*a, &block)
29
- if block
30
- capture(block){super}
31
- else
32
- capture{super}
33
- end
34
- end
35
-
36
- # Capture the inside of the form, injecting it into the template if
37
- # a block is given, or returning it as a string if not.
38
- def form(*a, &block)
39
- if block
40
- capture(block){super}
41
- else
42
- super
43
- end
44
- end
45
-
46
- # If a block is given, inject an opening tag into the
47
- # output, inject any given children into the output, yield to the
48
- # block, inject a closing tag into the output.
49
- # If a block is not given, just return the tag created.
50
- def tag(type, attr={}, children=[], &block)
51
- tag = _tag(type, attr, children)
52
- if block
53
- capture(block) do
54
- emit(serialize_open(tag))
55
- Array(tag.children).each{|c| emit(c)}
56
- yield self
57
- emit(serialize_close(tag))
58
- end
59
- else
60
- tag
61
- end
62
- end
63
-
64
- def capture(block=String.new) # :nodoc:
65
- buf_was, @output = @output, block.is_a?(Proc) ? (eval("@_out_buf", block.binding) || @output) : block
66
- yield
67
- ret = @output
68
- @output = buf_was
69
- ret
70
- end
71
- end
72
- end
73
- end
74
-
data/lib/forme/sinatra.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require 'forme/erb'
4
-
5
- module Forme
6
- # For backwards compatibility only. New code should
7
- # require 'forme/erb' and include the Forme::ERB::Helper
8
- # class:
9
- #
10
- # helpers Forme::ERB::Helper
11
- module Sinatra
12
- ERB = Forme::ERB::Helper
13
- Erubis = ERB
14
- Form = Forme::ERB::Form
15
- HIDDEN_TAGS = Forme::ERB::HIDDEN_TAGS
16
- end
17
- end