Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Update documentation in lib/forme.rb

  • Loading branch information...
commit 931236900d4ee4cab02b51c04e6d7d74aa78a0a1 1 parent 9a3f378
Jeremy Evans authored

Showing 2 changed files with 208 additions and 82 deletions. Show diff stats Hide diff stats

  1. +4 2 README.rdoc
  2. +204 80 lib/forme.rb
6 README.rdoc
Source Rendered
@@ -25,8 +25,10 @@ Without an object, Forme is a simple form builder:
25 25 f.input(:text, :value=>'foo', :name=>'bar') # '<input name="bar" type="text" value="foo"/>'
26 26 f.close # '</form>'
27 27
28   -With an object, calls +forme_input+ on the obj with the form, field, and options, which
29   -should return a <tt>Forme::Input</tt> or <tt>Forme::Tag</tt> instance.
  28 +With an object, <tt>Form#input</tt> calls +forme_input+ on the obj with the form, field, and options, which
  29 +should return a <tt>Forme::Input</tt> or <tt>Forme::Tag</tt> instance. Also, in <tt>Form#initialize</tt>,
  30 ++forme_config+ is called on object with the form if the object responds to it, allowing customization of
  31 +the entire form based on the object.
30 32
31 33 f = Forme::Form.new(obj)
32 34 f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo"/>'
284 lib/forme.rb
... ... @@ -1,13 +1,13 @@
1 1 require 'forme/version'
2 2
3   -# Forme is designed to make creating forms easier. Flexibility and
  3 +# Forme is designed to make creating HTML forms easier. Flexibility and
4 4 # simplicity are primary objectives. The basic usage involves creating
5 5 # a <tt>Forme::Form</tt> instance, and calling +input+ and +tag+ methods
6 6 # to return html strings for widgets, but it could also be used for
7 7 # serializing to other formats, or even as a DSL for a GUI application.
8 8 #
9 9 # In order to be flexible, Forme stores tags in abstract form until
10   -# output is requested. There are two separate abstract forms that Forme
  10 +# output is requested. There are two separate abstract <i>forms</i> that Forme
11 11 # uses. One is <tt>Forme::Input</tt>, and the other is <tt>Forme::Tag</tt>.
12 12 # <tt>Forme::Input</tt> is a high level abstract form, while <tt>Forme::Tag</tt>
13 13 # is a low level abstract form.
@@ -18,9 +18,9 @@
18 18 # <tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
19 19 # For example, these both compile by default to the same select tag:
20 20 #
21   -# Forme::Input.new(:select, :options=>[['foo', 1]])
  21 +# f.input(:select, :options=>[['foo', 1]])
22 22 # # or
23   -# Forme::Tag.new(:select, {}, [Forme.Tag.new(:option, {:value=>1}, ['foo'])])
  23 +# f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
24 24 #
25 25 # The processing of high level <tt>Forme::Input</tt>s into raw html
26 26 # data is broken down to the following steps (called transformers):
@@ -37,25 +37,51 @@
37 37 # 4. +Serializer+: converts a <tt>Forme::Tag</tt> instance into a
38 38 # string.
39 39 #
40   -# Technically, only the +Formatter+ and +Serializer+ are necessary,
41   -# as it is up to the +Formatter+ to call the +Labeler+ and/or +ErrorHandler+ (if necessary) and
42   -# the +Wrapper+.
  40 +# Technically, only the +Serializer+ is necessary. The +input+
  41 +# and +tag+ methods return +Input+ and +Tag+ objects. These objects
  42 +# both have +to_s+ defined to call the appropriate +Serializer+ with
  43 +# themselves. The +Serializer+ calls the appropriate +Formatter+ if
  44 +# it encounters an +Input+ instance, and attempts to serialize the
  45 +# output of that (which is usually a +Tag+ instance). It is up to
  46 +# the +Formatter+ to call the +Labeler+ and/or +ErrorHandler+ (if
  47 +# necessary) and the +Wrapper+.
