forme 2.6.0 → 2.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0078a295325f1880c32a870466a7e280a0cd324e2f8bf91ea81125bf557d225
4
- data.tar.gz: 120e19dde7e39176a4693a4ab46f7f1c2f4d86265f3de4946af6a1d40f5fd524
3
+ metadata.gz: af9c688d8d8f4432cfe214dbc58332a11d57c50e9309b96ba30e7396865a19a7
4
+ data.tar.gz: 7c66b8036e5d34a78055e8ba046501f70dcab1b066bf0836548acc5219bcc5b9
5
5
  SHA512:
6
- metadata.gz: f13bb7fdfaf90be6af18cc67403d4e36f963c6258eeb49bbc4579b356534172fa4d25380f032ef7a80954f532de3a63f67e3ad3a985c0225d4d21db0245fe387
7
- data.tar.gz: 6ec1d4cbee834565239953a12b826b9b190c4f80901b6dc559954c7414889a1c0691e3a16b25dd5d2176a079ae3826a3b9e13bb6c23e323979046af98288208f
6
+ metadata.gz: aa5077f2c26acd92526dc3db78aa45c69c5c7ede218120b4eed39683bf8bf4a351b418bd8f8765fd9612e72d0e8879eab5617c9ac9d193103ff5b2c95afd17a6
7
+ data.tar.gz: b1999c8bc8ee43a1f3dc1a4601087f067750118cff71b0caf9ba0729e4b7555ffbd3f58ded0bda79f5a53c37a212e79951651e60e9f063c320f6dcda62f67237
data/CHANGELOG CHANGED
@@ -1,3 +1,19 @@
1
+ === 2.7.0 (2025-09-16)
2
+
3
+ * Omit closing / for void element tags (only used previously for xhtml compliance) (jeremyevans)
4
+
5
+ * Allow emit: false option to work correctly for non-model template forms (jeremyevans)
6
+
7
+ * Support :label_attr as an option-specific option for radioset/checkboxset options (jeremyevans)
8
+
9
+ * Allow Tag#initialize to accept a block, and treat it the same as the children argument (jeremyevans)
10
+
11
+ * Add Labeler::Explicit#id_for_input private method to allow subclasses to easily get the id (jeremyevans)
12
+
13
+ * Support Sequel::Model#forme_required_abbr_title to control the content of the title attribute for abbr tags (jeremyevans)
14
+
15
+ * Add Serializer#self_closing_tag? private method for easier overriding in subclasses (jeremyevans)
16
+
1
17
  === 2.6.0 (2024-06-18)
2
18
 
3
19
  * Add Roda forme_erubi_capture_block plugin to support erubi/capture_block <%= form do %> <% end %> tags (jeremyevans)
data/README.rdoc CHANGED
@@ -25,11 +25,11 @@ showing usage without a related object:
25
25
  This results in the following HTML:
26
26
 
27
27
  <form action="/foo">
28
- <input name="bar" type="text"/>
28
+ <input name="bar" type="text">
29
29
  <fieldset>
30
30
  <textarea name="baz"></textarea>
31
31
  </fieldset>
32
- <input type="submit" value="Update"/>
32
+ <input type="submit" value="Update">
33
33
  </form>
34
34
 
35
35
  Forme also supports forms that are associated with objects, and
@@ -46,10 +46,10 @@ This results in the following HTML:
46
46
 
47
47
  <form action="/foo" method="post">
48
48
  <label>Name:
49
- <input id="album_name" name="album[name]" type="text" value="Rising Force"/>
49
+ <input id="album_name" name="album[name]" type="text" value="Rising Force">
50
50
  </label>
51
51
  <label>Copies Sold:
52
- <input id="album_copies_sold" inputmode="numeric" name="album[copies_sold]" pattern="-?[0-9]*" type="text" value="100000"/>
52
+ <input id="album_copies_sold" inputmode="numeric" name="album[copies_sold]" pattern="-?[0-9]*" type="text" value="100000">
53
53
  </label>
