forme 1.11.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +54 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +235 -209
  5. data/Rakefile +1 -7
  6. data/lib/forme/bs3.rb +18 -4
  7. data/lib/forme/erb.rb +13 -25
  8. data/lib/forme/form.rb +144 -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/formatter.rb +4 -1
  15. data/lib/forme/transformers/helper.rb +0 -1
  16. data/lib/forme/transformers/inputs_wrapper.rb +4 -4
  17. data/lib/forme/version.rb +2 -2
  18. data/lib/forme.rb +15 -2
  19. data/lib/roda/plugins/forme.rb +1 -1
  20. data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
  21. data/lib/roda/plugins/forme_route_csrf.rb +16 -34
  22. data/lib/roda/plugins/forme_set.rb +39 -76
  23. data/lib/sequel/plugins/forme.rb +40 -50
  24. data/lib/sequel/plugins/forme_i18n.rb +3 -1
  25. data/lib/sequel/plugins/forme_set.rb +3 -1
  26. data/spec/all.rb +1 -1
  27. data/spec/bs3_reference_spec.rb +18 -18
  28. data/spec/bs3_sequel_plugin_spec.rb +17 -17
  29. data/spec/bs3_spec.rb +23 -11
  30. data/spec/erb_helper.rb +69 -58
  31. data/spec/erubi_capture_helper.rb +198 -0
  32. data/spec/forme_spec.rb +21 -32
  33. data/spec/rails_integration_spec.rb +39 -25
  34. data/spec/roda_integration_spec.rb +118 -70
  35. data/spec/sequel_helper.rb +0 -1
  36. data/spec/sequel_i18n_helper.rb +1 -1
  37. data/spec/sequel_i18n_plugin_spec.rb +3 -2
  38. data/spec/sequel_plugin_spec.rb +29 -12
  39. data/spec/sequel_set_plugin_spec.rb +9 -2
  40. data/spec/shared_erb_specs.rb +71 -0
  41. data/spec/sinatra_integration_spec.rb +5 -6
  42. data/spec/spec_helper.rb +21 -8
  43. metadata +9 -7
  44. data/lib/forme/erb_form.rb +0 -74
  45. data/lib/forme/sinatra.rb +0 -17
data/README.rdoc CHANGED
@@ -6,91 +6,75 @@ Forme is a HTML forms library for ruby with the following goals:
6
6
  2. Have a simple API
7
7
  3. Support forms both with and without related objects
8
8
  4. Allow compiling down to different types of output
9
+ 5. Integrate easily into web frameworks
9
10
 
10
11
  = Introduction
11
12
 
12
13
  Forme is designed to make creating HTML forms easier. Flexibility and
13
- simplicity are primary objectives. The basic usage involves creating
14
- a <tt>Forme::Form</tt> instance, and calling +input+ and +tag+ methods
15
- to return html strings for widgets, but it could also be used for
16
- serializing to other formats, or even as a DSL for a GUI application.
14
+ ease of use are the primary objectives. Here's a basic example,
15
+ showing usage without a related object:
17
16
 
18
- In order to be flexible, Forme stores tags in abstract form until
19
- output is requested. There are two separate abstract <i>forms</i> that Forme
20
- uses. One is <tt>Forme::Input</tt>, and the other is <tt>Forme::Tag</tt>.
21
- <tt>Forme::Input</tt> is a high level abstract form, while <tt>Forme::Tag</tt>
22
- is a low level abstract form.
23
-
24
- The difference between <tt>Forme::Input</tt> and <tt>Forme::Tag</tt>
25
- is that <tt>Forme::Tag</tt> directly represents the underlying html
26
- tag, containing a type, optional attributes, and children, while the
27
- <tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
28
- For example, these both compile by default to the same select tag:
17
+ Forme.form({:action=>'/foo'}) do |f|
18
+ f.input(:text, :name=>'bar')
19
+ f.tag(:fieldset) do
20
+ f.input(:textarea, :name=>'baz')
21
+ end
22
+ f.button('Update')
23
+ end
29
24
 
30
- f.input(:select, :options=>[['foo', 1]])
31
- # or
32
- f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
25
+ This results in the following HTML:
33
26
 
34
- The processing of high level <tt>Forme::Input</tt>s into raw html
35
- data is broken down to the following steps (called transformers):
27
+ <form action="/foo">
28
+ <input name="bar" type="text"/>
29
+ <fieldset>
30
+ <textarea name="baz"></textarea>
31
+ </fieldset>
32
+ <input type="submit" value="Update"/>
33
+ </form>
36
34
 