43 48 #
44 49 # There is also an +InputsWrapper+ transformer, that is called by
45 50 # <tt>Forme::Form#inputs</tt>. It's used to wrap up a group of
46 51 # related options (in a fieldset by default).
47 52 #
48   -# The <tt>Forme::Form</tt> object takes the 4 processors as options (:formatter,
49   -# :labeler, :wrapper, and :serializer), all of which should be objects responding
50   -# to +call+ (so you can use procs) or be symbols registered with the library.
  53 +# The <tt>Forme::Form</tt> object takes the 6 transformers as options (:formatter,
  54 +# :labeler, :error_handler, :wrapper, :inputs_wrapper, and :serializer), all of which
  55 +# should be objects responding to +call+ (so you can use +Proc+s) or be symbols
  56 +# registered with the library using <tt>Forme.register_transformer</tt>:
  57 +#
  58 +# Forme.register_transformer(:wrapper, :p){|t| t.tag(:p, {}, t)}
  59 +#
  60 +# Most of the transformers can be overridden on a per instance basis by
  61 +# passing the appopriate option to +input+ or +inputs+:
  62 +#
  63 +# f.input(:name, :wrapper=>:p)
51 64 module Forme
52 65 # Exception class for exceptions raised by Forme.
53 66 class Error < StandardError
54 67 end
55 68
  69 + # Main hash storing the registered transformers. Maps transformer type symbols to subhashes
  70 + # containing the registered transformers for that type. Those subhashes should have symbol
  71 + # keys and values that are either classes or objects that respond to +call+.
56 72 TRANSFORMERS = {:formatter=>{}, :serializer=>{}, :wrapper=>{}, :error_handler=>{}, :labeler=>{}, :inputs_wrapper=>{}}
57 73
  74 + # Register a new transformer with this library. Arguments:
  75 + # +type+ :: Transformer type symbol
  76 + # +sym+ :: Transformer name symbol
  77 + # <tt>obj/block</tt> :: Transformer to associate with this symbol. Should provide either
  78 + # +obj+ or +block+, but not both. If +obj+ is given, should be
  79 + # either a +Class+ instance or it should respond to +call+. If a
  80 + # +Class+ instance is given, instances of that class should respond
  81 + # to +call+, and the a new instance of that class should be used
  82 + # for each transformation.
58 83 def self.register_transformer(type, sym, obj=nil, &block)
  84 + raise Error, "Not a valid transformer type" unless TRANSFORMERS.has_key?(type)
59 85 raise Error, "Must provide either block or obj, not both" if obj && block
60 86 TRANSFORMERS[type][sym] = obj||block
61 87 end
@@ -66,16 +92,17 @@ def self.form(*a, &block)
66 92 end
67 93
68 94 # The +Form+ class is the main entry point to the library.
69   - # Using the +input+ and +tag+ methods, one can easily create
70   - # html tag strings.
  95 + # Using the +form+, +input+, +tag+, and +inputs+ methods, one can easily build
  96 + # an abstract syntax tree of +Tag+ and +Input+ instances, which can be serialized
  97 + # to a string using +to_s+.
71 98 class Form
72   - # The object related to this form, if any. If the +Form+ has an associated
  99 + # The object related to the receiver, if any. If the +Form+ has an associated
73 100 # obj, then calls to +input+ are assumed to be accessing fields of the object
74 101 # instead to directly representing input types.
75 102 attr_reader :obj
76 103
77   - # A hash of options for the +Form+. Currently, the following are recognized by
78   - # default (but a customized +formatter+ could use more options):
  104 + # A hash of options for the receiver. Currently, the following are recognized by
  105 + # default:
79 106 # :obj :: Sets the +obj+ attribute
80 107 # :error_handler :: Sets the +error_handler+ for the form
81 108 # :formatter :: Sets the +formatter+ for the form
@@ -109,7 +136,7 @@ class Form
109 136 # Must respond to +call+ or be a registered symbol.
110 137 attr_reader :serializer
111 138
112   - # Create a +Form+ object and yield it to the block,
  139 + # Create a +Form+ instance and yield it to the block,
