forme 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7427b1117f14a93c292826f8d5d25ceacc3d8948d720176a4a5c131b40875284
4
- data.tar.gz: 8d992d583b50af76e3abf54ca3bcbd385f23bf3434d4d6bd761ee0c82ec75975
3
+ metadata.gz: 79c0b3986af69becb74de866d9027eafb1af2b148056c60963e8c8c6af04ad3d
4
+ data.tar.gz: 8478ef6951317b7a33bf7c3b2630291bcd94bb94fcbb2820ef89d08c0addfaec
5
5
  SHA512:
6
- metadata.gz: a6fab6a2f89db35fea78cfa851bc6632d8c88d56bc683ebdd5af7f674325f71ab57efa8f327c00150afc5e24cdb7a39b8e4d2a734dafe228bca1794bf5a70514
7
- data.tar.gz: fb11b777c89ac1ffdf18265ddc563d527cfd531505d23748957b233f87abd3e14ff5a52e43b335969ae41d71502e7bb5dec8fb12280bf3869ffc3159f7b688dc
6
+ metadata.gz: c63cedc392288fba47d26da036ed2ad145acf4493683600cbad71238f66fd61dfeb91cadc1db68ab2211ff3cf6cd69622f17934f9ea0be4e4006a53c2baa0a07
7
+ data.tar.gz: ef4a1d7b5bfdd0dc83d5f52b87f8dbc0785f03ccdfdb8d7e1bdfe160e85636fc2165fae7916489c8d22ba082293a64b3e0a466c67e4a4fe3a90726f4d228ffb1
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 2.5.0 (2024-02-13)
2
+
3
+ * Add hidden inputs to work with formaction/formmethod support in Roda 3.77+ route_csrf plugin (jeremyevans)
4
+
5
+ * Support :formaction option on buttons (jeremyevans)
6
+
7
+ * Support emit: false option for non-rails template forms allowing block based form use without appending to template (jeremyevans)
8
+
9
+ === 2.4.1 (2023-09-19)
10
+
11
+ * Add dependency on bigdecimal, as bigdecimal is moving from standard library to bundled gem in Ruby 3.4 (jeremyevans)
12
+
1
13
  === 2.4.0 (2023-04-05)
2
14
 
3
15
  * Support Sequel::Model#forme_use_required_abbr? to control whether to add abbr * tag for required inputs (jeremyevans) (#105)
data/README.rdoc CHANGED
@@ -800,7 +800,7 @@ For new code, it is recommended to use forme_route_csrf, as that uses Roda's rou
800
800
  plugin, which supports more secure request-specific CSRF tokens. In both cases, usage in ERB
801
801
  templates is the same:
802
802
 
803
- <% form(@obj, :action=>'/foo') do |f| %>
803
+ <% form(@obj, action: '/foo') do |f| %>
804
804
  <%= f.input(:field) %>
805
805
  <% f.tag(:fieldset) do %>
806
806
  <%= f.input(:field_two) %>
@@ -810,6 +810,8 @@ templates is the same:
810
810
  The forme_route_csrf plugin's +form+ method supports the following options
811
811
  in addition to the default +Forme.form+ options:
812
812
 
813
+ :emit :: Set to false to not emit implicit tags into template. This should only be
814
+ used if you are not modifying the template inside the block.
813
815
  :csrf :: Set to force whether a CSRF tag should be included. By default, a CSRF
814
816
  tag is included if the form's method is one of the request methods checked
815
817
  by the Roda route_csrf plugin.
@@ -818,6 +820,19 @@ in addition to the default +Forme.form+ options:
818
820
  CSRF token unless the Roda route_csrf plugin has been
819
821
  configured to support non-request specific tokens.
820
822
 
823
+ The <tt>emit: false</tt> option allows you to do:
824
+
825
+ <%= form(@obj, {action: '/foo'}, emit: false) do |f|
826
+ f.input(:field)
827
+ f.tag(:fieldset) do
828
+ f.input(:field_two)
829
+ end
830
+ end %>
831
+
832
+ This is useful if you are calling some method that calls +form+ with a block,
833
+ where the resulting entire Forme::Forme object will be literalized into the
834
+ template. The form will include the CSRF token and forme_set metadata as appropriate.
835
+
821
836
  The forme plugin does not require any csrf plugin, but will transparently use
