forme 1.12.0 → 2.2.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +54 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +228 -206
  5. data/Rakefile +1 -7
  6. data/lib/forme/bs3.rb +23 -9
  7. data/lib/forme/erb.rb +13 -25
  8. data/lib/forme/form.rb +146 -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/error_handler.rb +10 -10
  15. data/lib/forme/transformers/formatter.rb +32 -34
  16. data/lib/forme/transformers/helper.rb +0 -1
  17. data/lib/forme/transformers/inputs_wrapper.rb +4 -4
  18. data/lib/forme/version.rb +2 -2
  19. data/lib/forme.rb +13 -2
  20. data/lib/roda/plugins/forme.rb +1 -1
  21. data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
  22. data/lib/roda/plugins/forme_route_csrf.rb +16 -34
  23. data/lib/roda/plugins/forme_set.rb +39 -76
  24. data/lib/sequel/plugins/forme.rb +45 -54
  25. data/lib/sequel/plugins/forme_i18n.rb +3 -1
  26. data/lib/sequel/plugins/forme_set.rb +2 -4
  27. data/spec/all.rb +1 -1
  28. data/spec/bs3_reference_spec.rb +291 -314
  29. data/spec/bs3_sequel_plugin_spec.rb +155 -155
  30. data/spec/bs3_spec.rb +247 -206
  31. data/spec/erb_helper.rb +69 -58
  32. data/spec/erubi_capture_helper.rb +198 -0
  33. data/spec/forme_coverage.rb +1 -0
  34. data/spec/forme_spec.rb +438 -377
  35. data/spec/rails_integration_spec.rb +21 -11
  36. data/spec/roda_integration_spec.rb +136 -70
  37. data/spec/sequel_helper.rb +3 -2
  38. data/spec/sequel_i18n_helper.rb +1 -1
  39. data/spec/sequel_i18n_plugin_spec.rb +6 -6
  40. data/spec/sequel_plugin_spec.rb +262 -150
  41. data/spec/sequel_set_plugin_spec.rb +9 -3
  42. data/spec/shared_erb_specs.rb +71 -0
  43. data/spec/sinatra_integration_spec.rb +31 -6
  44. data/spec/spec_helper.rb +21 -8
  45. metadata +8 -6
  46. data/lib/forme/erb_form.rb +0 -74
  47. data/lib/forme/sinatra.rb +0 -17
data/Rakefile CHANGED
@@ -50,7 +50,7 @@ end
50
50
 
51
51
  desc "Run specs"
52
52
  task :spec do
53
- sh "#{FileUtils::RUBY} spec/all.rb"
53
+ sh "#{FileUtils::RUBY} #{'-w' if RUBY_VERSION >= '3'} spec/all.rb"
54
54
  end
55
55
  task :default => :spec
56
56
 
@@ -60,12 +60,6 @@ task :spec_cov do
60
60
  sh "#{FileUtils::RUBY} spec/all.rb"
61
61
  end
62
62
 
63
- desc "Run specs with -w, some warnings filtered"
64
- task :spec_w do
65
- ENV['WARNING'] = '1'
66
- sh "#{FileUtils::RUBY} -w spec/all.rb"
67
- end
68
-
69
63
  ### Other
70
64
 
71
65
  desc "Print #{NAME} version"
data/lib/forme/bs3.rb CHANGED
@@ -24,6 +24,7 @@ module Forme
24
24
  attr = attr ? attr.dup : {}
25
25
  Forme.attr_classes(attr, 'help-block with-errors')
26
26
  return [tag] if input.opts[:skip_error_message]
27
+ attr[:id] ||= input.opts[:error_id]
27
28
 
28
29
  case input.type
29
30
  when :submit, :reset
@@ -80,12 +81,28 @@ module Forme
80
81
  copy_options_to_attributes(ATTRIBUTE_OPTIONS)