113 140 # injecting the opening form tag before yielding and
114 141 # the closing form tag after yielding.
115 142 #
@@ -158,6 +185,8 @@ def initialize(obj=nil, opts={})
158 185 @nesting = []
159 186 end
160 187
  188 + # If there is a related transformer, call it with the given +args+ and +block+.
  189 + # Otherwise, attempt to return the initial input without modifying it.
161 190 def transform(type, trans, *args, &block)
162 191 if trans = transformer(type, trans)
163 192 trans.call(*args, &block)
@@ -173,6 +202,14 @@ def transform(type, trans, *args, &block)
173 202 end
174 203 end
175 204
  205 + # Get the related transformer for the given transformer type. Output depends on the type
  206 + # of +trans+:
  207 + # +Symbol+ :: Assume a request for a registered transformer, so look it up in the +TRANSFORRMERS+ hash.
  208 + # +Hash+ :: If +type+ is also a key in +trans+, return the related value from +trans+, unless the related
  209 + # value is +nil+, in which case, return +nil+. If +type+ is not a key in +trans+, use the
  210 + # default transformer for the receiver.
  211 + # +nil+ :: Assume the default transformer for this receiver.
  212 + # otherwise :: return +trans+ directly if it responds to +call+, and raise an +Error+ if not.
176 213 def transformer(type, trans)
177 214 case trans
178 215 when Symbol
@@ -207,21 +244,25 @@ def format(input)
207 244 transform(:formatter, input.opts, input)
208 245 end
209 246
  247 + # Empty method designed to ease integration with other libraries where
  248 + # Forme is used in template code and some output implicitly
  249 + # created by Forme needs to be injected into the template output.
210 250 def emit(tag)
211 251 end
212 252
213   - # Creates an +Input+ with the given +field+ and +opts+, and returns
214   - # a serialized version of the formatted input.
  253 + # Creates an +Input+ with the given +field+ and +opts+ associated with
  254 + # the receiver, and add it to the list of children to the currently
  255 + # open tag.
215 256 #
216 257 # If the form is associated with an +obj+, or the :obj key exists in
217   - # the +opts+ argument, treats the +field+ as a call to the obj. If the
218   - # obj responds to +forme_input+, that method is called with the field
  258 + # the +opts+ argument, treats the +field+ as a call to the +obj+. If
  259 + # +obj+ responds to +forme_input+, that method is called with the +field+
219 260 # and a copy of +opts+. Otherwise, the field is used as a method call
220   - # on the obj and a text input is created with the result.
  261 + # on the +obj+ and a text input is created with the result.
221 262 #
222   - # If no +obj+ is associated with the form, +field+ represents an input
223   - # type (e.g. :text, :textarea, :select), and an input is created directly
224   - # with the field and opts.
  263 + # If no +obj+ is associated with the receiver, +field+ represents an input
  264 + # type (e.g. <tt>:text</tt>, <tt>:textarea</tt>, <tt>:select</tt>), and
  265 + # an input is created directly with the +field+ and +opts+.
225 266 def input(field, opts={})
226 267 if opts.has_key?(:obj)
227 268 opts = opts.dup
@@ -242,44 +283,54 @@ def input(field, opts={})
242 283 input
243 284 end
244 285
  286 + # Create a new +Input+ associated with the receiver with the given
  287 + # arguments, doing no other processing.
245 288 def _input(*a)
246   - input = Input.new(self, *a)
  289 + Input.new(self, *a)
247 290 end
248 291
249 292 # Creates a tag using the +inputs_wrapper+ (a fieldset by default), calls
250   - # input on each given argument, and yields to the block if it is given.
  293 + # input on each element of +inputs+, and yields to if given a block.
251 294 # You can use array arguments if you want inputs to be created with specific
252 295 # options:
253 296 #
254 297 # inputs([:field1, :field2])
255 298 # inputs([[:field1, {:name=>'foo'}], :field2])
256   - def inputs(ins=[], opts={})
  299 + #
  300 + # The given +opts+ are passed to the +inputs_wrapper+, and the default
  301 + # +inputs_wrapper+ supports a <tt>:legend</tt> option that is used to
  302 + # set the legend for the fieldset.
  303 + def inputs(inputs=[], opts={})