54
54
  </form>
55
55
 
@@ -95,7 +95,7 @@ While not typically done, you can instantiate Forme::Form objects directly and u
95
95
  f = Forme::Form.new
96
96
  f.open(:action=>'/foo', :method=>:post) # '<form action="/foo" method="post">'
97
97
  f.input(:textarea, :value=>'foo', :name=>'bar') # '<textarea name="bar">foo</textarea>'
98
- f.input(:text, :value=>'foo', :name=>'bar') # '<input name="bar" type="text" value="foo"/>'
98
+ f.input(:text, :value=>'foo', :name=>'bar') # '<input name="bar" type="text" value="foo">'
99
99
  f.close # '</form>'
100
100
 
101
101
  With an object, <tt>Form#input</tt> calls +forme_input+ on the obj with the form, field, and options, which
@@ -104,14 +104,14 @@ should return a <tt>Forme::Input</tt> or <tt>Forme::Tag</tt> instance. Also, in
104
104
  the entire form based on the object.
105
105
 
106
106
  f = Forme::Form.new(obj)
107
- f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo"/>'
107
+ f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo">'
108
108
 
109
109
  If the object doesn't respond to +forme_input+, it falls back to creating text fields
110
110
  with the name and id set to the field name and the value set by calling the given method
111
111
  on the object (or using #[] if the object is a hash).
112
112
 
113
113
  f = Forme::Form.new([:foo])
114
- f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
114
+ f.input(:first) # '<input id="first" name="first" type="text" value="foo">'
115
115
 
116
116
  = Forme::Form Creation
117
117
 
@@ -187,25 +187,25 @@ This adds an input to the form. If the form has an associated object, and that
187
187
  object responds to +forme_input+, calls forme_input with the argument and options:
188
188
 
189
189
  f = Forme::Form.new(obj)
190
- f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo"/>'
190
+ f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo">'
191
191
 
192
192
  If the form has an associated object, and that object does not respond to +forme_input+,
193
193
  calls the method on the object (or uses [] if the object is a hash), and uses the result
194
194
  as the value for a text input:
195
195
 
196
196
  f = Forme::Form.new([:foo])
197
- f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
197
+ f.input(:first) # '<input id="first" name="first" type="text" value="foo">'
198
198
 
199
199
  If the object does not respond to +forme_input+, you can change the type of the input
200
200
  via the +:type+ option:
201
201
 
202
202
  f = Forme::Form.new(obj)
203
- f.input(:field, :type=>:email) # '<input id="obj_field" name="obj[field]" type="email" value="foo"/>'
203
+ f.input(:field, :type=>:email) # '<input id="obj_field" name="obj[field]" type="email" value="foo">'
204
204
 
205
205
  If the form does not have an associated object, the first argument is used as the input type:
206
206
 
207
207
  f = Forme::Form.new
208
- f.input(:text) # '<input type="text" />'
208
+ f.input(:text) # '<input type="text" >'
209
209
 
210
210
  The second argument is an options hash. See below for the supported input types and options.
211
211
 
@@ -226,7 +226,7 @@ Which results in a form similar to the following:
226
226
 
227
227
  <form>
228
228
  <span class="foo">
229
- <input type="text"/>
229
+ <input type="text">
230
230
  </span>
231
231
  </form>
232
232
 
@@ -238,7 +238,7 @@ so it uses a +fieldset+ by default). You can give the inputs to add as an enumer
238
238
  f.inputs([:textarea, [:text, :value=>'a']])
239
239
  # <fieldset>
240
240
  # <textarea></textarea>
241
- # <input type="text" value="a"/>
241
+ # <input type="text" value="a">
242
242
  # </fieldset>
243
243
 
244
244
  You can also provide a block:
@@ -262,17 +262,17 @@ There is also one option specific to the inputs method:
262
262
  This adds a submit input to the form:
263
263
 
264
264
  f.button
265
- # <input type="submit"/>
265
+ # <input type="submit">
266
266
 
267
267
  It can be called with a string to provide a value for the button:
268
268
 
269
269
  f.button('Search')
270
- # <input type="submit" value="Search"/>
270
+ # <input type="submit" value="Search">
271
271
 
272
272
  It can be called with a hash to provide options for the submit input:
273
273
 
274
274
  f.button(value: 'Search', class: 'btn')
275
- # <input class="btn" type="submit" value="Search"/>
275
+ # <input class="btn" type="submit" value="Search">
276
276
 
277
277
  == with_opts
278
278
 
@@ -280,12 +280,12 @@ This requires a block, and modifies the Forme::Form's options inside the block,
280
280
  restoring the options when the block returns:
281
281
 
282
282
  f.input(:text)
283
- # <input type="text"/>
283
+ # <input type="text">
284
284
 
285
285
  f.with_opts(wrapper: :li) do
286
286
  f.input(:text)
287
287
  end
288
- # <li><input type="text"/></li>
288
+ # <li><input type="text"></li>
289
289
 
290
290
  This supports most options you can provide to Forme::Form, but not all.
291
291
 
@@ -297,10 +297,10 @@ existing namespaces:
297
297
 
298
298
  Forme.form([:foo], {action: '/path'}, namespace: 'a') do |f|
299
299
  f.input(:first)
300
- # <input id="a_first" name="a[first]" type="text" value="foo"/>
300
+ # <input id="a_first" name="a[first]" type="text" value="foo">
301
301
  f.with_obj(['foobar'], 'b') do |o|
302
302
  f.input(:first, :size=>o.first.size)
303
- # <input id="a_b_first" name="a[b][first]" size="6" type="text" value="foobar"/>
303
+ # <input id="a_b_first" name="a[b][first]" size="6" type="text" value="foobar">
304
304
  end
305
305
  end
306
306
 
@@ -315,8 +315,8 @@ index of the object in the enumerable, and includes the index in the namespace:
315
315
  f.each_obj(objectlist, 'b') do |o, i|
316
316
  f.input(:first, :size=>10+i)
317
317
  end
318
- # <input id="a_b_0_first" name="a[b][0][first]" size="10" type="text" value="foobar"/>
319
- # <input id="a_b_1_first" name="a[b][1][first]" size="11" type="text" value="good"/>
318
+ # <input id="a_b_0_first" name="a[b][0][first]" size="10" type="text" value="foobar">
319
+ # <input id="a_b_1_first" name="a[b][1][first]" size="11" type="text" value="good">
320
320
  end
321
321
 
322
322
  = Sequel Support
@@ -375,16 +375,16 @@ to the current object.
375
375
  This will create a form similar to:
376
376
 
377
377
  <form action="/foo" method="post">
378
- <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
378
+ <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"></label>
379
379
  <label>Artist: <select id="album_artist_id" name="album[artist_id]">
380
380
  <option selected="selected" value="1">Elvis Presley</option>
381
381
  <option value="2">The Beatles</option>
382
382
  <option value="3">The Monkeys</option>
383
383
  </select></label>
384
384
  <span class="label">Tags:
385
- <label><input checked="checked" id="album_tag_pks_1" name="album[tag_pks][]" type="checkbox" value="1"/> Rock and Roll</label>
386
- <label><input id="album_tag_pks_2" name="album[tag_pks][]" type="checkbox" value="2"/> Blues</label>
387
- <label><input id="album_tag_pks_3" name="album[tag_pks][]" type="checkbox" value="3"/> Country</label>
385
+ <label><input checked="checked" id="album_tag_pks_1" name="album[tag_pks][]" type="checkbox" value="1"> Rock and Roll</label>
386
+ <label><input id="album_tag_pks_2" name="album[tag_pks][]" type="checkbox" value="2"> Blues</label>
387
+ <label><input id="album_tag_pks_3" name="album[tag_pks][]" type="checkbox" value="3"> Country</label>
388
388
  </span>