822
837
  Rack::Csrf if it is available. If Rack::Csrf is available a CSRF tag if the form's
823
838
  method is +POST+, with no configuration ability.
@@ -856,7 +871,8 @@ It allows you to use the following API in your erb templates:
856
871
  <% end %>
857
872
 
858
873
  In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt> (this is the
859
- default in Sinatra).
874
+ default in Sinatra). The Sinatra extension also supports the <tt>emit: false</tt> option to not
875
+ directly modify the related template (see example in the Roda section for usage).
860
876
 
861
877
  = Rails Support
862
878
 
@@ -72,9 +72,9 @@ module Forme
72
72
  private
73
73
 
74
74
  def _forme_form(obj, attr, opts, &block)
75
- if block_given?
75
+ if block && opts[:emit] != false
76
76
  erb_form = buffer = offset = nil
77
- block = proc do
77
+ form_block = proc do
78
78
  wrapped_form = erb_form.instance_variable_get(:@form)
79
79
  buffer = wrapped_form.to_s
80
80
  offset = buffer.length
@@ -83,9 +83,9 @@ module Forme
83
83
  offset = buffer.length
84
84
  end
85
85
 
86
- f, attr, block = _forme_wrapped_form_class.form_args(obj, attr, opts, &block)
86
+ f, attr, form_block = _forme_wrapped_form_class.form_args(obj, attr, opts, &form_block)
87
87
  erb_form = _forme_form_class.new(f, self)
88
- erb_form.form(attr, &block)
88
+ erb_form.form(attr, &form_block)
89
89
  erb_form.emit(buffer[offset, buffer.length])
90
90
  else
91
91
  _forme_wrapped_form_class.form(obj, attr, opts, &block)
@@ -268,6 +268,12 @@ module Forme
268
268
  ret
269
269
  end
270
270
 
271
+ # Formats a submit input. Respects :formaction option.
272
+ def format_submit
273
+ copy_options_to_attributes([:formaction])
274
+ _format_input(:submit)
275
+ end
276
+
271
277
  # Formats a textarea. Respects the following options:
272
278
  # :value :: Sets value as the child of the textarea.
273
279
  def format_textarea
data/lib/forme/version.rb CHANGED
@@ -6,7 +6,7 @@ module Forme
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Forme, updated for new feature releases of Forme.
9
- MINOR = 4
9
+ MINOR = 5
10
10
 
11
11
  # The patch version of Forme, updated only for bug fixes from the last
12
12
  # feature release.
@@ -33,8 +33,8 @@ class Roda
33
33
  end
34
34
 
35
35
  module InstanceMethods
36
- def form(*)
37
- if block_given?
36
+ def _forme_form(obj, attr, opts, &block)
37
+ if block && opts[:emit] != false
38
38
  capture_erb do
39
39
  super
40
40
  instance_variable_get(render_opts[:template_opts][:outvar])
@@ -36,7 +36,7 @@ class Roda
36
36
  end
37
37
 
38
38
  if apply_csrf
39
- token = if opts.fetch(:use_request_specific_token){use_request_specific_csrf_tokens?}
39
+ token = if use_request_specific_token = opts.fetch(:use_request_specific_token){use_request_specific_csrf_tokens?}
40
40
  csrf_token(csrf_path(attr[:action]), method)
41
41
  else
42
42
  csrf_token
@@ -46,6 +46,23 @@ class Roda
46
46
  opts[:_before] = lambda do |form|
47
47
  form.tag(:input, :type=>:hidden, :name=>csrf_field, :value=>token)
48
48
  end
49
+
50
+ if use_request_specific_token && (formaction_field = csrf_options[:formaction_field])
51
+ formactions = opts[:formactions] = []
52
+ formaction_tokens = opts[:formaction_tokens] = {}
53
+ _after = opts[:_after]
54
+ opts[:formaction_csrfs] = [formaction_field, formaction_tokens]
55
+ formaction_field = csrf_options[:formaction_field]
56
+ opts[:_after] = lambda do |form|
57
+ formactions.each do |action, method|
58
+ path = csrf_path(action)
59
+ fa_token = csrf_token(path, method)
60
+ formaction_tokens[path] = fa_token
61
+ form.tag(:input, :type=>:hidden, :name=>"#{formaction_field}[#{path}]", :value=>fa_token)
62
+ end
63
+ _after.call(form) if _after
64
+ end
65
+ end
49
66
  end