257 304 transform(:inputs_wrapper, opts, self, opts) do
258   - ins.each do |i|
  305 + inputs.each do |i|
259 306 emit(input(*i))
260 307 end
261 308 yield if block_given?
262 309 end
263 310 end
264 311
265   - # Returns a string representing the opening of the form tag.
266   - # Requires the serializer implements +serialize_open+.
  312 + # Returns a string representing the opening of the form tag for serializers
  313 + # that support opening tags.
267 314 def open(attr)
268 315 serializer.serialize_open(_tag(:form, attr)) if serializer.respond_to?(:serialize_open)
269 316 end
270 317
271   - # Returns a string representing the closing of the form tag.
272   - # Requires the serializer implements +serialize_close+.
  318 + # Returns a string representing the closing of the form tag, for serializers
  319 + # that support closing tags.
273 320 def close
274 321 serializer.serialize_close(_tag(:form)) if serializer.respond_to?(:serialize_close)
275 322 end
276 323
  324 + # Create a +Tag+ associated to the receiver with the given arguments and block,
  325 + # doing no other processing.
277 326 def _tag(*a, &block)
278 327 tag = Tag.new(self, *a, &block)
279 328 end
280 329
281   - # Creates a +Tag+ instance with the given arguments, and returns
282   - # a serialized version of it.
  330 + # Creates a +Tag+ associated to the receiver with the given arguments.
  331 + # Add the tag to the the list of children for the currently open tag.
  332 + # If a block is given, make this tag the currently open tag while inside
  333 + # the block.
283 334 def tag(*a, &block)
284 335 tag = _tag(*a)
285 336 self << tag
@@ -287,15 +338,15 @@ def tag(*a, &block)
287 338 tag
288 339 end
289 340
290   - # Creates a :submit +Input+ with the given opts, and returns a serialized
291   - # version of the formatted input.
  341 + # Creates a :submit +Input+ with the given opts, adding it to the list
  342 + # of children for the currently open tag.
292 343 def button(opts={})
293 344 input = _input(:submit, opts)
294 345 self << input
295 346 input
296 347 end
297 348
298   - # Add the input/tag to the innermost nesting tag.
  349 + # Add the +Input+/+Tag+ instance given to the currently open tag.
299 350 def <<(tag)
300 351 if n = @nesting.last
301 352 n << tag
@@ -309,9 +360,9 @@ def serialize(tag)
309 360
310 361 private
311 362
312   - # Add a new nesting level by entering the tag. Yield
313   - # while inside the tag, and ensure when the block
314   - # returns to remove the nesting level.
  363 + # Make the given tag the currently open tag, and yield. After the
  364 + # block returns, make the previously open tag the currently open
  365 + # tag.
315 366 def nest(tag)
316 367 @nesting << tag
317 368 yield self
@@ -320,15 +371,16 @@ def nest(tag)
320 371 end
321 372 end
322 373
323   - # High level abstract tag form. Doesn't contain any logic.
  374 + # High level abstract tag form, transformed by formatters into the lower
  375 + # level +Tag+ form (or a +TagArray+ of them).
324 376 class Input
325   - # The +Form+ object related to this +Input+.
  377 + # The +Form+ object related to the receiver.
326 378 attr_reader :form
327 379
328 380 # The type of input, should be a symbol (e.g. :submit, :text, :select).
329 381 attr_reader :type
330 382
331   - # The options hash for this +Input+.
  383 + # The options hash for the receiver.
332 384 attr_reader :opts
333 385
334 386 # Set the +form+, +type+, and +opts+.
@@ -336,28 +388,31 @@ def initialize(form, type, opts={})
336 388 @form, @type, @opts = form, type, opts
337 389 end
338 390
  391 + # Return a string containing the serialized content of the receiver.