81
82
  copy_boolean_options_to_attributes(ATTRIBUTE_BOOLEAN_OPTIONS)
82
83
  handle_key_option
84
+ handle_errors_option
83
85
 
84
86
  Forme.attr_classes(@attr, @opts[:class]) if @opts.has_key?(:class)
85
- # Forme.attr_classes(@attr, 'error') if @opts[:error]
87
+
88
+ if @opts[:error] && input.type != :submit && input.type != :reset
89
+ # Forme.attr_classes(@attr, 'error')
90
+ @attr["aria-invalid"] = "true"
91
+ if @opts.fetch(:error_handler, true)
92
+ if @opts[:error_id]
93
+ @attr['aria-describedby'] ||= @opts[:error_id]
94
+ else
95
+ if id = @attr[:id] || @attr['id']
96
+ error_id = @attr['aria-describedby'] ||= "#{id}_error_message"
97
+ @opts[:error_id] = error_id
98
+ end
99
+ end
100
+ end
101
+ end
86
102
 
87
103
  if data = opts[:data]
88
104
  data.each do |k, v|
105
+ k = k.to_s.tr("_", "-") if k.is_a?(Symbol) && input.opts[:dasherize_data]
89
106
  sym = :"data-#{k}"
90
107
  @attr[sym] = v unless @attr.has_key?(sym)
91
108
  end
@@ -113,7 +130,7 @@ module Forme
113
130
  end
114
131
 
115
132
  def _format_set(type, tag_attrs={})
116
- raise Error, "can't have radioset with no options" unless @opts[:optgroups] || @opts[:options]
133
+ raise Error, "can't have radioset or checkboxset with no options" unless @opts[:optgroups] || @opts[:options]
117
134
  key = @opts[:key]
118
135
  name = @opts[:name]
119
136
  id = @opts[:id]
@@ -210,7 +227,7 @@ module Forme
210
227
  Forme.attr_classes(attr, 'inputs')
211
228
  if legend = opts[:legend]
212
229
  form.tag(:fieldset, attr) do
213
- form.emit(form.tag(:legend, opts[:legend_attr], legend))
230
+ form.tag(:legend, opts[:legend_attr], legend)
214
231
  yield
215
232
  end
216
233
  else
@@ -230,11 +247,11 @@ module Forme
230
247
  attr = opts[:attr] ? opts[:attr].dup : { :class=>'table table-bordered'}
231
248
  form.tag(:table, attr) do
232
249
  if legend = opts[:legend]
233
- form.emit(form.tag(:caption, opts[:legend_attr], legend))
250
+ form.tag(:caption, opts[:legend_attr], legend)
234
251
  end
235
252
 
236
253
  if (labels = opts[:labels]) && !labels.empty?
237
- form.emit(form.tag(:tr, {}, labels.map{|l| form._tag(:th, {}, l)}))
254
+ form.tag(:tr, {}, labels.map{|l| form._tag(:th, {}, l)})
238
255
  end
239
256
 
240
257
  yield
@@ -268,7 +285,7 @@ module Forme
268
285
  label_attr = input.opts[:label_attr]
269
286
  label_attr = label_attr ? label_attr.dup : {}
270
287
 
271
- label_attr[:for] = label_attr[:for] === false ? nil : input.opts.fetch(:label_for, id)
288
+ label_attr[:for] = label_attr[:for] == false ? nil : input.opts.fetch(:label_for, id)
272
289
  label = input.opts[:label]
273
290
  lpos = input.opts[:label_position] || ([:radio, :checkbox].include?(input.type) ? :after : :before)
274
291
 
@@ -303,9 +320,6 @@ module Forme
303
320
 
304
321
  case input.type
305
322
  when :submit, :reset
306
- klass.delete('form-group')
307
- attr[:class] = klass.sort.uniq.join(' ').strip
308
- attr.delete(:class) if attr[:class].empty?
309
323
  [tag]
310
324
  when :radio, :checkbox
