forme 0.9.2 → 0.10.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
  SHA1:
3
- metadata.gz: 631cc2f4948e4efca43764c957b89a191cf42183
4
- data.tar.gz: e4b438e00bb85b76207c4c010c2346f66e0fbf57
3
+ metadata.gz: 610c1c28c2ed6fc3c4f36d520c4e67fea4fa9c1f
4
+ data.tar.gz: 7bb48306b738007c7c40c0673ad964c94f1e4c0d
5
5
  SHA512:
6
- metadata.gz: 1406aec8ddec78e1b8fc25ae0d9812d4518d9aae7c65bb2daa27dff300970dbaff4b71c96d0254b7638166995056ddede4d316b287d59c71b6e410cc314daccc
7
- data.tar.gz: 3ae282714c78f13d8115caacdf06d4f8037123ee2ece35ea752a31a6fe05e9124eb29aa5162fb785e1f35b88a892a50cb95e86324b62171e24bf1e1b51d5dad0
6
+ metadata.gz: a6076239cb78c5f4ad271fb77d5b65947f75899243633e49281ae0d2c350799d134d4deb542aa8129e912f427a0a46ce195bd5f21d34904ab1505e738aab75dd
7
+ data.tar.gz: de392606364637b2b8999151ff18854bbc0e0b2ec62d54f123ce563b986814e5311154b7c825687274dc16f4e5b579cc0f6a44f5a37c34d08338ee93214cd939
data/CHANGELOG CHANGED
@@ -1,3 +1,59 @@
1
+ === 0.10.0 (2014-07-01)
2
+
3
+ * Use #[] instead of #send to get input value for object forms if object is a hash (jeremyevans)
4
+
5
+ * Add Form#each_obj, for iterating over an Enumerable of objects, using with_obj for each object (jeremyevans)
6
+
7
+ * Add Form#with_obj, for changing a Form's object and namespace temporarily (jeremyevans)
8
+
9
+ * Support changing the namespace for a Form temporarily using with_opts(:namespace=>['ns1', 'ns2']) (jeremyevans)
10
+
11
+ * Use current namespace for form object inputs if :id/:name/:key is not specified (jeremyevans)
12
+
13
+ * Remove SequelForm#nested_associations accessor methods, no longer necessary (jeremyevans)
14
+
15
+ * Support changing the object for a Form temporarily using with_opts(:obj=>new_obj) (jeremyevans)
16
+
17
+ * Add :table, :tr, :ol, and :fieldset_ol wrappers, which automatically set wrapper and inputs_wrapper appropriately (jeremyevans)
18
+
19
+ * Add subform :grid option in Sequel plugin, for more compact editing of nested *_to_many associations (jeremyevans)
20
+
21
+ * Make table inputs_wrapper accept a :labels option and automatically set up th tags with the labels for each column (jeremyevans)
22
+
23
+ * Form#inputs now accepts a :nested_inputs_wrapper option to set default inputs_wrapper transformer inside the block (jeremyevans)
24
+
25
+ * Add tr inputs_wrapper and td wrapper, for horizontal layout of inputs inside a table (jeremyevans)
26
+
27
+ * Form#inputs now accepts transformer options (e.g :wrapper) and automatically calls with_opts (jeremyevans)
28
+
29
+ * Remove Form#format and Form#serialize (jeremyevans)
30
+
31
+ * Remove Form#{formatter,labeler,error_handler,wrapper,inputs_wrapper} accessors (jeremyevans)
32
+
33
+ * Add Form.with_opts method to override opts for the given block (jeremyevans)
34
+
35
+ * Remove Form#use_serializer and Serializer module (jeremyevans)
36
+
37
+ * table inputs_wrapper now respects the :legend and :legend_attr options, using a caption (jeremyevans)
38
+
39
+ * ol, div, and table inputs_wrappers now respect the :attr option (jeremyevans)
40
+
41
+ * Make subform always use the inputs_wrapper, even if :inputs is not given (jeremyevans)
42
+
43
+ * Allow input_defaults to work with symbol keys for inputs that use symbol types (jeremyevans)
44
+
45
+ * Support Form :values option, for automatically setting value attributes for inputs from submitted params (jeremyevans)
46
+
47
+ * Support :autofocus option for setting autofocus attribute, similar to :required and :disabled (jeremyevans)
48
+
49
+ * Add Forme.default_add_blank_prompt for setting default prompt used for :add_blank option (jeremyevans)
50
+
51
+ * Support radioset and checkboxset Input types (jeremyevans)
52
+
53
+ * Support :key and :key_id options for Inputs, for automatically setting name/id attributes based on current namespace (jeremyevans)
54
+
55
+ * Move namespace handling from Sequel plugin into the core (jeremyevans)
56
+
1
57
  === 0.9.2 (2014-04-10)