339 392 def to_s
340 393 form.serialize(self)
341 394 end
342 395
  396 + # Transform the receiver into a lower level +Tag+ form (or a +TagArray+
  397 + # of them).
343 398 def format
344 399 form.format(self)
345 400 end
346 401 end
347 402
348   - # Low level abstract tag form. Doesn't contain any logic.
  403 + # Low level abstract tag form, where each instance represents a
  404 + # html tag with attributes and children.
349 405 class Tag
350   - # The +Form+ object related to this +Tag+.
  406 + # The +Form+ object related to the receiver.
351 407 attr_reader :form
352 408
353 409 # The type of tag, should be a symbol (e.g. :input, :select).
354 410 attr_reader :type
355 411
356   - # The attributes hash of this +Tag+.
  412 + # The attributes hash of this receiver.
357 413 attr_reader :attr
358 414
359   - # Any children of this +Tag+, should be an array of +Tag+ objects
360   - # or strings (representing text nodes).
  415 + # A +TagArray+ instance representing the children of the receiver.
361 416 attr_reader :children
362 417
363 418 # Set the +form+, +type+, +attr+, and +children+.
@@ -366,29 +421,38 @@ def initialize(form, type, attr={}, children=[])
366 421 @form, @type, @attr, @children = form, type, attr, children
367 422 end
368 423
369   - # Adds a child to the list of receiver's children.
  424 + # Adds a child to the array of receiver's children.
370 425 def <<(child)
371 426 children << child
372 427 end
373 428
  429 + # Create a new +Tag+ instance with the given arguments and block
  430 + # related to the receiver's +form+.
374 431 def tag(*a, &block)
375 432 form._tag(*a, &block)
376 433 end
377 434
  435 + # Return a string containing the serialized content of the receiver.
378 436 def to_s
379 437 form.serialize(self)
380 438 end
381 439 end
382 440
  441 + # Array subclass related to a specific +Form+ instance.
383 442 class TagArray < Array
  443 + # The +Form+ instance related to the receiver.
384 444 attr_accessor :form
385 445
  446 + # Create a new instance using +contents+, associated to
  447 + # the given +form+.
386 448 def self.new(form, contents)
387 449 a = super(contents)
388 450 a.form = form
389 451 a
390 452 end
391 453
  454 + # Create a new +Tag+ instance with the given arguments and block
  455 + # related to the receiver's +form+.
392 456 def tag(*a, &block)
393 457 form._tag(*a, &block)
394 458 end
@@ -405,12 +469,34 @@ class Formatter
405 469
406 470 # The default formatter used by the library. Any custom formatters should
407 471 # probably inherit from this formatter unless they have very special needs.
  472 + #
  473 + # Unlike most other transformers which are registered as instances and use
  474 + # a functional style, this class is registered as a class due to the large
  475 + # amount of state it uses.
  476 + #
  477 + # Registered as :default.
408 478 class Formatter::Default < Formatter
409 479 Forme.register_transformer(:formatter, :default, self)
410 480
411   - attr_reader :input
  481 + # The +Form+ instance for the receiver, taken from the +input+.
412 482 attr_reader :form
  483 +
  484 + # The +Input+ instance for the receiver. This is what the receiver
  485 + # converts to the lower level +Tag+ form (or a +TagArray+ of them).
  486 + attr_reader :input
  487 +
  488 + # The attributes to to set on the lower level +Tag+ form returned.
  489 + # This are derived from the +input+'s +opts+, but some processing is done on
  490 + # them.
413 491 attr_reader :attr
  492 +
  493 + # The options hash related to this formatter's processing, derived
  494 + # from the +input+'s +opts+. Keys used:
  495 + # :error :: An error message for the +input+
  496 + # :error_handler :: A custom +error_handler+ to use, instead of the +form+'s default
  497 + # :label :: A label for the +input+
  498 + # :labeler :: A custom +labeler+ to use, instead of the +form+'s default
  499 + # :wrapper :: A custom +wrapper+ to use, instead of the +form+'s default