311
325
  klass.delete('form-group')
data/lib/forme/erb.rb CHANGED
@@ -1,36 +1,24 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'forme/erb_form'
3
+ require_relative 'template'
4
4
 
5
5
  module Forme
6
6
  module ERB
7
- HIDDEN_TAGS = []
7
+ # This is the module used to add the Forme integration to ERB templates, with optional support for
8
+ # rack_csrf for CSRF handling.
9
+ module Helper
10
+ include Template::Helper
8
11
 
9
- # Add a hidden tag proc that will be used for all forms created via Forme::ERB::Helper#form.
10
- # The block is yielded the Forme::Tag object for the form tag.
11
- # The block should return either nil if hidden tag should be added, or a Forme::Tag object (or an array of them),
12
- # or a hash with keys specifying the name of the tags and the values specifying the values of the tags .
13
- def self.add_hidden_tag(&block)
14
- HIDDEN_TAGS << block
15
- end
12
+ private
16
13
 
17
- # Add CSRF token tag by default for POST forms
18
- add_hidden_tag do |tag|
19
- if defined?(::Rack::Csrf) && (form = tag.form) && (env = form.opts[:env]) && env['rack.session'] && (tag.attr[:method] || tag.attr['method']).to_s.upcase == 'POST'
20
- {::Rack::Csrf.field=>::Rack::Csrf.token(env)}
21
- end
22
- end
14
+ def _forme_form_options(obj, attr, opts)
15
+ super
23
16
 
24
- # This is the module used to add the Forme integration
25
- # to ERB.
26
- module Helper
27
- # Create a +Form+ object tied to the current output buffer,
28
- # using the standard ERB hidden tags.
29
- def form(obj=nil, attr={}, opts={}, &block)
30
- h = {:hidden_tags=>Forme::ERB::HIDDEN_TAGS, :env=>env}
31
- h[:output] = @_out_buf if block
32
- (obj.is_a?(Hash) ? attr = attr.merge(h) : opts = opts.merge(h))
33
- Form.form(obj, attr, opts, &block)
17
+ if defined?(::Rack::Csrf) && env['rack.session']
18
+ opts[:_before_post] = lambda do |form|
19
+ form.tag(:input, :type=>:hidden, :name=>::Rack::Csrf.field, :value=>::Rack::Csrf.token(env))
20
+ end
21
+ end
34
22
  end
35
23
  end
36
24
  end
data/lib/forme/form.rb CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  module Forme
4
4
  # The +Form+ class is the main entry point to the library.
5
- # Using the +form+, +input+, +tag+, and +inputs+ methods, one can easily build
6
- # an abstract syntax tree of +Tag+ and +Input+ instances, which can be serialized
7
- # to a string using +to_s+.
5
+ # Using the +form+, +input+, +tag+, and +inputs+ methods, one can return HTML
6
+ # form tag string (or fragments of an HTML form tag).
8
7
  class Form
9
8
  # A hash of options for the form.
10
9
  attr_reader :opts
@@ -13,13 +12,17 @@ module Forme
13
12
  # input type keys and values that are hashes of input options.
14
13
  attr_reader :input_defaults
15
14
 
16
- # The hidden tags to automatically add to the form.
17
- attr_reader :hidden_tags
15
+ # The attributes used for the form tag for this form.
16
+ attr_reader :form_tag_attributes
18
17
 
19
18
  # The +serializer+ determines how +Tag+ objects are transformed into strings.
20
19
  # Must respond to +call+ or be a registered symbol.
21
20
  attr_reader :serializer
22
21
 
22
+ # The contents of the form as a string. This should not be mutated by
23
+ # external code.
24
+ attr_reader :to_s
25
+
23
26
  # Use appropriate Form subclass for object based on the current class, if the
24
27
  # object responds to +forme_form_class+.
25
28
  def self.new(obj=nil, opts={})
@@ -30,23 +33,9 @@ module Forme
30
33
  end