2
58
 
3
59
  * Make association_select_options compatible with Sequel 4.10+ (jeremyevans)
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2013 Jeremy Evans
1
+ Copyright (c) 2011-2014 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/README.rdoc CHANGED
@@ -7,21 +7,83 @@ Forme is a HTML forms library for ruby with the following goals:
7
7
  3. Support forms both with and without related objects
8
8
  4. Allow compiling down to different types of output
9
9
 
10
- = Installation
11
-
12
- sudo gem install forme
10
+ = Introduction
11
+
12
+ 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.
17
+
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:
29
+
30
+ f.input(:select, :options=>[['foo', 1]])
31
+ # or
32
+ f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
33
+
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):
36
+
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
+ * +Labeler+: If the <tt>Forme::Input</tt> instance has a label,
42
+ takes the formatted output and labels it.
43
+ * +Wrapper+: Takes the output of the formatter, labeler, and
44
+ error_handler transformers, and wraps it in another tag (or just
45
+ returns it unmodified).
46
+ * +Serializer+: converts a <tt>Forme::Tag</tt> instance into an
47
+ html string.
48
+
49
+ Technically, only the +Serializer+ is necessary. The +input+
50
+ and +tag+ methods return +Input+ and +Tag+ objects. These objects
51
+ both have +to_s+ defined to call the appropriate +Serializer+ with
52
+ themselves. The +Serializer+ calls the appropriate +Formatter+ if
53
+ it encounters an +Input+ instance, and attempts to serialize the
54
+ output of that (which is usually a +Tag+ instance). It is up to
55
+ the +Formatter+ to call the +Labeler+ and/or +ErrorHandler+ (if
56
+ necessary) and the +Wrapper+.
57
+
58
+ There is also an +InputsWrapper+ transformer, that is called by
59
+ <tt>Forme::Form#inputs</tt>. It's used to wrap up a group of
60
+ related options (in a fieldset by default).
61
+
62
+ The <tt>Forme::Form</tt> object takes the 6 transformers as options (:formatter,
63
+ :labeler, :error_handler, :wrapper, :inputs_wrapper, and :serializer), all of which
64
+ should be objects responding to +call+ (so you can use +Proc+s) or be symbols
65
+ registered with the library using <tt>Forme.register_transformer</tt>:
66
+
67
+ Forme.register_transformer(:wrapper, :p){|t| t.tag(:p, {}, t)}
68
+
69
+ Most of the transformers can be overridden on a per instance basis by
70
+ passing the appopriate option to +input+ or +inputs+:
71
+
72
+ f.input(:name, :wrapper=>:p)
13
73
 
14
- = Demo Site
15
74
 
16
- A demo site is available at http://forme-demo.jeremyevans.net
17
-
18
- = Documentation Site
75
+ = Installation
19
76
 
20
- RDoc Documentation is available at http://forme.jeremyevans.net
77
+ gem install forme
21
78
 
22
- = Source Code
79
+ = Links
23
80
 
24
- Source code is available on GitHub at https://github.com/jeremyevans/forme
81
+ Demo Site :: http://forme-demo.jeremyevans.net
82
+ RDoc :: http://forme.jeremyevans.net
83
+ Source :: https://github.com/jeremyevans/forme
84
+ IRC :: irc://irc.freenode.net/forme
85
+ Google Group :: https://groups.google.com/forum/#!forum/ruby-forme
86
+ Bug Tracker :: https://github.com/jeremyevans/forme/issues
25
87
 
26
88
  = Basic Usage
27
89
 
@@ -43,7 +105,7 @@ the entire form based on the object.
43
105
 
44
106
  If the object doesn't respond to +forme_input+, it falls back to creating text fields
45
107
  with the name and id set to the field name and the value set by calling the given method