414 500 attr_reader :opts
415 501
416 502 # Used to specify the value of the hidden input created for checkboxes.
@@ -420,9 +506,10 @@ class Formatter::Default < Formatter
420 506 CHECKBOX_MAP = Hash.new(0)
421 507 CHECKBOX_MAP['t'] = 'f'
422 508
423   - # Transform the +input+ into a +Tag+ instance, wrapping it with the +form+'s
424   - # wrapper, and the form's +error_handler+ and +labeler+ if the input has an
425   - # error or a label.
  509 + # Transform the +input+ into a +Tag+ instance (or +TagArray+ of them),
  510 + # wrapping it with the +form+'s wrapper, and the form's +error_handler+
  511 + # and +labeler+ if the +input+ has an <tt>:error</tt> or <tt>:label</tt>
  512 + # options.
426 513 def call(input)
427 514 @input = input
428 515 @form = input.form
@@ -444,7 +531,8 @@ def call(input)
444 531
445 532 private
446 533
447   - # Convert the +Input+ to a +Tag+.
  534 + # Dispatch to a format_<i>type</i> method if there is one that matches the
  535 + # type, otherwise, call +format_input+ with the given +type+.
448 536 def convert_to_tag(type)
449 537 meth = :"format_#{type}"
450 538 if respond_to?(meth, true)
@@ -486,7 +574,7 @@ def format_radio
486 574 end
487 575
488 576 # The default fallback method for handling inputs. Assumes an input tag
489   - # with the type attribute set the the type of the input.
  577 + # with the type attribute set to input.
490 578 def format_input(type)
491 579 @attr[:type] = type
492 580 tag(:input)
@@ -498,6 +586,9 @@ def format_input(type)
498 586 # an array, takes the first entry in the hash as the text child
499 587 # of the option, and the last entry as the value of the option.
500 588 # if not set, ignores the remaining options.
  589 + # :add_blank :: Add a blank option if true. If the value is a string,
  590 + # use it as the text content of the blank option. The value of
  591 + # the blank option is always the empty string.
501 592 # :text_method :: If set, each entry in the array has this option called on
502 593 # it to get the text of the object.
503 594 # :value_method :: If set (and :text_method is set), each entry in the array
@@ -563,11 +654,16 @@ def format_textarea
563 654 end
564 655 end
565 656
  657 + # If +tag+ is an +Array+ and not a +TagArray+, turn it into
  658 + # a +TagArray+ related to the receiver's +form+. Otherwise,
  659 + # return +tag+.
566 660 def handle_array(tag)
567 661 (tag.is_a?(Array) && !tag.is_a?(TagArray)) ? TagArray.new(form, tag) : tag
568 662 end
569 663
570   - # Normalize the options used for all input types.
  664 + # Normalize the options used for all input types. Handles:
  665 + # :required :: Sets the +required+ attribute on the resulting tag if true.
  666 + # :disabled :: Sets the +disabled+ attribute on the resulting tag if true.
571 667 def normalize_options
572 668 @attr[:required] = :required if @attr.delete(:required)
573 669 @attr[:disabled] = :disabled if @attr.delete(:disabled)
@@ -579,6 +675,8 @@ def normalize_options
579 675 @attr.delete(:formatter)
580 676 end
581 677
  678 + # Create a +Tag+ instance related to the receiver's +form+ with the given
  679 + # arguments.
582 680 def tag(type, attr=@attr, children=[])
583 681 form._tag(type, attr, children)
584 682 end
@@ -599,12 +697,17 @@ def wrap_tag_with_label(label, tag)
599 697 end
600 698 end
601 699
602   - # Formatter that disables all input fields
  700 + # Formatter that disables all input fields,
  701 + #
  702 + # Registered as :disabled.
603 703 class Formatter::Disabled < Formatter::Default
604 704 Forme.register_transformer(:formatter, :disabled, self)
605 705
606 706 private
607 707
  708 + # Unless the :disabled option is specifically set
  709 + # to +false+, set the :disabled attribute on the
  710 + # resulting tag.