31
34
  end
32
35
 
33
- # Create a +Form+ instance and yield it to the block,
34
- # injecting the opening form tag before yielding and
35
- # the closing form tag after yielding.
36
- #
37
- # Argument Handling:
38
- # No args :: Creates a +Form+ object with no options and not associated
39
- # to an +obj+, and with no attributes in the opening tag.
40
- # 1 hash arg :: Treated as opening form tag attributes, creating a
41
- # +Form+ object with no options.
42
- # 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
43
- # and no attributes in the opening tag.
44
- # 2 hash args :: First hash is opening attributes, second hash is +Form+
45
- # options.
46
- # 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
47
- # opening attributes, third if provided is
48
- # +Form+'s options.
49
- def self.form(obj=nil, attr={}, opts={}, &block)
36
+ # Parse the args given to #form and return Form instance, form tag attributes,
37
+ # and block for form.
38
+ def self.form_args(obj, attr, opts, &block)
50
39
  f = if obj.is_a?(Hash)
51
40
  raise Error, "Can't provide 3 hash arguments to form" unless opts.empty?
52
41
  opts = attr
@@ -60,12 +49,32 @@ module Forme
60
49
  button = opts[:button]
61
50
  if ins || button
62
51
  block = proc do |form|
63
- form._inputs(ins, opts) if ins
52
+ form.inputs(ins, opts) if ins
64
53
  yield form if block_given?
65
- form.emit(form.button(button)) if button
54
+ form.button(button) if button
66
55
  end
67
56
  end
68
57
 
58
+ [f, attr, block]
59
+ end
60
+
61
+ # Create a +Form+ instance and yield it to the block. Returns an HTML string
62
+ # for the form tag.
63
+ #
64
+ # Argument Handling:
65
+ # No args :: Creates a +Form+ object with no options and not associated
66
+ # to an +obj+, and with no attributes in the opening tag.
67
+ # 1 hash arg :: Treated as opening form tag attributes, creating a
68
+ # +Form+ object with no options.
69
+ # 1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
70
+ # and no attributes in the opening tag.
71
+ # 2 hash args :: First hash is opening attributes, second hash is +Form+
72
+ # options.
73
+ # 1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
74
+ # opening attributes, third if provided is
75
+ # +Form+'s options.
76
+ def self.form(obj=nil, attr={}, opts={}, &block)
77
+ f, attr, block = form_args(obj, attr, opts, &block)
69
78
  f.form(attr, &block)
70
79
  end
71
80
 
@@ -97,27 +106,33 @@ module Forme
97
106
 
98
107
  @serializer = @opts[:serializer]
99
108
  @input_defaults = @opts[:input_defaults] || {}
100
- @hidden_tags = @opts[:hidden_tags]
101
- @nesting = []
109
+ @to_s = String.new
102
110
  end
103
111
 
104
- # Create a form tag with the given attributes.
105
- def form(attr={}, &block)
112
+ # Create a form tag with the given attributes. Returns an HTML string for
113
+ # the generated form tag.
114
+ def form(attr={})
106
115
  if obj && !attr[:method] && !attr['method'] && obj.respond_to?(:forme_default_request_method)
107
- attr = attr.merge('method'=>obj.forme_default_request_method)
116
+ attr = Hash[attr]
117
+ attr['method'] = obj.forme_default_request_method
118
+ end
119
+ @form_tag_attributes = attr
120
+
121
+ tag(:form, attr) do
122
+ before_form_yield
123
+ yield self if block_given?
124
+ after_form_yield
108
125
  end
109
- tag(:form, attr, method(:hidden_form_tags), &block)
110
126
  end
111
127
 
112
- # Empty method designed to ease integration with other libraries where
113
- # Forme is used in template code and some output implicitly
114
- # created by Forme needs to be injected into the template output.
115
- def emit(tag)
128
+ # Whether the method for this form is POST. Only callable after calling
129
+ # #form.
130
+ def post?
131
+ (form_tag_attributes[:method] || form_tag_attributes['method']).to_s.upcase == 'POST'
116
132
  end