389
389
  </form>
390
390
 
@@ -434,22 +434,22 @@ form similar to:
434
434
 
435
435
  <form action="/foo" method="post">
436
436
 
437
- <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
437
+ <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"></label>
438
438
 
439
- <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/>
439
+ <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1">
440
440
  <fieldset class="inputs"><legend>Artist</legend>
441
- <label>Name: <input id="album_artist_attributes_name" name="album[artist_attributes][name]" type="text" value="Elvis Presley"/></label>
441
+ <label>Name: <input id="album_artist_attributes_name" name="album[artist_attributes][name]" type="text" value="Elvis Presley"></label>
442
442
  </fieldset>
443
443
 
444
- <input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/>
444
+ <input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1">
445
445
  <fieldset class="inputs"><legend>Track #1</legend>
446
- <label>Number: <input id="album_tracks_attributes_0_number" inputmode="numeric" name="album[tracks_attributes][0][number]" pattern="-?[0-9]*" type="text" value="1"/></label>
447
- <label>Name: <input id="album_tracks_attributes_0_name" name="album[tracks_attributes][0][name]" type="text" value="Blue Hawaii"/></label>
446
+ <label>Number: <input id="album_tracks_attributes_0_number" inputmode="numeric" name="album[tracks_attributes][0][number]" pattern="-?[0-9]*" type="text" value="1"></label>
447
+ <label>Name: <input id="album_tracks_attributes_0_name" name="album[tracks_attributes][0][name]" type="text" value="Blue Hawaii"></label>
448
448
  </fieldset>
449
- <input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/>
449
+ <input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2">
450
450
  <fieldset class="inputs"><legend>Track #2</legend>
451
- <label>Number: <input id="album_tracks_attributes_1_number" inputmode="numeric" name="album[tracks_attributes][1][number]" pattern="-?[0-9]*" type="text" value="2"/></label>
452
- <label>Name: <input id="album_tracks_attributes_1_name" name="album[tracks_attributes][1][name]" type="text" value="Almost Always True"/></label>
451
+ <label>Number: <input id="album_tracks_attributes_1_number" inputmode="numeric" name="album[tracks_attributes][1][number]" pattern="-?[0-9]*" type="text" value="2"></label>
452
+ <label>Name: <input id="album_tracks_attributes_1_name" name="album[tracks_attributes][1][name]" type="text" value="Almost Always True"></label>
453
453
  </fieldset>
454
454
 
455
455
  </form>
data/lib/forme/bs3.rb CHANGED
@@ -380,7 +380,7 @@ module Forme
380
380
  tag.attr[:class] = "form-control #{klass.gsub(/\s*form-control\s*/,'')}".strip
381
381
  end
382
382
 
383
- return "<#{tag.type}#{attr_html(tag.attr)}/>"
383
+ return "<#{tag.type}#{attr_html(tag.attr)}>"
384
384
 
385
385
  when :textarea, :select
386
386
  klass = tag.attr[:class] ? "form-control #{tag.attr[:class].to_s}" : ''
data/lib/forme/tag.rb CHANGED
@@ -18,9 +18,9 @@ module Forme
18
18
  attr_reader :children
19
19
 
20
20
  # Set the +form+, +type+, +attr+, and +children+.
21
- def initialize(form, type, attr={}, children=nil)
21
+ def initialize(form, type, attr={}, children=nil, &block)
22
22
  @form, @type, @attr = form, type, (attr||{})
23
- @children = parse_children(children)
23
+ @children = parse_children(children||block)
24
24
  end
25
25
 
26
26
  # Create a new +Tag+ instance with the given arguments and block
@@ -58,14 +58,14 @@ module Forme
58
58
  # using the standard ERB hidden tags.