50
67
  end
51
68
  end
@@ -102,7 +102,9 @@ class Roda
102
102
  def _forme_form_options(obj, attr, opts)
103
103
  super
104
104
 
105
+ _after = opts[:_after]
105
106
  opts[:_after] = lambda do |form|
107
+ _after.call(form) if _after
106
108
  if (obj = form.opts[:obj]) && obj.respond_to?(:forme_inputs) && (forme_inputs = obj.forme_inputs)
107
109
  columns = []
108
110
  valid_values = {}
@@ -129,6 +131,9 @@ class Roda
129
131
  data['columns'] = columns
130
132
  data['namespaces'] = form.opts[:namespace]
131
133
  data['csrf'] = form.opts[:csrf]
134
+ if (formactions = form.opts[:formaction_csrfs]) && !formactions[1].empty?
135
+ data['formaction_csrfs'] = formactions
136
+ end
132
137
  data['valid_values'] = valid_values unless valid_values.empty?
133
138
  data['form_version'] = form.opts[:form_version] if form.opts[:form_version]
134
139
 
@@ -154,8 +159,16 @@ class Roda
154
159
 
155
160
  data = JSON.parse(data)
156
161
  csrf_field, hmac_csrf_value = data['csrf']
162
+ formaction_csrf_field, formaction_values = data['formaction_csrfs']
163
+
157
164
  if csrf_field
158
- csrf_value = params[csrf_field].to_s
165
+ formaction_params = params[formaction_csrf_field]
166
+ if formaction_csrf_field && (formaction_params = params[formaction_csrf_field]).is_a?(Hash) && (csrf_value = formaction_params[request.path])
167
+ hmac_csrf_value = formaction_values[request.path]
168
+ else
169
+ csrf_value = params[csrf_field].to_s
170
+ end
171
+
159
172
  hmac_csrf_value = hmac_csrf_value.to_s
160
173
  unless Rack::Utils.secure_compare(csrf_value.ljust(hmac_csrf_value.length), hmac_csrf_value) && csrf_value.length == hmac_csrf_value.length
161
174
  return _forme_parse_error(:csrf_mismatch, obj)
@@ -17,6 +17,22 @@ module Sequel # :nodoc:
17
17
  # that use a <tt>Sequel::Model</tt> instance as the form's
18
18
  # +obj+.
19
19
  module SequelForm
20
+ # If the form has the :formactions option and the button has the
21
+ # formaction option or attribute, append the action and method
22
+ # for this button to the formactions. This is used by the
23
+ # Roda forme_route_csrf and forme_set plugins so that formaction
24
+ # can work as expected.
25
+ def button(opts={})
26
+ if opts.is_a?(Hash) && (formactions = self.opts[:formactions]) &&
27
+ (formaction = opts[:formaction] || ((attr = opts[:attr]) && (attr[:formaction] || attr['formaction'])))
28
+ formmethod = opts[:formmethod] ||
29
+ ((attr = opts[:attr]) && (attr[:formmethod] || attr['formmethod'])) ||
30
+ ((attr = form_tag_attributes) && (attr[:method] || attr['method']))
31
+ formactions << [formaction, formmethod]
32
+ end
33
+ super
34
+ end
35
+
20
36
  # Use the post method by default for Sequel forms, unless
21
37
  # overridden with the :method attribute.
22
38
  def form(attr={}, &block)
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.5.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: 2023-04-05 00:00:00.000000000 Z
11
+ date: 2024-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bigdecimal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -225,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
239
  - !ruby/object:Gem::Version
226
240
  version: '0'
227
241
  requirements: []
228
- rubygems_version: 3.4.10
242
+ rubygems_version: 3.5.3
229
243
  signing_key:
230
244
  specification_version: 4
231
245
  summary: HTML forms library