117
133
 
118
134
  # Creates an +Input+ with the given +field+ and +opts+ associated with
119
- # the receiver, and add it to the list of children to the currently
120
- # open tag.
135
+ # the receiver. Returns the HTML generated by the given input.
121
136
  #
122
137
  # If the form is associated with an +obj+, or the :obj key exists in
123
138
  # the +opts+ argument, treats the +field+ as a call to the +obj+. If
@@ -129,36 +144,39 @@ module Forme
129
144
  # type (e.g. <tt>:text</tt>, <tt>:textarea</tt>, <tt>:select</tt>), and
130
145
  # an input is created directly with the +field+ and +opts+.
131
146
  def input(field, opts={})
132
- if opts.has_key?(:obj)
133
- opts = opts.dup
134
- obj = opts.delete(:obj)
135
- else
136
- obj = self.obj
137
- end
138
- input = if obj
139
- if obj.respond_to?(:forme_input)
140
- obj.forme_input(self, field, opts.dup)
141
- else
147
+ content_added do
148
+ if opts.has_key?(:obj)
142
149
  opts = opts.dup
143
- opts[:key] = field unless opts.has_key?(:key)
144
- type = opts.delete(:type) || :text
145
- unless opts.has_key?(:value) || type == :file
146
- opts[:value] = if obj.is_a?(Hash)
147
- obj[field]
148
- else
149
- obj.send(field)
150
+ obj = opts.delete(:obj)
151
+ else
152
+ obj = self.obj
153
+ end
154
+
155
+ input = if obj
156
+ if obj.respond_to?(:forme_input)
157
+ obj.forme_input(self, field, opts.dup)
158
+ else
159
+ opts = opts.dup
160
+ opts[:key] = field unless opts.has_key?(:key)
161
+ type = opts.delete(:type) || :text
162
+ unless opts.has_key?(:value) || type == :file
163
+ opts[:value] = if obj.is_a?(Hash)
164
+ obj[field]
165
+ else
166
+ obj.send(field)
167
+ end
150
168
  end
169
+ _input(type, opts)
151
170
  end
152
- _input(type, opts)
171
+ else
172
+ _input(field, opts)
153
173
  end
154
- else
155
- _input(field, opts)
174
+
175
+ self << input
156
176
  end
157
- self << input
158
- input
159
177
  end
160
178
 
161
- # Create a new +Input+ associated with the receiver with the given
179
+ # Return a new +Input+ associated with the receiver with the given
162
180
  # arguments, doing no other processing.
163
181
  def _input(*a)
164
182
  Input.new(self, *a)
@@ -182,6 +200,8 @@ module Forme
182
200
  # wrapper to use for this inputs call. You can use the :nested_inputs_wrapper
183
201
  # option to set the default :inputs_wrapper option for the duration of the block.
184
202
  #
203
+ # Returns the HTML generated by the inputs added to the form.
204
+ #
185
205
  # This can also be called with a single hash argument to just use an options hash:
186
206
  #
187
207
  # f.inputs(:legend=>'Foo') do
@@ -193,32 +213,28 @@ module Forme
193
213
  # f.inputs do
194
214
  # # ...
195
215
  # end
196
- def inputs(inputs=[], opts={}, &block)
197
- _inputs(inputs, opts, &block)
198
- end
199
-
200
- # Internals of #inputs, should be used internally by the library, where #inputs
201
- # is designed for external use.
202
- def _inputs(inputs=[], opts={}) # :nodoc:
203
- if inputs.is_a?(Hash)
204
- opts = inputs.merge(opts)
205
- inputs = []
206
- end
216
+ def inputs(inputs=[], opts={})
217
+ content_added do
218
+ if inputs.is_a?(Hash)
219
+ opts = inputs.merge(opts)
220
+ inputs = []
221
+ end
207
222
 