59
59
  def form(obj=nil, attr={}, opts={}, &block)
60
60
  if obj.is_a?(Hash)
61
- attribs = obj
62
- options = attr = attr.dup
61
+ opts = attr.dup
62
+ attr = obj
63
+ obj = opts.delete(:obj)
63
64
  else
64
- attribs = attr
65
- options = opts = opts.dup
65
+ opts = opts.dup
66
66
  end
67
67
 
68
- _forme_form_options(obj, attribs, options)
68
+ _forme_form_options(obj, attr, opts)
69
69
  _forme_form(obj, attr, opts, &block)
70
70
  end
71
71
 
@@ -237,9 +237,9 @@ module Forme
237
237
  last_input = nil
238
238
  ret = process_select_optgroups(:_format_set_optgroup) do |label, value, sel, attrs|
239
239
  value = label if value.nil?
240
- label_attr = {:class=>:option}
241
- label_attr.merge!(tag_label_attr) if tag_label_attr
242
- r_opts = attrs.merge(tag_attrs).merge(:label=>label||value, :label_attr=>label_attr, :wrapper=>tag_wrapper, :labeler=>tag_labeler, :error=>nil, :error_attr=>nil)
240
+ label_attr = attrs[:label_attr] || {:class=>:option}
241
+ label_attr = label_attr.merge(tag_label_attr) if tag_label_attr
242
+ r_opts = attrs.merge(tag_attrs).merge!(:label=>label||value, :label_attr=>label_attr, :wrapper=>tag_wrapper, :labeler=>tag_labeler, :error=>nil, :error_attr=>nil, :parent=>self)
243
243
  if r_opts[:value].nil?
244
244
  r_opts[:value] = value unless value.nil?
245
245
  end
@@ -579,7 +579,7 @@ module Forme
579
579
  when String
580
580
  text = text.gsub(/\A[\r\n]+|[\r\n]+\z/, '').split(/(?:\r?\n)(?:\r?\n)+/).map do |t|
581
581
  t = Forme.h(t)
582
- t.gsub!(/\r?\n/, "<br />")
582
+ t.gsub!(/\r?\n/, "<br>")
583
583
  tag(:p, {}, Forme.raw(t))
584
584
  end
585
585
  end
@@ -50,16 +50,7 @@ module Forme
50
50
  # :label_for option is used, the label created will not be
51
51
  # associated with an input.
52
52
  def call(tag, input)
53
- unless id = input.opts[:id]
54
- if key = input.opts[:key]
55
- namespaces = input.form_opts[:namespace]
56
- id = "#{namespaces.join('_')}#{'_' unless namespaces.empty?}#{key}"
57
- if key_id = input.opts[:key_id]
58
- id += "_#{key_id.to_s}"
59
- end
60
- end
61
- end
62
-
53
+ id = id_for_input(input)
63
54
  label_attr = input.opts[:label_attr]
64
55
  label_attr = label_attr ? label_attr.dup : {}
65
56
  label_attr[:for] ||= input.opts.fetch(:label_for, id)
@@ -76,6 +67,23 @@ module Forme
76
67
 
77
68
  t
78
69
  end
70
+
71
+ private
72
+
73
+ # Determine the appropriate id for the input, to use in the for attribute
74
+ def id_for_input(input)
75
+ unless id = input.opts[:id]
76
+ if key = input.opts[:key]
77
+ namespaces = input.form_opts[:namespace]
78
+ id = "#{namespaces.join('_')}#{'_' unless namespaces.empty?}#{key}"
79
+ if key_id = input.opts[:key_id]
80
+ id += "_#{key_id.to_s}"
81
+ end
82
+ end
83
+ end
84
+
85
+ id
86
+ end
79
87
  end
80
88
 
81
89
  class Labeler::Span
@@ -19,8 +19,8 @@ module Forme
19
19
  def call(tag)