37
- +Formatter+ :: converts a <tt>Forme::Input</tt> instance into a
38
- <tt>Forme::Tag</tt> instance (or array of them).
39
- +ErrorHandler+ :: If the <tt>Forme::Input</tt> instance has a error,
40
- takes the formatted tag and marks it as having the error.
41
- +Helper+ :: If the <tt>Forme::Input</tt> instance has any help text,
42
- adds the help text in a separate tag.
43
- +Labeler+ :: If the <tt>Forme::Input</tt> instance has a label,
44
- takes the formatted output and labels it.
45
- +Wrapper+ :: Takes the output of the formatter, labeler, and
46
- error_handler transformers, and wraps it in another tag (or just
47
- returns it unmodified).
48
- +Serializer+ :: converts a <tt>Forme::Tag</tt> instance into an
49
- html string.
50
-
51
- Technically, only the +Serializer+ is necessary. The <tt>Forme::Form#input</tt>
52
- and <tt>Forme::Form#tag</tt> methods return +Input+ and +Tag+ objects. These objects
53
- both have +to_s+ defined to call the appropriate +Serializer+ with
54
- themselves. The +Serializer+ calls the appropriate +Formatter+ if
55
- it encounters an +Input+ instance, and attempts to serialize the
56
- output of that (which is usually a +Tag+ instance). It is up to
57
- the +Formatter+ to call the +Labeler+, +ErrorHandler+, +Helper+,
58
- and/or +Wrapper+.
59
-
60
- The <tt>Forme::Form</tt> object takes the 6 transformers as options (:formatter,
61
- :labeler, :error_handler, :helper, :wrapper, :inputs_wrapper, and :serializer), all of which
62
- should be objects responding to +call+ (so you can use +Proc+s) or be symbols
63
- registered with the library using <tt>Forme.register_transformer</tt>:
35
+ Forme also supports forms that are associated with objects, and
36
+ has specific support for Sequel::Model objects to allow easily building
37
+ forms for such objects. The Sequel support handles inputs based on
38
+ database columns, and automatically handles labels and errors:
64
39
 
65
- Forme.register_transformer(:wrapper, :p) do |tag, input|
66
- input.tag(:p, {}, tag)
40
+ Forme.form(Album[1], action: '/foo') do |f|
41
+ f.input :name
42
+ f.input :copies_sold
67
43
  end
68
44
 
69
- Most transformers are called with two arguments, +tag+ and +input+. +tag+
70
- is a <tt>Forme::Tag</tt> instance, and +input+ is a <tt>Forme::Input</tt>
71
- instance. The +Formatter+ and +Serializer+ transformers are the two
72
- exceptions, with +Formatter+ being called with just an +input+, and
73
- +Serializer+ potentionally being called with any object. The +Serializer+
74
- will in general recursively call itself with children of the argument
75
- given.
76
-
77
- There is also an +InputsWrapper+ transformer, that is called by
78
- <tt>Forme::Form#inputs</tt>. It's used to wrap up a group of
79
- related options (in a fieldset by default). It takes +form+
80
- (<tt>Forme::Form</tt> instance) and +input_opts+ (+Hash+) arguments.
45
+ This results in the following HTML:
81
46
 
82
- Most of the transformers can be overridden on a per instance basis by
83
- passing the appropriate option to +input+ or +inputs+:
84
-
85
- f.input(:name, :wrapper=>:p)
47
+ <form action="/foo" method="post">
48
+ <label>Name:
49
+ <input id="album_name" name="album[name]" type="text" value="Rising Force"/>
50
+ </label>
51
+ <label>Copies Sold:
52
+ <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/>
53
+ </label>
54
+ </form>
86
55
 
87
- Existing transformers can be easily extended (ie, to set the class attribute),
88
- by creating your own transformer and then calling the existing transformer.
56
+ In addition to integrating with Sequel, Form also integrates into
57
+ three separate web frameworks, Roda, Rails, and Sinatra, allowing
58
+ use of forms inside templates. This is the most common usage of Forme.
59
+
60
+ One distinct advantage of Forme over other form libraries is the use
61
+ of an abstract syntax tree internally, allowing the same form code to
62
+ compile to different HTML with different options. For example, it
63
+ allows using the exactly same form code to display a form you can modify
64
+ as well as a read-only view, just by passing a single option when
65
+ creating the form. For example, with the first example in this section,
66
+ if you pass the <tt>formatter: :readonly</tt> option, you get the
67
+ following HTML instead:
68
+
69
+ <form action="/foo">
70
+ <span class="readonly-text"></span>
71
+ <fieldset>
72
+ <div class="readonly-textarea"></div>
73
+ </fieldset>
74
+ </form>
89
75
 
90
- Forme.register_transformer(:labeler, :explicit) do |tag, input|
91
- input.opts[:label_attr] ||= { :class => 'label' }
92
- Forme::Labeler::Explicit.new.call(tag, input)
93
- end
76
+ This allows you to reuse the same form code in multiple contexts,
77
+ which can save considerable development time.
94
78
 
95
79
  = Installation
96
80
 
@@ -101,13 +85,12 @@ by creating your own transformer and then calling the existing transformer.
101
85
  Demo Site :: http://forme-demo.jeremyevans.net
102
86
  RDoc :: http://forme.jeremyevans.net
103
87
  Source :: https://github.com/jeremyevans/forme
104
- IRC :: irc://irc.freenode.net/forme
105
- Google Group :: https://groups.google.com/forum/#!forum/ruby-forme
88
+ Discussion Forum :: https://github.com/jeremyevans/forme/discussions
106
89
  Bug Tracker :: https://github.com/jeremyevans/forme/issues
107
90
 
108
- = Basic Usage
91
+ = Direct Instantiation
109
92
 
110
- Without an object, Forme is a simple form builder:
93
+ While not typically done, you can instantiate Forme::Form objects directly and use them:
111
94
 
112
95
  f = Forme::Form.new
113
96
  f.open(:action=>'/foo', :method=>:post) # '<form action="/foo" method="post">'