208
- form_opts = {}
209
- form_opts[:inputs_wrapper] = opts[:nested_inputs_wrapper] if opts[:nested_inputs_wrapper]
210
- TRANSFORMER_TYPES.each do |t|
211
- if opts.has_key?(t) && t != :inputs_wrapper
212
- form_opts[t] = opts[t]
223
+ form_opts = {}
224
+ form_opts[:inputs_wrapper] = opts[:nested_inputs_wrapper] if opts[:nested_inputs_wrapper]
225
+ TRANSFORMER_TYPES.each do |t|
226
+ if opts.has_key?(t) && t != :inputs_wrapper
227
+ form_opts[t] = opts[t]
228
+ end
213
229
  end
214
- end
215
230
 
216
- Forme.transform(:inputs_wrapper, opts, @opts, self, opts) do
217
- with_opts(form_opts) do
218
- inputs.each do |i|
219
- emit(input(*i))
231
+ Forme.transform(:inputs_wrapper, opts, @opts, self, opts) do
232
+ with_opts(form_opts) do
233
+ inputs.each do |i|
234
+ input(*i)
235
+ end
236
+ yield if block_given?
220
237
  end
221
- yield if block_given?
222
238
  end
223
239
  end
224
240
  end
@@ -255,35 +271,34 @@ module Forme
255
271
  end
256
272
 
257
273
  # Creates a +Tag+ associated to the receiver with the given arguments.
258
- # Add the tag to the the list of children for the currently open tag.
259
- # If a block is given, make this tag the currently open tag while inside
260
- # the block.
274
+ # If a block is given, yield to the block inside the generated tag.
275
+ # Returns the HTML added to the form by the addition of this tag.
261
276
  def tag(*a, &block)
262
- tag = _tag(*a)
263
- self << tag
264
- nest(tag, &block) if block
265
- tag
266
- end
267
-
268
- # Aliased for tag. Workaround for issue with rails plugin.
269
- def tag_(*a, &block) # :nodoc:
270
- tag(*a, &block)
277
+ content_added do
278
+ tag = _tag(*a)
279
+ if block
280
+ self << serialize_open(tag)
281
+ if children = tag.children
282
+ children.each{|child| self << child}
283
+ end
284
+ yield self
285
+ self << serialize_close(tag)
286
+ else
287
+ self << tag
288
+ end
289
+ end
271
290
  end
272
291
 
273
- # Creates a :submit +Input+ with the given opts, adding it to the list
274
- # of children for the currently open tag.
292
+ # Creates a :submit +Input+ with the given opts. Returns the generated
293
+ # HTML for the input.
275
294
  def button(opts={})
276
295
  opts = {:value=>opts} if opts.is_a?(String)
277
- input = _input(:submit, opts)
278
- self << input
279
- input
296
+ content_added{self << _input(:submit, opts)}
280
297
  end
281
298
 
282
- # Add the +Input+/+Tag+ instance given to the currently open tag.
299
+ # Add the +Input+/+Tag+ instance to the HTML buffer.
283
300
  def <<(tag)
284
- if n = @nesting.last
285
- n << tag
286
- end
301
+ @to_s << tag.to_s
287
302
  end
288
303
 
289
304
  # Calls the block for each object in objs, using with_obj with the given namespace
@@ -296,18 +311,11 @@ module Forme
296
311
  end
297
312
  end
298
313
 
299
- # Return a new string that will not be html escaped by the default serializer.
314
+ # Return a new string that will not be HTML escaped by the default serializer.
300
315
  def raw(s)
301
316
  Forme.raw(s)
302
317
  end
303
318
 
304
- # Marks the string as containing already escaped output. Returns string given
305
- # by default, but subclasses for specific web frameworks can handle automatic
306
- # html escaping by overriding this.
307
- def raw_output(s)
308
- s
309
- end
310
-
311
319
  # Temporarily override the given object and namespace for the form. Any given