608 711 def normalize_options
609 712 if @attr.delete(:disabled) == false
610 713 super
@@ -615,8 +718,10 @@ def normalize_options
615 718 end
616 719 end
617 720
618   - # Formatter that uses text spans for most input types,
  721 + # Formatter that uses span tags with text for most input types,
619 722 # and disables radio/checkbox inputs.
  723 + #
  724 + # Registered as :readonly.
620 725 class Formatter::ReadOnly < Formatter::Default
621 726 Forme.register_transformer(:formatter, :readonly, self)
622 727
@@ -628,7 +733,7 @@ def format_checkbox
628 733 super
629 734 end
630 735
631   - # Use a span with plain text instead of an input field.
  736 + # Use a span with text instead of an input field.
632 737 def format_input(type)
633 738 tag(:span, {}, @attr[:value])
634 739 end
@@ -639,11 +744,12 @@ def format_radio
639 744 super
640 745 end
641 746
642   - # Use a span with plain text of the selected value instead of a select box.
  747 + # Use a span with text of the selected values instead of a select box.
643 748 def format_select
644 749 tag(:span, {}, [super.children.select{|o| o.attr[:selected]}.map{|o| o.children}.join(', ')])
645 750 end
646 751
  752 + # Use a span with text instead of a text area.
647 753 def format_textarea
648 754 tag(:span, {}, @attr[:value])
649 755 end
@@ -656,6 +762,8 @@ class ErrorHandler
656 762 # Default error handler used by the library, using an "error" class
657 763 # for the input field and a span tag with an "error_message" class
658 764 # for the error message.
  765 + #
  766 + # Registered as :default.
659 767 class ErrorHandler::Default < ErrorHandler
660 768 Forme.register_transformer(:error_handler, :default, new)
661 769
@@ -680,10 +788,14 @@ class Labeler
680 788
681 789 # Default labeler used by the library, using implicit labels (where the
682 790 # label tag encloses the other tag).
  791 + #
  792 + # Registered as :default.
683 793 class Labeler::Default < Labeler
684 794 Forme.register_transformer(:labeler, :default, new)
685 795
686   - # Return a label tag wrapping the given tag.
  796 + # Return a label tag wrapping the given tag. For radio and checkbox
  797 + # inputs, the label occurs directly after the tag, for all other types,
  798 + # the label occurs before the tag.
687 799 def call(label, tag)
688 800 t = if tag.is_a?(Tag) && tag.type == :input && [:radio, :checkbox].include?(tag.attr[:type])
689 801 [tag, " #{label}"]
@@ -694,14 +806,18 @@ def call(label, tag)
694 806 end
695 807 end
696 808
697   - # Explicit labelers that creates a separate label tag that references
  809 + # Explicit labeler that creates a separate label tag that references
698 810 # the given tag's id using a +for+ attribute. Requires that all tags
699 811 # with labels have +id+ fields.
  812 + #
  813 + # Registered as :explicit.
700 814 class Labeler::Explicit < Labeler
701 815 Forme.register_transformer(:labeler, :explicit, new)
702 816
703   - # Return an array with a label tag as the first entry and the given
704   - # tag as the second.
  817 + # Return an array with a label tag as the first entry and +tag+ as
  818 + # a second entry. If +tag+ is an array, scan it for the first +Tag+
  819 + # instance that isn't hidden (since hidden tags shouldn't have labels).
  820 + # If the +tag+ doesnt' have an id attribute, an +Error+ is raised.
705 821 def call(label, tag)
706 822 t = tag.is_a?(Tag) ? tag : tag.find{|tg| tg.is_a?(Tag) && tg.attr[:type] != :hidden}
707 823 id = t.attr[:id]
@@ -718,11 +834,15 @@ def call(label, tag)
718 834 class InputsWrapper
719 835 end
720 836
721   - # Default inputs_wrapper class used by the library, uses a fieldset.
  837 + # Default inputs_wrapper used by the library, uses a fieldset.
  838 + #
  839 + # Registered as :default.