46
- on the object.
108
+ on the object (or using #[] if the object is a hash).
47
109
 
48
110
  f = Forme::Form.new([:foo])
49
111
  f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
@@ -57,12 +119,14 @@ Forme comes with a DSL:
57
119
  f.tag(:fieldset) do
58
120
  f.input(:textarea, :name=>'baz')
59
121
  end
122
+ f.button('Update')
60
123
  end
61
124
  # <form action="/foo">
62
125
  # <input name="bar" type="text"/>
63
126
  # <fieldset>
64
127
  # <textarea name="baz"></textarea>
65
128
  # </fieldset>
129
+ # <input type="submit" value="Update"/>
66
130
  # </form>
67
131
 
68
132
  You can wrap up multiple inputs with the <tt>:inputs</tt> method:
@@ -82,6 +146,541 @@ You can even do everything in a single method call:
82
146
  Forme.form({:action=>'/foo'},
83
147
  :inputs=>[[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
84
148
 
149
+ = Forme::Form Creation
150
+
151
+ As shown above, the general way to create Forme::Form instances is via the Forme.form method.
152
+ This method takes up to 3 arguments, and yields the Forme::Form object to the block (if given).
153
+ Here are the argument styles that you can use for Forme.form.
154
+
155
+ No args :: Creates a +Form+ object with no options and not associated
156
+ to an +obj+, and with no attributes in the opening tag.
157
+ 1 hash arg :: Treated as opening form tag attributes, creating a
158
+ +Form+ object with no options.
159
+ 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
160
+ and no attributes in the opening tag.
161
+ 2 hash args :: First hash is opening attributes, second hash is +Form+
162
+ options.
163
+ 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
164
+ opening attributes, third if provided is
165
+ +Form+'s options.
166
+
167
+ Examples:
168
+
169
+ # No arguments
170
+ Forme.form
171
+
172
+ # 1 hash argument (attributes)
173
+ Forme.form(:action=>'/foo')
174
+
175
+ # 1 non-hash argument (a reference object used when building the form)
176
+ Forme.form(Album[1])
177
+
178
+ # 2 hash arguments (attributes, and options)
179
+ Forme.form({:action=>'/foo'}, :values=>params)
180
+
181
+ # 1 non-hash argument, 1-2 hash arguments (ref obj, attributes, options)
182
+ Forme.form(Album[1], :action=>'/foo')
183
+ Forme.form(Album[1], {:action=>'/foo'}, :values=>params)
184
+
185
+ 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:
186
+
187
+ Forme.form({:action=>'/foo'}, :obj=>{:foo=>'bar'})
188
+
189
+ You can also create Forme::Form objects the normal ruby way using Forme::Form#new. The
190
+ difference between Forme::Form#new and Forme.form is that Forme.form includes the enclosing
191
+ <form> tag, where Forme::Form#new does not. Because of this, Forme::Form does not accept
192
+ a hash of <form> tag attributes, so it has the following API:
193
+
194
+ # No arguments
195
+ Forme::Form.new
196
+
197
+ # 1 hash argument
198
+ Forme::Form.new(:values=>params)
199
+
200
+ # 1 non-hash argument
201
+ Forme::Form.new(Album[1])
202
+
203
+ # 1 non-hash argument, 1-2 hash arguments
204
+ Forme::Form.new(Album[1], :values=>params)
205
+
206
+ = Forme::Form Methods
207
+
208
+ == form
209
+
210
+ If you create a Form via Forme::Forme#new, you can use the form method to create a form tag:
211
+
212
+ f = Forme::Form.new
213
+ f.form(:action=>'/foo')
214
+
215
+ This is what Forme.form uses internally to create the <form> tag
216
+
217
+ == input
218
+
219
+ This adds an input to the form. If the form has an associated object, and that
220
+ object responds to +forme_input+, calls forme_input with the argument and options:
221
+
222
+ f = Forme::Form.new(obj)
223
+ f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo"/>'
224
+
225
+ If the form has an associated object, and that object does not respond to +forme_iuput+,
226
+ calls the method on the object (or uses [] if the object is a hash), and uses the result
227
+ as the value:
228
+
229
+ f = Forme::Form.new([:foo])
230
+ f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
231
+
232
+ If the form does not have an assocaited object, uses the first argument as the input
233
+ type:
234
+
235
+ f = Forme::Form.new
236
+ f.input(:text) # '<input type="text" />'
237
+
238
+ The second argument is an options hash. See below for the supported input types and options.
239
+
240
+ == tag
241
+
242
+ This adds a tag to the form. If a block is given, yields to the block, and tags and inputs
243
+ inside the block are placed inside the tag. The first argument is the type of tag to create,
244
+ and the second argument if given should be a hash of tag attributes. This allows you to nest
245
+ inputs inside tags:
246
+
247
+ Forme.form do |f|
248
+ f.tag(:span, :class="foo") do
249
+ f.input(:text)
250
+ end
251
+ end
252
+
253
+ Which results in a form similar to the following:
254
+
255
+ <form>
256
+ <span class="foo">
257
+ <input type="text"/>
258
+ </span>
259
+ </form>
260
+
261
+ == inputs
262
+
263
+ This wraps multiple inputs in a tag (it uses the inputs_wrapper transformer discussed below,
264
+ so it uses a fieldset by default). You can give the inputs to add as an enumerable argument:
265
+
266
+ f.inputs([:textarea, [:text, :value=>'a']])
267
+ # <fieldset>
268
+ # <textarea></textarea>
269
+ # <input type="text" value="a"/>
270
+ # </fieldset>
271
+
272
+ You can also provide a block:
273
+
274
+ f.inputs([:textarea]) do
275
+ f.input(:text, :value=>'a')
276
+ end
277
+
278
+ Any options given are passed to the inputs_wrapper (so you can use options such as :legend
279
+ to set a legend for the fieldset), and also to the the with_opts (so you can use options
280
+ such as :wrapper to modify the default wrapper transformer for inputs inside the block).
281
+ There is also one option specific to the inputs method:
282
+
283
+ :nested_inputs_wrapper :: Sets the default inputs_wrapper to use for calls to inputs inside
284
+ the block. The reason for this option is that :inputs_wrapper
285
+ option affects the current call to inputs, so if you want to
286
+ use a different inputs_wrapper for nested calls, you need this option.
287
+
288
+ == button
289
+
290
+ This adds a submit input to the form:
291
+
292
+ f.button
293
+ # <input type="submit"/>
294
+
295
+ It can be called with a string to provide a value for the button:
296
+
297
+ f.button('Search')
298
+ # <input type="submit" value="Search"/>
299
+
300
+ It can be called with a hash to provide options for the submit input:
301
+
302
+ f.button(:value=>'Search', :class=>'btn')
303
+ # <input class="btn" type="submit" value="Search"/>
304
+
305
+ == with_opts
306
+
307
+ This requires a block, and modifies the Form's options inside the block,
308
+ restoring the options when the block returns:
309
+
310
+ f.input(:text)
311
+ # <input type="text"/>
312
+ f.with_opts(:wrapper=>:li) do
313
+ f.input(:text)
314
+ end
315
+ # <li><input type="text"/></li>
316
+
317
+ This supports most options you can provide to the Form, but not all.
318
+
319
+ == with_obj
320
+
321
+ This uses with_opts to change the Form's object temporarily, but it
322
+ yields the object to the block, and also supports appending to the
323
+ existing namespaces:
324
+
325
+ Forme.form([:foo], :namespace=>'a') do |f|
326
+ f.input(:first)
327
+ # <input id="a_first" name="a[first]" type="text" value="foo"/>
328
+ f.with_obj(['foobar'], 'b') do |o|
329
+ f.input(:first, :size=>o.first.size)
330
+ # <input id="a_b_first" name="a[b][first]" size="6" type="text" value="foobar"/>
331
+ end
332
+ end
333
+
334
+ == each_obj
335
+
336
+ This allows you to provide an object-yielding enumerable. Forme will call with_obj with
337
+ each object in the enumerable. It yields each object as well as the index of the
338
+ object in the enumerable, and includes the index in the namespace:
339
+
340
+ objectlist = ['foobar', ['good']]
341
+ Forme.form([:foo], :namespace=>'a') do |f|
342
+ f.each_obj(objectlist, 'b') do |o, i|
343
+ f.input(:first, :size=>10+i)
344
+ end
345
+ # <input id="a_b_0_first" name="a[b][0][first]" size="10" type="text" value="foobar"/>
346
+ # <input id="a_b_1_first" name="a[b][1][first]" size="11" type="text" value="good"/>
347
+ end
348
+
349
+ = Sequel Support
350
+
351
+ Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to enable), that makes
352
+ Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
353
+
354
+ == Basics
355
+
356
+ The Sequel support handles inputs based on database columns, and automatically handles labels and errors.
357
+
358
+ Forme.form(Album[1], :action=>'/foo') do |f|
359
+ f.input :name
360
+ f.input :copies_sold
361
+ end
362
+
363
+ This will create a form similar to:
364
+
365
+ <form action="/foo" method="post">
366
+ <label>Name: <input id="album_name" name="album[name]" type="text" value="Rising Force"/></label>
367
+ <label>Copies Sold: <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/></label>
368
+ </form>
369
+
370
+ The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
371
+ +validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
372
+ based on the format, numericality, and length validations.
373
+
374
+ == specialized input options
375
+
376
+ In addition to the default Forme options, the Sequel support includes, for specific column types,
377
+ these additional options to the #input method:
378
+ .
379
+
380
+ === boolean
381
+
382
+ :as :: Can be set to :select, :radio, or :checkbox. :select will use a select input with three
383
+ options, a blank option, a true option, and a false option. :radio will use two radio
384
+ inputs, one for true and one for false. :checkbox will use a single checkbox input.
385
+ By default, uses :select if NULL values are allowed and the option is not required, and
386
+ :checkbox otherwise.
387
+ :false_label :: The value to use for the false label, 'No' by default.
388
+ :false_value :: The value to use for the false input, 'f' by default.
389
+ :true_label :: The value to use for the true label, 'Yes' by default.
390
+ :true_value :: The value to use for the true input, 't' by default.
391
+
392
+ == string
393
+
394
+ :as :: Can be set to :textarea to use a textarea input. You can use the usual attributes hash or a stylesheet to
395
+ control the size of the textarea.
396
+
397
+ == associations
398
+
399
+ The Sequel support also handles associations, allowing you to change which objects are associated
400
+ to the current object.
401
+
402
+ Forme.form(Album[1], :action=>'/foo') do |f|
403
+ f.input :name
404
+ f.input :artist
405
+ f.input :tags, :as=>:checkbox
406
+ end
407
+
408
+ This will create a form similar to:
409
+
410
+ <form action="/foo" method="post">
411
+ <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
412
+ <label>Artist: <select id="album_artist_id" name="album[artist_id]">
413
+ <option selected="selected" value="1">Elvis Presley</option>
414
+ <option value="2">The Beatles</option>
415
+ <option value="3">The Monkeys</option>
416
+ </select></label>
417
+ <span class="label">Tags:
418
+ <label><input checked="checked" id="album_tag_pks_1" name="album[tag_pks][]" type="checkbox" value="1"/> Rock and Roll</label>
419
+ <label><input id="album_tag_pks_2" name="album[tag_pks][]" type="checkbox" value="2"/> Blues</label>
420
+ <label><input id="album_tag_pks_3" name="album[tag_pks][]" type="checkbox" value="3"/> Country</label>
421
+ </span>
422
+ </form>
423
+
424
+ For one_to_many and many_to_many associations, you will probably want to use the
425
+ +association_pks+ plugin that ships with Sequel.
426
+
427
+ association input options:
428
+
429
+ :as :: For many_to_one associations, set to :radio to use a series of radio buttons instead
430
+ a select input. For one_to_many and many_to_many associations, set to :checkbox to
431
+ use a series of checkboxes instead of a multiple select input.
432
+ :dataset :: If a Dataset, uses the dataset to retrieve the options. If a Proc or Method,
433
+ calls the proc or method with the default dataset, and should return a modified
434
+ dataset to use.
435
+ :options :: Specify the options to use for the input(s), instead of querying the database.
436
+ :name_method :: If a String or Symbol, treats it as a method name and calls it on each object
437
+ returned by the dataset to get the text to use for the option. If not given,
438
+ tries the following method names in order: :forme_name, :name, :title, :number.
439
+ If given and not a String or Symbol, a callable object is assumed, and the value
440
+ is called with each object and should return the text to use for the option.
441
+
442
+ == subform
443
+
444
+ The Sequel support includes a method called subform, which can handle nested_attributes:
445
+
446
+ Forme.form(Album[1], :action=>'/foo') do |f|
447
+
448
+ f.input :name
449
+
450
+ f.subform :artist do
451
+ f.input :name
452
+ end
453
+
454
+ f.subform :tracks do
455
+ f.input :number
456
+ f.input :name
457
+ end
458
+
459
+ end
460
+
461
+ This adds an input for editing the artist's name after the album's inputs, as well as
462
+ inputs for editing the number and name for all of the tracks in the album, creating a
463
+ form similar to:
464
+
465
+ <form action="/foo" method="post">
466
+
467
+ <label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
468
+
469
+ <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/>
470
+ <fieldset class="inputs"><legend>Artist</legend>
471
+ <label>Name: <input id="album_artist_attributes_name" name="album[artist_attributes][name]" type="text" value="Elvis Presley"/></label>
472
+ </fieldset>
473
+
474
+ <input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/>
475
+ <fieldset class="inputs"><legend>Track #1</legend>
476
+ <label>Number: <input id="album_tracks_attributes_0_number" name="album[tracks_attributes][0][number]" type="number" value="1"/></label>
477
+ <label>Name: <input id="album_tracks_attributes_0_name" name="album[tracks_attributes][0][name]" type="text" value="Blue Hawaii"/></label>
478
+ </fieldset>
479
+ <input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/>
480
+ <fieldset class="inputs"><legend>Track #2</legend>
481
+ <label>Number: <input id="album_tracks_attributes_1_number" name="album[tracks_attributes][1][number]" type="number" value="2"/></label>
482
+ <label>Name: <input id="album_tracks_attributes_1_name" name="album[tracks_attributes][1][name]" type="text" value="Almost Always True"/></label>
483
+ </fieldset>
484
+
485
+ </form>
486
+
487
+ <em>Note: blank lines added for clarity; they would not appear in the actual output</em>
488
+
489
+ subform options:
490
+
491
+ :inputs :: Automatically call +inputs+ with the given values. Using
492
+ this, it is not required to pass a block to the method,
493
+ though it will still work if you do.
494
+ :legend :: Overrides the default :legend used (which is based on the
495
+ association name). You can also use a proc as the value,
496
+ which will called with each associated object (and the position
497
+ in the associated object already for *_to_many associations),
498
+ and should return the legend string to use for that object.
499
+ :grid :: Sets up a table with one row per associated object, and
500
+ one column per field.
501
+ :labels :: When using the :grid option, override the labels that would
502
+ be created via the :inputs option. If you are not providing
503
+ an :inputs option or are using a block with additional inputs,
504
+ you should specify this option.
505
+
506
+ = Sinatra Support
507
+
508
+ Forme ships with a Sinatra extension that you can get by <tt>require "forme/sinatra"</tt> and using
509
+ <tt>helpers Forme::Sinatra::ERB</tt> in your Sinatra::Base subclass. It allows you to use the
510
+ following API in your Sinatra ERB forms:
511
+
512
+ <% form(@obj, :action=>'/foo') do |f| %>
513
+ <%= f.input(:field) %>
514
+ <% f.tag(:fieldset) do %>
515
+ <%= f.input(:field_two) %>
516
+ <% end %>
517
+ <% end %>
518
+
519
+ This example is for ERB/Erubis. Other Sinatra template libraries work differently and
520
+ do not support this integration.
521
+
522
+ = Rails Support
523
+
524
+ Forme ships with a Rails extension that you can get by <tt>require "forme/rails"</tt> and using
525
+ <tt>helpers Forme::Rails::ERB</tt> in your controller. If allows you to use the following API
526
+ in your Rails forms:
527
+
528
+ <%= forme(@obj, :action=>'/foo') do |f| %>
529
+ <%= f.input(:field) %>
530
+ <%= f.tag(:fieldset) do %>
531
+ <%= f.input(:field_two) %>
532
+ <% end %>
533
+ <% end %>
534
+
535
+ This has been tested on Rails 3.2-4.1, but should hopefully work on Rails 3.0+.
536
+
537
+ = Input Types and Options
538
+
539
+ These are the types and options supported by Forme::Input objects, usually
540
+ created via Forme::Form#input:
541
+
542
+ == General Options
543
+
544
+ These options are supported by all of the input types:
545
+
546
+ :attr :: The attributes hash to use for the given tag, takes precedence over
547
+ other options that set attributes.
548
+ :autofocus :: Set the autofocus attribute if true
549
+ :class :: A class to use. Unlike other options, this is combined with the
550
+ classes set in the :attr hash.
551
+ :data :: A hash of data-* attributes for the resulting tag. Keys in this hash
552
+ will have attributes created with data- prepended to the attribute name.
553
+ :disabled :: Set the disabled attribute if true
554
+ :error :: Set an error message, invoking the error_handler
555
+ :error_handler :: Set a custom error_handler, overriding the form's default
556
+ :id :: The id attribute to use
557
+ :key :: The base to use for the name and id attributes, based on the current
558
+ namespace for the form.
559
+ :label :: Set a label, invoking the labeler
560
+ :labeler :: Set a custom labeler, overriding the form's default
561
+ :name :: The name attribute to use
562
+ :placeholder :: The placeholder attribute to use
563
+ :required :: Set the required attribute if true
564
+ :value :: The value attribute to use for input tags, the content of the textarea
565
+ for textarea tags, or the selected option(s) for select tags.
566
+ :wrapper :: Set a custom wrapper, overriding the form's default
567
+
568
+ == Input Types
569
+
570
+ === :checkbox
571
+
572
+ Creates an input tag with type checkbox, as well as a hidden input tag. Options:
573
+
574
+ :checked :: Mark the checkbox as checked.
575
+ :hidden_value :: The value to use for the hidden input tag.
576
+ :no_hidden :: Don't create a hidden input tag.
577
+
578
+ === :radio
579
+
580
+ Creates an input tag with type radio. Options:
581
+
582
+ :checked :: Mark the radio button as checked.
583
+
584
+ === :date
585
+
586
+ By default, creates an input tag with type date. With the :as=>:select option, creates
587
+ 3 select boxes, one for the year, month, and day. Options:
588
+
589
+ :as :: When value is :select, uses 3 select boxes.
590
+
591
+ === :datetime
592
+
593
+ By default, creates an input tag with type datetime. With the :as=>:select option, creates
594
+ 6 select boxes, one for the year, month, day, hour, minute, and second. Options:
595
+
596
+ :as :: When value is :select, uses 6 select boxes.
597
+
598
+ === :select
599
+
600
+ Creates a select tag, containing option tags specified by the :options option. Options:
601
+
602
+ :add_blank :: Add a blank option if true. If the value is a string,
603
+ use it as the text content of the blank option. The default value can be
604
+ set with Forme.default_add_blank_prompt, and defaults to the empty string.
605
+ :multiple :: Creates a multiple select box.
606
+ :options :: an array of options used for creating option tags.
607
+ If the :text_method and :value_method are not given and the entry is an
608
+ array, uses the first entry of the array as the text of the option, and
609
+ the second entry of the array as the value of the option.
610
+ :selected :: The value that should be selected. Any options that are equal to
611
+ this value (or included in this value if a multiple select box),
612
+ are set to selected.
613
+ :text_method :: If set, each entry in the array has this option called on
614
+ it to get the text of the object.
615
+ :value :: Same as :selected, but has lower priority.
616
+ :value_method :: If set (and :text_method is set), each entry in the array
617
+ has this method called on it to get the value of the option.
618
+
619
+ === :checkboxset
620
+
621
+ Creates a set of checkbox inputs all using the same name. Supports the same options
622
+ as the select type, except that the :multiple option is assumed to be true.
623
+
624
+ === :radioset
625
+
626
+ Creates a set of radio buttons all using the same name. Supports the same options
627
+ as the select type.
628
+
629
+ === :textarea
630
+
631
+ Creates a textarea tag. Options:
632
+
633
+ :cols :: The number of columns in the text area.
634
+ :rows :: The number of rows in the text area.
635
+
636
+ == all others
637
+
638
+ Creates an input tag with the given type. This makes it easy to use inputs such
639
+ as text and password, as well as newer HTML5 inputs such as number or email. Options:
640
+
641
+ :size :: Uses the size attribute on the tag
642
+ :maxlength :: Use the maxlength attribute on the tag
643
+
644
+ == Form options
645
+
646
+ These are the options supported by Forme::Form object, mostly used to set
647
+ the defaults for Inputs created via the form:
648
+
649
+ :config :: The configuration to use, which automatically sets defaults
650
+ for the transformers to use.
651
+ :error_handler :: Sets the default error_handler for the form's inputs
652
+ :formatter :: Sets the default formatter for the form's inputs
653
+ :hidden_tags :: Sets the hidden tags to automatically add to this form, see below.
654
+ :input_defaults :: Sets the default options for each input type. This should
655
+ be a hash with input type keys, where the values are the
656
+ hash of default options to use for the input type.
657
+ :inputs_wrapper :: Sets the default inputs_wrapper for the form
658
+ :labeler :: Sets the default labeler for the form's inputs
659
+ :namespace :: Sets the default namespace(s) to use for the form. Namespacing
660
+ will automatically create namespaced name and id attributes for
661
+ inputs that use the :key option.
662
+ :obj :: Sets the default +obj+ for the form's inputs.
663
+ :serializer :: Sets the serializer for the form
664
+ :values :: The values from a previous form submission, used to set default
665
+ values for inputs when the inputs use the :key option.
666
+ :wrapper :: Sets the default wrapper for the form's inputs
667
+
668
+ For forms created by Forme.form, the following options are supported:
669
+
670
+ :inputs :: An array of inputs to create inside the form, before yielding
671
+ to the block.
672
+ :button :: A button to add to the form, after yielding to the block.
673
+
674
+ === :hidden_tags
675
+
676
+ This should be an array, where elements are one of the following types:
677
+
678
+ String, Array, Forme::Tag :: Added directly as a child of the form tag.
679
+ Hash :: Adds a hidden tag for each entry, with keys as the name of the hidden
680
+ tag and values as the value of the hidden tag.
681
+ Proc :: Will be called with the form tag object, and should return an instance
682
+ of one of the handled types (or nil to not add a tag).
683
+
85
684
  = Basic Design
86
685
 
87
686
  Internally, Forme builds an abstract syntax tree of objects that
@@ -142,23 +741,52 @@ Forme ships with a bunch of built-in transformers that you can use:
142
741
  :default :: uses implicit labels, where the tag is a child of the label tag
143
742
  :explicit :: uses explicit labels with the for attribute, where tag is a sibling of the label tag
144
743
 
744
+ Both of these respect the following options:
745
+
746
+ :label_position :: Can be set to :before or :after to place the label before or after the the input.
747
+ :label_attr :: A hash of attributes to use for the label tag
748
+
145
749
  === +wrapper+
146
750
 
147
751
  :default :: returns tag without wrapping
752
+ :div :: wraps tag in div tag
753
+ :fieldset_ol :: same as :li, but also sets +inputs_wrapper+ to :fieldset_ol
148
754
  :li :: wraps tag in li tag
755
+ :ol :: same as :li, but also sets +inputs_wrapper+ to :ol
149
756
  :p :: wraps tag in p tag
150
- :div :: wraps tag in div tag
151
757
  :span :: wraps tag in span tag
758
+ :table :: same as :trtd, but also sets +inputs_wrapper+ to :table
759
+ :td :: wraps tag in a td tag
760
+ :tr :: same as :td, but also sets +inputs_wrapper+ to :tr
152
761
  :trtd :: wraps tag in a tr tag with a td for the label and a td for the tag, useful for lining up
153
762
  inputs with the :explicit labeler without CSS
154
763
 
764
+ All of these except for :default respect the following options:
765
+
766
+ :wrapper_attr :: A hash of attributes to use for the wrapping tag.
767
+
155
768
  === +inputs_wrapper+
156
769
 
157
770
  :default :: uses a fieldset to wrap inputs
158
- :ol :: uses an ol tag to wrap inputs, useful with :li wrapper
159
771
  :div :: uses a div tag to wrap inputs
160
772
  :fieldset_ol :: use both a fieldset and an ol tag to wrap inputs
773
+ :ol :: uses an ol tag to wrap inputs, useful with :li wrapper
161
774
  :table :: uses a table tag to wrap inputs, useful with :trtd wrapper
775
+ :tr :: uses a tr tag to wrap inputs, useful with :td wrapper
776
+
777
+ All of these support the following options:
778
+
779
+ :attr :: A hash of attributes to use for the wrapping tag.
780
+
781
+ The :default, :fieldset_ol, and :table inputs_wrappers support the following options:
782
+
783
+ :legend :: A text description for the inputs, using the legend tag for fieldsets and
784
+ the caption tag for a table.
785
+ :legend_attr :: A hash of attributes for the legend/caption tag.
786
+
787
+ The :table inputs_wrapper also supports the following options:
788
+
789
+ :labels :: An array of labels, used to setup a row of table headers with the labels.
162
790
 
163
791
  == Configurations
164
792
 
@@ -184,61 +812,6 @@ You can mark a configuration as the default using:
184
812
 
185
813
  Forme.default_config = :mine
186
814
 
187
- = Sequel Support
188
-
189
- Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to enable), that makes
190
- Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
191
-
192
- It deals with inputs based on database columns, virtual columns, and associations. It also handles
193
- nested associations using the +subform+ method:
194
-
195
- Forme.form(Album[1], :action=>'/foo') do |f|
196
- f.inputs([:name, :copies_sold, :tags]) do
197
- f.subform(:artist, :inputs=>[:name])
198
- f.subform(:tracks, :inputs=>[:number, :name])
199
- end
200
- end
201
-
202
- For many_to_one associations, you can use the <tt>:as=>:radio</tt> option to use a series of radio buttons,
203
- and for one_to_many and many_to_many associations, you can use the <tt>:as=>:checkbox</tt> option to use a
204
- series of checkboxes. For one_to_many and many_to_many associations, you will probably want to use the
205
- +association_pks+ plugin that ships with Sequel.
206
-
207
- The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
208
- +validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
209
- based on the format, numericality, and length validations.
210
-
211
- = Sinatra Support
212
-
213
- Forme ships with a Sinatra extension that you can get by <tt>require "forme/sinatra"</tt> and using
214
- <tt>helpers Forme::Sinatra::ERB</tt> in your Sinatra::Base subclass. It allows you to use the
215
- following API in your Sinatra ERB forms:
216
-
217
- <% form(@obj, :action=>'/foo') do |f| %>
218
- <%= f.input(:field) %>
219
- <% f.tag(:fieldset) do %>
220
- <%= f.input(:field_two) %>
221
- <% end %>
222
- <% end %>
223
-
224
- This example is for ERB/Erubis. Other Sinatra template libraries work differently and
225
- probably do not support this integration.
226
-
227
- = Rails Support
228
-
229
- Forme ships with a Rails extension that you can get by <tt>require "forme/rails"</tt> and using
230
- <tt>helpers Forme::Rails::ERB</tt> in your controller. If allows you to use the following API
231
- in your Rails forms:
232
-
233
- <%= forme(@obj, :action=>'/foo') do |f| %>
234
- <%= f.input(:field) %>
235
- <%= f.tag(:fieldset) do %>
236
- <%= f.input(:field_two) %>
237
- <% end %>
238
- <% end %>
239
-
240
- This has been tested on Rails 3.2, but should hopefully work on Rails 3.0+.
241
-
242
815
  = Other Similar Projects
243
816
 
244
817
  All of these have external dependencies:
@@ -248,7 +821,11 @@ All of these have external dependencies:
248
821
  3. simple_form
249
822
  4. padrino-helpers
250
823
 
251
- Forme's API draws a lot of inspiration from both Formtastic and simple_form.
824
+ Forme's DSL draws a lot of inspiration from both Formtastic and simple_form.
825
+
826
+ = License
827
+
828
+ MIT
252
829
 
253
830
  = Author
254
831