312
320
  # namespaces are appended to the form's current namespace.
313
321
  def with_obj(obj, namespace=nil)
@@ -325,7 +333,9 @@ module Forme
325
333
  copy_inputs_wrapper_from_wrapper(opts, @opts)
326
334
  yield
327
335
  ensure
336
+ # :nocov:
328
337
  @opts = orig_opts if orig_opts
338
+ # :nocov:
329
339
  end
330
340
 
331
341
  private
@@ -338,53 +348,40 @@ module Forme
338
348
  end
339
349
  end
340
350
 
341
- # Return array of hidden tags to use for this form,
342
- # or nil if the form does not have hidden tags added automatically.
343
- def hidden_form_tags(form_tag)
344
- if hidden_tags
345
- tags = []
346
- hidden_tags.each do |hidden_tag|
347
- hidden_tag = hidden_tag.call(form_tag) if hidden_tag.respond_to?(:call)
348
- tags.concat(parse_hidden_tags(hidden_tag))
349
- end
350
- tags
351
- end
352
- end
353
-
354
- # Handle various types of hidden tags for the form.
355
- def parse_hidden_tags(hidden_tag)
356
- case hidden_tag
357
- when Array
358
- hidden_tag
359
- when Tag, String
360
- [hidden_tag]
361
- when Hash
362
- hidden_tag.map{|k,v| _tag(:input, :type=>:hidden, :name=>k, :value=>v)}
363
- when nil
364
- []
365
- else
366
- raise Error, "unhandled hidden_tag response: #{hidden_tag.inspect}"
367
- end
368
- end
369
-
370
- # Make the given tag the currently open tag, and yield. After the
371
- # block returns, make the previously open tag the currently open
372
- # tag.
373
- def nest(tag)
374
- @nesting << tag
375
- yield self
376
- ensure
377
- @nesting.pop
351
+ # Return the HTML content added by the block.
352
+ def content_added
353
+ offset = @to_s.length
354
+ yield
355
+ @to_s[offset, @to_s.length]
378
356
  end
379
357
 
380
358
  # Return a serialized opening tag for the given tag.
381
359
  def serialize_open(tag)
382
- raw_output(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
360
+ serializer.serialize_open(tag) if serializer.respond_to?(:serialize_open)
383
361
  end
384
362
 
385
363
  # Return a serialized closing tag for the given tag.
386
364
  def serialize_close(tag)
387
- raw_output(serializer.serialize_close(tag)) if serializer.respond_to?(:serialize_close)
365
+ serializer.serialize_close(tag) if serializer.respond_to?(:serialize_close)
366
+ end
367
+
368
+ # Call before hooks if defined.
369
+ def before_form_yield
370
+ # _before_post and _before hooks are only for internal use
371
+ opts[:_before_post].call(self) if opts[:_before_post] && post?
372
+ opts[:_before].call(self) if opts[:_before]
373
+
374
+ # before hook is for external use
375
+ opts[:before].call(self) if opts[:before]
376
+ end
377
+
378
+ # Call after hooks if defined.
379
+ def after_form_yield
380
+ # after hook is for external use
381
+ opts[:after].call(self) if opts[:after]
382
+
383
+ # _after hook is only for internal use
384
+ opts[:_after].call(self) if opts[:_after]
388
385
  end
389
386
  end
390
387
  end
data/lib/forme/input.rb CHANGED
@@ -32,7 +32,7 @@ module Forme
32
32
 
33
33
  # Return a string containing the serialized content of the receiver.
34
34
  def to_s
35
- form.raw_output(Forme.transform(:serializer, @opts, @form_opts, self))
35
+ Forme.transform(:serializer, @opts, @form_opts, self)
36
36
  end
37
37
 
38
38
  # Transform the receiver into a lower level +Tag+ form (or an array