20
20
  case tag
21
21
  when Tag
22
- if SELF_CLOSING.include?(tag.type)
23
- "<#{tag.type}#{attr_html(tag.attr)}/>"
22
+ if self_closing_tag?(tag.type)
23
+ "<#{tag.type}#{attr_html(tag.attr)}>"
24
24
  else
25
25
  "#{serialize_open(tag)}#{call(tag.children)}#{serialize_close(tag)}"
26
26
  end
@@ -79,6 +79,12 @@ module Forme
79
79
  attr = attr.to_a.reject{|k,v| v.nil?}
80
80
  " #{attr.map{|k, v| "#{k}=\"#{attr_value(v)}\""}.sort.join(' ')}" unless attr.empty?
81
81
  end
82
+
83
+ # Return whether the tag is self closing. this can be overridden in subclasses
84
+ # to make additional types self closing.
85
+ def self_closing_tag?(type)
86
+ SELF_CLOSING.include?(type)
87
+ end
82
88
  end
83
89
 
84
90
  # Overrides formatting of dates and times to use an American format without
@@ -94,7 +100,7 @@ module Forme
94
100
  attr.delete(:type)
95
101
  attr.delete('type')
96
102
  attr['type'] = 'text'
97
- "<#{tag.type}#{attr_html(attr)}/>"
103
+ "<#{tag.type}#{attr_html(attr)}>"
98
104
  else
99
105
  super
100
106
  end
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 = 6
9
+ MINOR = 7
10
10
 
11
11
  # The patch version of Forme, updated only for bug fixes from the last
12
12
  # feature release.
@@ -223,7 +223,7 @@ module Sequel # :nodoc:
223
223
  # is required.
224
224
  def handle_label(f)
225
225
  opts[:label] = humanize(field) unless opts.has_key?(:label)
226
- opts[:label] = [opts[:label], form._tag(:abbr, {:title=>'required'}, '*')] if opts[:label] && opts[:required] && obj.forme_use_required_abbr?
226
+ opts[:label] = [opts[:label], form._tag(:abbr, {:title=>obj.forme_required_abbr_title}, '*')] if opts[:label] && opts[:required] && obj.forme_use_required_abbr?
227
227
  end
228
228
 
229
229
  # Update the attributes and options for any recognized validations
@@ -508,6 +508,11 @@ module Sequel # :nodoc:
508
508
  'post'
509
509
  end
510
510
 
511
+ # The content of the title attribute of the abbr tag included in labels that are required.
512
+ def forme_required_abbr_title
513
+ 'required'
514
+ end
515
+
511
516
  # Whether to set an abbr tag in labels for required inputs.
512
517
  def forme_use_required_abbr?
513
518
  true
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-06-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bigdecimal
@@ -176,9 +175,9 @@ email: code@jeremyevans.net
176
175
  executables: []
177
176
  extensions: []
178
177
  extra_rdoc_files:
179
- - README.rdoc
180
178
  - CHANGELOG
181
179
  - MIT-LICENSE
180
+ - README.rdoc
182
181
  files:
183
182
  - CHANGELOG
184
183
  - MIT-LICENSE
@@ -218,7 +217,6 @@ metadata:
218
217
  documentation_uri: http://forme.jeremyevans.net
219
218
  mailing_list_uri: https://github.com/jeremyevans/forme/discussions
220
219
  source_code_uri: https://github.com/jeremyevans/forme
221
- post_install_message:
222
220
  rdoc_options:
223
221
  - "--quiet"
224
222
  - "--line-numbers"
@@ -240,8 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
240
238
  - !ruby/object:Gem::Version
241
239
  version: '0'
242
240
  requirements: []
243
- rubygems_version: 3.5.9
244
- signing_key:
241
+ rubygems_version: 3.6.9
245
242
  specification_version: 4
246
243
  summary: HTML forms library
247
244
  test_files: []