@@ -130,47 +113,11 @@ on the object (or using #[] if the object is a hash).
130
113
  f = Forme::Form.new([:foo])
131
114
  f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
132
115
 
133
- = DSL
134
-
135
- Forme comes with a DSL:
136
-
137
- Forme.form(:action=>'/foo') do |f|
138
- f.input(:text, :name=>'bar')
139
- f.tag(:fieldset) do
140
- f.input(:textarea, :name=>'baz')
141
- end
142
- f.button('Update')
143
- end
144
- # <form action="/foo">
145
- # <input name="bar" type="text"/>
146
- # <fieldset>
147
- # <textarea name="baz"></textarea>
148
- # </fieldset>
149
- # <input type="submit" value="Update"/>
150
- # </form>
151
-
152
- You can wrap up multiple inputs with the <tt>:inputs</tt> method:
153
-
154
- Forme.form(:action=>'/foo') do |f|
155
- f.inputs([[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
156
- end
157
- # <form action="/foo">
158
- # <fieldset class="inputs">
159
- # <input name="bar" type="text"/>
160
- # <textarea name="baz"></textarea>
161
- # </fieldset>
162
- # </form>
163
-
164
- You can even do everything in a single method call:
165
-
166
- Forme.form({:action=>'/foo'},
167
- :inputs=>[[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
168
-
169
116
  = Forme::Form Creation
170
117
 
171
- As shown above, the general way to create Forme::Form instances is via the Forme.form method.
172
- This method takes up to 3 arguments, and yields the Forme::Form object to the block (if given).
173
- Here are the argument styles that you can use for Forme.form.
118
+ +Forme.form+ takes up to 3 arguments, and yields the Forme::Form
119
+ object to the block (if given). Here are the argument styles that you can
120
+ use for +Forme.form+.
174
121
 
175
122
  No args :: Creates a +Form+ object with no options and not associated
176
123
  to an +obj+, and with no attributes in the opening tag.
@@ -190,21 +137,21 @@ Examples:
190
137
  Forme.form
191
138
 
192
139
  # 1 hash argument (attributes)
193
- Forme.form(:action=>'/foo')
140
+ Forme.form(action: '/foo')
194
141
 
195
142
  # 1 non-hash argument (a reference object used when building the form)
196
143
  Forme.form(Album[1])
197
144
 
198
145
  # 2 hash arguments (attributes, and options)
199
- Forme.form({:action=>'/foo'}, :values=>params)
146
+ Forme.form({action: '/foo'}, values: params)
200
147
 
201
148
  # 1 non-hash argument, 1-2 hash arguments (ref obj, attributes, options)
202
- Forme.form(Album[1], :action=>'/foo')
203
- Forme.form(Album[1], {:action=>'/foo'}, :values=>params)
149
+ Forme.form(Album[1], action: '/foo')
150
+ Forme.form(Album[1], {action: '/foo'}, values: params)
204
151
 
205
152
  If you want a Forme::Form instance where the reference object is a Hash, then you need to pass the hash object using the :obj option:
206
153
 
207
- Forme.form({:action=>'/foo'}, :obj=>{:foo=>'bar'})
154
+ Forme.form({action: '/foo'}, obj: {foo: 'bar'})
208
155
 
209
156
  You can also create Forme::Form objects the normal ruby way using Forme::Form#new. The
210
157
  difference between Forme::Form#new and Forme.form is that Forme.form includes the enclosing
@@ -215,13 +162,13 @@ a hash of <form> tag attributes, so it has the following API:
215
162
  Forme::Form.new
216
163
 
217
164
  # 1 hash argument
218
- Forme::Form.new(:values=>params)
165
+ Forme::Form.new(values: params)
219
166
 
220
167
  # 1 non-hash argument
221
168
  Forme::Form.new(Album[1])
222
169
 
223
170
  # 1 non-hash argument, 1-2 hash arguments
224
- Forme::Form.new(Album[1], :values=>params)
171
+ Forme::Form.new(Album[1], values: params)
225
172
 
226
173
  = Forme::Form Methods
227
174
 
@@ -230,9 +177,9 @@ a hash of <form> tag attributes, so it has the following API:
230
177
  If you create a Form via Forme::Forme#new, you can use the form method to create a form tag:
231
178
 
232
179
  f = Forme::Form.new
233
- f.form(:action=>'/foo')
180
+ f.form(action: '/foo')
234
181
 
235
- This is what Forme.form uses internally to create the <form> tag
182
+ This is what Forme.form uses internally to create the +<form>+ tag
236
183
 
237
184
  == input
238
185
 
@@ -285,8 +232,8 @@ Which results in a form similar to the following:
285
232
 
286
233
  == inputs
287
234
 
288
- This wraps multiple inputs in a tag (it uses the inputs_wrapper transformer discussed below,
289
- so it uses a fieldset by default). You can give the inputs to add as an enumerable argument:
235
+ This wraps multiple inputs in a tag (it uses the +:inputs_wrapper+ transformer discussed below,
236
+ so it uses a +fieldset+ by default). You can give the inputs to add as an enumerable argument:
290
237
 
291
238
  f.inputs([:textarea, [:text, :value=>'a']])
292
239
  # <fieldset>
@@ -300,13 +247,13 @@ You can also provide a block:
300
247
  f.input(:text, :value=>'a')
301
248
  end
302
249
 
303
- Any options given are passed to the inputs_wrapper (so you can use options such as :legend
304
- to set a legend for the fieldset), and also to the the with_opts (so you can use options
305
- such as :wrapper to modify the default wrapper transformer for inputs inside the block).
250
+ Any options given are passed to the +inputs_wrapper+ (so you can use options such as +:legend+
251
+ to set a legend for the fieldset), and also to the +with_opts+ method (so you can use options
252
+ such as +:wrapper+ to modify the default wrapper transformer for inputs inside the block).
306
253
  There is also one option specific to the inputs method:
307
254
 
308
255
  :nested_inputs_wrapper :: Sets the default inputs_wrapper to use for calls to inputs inside
309
- the block. The reason for this option is that :inputs_wrapper
256
+ the block. The reason for this option is that +:inputs_wrapper+
310
257
  option affects the current call to inputs, so if you want to
311
258
  use a different inputs_wrapper for nested calls, you need this option.
312
259
 
@@ -324,30 +271,31 @@ It can be called with a string to provide a value for the button:
324
271
 
325
272
  It can be called with a hash to provide options for the submit input:
326
273
 
327
- f.button(:value=>'Search', :class=>'btn')
274
+ f.button(value: 'Search', class: 'btn')
328
275
  # <input class="btn" type="submit" value="Search"/>
329
276
 
330
277
  == with_opts
331
278
 
332
- This requires a block, and modifies the Form's options inside the block,
279
+ This requires a block, and modifies the Forme::Form's options inside the block,
333
280
  restoring the options when the block returns:
334
281
 
335
282
  f.input(:text)
336
283
  # <input type="text"/>
337
- f.with_opts(:wrapper=>:li) do
284
+
285
+ f.with_opts(wrapper: :li) do
338
286
  f.input(:text)
339
287
  end
340
288
  # <li><input type="text"/></li>
341
289
 
342
- This supports most options you can provide to the Form, but not all.
290
+ This supports most options you can provide to Forme::Form, but not all.
343
291
 
344
292
  == with_obj
345
293
 
346
- This uses with_opts to change the Form's object temporarily, but it
294
+ This uses +with_opts+ to change the Forme::Form object temporarily. It
347
295
  yields the object to the block, and also supports appending to the
348
296
  existing namespaces:
349
297
 
350
- Forme.form([:foo], :namespace=>'a') do |f|
298
+ Forme.form([:foo], {action: '/path'}, namespace: 'a') do |f|
351
299
  f.input(:first)
352
300
  # <input id="a_first" name="a[first]" type="text" value="foo"/>
353
301
  f.with_obj(['foobar'], 'b') do |o|
@@ -358,11 +306,11 @@ existing namespaces:
358
306
 
359
307
  == each_obj
360
308
 
361
- This allows you to provide an object-yielding enumerable. Forme will call with_obj with
362
- each object in the enumerable. It yields each object as well as the index of the
363
- object in the enumerable, and includes the index in the namespace:
309
+ This allows you to provide an object-yielding enumerable. +each_object+ will call
310
+ +with_obj+ with each object in the enumerable. It yields each object as well as the
311
+ index of the object in the enumerable, and includes the index in the namespace:
364
312
 
365
- objectlist = ['foobar', ['good']]
313
+ objectlist = [['foobar'], ['good']]
366
314
  Forme.form([:foo], :namespace=>'a') do |f|
367
315
  f.each_obj(objectlist, 'b') do |o, i|
368
316
  f.input(:first, :size=>10+i)
@@ -377,7 +325,7 @@ Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to en
377
325
  Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
378
326
  An additional instance method, +forme_namespace+ can optionally be defined to customize how model classnames
379
327
  are transformed into form classes and input IDs and names. This can be useful if your Sequel::Model classes
380
- are nested under a parent namespace. It falls back to the behaviour of Sequel::Model#underscore.
328
+ are nested under a parent namespace. The default namespace uses Sequel::Model#underscore.
381
329
 
382
330
  module Admin
383
331
  class Albums < Sequel::Model
@@ -387,27 +335,11 @@ are nested under a parent namespace. It falls back to the behaviour of Sequel::M
387
335
  end
388
336
  end
389
337
 
390
- == Basics
391
-
392
- The Sequel support handles inputs based on database columns, and automatically handles labels and errors.
393
-
394
- Forme.form(Album[1], :action=>'/foo') do |f|
395
- f.input :name
396
- f.input :copies_sold
397
- end
398
-
399
- This will create a form similar to:
400
-
401
- <form action="/foo" method="post">
402
- <label>Name: <input id="album_name" name="album[name]" type="text" value="Rising Force"/></label>
403
- <label>Copies Sold: <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/></label>
404
- </form>
405
-
406
- The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
407
- +validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
338
+ The Sequel :forme plugin also integerates with Sequel's validation reflection support that comes with the
339
+ Sequel validation_class_methods plugin. It will add +pattern+ and +maxlength+ attributes
408
340
  based on the format, numericality, and length validations.
409
341
 
410
- == specialized input options
342
+ == Specialized input options for specific column types
411
343
 
412
344
  In addition to the default Forme options, the Sequel support includes, for specific column types,
413
345
  these additional options to the #input method:
@@ -569,7 +501,7 @@ One way to handle the form submission is to use Sequel::Model#set_fields.
569
501
  Note that you have to specify the parameter names again as the second argument to
570
502
  set_fields.
571
503
 
572
- Handling Submitted parameters becomes more complex as your forms become more complex.
504
+ Handling submitted parameters becomes more complex as your forms become more complex.
573
505
  For example, if you are only displaying certain form fields in certain situations:
574
506
 
575
507
  album = Album[1]
@@ -589,9 +521,9 @@ As you can see, you basically need to recreate the conditionals used when creati
589
521
  the form, so that that the processing of the form submission handles only the
590
522
  inputs that were displayed on the form.
591
523
 
592
- === forme_set Sequel plugin
524
+ === Sequel forme_set plugin
593
525
 
594
- The forme_set plugin is designed to make handling form submissions easier. What it does
526
+ The Sequel forme_set plugin is designed to make handling form submissions easier. What it does
595
527
  is record the form fields that are used on the object, and then it uses those fields
596
528
  to handle input submitted for the object. For example:
597
529
 
@@ -670,12 +602,12 @@ this is specific to the web framework you are using, but is it similar to:
670
602
 
671
603
  forme_set is not perfect, there are ways to use Forme that forme_set will not handle
672
604
  correctly. First, forme_set only works with forms that use model objects, and doesn't
673
- handle inputs where the :obj option is provided to change the input.
605
+ handle inputs where the +:obj+ option is provided to change the input.
674
606
  Additionally, forme_set does not currently handle subform/nested_attributes.
675
607
 
676
- In cases where forme_set does not handle things correctly, you can use forme_parse,
677
- which will return metadata that forme_set uses (forme_set calls forme_parse
678
- internally). forme_parse returns a hash with the following keys:
608
+ In cases where forme_set does not handle things correctly, you can use +forme_parse+,
609
+ which will return metadata that +forme_set+ uses (+forme_set+ calls +forme_parse+
610
+ internally). +forme_parse+ returns a hash with the following keys:
679
611
 
680
612
  :values :: A hash of values that can be used to update the model, suitable for passing
681
613
  to Sequel::Model#set.
@@ -683,21 +615,21 @@ internally). forme_parse returns a hash with the following keys:
683
615
  check that the submitted values for associated objects match one of the
684
616
  options for the input in the form.
685
617
 
686
- It is possible to use forme_set for the values it can handle, and set other fields manually
687
- using set_fields.
618
+ It is possible to use +forme_set+ for the values it can handle, and set other fields manually
619
+ using +set_fields+.
688
620
 
689
- === forme_set Roda plugin
621
+ === Roda forme_set plugin
690
622
 
691
- The forme_set Roda plugin builds on the forme_set Sequel plugin and is designed to make
692
- handling form submissions even easier. This plugin uses a hidden form input to store which
693
- fields were used to build the form, as well as some other metadata. It uses another hidden
623
+ The Roda forme_set plugin builds on the Sequel forme_set plugin and is designed to make
624
+ handling form submissions even easier. This plugin adds a hidden form input to store which
625
+ fields were used to build the form, as well as some other metadata. It adds another hidden
694
626
  form input with an HMAC, so that on submission, if the HMAC matches, you can be sure that an
695
627
  attacker didn't add extra fields.
696
628
 
697
629
  There are a couple advantages to this plugin over using just the Sequel forme_set plugin.
698
630
  One is that you do not need to record the form fields when processing the submission of a
699
631
  form, since the information you need is included in the form submission. Another is that
700
- calling the forme_set method is simpler, since it can determine the necessary parameters.
632
+ calling the +forme_set+ method is simpler, since it can determine the necessary parameters.
701
633
 
702
634
  While you need code like this when using just the Sequel forme_set plugin:
703
635
 
@@ -824,20 +756,20 @@ plugin to handle form submissions involving multiple objects, or for the
824
756
  objects that were not passed when creating the form.
825
757
 
826
758
  Second, the Roda forme_set plugin does not handle cases where the field values
827
- are placed outside the forms default namespace. The Sequel forme_set plugin
759
+ are placed outside the form's default namespace. The Sequel forme_set plugin
828
760
  can handle those issues, as long as all values are in the same namespace, since
829
761
  the Sequel forme_set plugin requires you pass in the specific hash to use (the
830
- Roda forme_set plugin use the form's namespace information and the submitted
762
+ Roda forme_set plugin uses the form's namespace information and the submitted
831
763
  parameters to determine the hash to use).
832
764
 
833
765
  In cases where the Roda forme_set does not handle things correctly, you can use
834
766
  forme_parse, which will return metadata in the same format as the Sequel plugin
835
- forme_parse method, with the addition of a :form_version key in the hash for the
767
+ forme_parse method, with the addition of a +:form_version+ key in the hash for the
836
768
  form version.
837
769
 
838
770
  It is possible to use the Roda forme_set plugin for the submissions it can handle, the
839
771
  Sequel forme_set plugin for the submissions it can handle, and set other fields manually
840
- using the Sequel set_fields methods.
772
+ using the Sequel +set_fields+ methods.
841
773
 
842
774
  Note that when using the Roda forme_set plugin with an existing form, you should first
843
775
  enable the Roda plugin without actually using the Roda forme_set method. Do not
@@ -855,7 +787,15 @@ forme_i18n :: Handles translations for labels using i18n.
855
787
 
856
788
  = Roda Support
857
789
 
858
- Forme ships with three Roda plugins: forme_set (discussed above), forme, and forme_route_csrf.
790
+ Forme ships with multiple Roda plugins
791
+
792
+ * forme_set (discussed above)
793
+ * forme
794
+ * forme_route_csrf
795
+ * forme_erubi_capture
796
+
797
+ == forme_route_csrf and forme plugins
798
+
859
799
  For new code, it is recommended to use forme_route_csrf, as that uses Roda's route_csrf
860
800
  plugin, which supports more secure request-specific CSRF tokens. In both cases, usage in ERB
861
801
  templates is the same:
@@ -882,14 +822,29 @@ The forme plugin does not require any csrf plugin, but will transparently use
882
822
  Rack::Csrf if it is available. If Rack::Csrf is available a CSRF tag if the form's
883
823
  method is +POST+, with no configuration ability.
884
824
 
885
- Both plugins also support the following option:
825
+ == forme_erubi_capture plugin
826
+
827
+ The forme_erubi_capture plugin builds on the forme_route_csrf plugin, but it supports
828
+ the erubi/capture_end engine, which allows this syntax:
829
+
830
+ <%|= form(@obj, :action=>'/foo') do |f| %>
831
+ <%= f.input(:field) %>
832
+ <%|= f.tag(:fieldset) do %>
833
+ <%= f.input(:field_two) %>
834
+ <%| end %>
835
+ <%| end %>
836
+
837
+ If you use the forme_erubi_capture plugin, you need to manually set Roda to use the
838
+ erubi/capture_end engine, which you can do via:
839
+
840
+ require 'erubi/capture_end'
841
+ app.plugin :render, :engine_opts=>{'erb'=>{:engine_class=>Erubi::CaptureEndEngine}}
886
842
 
887
- :output :: The object that the form output should be injected into when
888
- injecting output (+@_out_buf+ by default).
843
+ The forme_erubi_capture plugin requires Roda 3.50.0+.
889
844
 
890
845
  = Sinatra Support
891
846
 
892
- Forme ships with a ERB extension that you can get by <tt>require "forme/erb"</tt> and using
847
+ Forme ships with a Sinatra extension that you can get by <tt>require "forme/erb"</tt> and using
893
848
  <tt>including Forme::ERB::Helper</tt>. This is tested to support ERB templates in Sinatra.
894
849
  It allows you to use the following API in your erb templates:
895
850
 
@@ -900,8 +855,8 @@ It allows you to use the following API in your erb templates:
900
855
  <% end %>
901
856
  <% end %>
902
857
 
903
- In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt>. If that
904
- is not the case, use the :output option to +form+ to specify the outvar.
858
+ In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt> (this is the
859
+ default in Sinatra).
905
860
 
906
861
  = Rails Support
907
862
 
@@ -916,7 +871,7 @@ in your Rails forms:
916
871
  <% end %>
917
872
  <% end %>
918
873
 
919
- This has been tested on Rails 3.2-5.2.
874
+ This has been tested on Rails 3.2-7.0.
920
875
 
921
876
  = Input Types and Options
922
877
 
@@ -927,8 +882,8 @@ created via Forme::Form#input:
927
882
 
928
883
  These options are supported by all of the input types:
929
884
 
930
- :attr :: The attributes hash to use for the given tag, takes precedence over
931
- other options that set attributes.
885
+ :attr :: The attributes hash to use for the given tag, attributes in this hash
886
+ take precedence over other options that set attributes.
932
887
  :autofocus :: Set the autofocus attribute if true
933
888
  :class :: A class to use. Unlike other options, this is combined with the
934
889
  classes set in the :attr hash.
@@ -940,6 +895,7 @@ These options are supported by all of the input types:
940
895
  :disabled :: Set the disabled attribute if true
941
896
  :error :: Set an error message, invoking the error_handler
942
897
  :error_handler :: Set a custom error_handler, overriding the form's default
898
+ :help :: Set help text to use, invoking the helper
943
899
  :helper :: Set a custom helper, overriding the form's default
944
900
  :id :: The id attribute to use
945
901
  :key :: The base to use for the name and id attributes, based on the current
@@ -956,7 +912,7 @@ These options are supported by all of the input types:
956
912
  for textarea tags, or the selected option(s) for select tags.
957
913
  :wrapper :: Set a custom wrapper, overriding the form's default
958
914
 
959
- == Input Types
915
+ == Input Type-Specific Options
960
916
 
961
917
  === :checkbox
962
918
 
@@ -974,18 +930,21 @@ Creates an input tag with type radio. Options:
974
930
 
975
931
  === :date / :datetime
976
932
 
977
- By default, creates an input tag with type date or datetime. With the :as=>:select option,
933
+ By default, creates an input tag with type date or datetime. With the <tt>as: :select</tt> option,
978
934
  creates multiple select options. Options:
979
935
 
980
936
  :as :: When value is :select, uses 3 or 6 select boxes by default.
981
- :order :: The order of select boxes when using :as=>:select. Entries should be a symbol
937
+ :order :: The order of select boxes when using <tt>as: :select</tt>. Entries should be a symbol
982
938
  for the select field and string to use a string
983
939
  (:date default: <tt>[:year, '-', :month, '-', :day]</tt>)
984
940
  (:datetime default: <tt>[:year, '-', :month, '-', :day, ' ', :hour, ':', :minute, ':', :second]</tt>)
985
941
  :select_labels :: The labels to use for the select boxes. Should be a hash keyed by the
986
- symbol used in order. By default, no labels are used.
942
+ symbol used (e.g. <tt>{:month=>'Month'}</tt>). By default, no labels are used.
987
943
  :select_options :: The options to use for the select boxes. Should be a hash keyed by the
988
- symbol used in order (e.g. <tt>{:year=>1970..2020}</tt>)
944
+ symbol used in order (e.g. <tt>{:year=>1970..2020}</tt>). The values
945
+ can be a number used as both the value and the text of the option or
946
+ an array with two elements, the first of which is the value for the option
947
+ and the second of which is the text for the option.
989
948
 
990
949
  === :select
991
950
 
@@ -1005,7 +964,8 @@ Creates a select tag, containing option tags specified by the :options option.
1005
964
  :options :: An enumerable of options used for creating option tags.
1006
965
  If the :text_method and :value_method are not given and the entry is an
1007
966
  array, uses the first entry of the array as the text of the option, and
1008
- the second entry of the array as the value of the option.
967
+ the last entry of the array as the value of the option. If the last entry
968
+ of the array is a hash, uses the hash as the attributes for the option.
1009
969
  :selected :: The value that should be selected. Any options that are equal to
1010
970
  this value (or included in this value if a multiple select box),
1011
971
  are set to selected.
@@ -1019,7 +979,7 @@ Creates a select tag, containing option tags specified by the :options option.
1019
979
  === :checkboxset
1020
980
 
1021
981
  Creates a set of checkbox inputs all using the same name. Supports the same options
1022
- as the select type, except that the :multiple option is assumed to be true. Also supports
982
+ as the :select type, except that the :multiple option is assumed to be true. Also supports
1023
983
  the following options:
1024
984
 
1025
985
  :tag_wrapper :: The wrapper transformer for individual tags in the set
@@ -1051,6 +1011,10 @@ as text and password, as well as newer HTML5 inputs such as number or email. Opt
1051
1011
  These are the options supported by Forme::Form object, mostly used to set
1052
1012
  the defaults for Inputs created via the form:
1053
1013
 
1014
+ :after :: A callable object that is yielded the Form instance after yielding to
1015
+ the block. Can be used to add hidden inputs to the end of the form.
1016
+ :before :: A callable object that is yielded the Form instance before yielding to
1017
+ the block. Can be used to add hidden inputs to the start of the form.
1054
1018
  :config :: The configuration to use, which automatically sets defaults
1055
1019
  for the transformers to use.
1056
1020
  :errors :: A Hash of errors from a previous form submission, used to set
@@ -1058,7 +1022,6 @@ the defaults for Inputs created via the form:
1058
1022
  :error_handler :: Sets the default error_handler for the form's inputs
1059
1023
  :helper :: Sets the default helper for the form's inputs
1060
1024
  :formatter :: Sets the default formatter for the form's inputs
1061
- :hidden_tags :: Sets the hidden tags to automatically add to this form, see below.
1062
1025
  :input_defaults :: Sets the default options for each input type. This should
1063
1026
  be a hash with input type keys, where the values are the
1064
1027
  hash of default options to use for the input type.
@@ -1079,17 +1042,7 @@ For forms created by Forme.form, the following options are supported:
1079
1042
  to the block.
1080
1043
  :button :: A button to add to the form, after yielding to the block.
1081
1044
 
1082
- === :hidden_tags
1083
-
1084
- This should be an array, where elements are one of the following types:
1085
-
1086
- String, Array, Forme::Tag :: Added directly as a child of the form tag.
1087
- Hash :: Adds a hidden tag for each entry, with keys as the name of the hidden
1088
- tag and values as the value of the hidden tag.
1089
- Proc :: Will be called with the form tag object, and should return an instance
1090
- of one of the handled types (or nil to not add a tag).
1091
-
1092
- = Basic Design
1045
+ = Internal Architecture
1093
1046
 
1094
1047
  Internally, Forme builds an abstract syntax tree of objects that
1095
1048
  represent the form. The abstract syntax tree goes through a
@@ -1099,15 +1052,88 @@ strings. Here are the main classes used by the library:
1099
1052
 
1100
1053
  <tt>Forme::Form</tt> :: main object
1101
1054
  <tt>Forme::Input</tt> :: high level abstract tag (a single +Input+ could represent a select box with a bunch of options)
1102
- <tt>Forme::Tag</tt> :: low level abstract tag representing an html tag (there would be a separate +Tag+ for each option in a select box)
1055
+ <tt>Forme::Tag</tt> :: low level abstract tag representing an HTML tag (there would be a separate +Tag+ for each option in a select box)
1056
+
1057
+ The difference between <tt>Forme::Input</tt> and <tt>Forme::Tag</tt>
1058
+ is that <tt>Forme::Tag</tt> directly represents the underlying HTML
1059
+ tag, containing a type, optional attributes, and children, while the
1060
+ <tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
1061
+ For example, these both compile by default to the same select tag:
1062
+
1063
+ f.input(:select, :options=>[['foo', 1]])
1064
+ # or
1065
+ f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
1103
1066
 
1104
1067
  The group of objects that perform the transformations to
1105
1068
  the abstract syntax trees are known as transformers.
1106
1069
  Transformers use a functional style, and all use a +call+-based
1107
1070
  API, so you can use a +Proc+ for any custom transformer.
1071
+ The processing of high level <tt>Forme::Input</tt>s into raw HTML
1072
+ fragments is performed through the following transformers:
1073
+
1074
+ +Formatter+ :: converts a <tt>Forme::Input</tt> instance into a
1075
+ <tt>Forme::Tag</tt> instance (or array of them).
1076
+ +ErrorHandler+ :: If the <tt>Forme::Input</tt> instance has a error,
1077
+ takes the formatted tag and marks it as having the error.
1078
+ +Helper+ :: If the <tt>Forme::Input</tt> instance has any help text,
1079
+ adds the help text in a separate tag.
1080
+ +Labeler+ :: If the <tt>Forme::Input</tt> instance has a label,
1081
+ takes the formatted output and labels it.
1082
+ +Wrapper+ :: Takes the output of the formatter, labeler, and
1083
+ error_handler transformers, and wraps it in another tag (or just
1084
+ returns it unmodified).
1085
+ +Serializer+ :: converts a <tt>Forme::Tag</tt> instance into an
1086
+ HTML string.
1087
+
1088
+ Technically, only the +Serializer+ is necessary. The Forme::Form#input
1089
+ and Forme::Form#tag methods internally create +Input+ and
1090
+ +Tag+ objects. Before returning results, the input or tag is converted
1091
+ to a string using +to_s+, which calls the appropriate +Serializer+.
1092
+ The +Serializer+ calls the appropriate +Formatter+ if it encounters an
1093
+ +Input+ instance, and attempts to serialize the output of that (which is
1094
+ usually a +Tag+ instance). It is up to the +Formatter+ to call the +Labeler+,
1095
+ +ErrorHandler+, +Helper+, and/or +Wrapper+.
1096
+
1097
+ The Forme::Form object takes the transformers as options (:formatter,
1098
+ :labeler, :error_handler, :helper, :wrapper, and :serializer), all of which
1099
+ should be objects responding to +call+ (so you can use <tt>Proc</tt>s) or be symbols
1100
+ registered with the library using <tt>Forme.register_transformer</tt>:
1101
+
1102
+ Forme.register_transformer(:wrapper, :p) do |tag, input|
1103
+ input.tag(:p, {}, tag)
1104
+ end
1105
+
1106
+ Most transformers are called with two arguments, +tag+ and +input+. +tag+
1107
+ is a <tt>Forme::Tag</tt> instance, and +input+ is a <tt>Forme::Input</tt>
1108
+ instance. The +Formatter+ and +Serializer+ transformers are the two
1109
+ exceptions, with +Formatter+ being called with just an +input+, and
1110
+ +Serializer+ potentionally being called with any object. The +Serializer+
1111
+ will in general recursively call itself with children of the argument
1112
+ given until a string is returned.
1113
+
1114
+ There is also an +InputsWrapper+ transformer, that is called by
1115
+ Forme::Form#inputs. It's used to wrap up a group of
1116
+ related options (in a +fieldset+ by default). It takes +form+
1117
+ (Forme::Form instance) and +input_opts+ (+Hash+) arguments.
1118
+
1119
+ Most of the transformers can be overridden on a per instance basis by
1120
+ passing the appropriate option to +input+ or +inputs+:
1121
+
1122
+ f.input(:name, :wrapper=>:p)
1123
+
1124
+ Existing transformers can be easily extended (ie, to set the class attribute),
1125
+ by creating your own transformer and then calling the existing transformer.
1126
+
1127
+ Forme.register_transformer(:labeler, :explicit) do |tag, input|
1128
+ input.opts[:label_attr] ||= { :class => 'label' }
1129
+ Forme::Labeler::Explicit.new.call(tag, input)
1130
+ end
1108
1131
 
1109
1132
  == Transformer Types
1110
1133
 
1134
+ You can override the type of transform for each form or input using the
1135
+ following options:
1136
+
1111
1137
  +serializer+ :: tags input/tag, returns string
1112
1138
  +formatter+ :: takes input, returns tag
1113
1139
  +error_handler+ :: takes tag and input, returns version of tag with errors noted
@@ -1240,7 +1266,7 @@ You can mark a configuration as the default using:
1240
1266
 
1241
1267
  === Bootstrap 3 Support
1242
1268
 
1243
- Forme ships with support for Bootstrap 3 HTML formatting. This support is shipped in
1269
+ Forme ships with support for Bootstrap 3-4 HTML formatting. This support is shipped in
1244
1270
  it's own file, so if you don't use it, you don't pay the memory penalty for loading
1245
1271
  it.
1246
1272
 
@@ -1256,7 +1282,7 @@ All of these have external dependencies:
1256
1282
  3. simple_form
1257
1283
  4. padrino-helpers
1258
1284
 
1259
- Forme's DSL draws a lot of inspiration from both Formtastic and simple_form.
1285
+ Forme's API draws a lot of inspiration from both Formtastic and simple_form.
1260
1286
 
1261
1287
  = License
1262
1288