722 840 class InputsWrapper::Default < InputsWrapper
723 841 Forme.register_transformer(:inputs_wrapper, :default, new)
724 842
725   - # Wrap the inputs in a fieldset
  843 + # Wrap the inputs in a fieldset. If the :legend
  844 + # option is given, add a +legend+ tag as the first
  845 + # child of the fieldset.
726 846 def call(form, opts)
727 847 if legend = opts.delete(:legend)
728 848 form.tag(:fieldset) do
@@ -735,7 +855,9 @@ def call(form, opts)
735 855 end
736 856 end
737 857
738   - # Use an ol tag to wrap the inputs
  858 + # Use an ol tag to wrap the inputs.
  859 + #
  860 + # Registered as :ol.
739 861 class InputsWrapper::OL < InputsWrapper
740 862 Forme.register_transformer(:inputs_wrapper, :ol, new)
741 863
@@ -745,11 +867,13 @@ def call(form, opts, &block)
745 867 end
746 868 end
747 869
748   - # Use a table tag to wrap the inputs
  870 + # Use a table tag to wrap the inputs.
  871 + #
  872 + # Registered as :table.
749 873 class InputsWrapper::Table < InputsWrapper
750 874 Forme.register_transformer(:inputs_wrapper, :table, new)
751 875
752   - # Wrap the inputs in a table tag
  876 + # Wrap the inputs in a table tag.
753 877 def call(form, opts, &block)
754 878 form.tag(:table, &block)
755 879 end
@@ -761,17 +885,13 @@ class Serializer
761 885
762 886 # Default serializer class used by the library. Any other serializer
763 887 # classes that want to produce html should probably subclass this class.
  888 + #
  889 + # Registered as :default.
764 890 class Serializer::Default < Serializer
765 891 Forme.register_transformer(:serializer, :default, new)
766 892
767 893 # Borrowed from Rack::Utils, map of single character strings to html escaped versions.
768   - ESCAPE_HTML = {
769   - "&" => "&amp;",
770   - "<" => "&lt;",
771   - ">" => "&gt;",
772   - "'" => "&#39;",
773   - '"' => "&quot;",
774   - }
  894 + ESCAPE_HTML = {"&" => "&amp;", "<" => "&lt;", ">" => "&gt;", "'" => "&#39;", '"' => "&quot;"}
775 895
776 896 # A regexp that matches all html characters requiring escaping.
777 897 ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
@@ -780,8 +900,10 @@ class Serializer::Default < Serializer
780 900 SELF_CLOSING = [:img, :input]
781 901
782 902 # Serialize the tag object to an html string. Supports +Tag+ instances,
  903 + # +Input+ instances (recursing into +call+ with the result of formatting the input),
783 904 # arrays (recurses into +call+ for each entry and joins the result), and
784   - # strings (html escapes them).
  905 + # (html escapes the string version of them, unless they include the +Raw+
  906 + # module, in which case no escaping is done).
785 907 def call(tag)
786 908 case tag
787 909 when Tag
@@ -792,7 +914,7 @@ def call(tag)
792 914 end
793 915 when Input
794 916 call(tag.format)
795   - when Array, TagArray
  917 + when Array
796 918 tag.map{|x| call(x)}.join
797 919 when Raw
798 920 tag.to_s
@@ -827,6 +949,8 @@ def attr_html(tag)
827 949
828 950
829 951 # Serializer class that converts tags to plain text strings.
  952 + #
  953 + # Registered at :text.
830 954 class Serializer::PlainText < Serializer
831 955 Forme.register_transformer(:serializer, :text, new)
832 956
@@ -856,10 +980,10 @@ def call(tag)
856 980 end
857 981 when Input
858 982 call(tag.format)
859   - when Array, TagArray
  983 + when Array
860 984 tag.map{|x| call(x)}.join
861 985 else
862   - tag
  986 + tag.to_s
863 987 end
864 988 end
865 989 end

0 comments on commit 9312369

Please sign in to comment.
Something went wrong with that request. Please try again.