forme 0.5.0 → 0.6.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.
data/CHANGELOG CHANGED
@@ -1 +1,37 @@
1
- === HEAD
1
+ === 0.6.0 (2011-08-01)
2
+
3
+ * Fix wrapping for :as=>:radio boolean fields to handle them like association :as=>:radio fields (jeremyevans)
4
+
5
+ * Fix handling of Raw :label option in for association fields with :as=>:radio and :as=>:checkbox in the Sequel plugin (jeremyevans)
6
+
7
+ * Use label text for :as=>:radio boolean fields in the Sequel plugin (jeremyevans)
8
+
9
+ * Support overriding the true/false label and values for :as=>:radio boolean fields in the Sequel plugin (jeremyevans)
10
+
11
+ * Allow overriding the type of input for schema columns and associations in the Sequel plugin (jeremyevans)
12
+
13
+ * Add the label before the error option, so the error always comes after the label (jeremyevans)
14
+
15
+ * Always add error class to formatted input tag, regardless of error_handler (jeremyevans)
16
+
17
+ * Add labels to inputs for fields that the object doesn't respond to in the Sequel plugin (jeremyevans)
18
+
19
+ * Allow customization for non-schema columns that the object responds to in the Sequel plugin (jeremyevans)
20
+
21
+ * Handle errors on all inputs in the Sequel plugin, not just those backed by columns (jeremyevans)
22
+
23
+ * Fix default error_handler if input yields an area of tags (jeremyevans)
24
+
25
+ * Support :as=>:radio option for boolean fields in the Sequel plugin (jeremyevans)
26
+
27
+ * Allow specifying label attributes with :label_attr in labelers (jeremyevans)
28
+
29
+ * Allow Form#inputs to be called with a single options hash argument (jeremyevans)
30
+
31
+ * Handle unrecognized fields in the Sequel plugin if a :type option is given (jeremyevans)
32
+
33
+ * Add required * to label even if :label is already specified in the Sequel plugin (jeremyevans)
34
+
35
+ === 0.5.0 (2011-07-01)
36
+
37
+ * Initial Release
@@ -355,6 +355,10 @@ module Forme
355
355
  # +inputs_wrapper+ supports a <tt>:legend</tt> option that is used to
356
356
  # set the legend for the fieldset.
357
357
  def inputs(inputs=[], opts={})
358
+ if inputs.is_a?(Hash)
359
+ opts = inputs.merge(opts)
360
+ inputs = []
361
+ end
358
362
  transform(:inputs_wrapper, opts, self, opts) do
359
363
  inputs.each do |i|
360
364
  emit(input(*i))
@@ -623,8 +627,8 @@ module Forme
623
627
  normalize_options
624
628
 
625
629
  tag = convert_to_tag(input.type)
626
- tag = wrap_tag_with_error(tag) if input.opts[:error]
627
630
  tag = wrap_tag_with_label(tag) if input.opts[:label]
631
+ tag = wrap_tag_with_error(tag) if input.opts[:error]
628
632
  wrap_tag(tag)
629
633
  end
630
634
 
@@ -803,6 +807,7 @@ module Forme
803
807
  end
804
808
 
805
809
  Forme.attr_classes(@attr, @opts[:class]) if @opts.has_key?(:class)
810
+ Forme.attr_classes(@attr, 'error') if @opts[:error]
806
811
 
807
812
  if data = opts[:data]
808
813
  data.each do |k, v|
@@ -907,12 +912,7 @@ module Forme
907
912
 
908
913
  # Return tag with error message span tag after it.
909
914
  def call(tag, input)
910
- msg_tag = tag.tag(:span, {:class=>'error_message'}, input.opts[:error])
911
- if tag.is_a?(Tag)
912
- attr = tag.attr
913
- Forme.attr_classes(attr, 'error')
914
- end
915
- [tag, msg_tag]
915
+ [tag, input.tag(:span, {:class=>'error_message'}, input.opts[:error])]
916
916
  end
917
917
  end
918
918
 
@@ -933,7 +933,7 @@ module Forme
933
933
  else
934
934
  [label, ": ", tag]
935
935
  end
936
- input.tag(:label, {}, t)
936
+ input.tag(:label, input.opts[:label_attr]||{}, t)
937
937
  end
938
938
  end
939
939
 
@@ -951,7 +951,7 @@ module Forme
951
951
  # :label_for option is used, the label created will not be
952
952
  # associated with an input.
953
953
  def call(tag, input)
954
- [input.tag(:label, {:for=>input.opts.fetch(:label_for, input.opts[:id])}, [input.opts[:label]]), tag]
954
+ [input.tag(:label, {:for=>input.opts.fetch(:label_for, input.opts[:id])}.merge(input.opts[:label_attr]||{}), [input.opts[:label]]), tag]
955
955
  end
956
956
  end
957
957
 
@@ -960,7 +960,7 @@ module Forme
960
960
  Forme.register_transformer(:wrapper, x){|tag, input| input.tag(x, input.opts[:wrapper_attr], Array(tag))}
961
961
  end
962
962
  Forme.register_transformer(:wrapper, :trtd) do |tag, input|
963
- a = Array(tag)
963
+ a = Array(tag).flatten
964
964
  input.tag(:tr, input.opts[:wrapper_attr], a.length == 1 ? input.tag(:td, {}, a) : [input.tag(:td, {}, [a.first]), input.tag(:td, {}, a[1..-1])])
965
965
  end
966
966
 
@@ -1,6 +1,6 @@
1
1
  module Forme
2
2
  # Version constant, use <tt>Forme.version</tt> instead.
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.6.0'.freeze
4
4
 
5
5
  # Returns the version as a frozen string (e.g. '0.1.0')
6
6
  def self.version
@@ -151,10 +151,11 @@ module Sequel # :nodoc:
151
151
  def input
152
152
  opts[:attr] = opts[:attr] ? opts[:attr].dup : {}
153
153
  opts[:wrapper_attr] = opts[:wrapper_attr] ? opts[:wrapper_attr].dup : {}
154
+ handle_errors(field)
155
+ handle_validations(field)
154
156
 
155
- if sch = obj.db_schema[field]
156
- handle_errors(field)
157
- handle_validations(field)
157
+ type = opts[:type]
158
+ if !type && (sch = obj.db_schema[field])
158
159
  meth = :"input_#{sch[:type]}"
159
160
  opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
160
161
  opts[:name] = form.namespaced_name(field) unless opts.has_key?(:name)
@@ -169,7 +170,7 @@ module Sequel # :nodoc:
169
170
  else
170
171
  input_other(sch)
171
172
  end
172
- elsif ref = obj.model.association_reflection(field)
173
+ elsif !type && (ref = obj.model.association_reflection(field))
173
174
  ::Forme.attr_classes(opts[:wrapper_attr], ref[:type])
174
175
  meth = :"association_#{ref[:type]}"
175
176
  if respond_to?(meth, true)
@@ -177,13 +178,20 @@ module Sequel # :nodoc:
177
178
  else
178
179
  raise Error, "Association type #{ref[:type]} not currently handled for association #{ref[:name]}"
179
180
  end
180
- elsif obj.respond_to?(field)
181
+ else
182
+ rt = obj.respond_to?(field)
183
+ raise(Error, "Unrecognized field used: #{field}") unless rt || type
184
+ meth = :"input_#{type}"
185
+ opts[:value] = nil unless rt || opts.has_key?(:value)
181
186
  opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
182
- opts[:name] = form.namespaced_name(field) unless opts.has_key?(:name)
187
+ opts[:name] = form.namespaced_name(field, opts[:multiple]) unless opts.has_key?(:name)
183
188
  handle_label(field)
184
- input_other({})
185
- else
186
- raise Error, "Unrecognized field used: #{field}"
189
+ if respond_to?(meth, true)
190
+ opts.delete(:type)
191
+ send(meth, opts)
192
+ else
193
+ input_other(opts)
194
+ end
187
195
  end
188
196
  end
189
197
 
@@ -205,13 +213,27 @@ module Sequel # :nodoc:
205
213
  # Set the label option appropriately, adding a * if the field
206
214
  # is required.
207
215
  def handle_label(f)
208
- unless opts.has_key?(:label)
209
- opts[:label] = if opts[:required]
210
- [humanize(field), form._tag(:abbr, {:title=>'required'}, '*')]
211
- else
212
- humanize(field)
213
- end
216
+ opts[:label] = humanize(field) unless opts.has_key?(:label)
217
+ opts[:label] = [opts[:label], form._tag(:abbr, {:title=>'required'}, '*')] if opts[:required]
218
+ end
219
+
220
+ # Add the label to the start of the array, returning the array.
221
+ def add_label(label, array)
222
+ if label
223
+ array.unshift(": ") unless label.is_a?(::Forme::Raw)
224
+ array.unshift(label)
214
225
  end
226
+ array
227
+ end
228
+
229
+ # Unset the wrapper and tag_wrapper options and return a
230
+ # array with the wrapper and tag_wrapper to use. The tag_wrapper
231
+ # is for wrapping each individual tag.
232
+ def get_wrappers
233
+ tag_wrapper = opts.delete(:tag_wrapper) || :default
234
+ wrapper = form.transformer(:wrapper, opts)
235
+ opts.delete(:wrapper)
236
+ [wrapper, tag_wrapper]
215
237
  end
216
238
 
217
239
  # Update the attributes and options for any recognized validations
@@ -284,11 +306,9 @@ module Sequel # :nodoc:
284
306
  handle_label(field)
285
307
  label = opts.delete(:label)
286
308
  val = opts.delete(:value)
287
- tag_wrapper = opts.delete(:tag_wrapper) || :default
288
- wrapper = form.transformer(:wrapper, opts)
289
- opts.delete(:wrapper)
309
+ wrapper, tag_wrapper = get_wrappers
290
310
  radios = opts.delete(:options).map{|l, pk| _input(:radio, opts.merge(:value=>pk, :wrapper=>tag_wrapper, :label=>l, :checked=>(pk == val)))}
291
- radios.unshift("#{label}: ")
311
+ add_label(label, radios)
292
312
  wrapper ? wrapper.call(radios, _input(:radio, opts)) : radios
293
313
  else
294
314
  opts[:id] = form.namespaced_id(key) unless opts.has_key?(:id)
@@ -317,11 +337,9 @@ module Sequel # :nodoc:
317
337
  if opts.delete(:as) == :checkbox
318
338
  label = opts.delete(:label)
319
339
  val = opts.delete(:value)
320
- tag_wrapper = opts.delete(:tag_wrapper) || :default
321
- wrapper = form.transformer(:wrapper, opts)
322
- opts.delete(:wrapper)
340
+ wrapper, tag_wrapper = get_wrappers
323
341
  cbs = opts.delete(:options).map{|l, pk| _input(:checkbox, opts.merge(:value=>pk, :wrapper=>tag_wrapper, :label=>l, :checked=>val.include?(pk), :no_hidden=>true))}
324
- cbs.unshift("#{label}: ")
342
+ add_label(label, cbs)
325
343
  wrapper ? wrapper.call(cbs, _input(:checkbox, opts)) : cbs
326
344
  else
327
345
  opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
@@ -346,7 +364,26 @@ module Sequel # :nodoc:
346
364
  # If the column allows +NULL+ values, use a three-valued select
347
365
  # input. If not, use a simple checkbox.
348
366
  def input_boolean(sch)
349
- if sch[:allow_null]
367
+ unless opts.has_key?(:as)
368
+ opts[:as] = sch[:allow_null] ? :select : :checkbox
369
+ end
370
+
371
+ case opts[:as]
372
+ when :radio
373
+ wrapper, tag_wrapper = get_wrappers
374
+ true_opts = opts.merge(:value=>opts[:true_value]||'t', :label=>opts[:true_label]||'Yes', :error=>nil, :wrapper=>tag_wrapper, :wrapper_attr=>{})
375
+ false_opts = opts.merge(:value=>opts[:false_value]||'f', :label=>opts[:false_label]||'No', :wrapper=>tag_wrapper, :wrapper_attr=>{})
376
+ if i = opts[:id]
377
+ true_opts[:id] = "#{i}_yes"
378
+ false_opts[:id] = "#{i}_no"
379
+ end
380
+ v = opts.has_key?(:value) ? opts[:value] : obj.send(field)
381
+ unless v.nil?
382
+ (v ? true_opts : false_opts)[:checked] = true
383
+ end
384
+ array = add_label(opts[:label], [_input(:radio, true_opts), _input(:radio, false_opts)])
385
+ wrapper ? wrapper.call(array, _input(:radio, opts)) : array
386
+ when :select
350
387
  v = opts[:value] || obj.send(field)
351
388
  opts[:value] = (v ? 't' : 'f') unless v.nil?
352
389
  opts[:add_blank] = true
@@ -177,10 +177,18 @@ describe "Forme plain forms" do
177
177
  @f.input(:text, :label=>'Foo', :value=>'foo').to_s.should == '<label>Foo: <input type="text" value="foo"/></label>'
178
178
  end
179
179
 
180
+ specify "should set label attributes with :label_attr option" do
181
+ @f.input(:text, :label=>'Foo', :value=>'foo', :label_attr=>{:class=>'bar'}).to_s.should == '<label class="bar">Foo: <input type="text" value="foo"/></label>'
182
+ end
183
+
180
184
  specify "should automatically note the input has errors if :error option is used" do
181
185
  @f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.should == '<input class="error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
182
186
  end
183
187
 
188
+ specify "should add an error message after the label" do
189
+ @f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :label=>"Foo").to_s.should == '<label>Foo: <input class="error" type="text" value="foo"/></label><span class="error_message">Bad Stuff!</span>'
190
+ end
191
+
184
192
  specify "should add to existing :class option if :error option is used" do
185
193
  @f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.should == '<input class="bar error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
186
194
  end
@@ -279,7 +287,7 @@ describe "Forme plain forms" do
279
287
  end
280
288
 
281
289
  specify "inputs should accept a :error_handler option to use a custom error_handler" do
282
- @f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.should == '<textarea id="foo"></textarea>!!! bar'
290
+ @f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.should == '<textarea class="error" id="foo"></textarea>!!! bar'
283
291
  end
284
292
 
285
293
  specify "#inputs should accept a :inputs_wrapper option to use a custom inputs_wrapper" do
@@ -295,13 +303,17 @@ describe "Forme plain forms" do
295
303
  end
296
304
 
297
305
  specify "inputs should accept a :error_handler=>nil option to not use an error_handler" do
298
- @f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.should == '<textarea id="foo"></textarea>'
306
+ @f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.should == '<textarea class="error" id="foo"></textarea>'
299
307
  end
300
308
 
301
309
  specify "#inputs should accept a :inputs_wrapper=>nil option to not use an inputs_wrapper" do
302
310
  @f.form{|f| f.inputs([:textarea], :inputs_wrapper=>nil)}.to_s.should == '<form><textarea></textarea></form>'
303
311
  end
304
312
 
313
+ specify "#inputs should treat a single hash argument as an options hash with no default inputs" do
314
+ @f.inputs(:inputs_wrapper=>:ol){@f.input(:textarea)}.to_s.should == '<ol><textarea></textarea></ol>'
315
+ end
316
+
305
317
  specify "invalid custom transformers should raise an Error" do
306
318
  proc{Forme::Form.new(:wrapper=>Object.new)}.should raise_error(Forme::Error)
307
319
  proc{@f.input(:textarea, :wrapper=>Object.new).to_s}.should raise_error(Forme::Error)
@@ -323,7 +335,7 @@ describe "Forme custom" do
323
335
  end
324
336
 
325
337
  specify "error_handlers can be specified as a proc" do
326
- Forme::Form.new(:error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}).input(:textarea, :name=>'foo', :error=>'bar').to_s.should == '<textarea name="foo"></textarea>!!! bar'
338
+ Forme::Form.new(:error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}).input(:textarea, :name=>'foo', :error=>'bar').to_s.should == '<textarea class="error" name="foo"></textarea>!!! bar'
327
339
  end
328
340
 
329
341
  specify "wrappers can be specified as a proc" do
@@ -434,18 +446,18 @@ end
434
446
 
435
447
  describe "Forme registering custom transformers" do
436
448
  specify "should have #register_transformer register a transformer object for later use" do
437
- Forme.register_transformer(:wrapper, :div, proc{|t, i| t.tag(:div, {}, [t])})
438
- Forme::Form.new(:wrapper=>:div).input(:textarea).to_s.should == '<div><textarea></textarea></div>'
449
+ Forme.register_transformer(:wrapper, :div2, proc{|t, i| i.tag(:div2, {}, [t])})
450
+ Forme::Form.new(:wrapper=>:div2).input(:textarea).to_s.should == '<div2><textarea></textarea></div2>'
439
451
  end
440
452
 
441
453
  specify "should have #register_transformer register a transformer block for later use" do
442
- Forme.register_transformer(:wrapper, :div1){|t, i| t.tag(:div1, {}, [t])}
454
+ Forme.register_transformer(:wrapper, :div1){|t, i| i.tag(:div1, {}, [t])}
443
455
  Forme::Form.new(:wrapper=>:div1).input(:textarea).to_s.should == '<div1><textarea></textarea></div1>'
444
456
  end
445
457
 
446
458
  specify "should have #register_transformer raise an error if given a block and an object" do
447
459
  proc do
448
- Forme.register_transformer(:wrapper, :div1, proc{|t, i| t}){|t| t.tag(:div1, {}, [t])}
460
+ Forme.register_transformer(:wrapper, :div1, proc{|t, i| t}){|t, i| i.tag(:div1, {}, [t])}
449
461
  end.should raise_error(Forme::Error)
450
462
  end
451
463
  end
@@ -124,6 +124,10 @@ describe "Forme Sequel::Model forms" do
124
124
  @b.input(:name, :required=>true).to_s.should == '<label>Name<abbr title="required">*</abbr>: <input id="album_name" name="album[name]" required="required" type="text" value="b"/></label>'
125
125
  end
126
126
 
127
+ specify "should add required to label even if :label option specified" do
128
+ @b.input(:name, :required=>true, :label=>'Foo').to_s.should == '<label>Foo<abbr title="required">*</abbr>: <input id="album_name" name="album[name]" required="required" type="text" value="b"/></label>'
129
+ end
130
+
127
131
  specify "should include required wrapper class if required" do
128
132
  f = Forme::Form.new(@ab, :wrapper=>:li)
129
133
  f.input(:name, :required=>true).to_s.should == '<li class="string required"><label>Name<abbr title="required">*</abbr>: <input id="album_name" name="album[name]" required="required" type="text" value="b"/></label></li>'
@@ -139,11 +143,44 @@ describe "Forme Sequel::Model forms" do
139
143
  @c.input(:platinum).to_s.should == '<label><input id="album_platinum_hidden" name="album[platinum]" type="hidden" value="f"/><input checked="checked" id="album_platinum" name="album[platinum]" type="checkbox" value="t"/> Platinum</label>'
140
144
  end
141
145
 
146
+ specify "should use radio buttons for boolean fields if :as=>:radio is used" do
147
+ @b.input(:platinum, :as=>:radio).to_s.should == 'Platinum: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label>'
148
+ @c.input(:platinum, :as=>:radio).to_s.should == 'Platinum: <label><input checked="checked" id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label>'
149
+ end
150
+
151
+ specify "should wrap both inputs if :as=>:radio is used" do
152
+ @b = Forme::Form.new(@ab, :wrapper=>:li)
153
+ @b.input(:platinum, :as=>:radio).to_s.should == '<li class="boolean">Platinum: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label></li>'
154
+ @b.input(:platinum, :as=>:radio, :wrapper=>:div, :tag_wrapper=>:span).to_s.should == '<div class="boolean">Platinum: <span><label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label></span><span><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label></span></div>'
155
+ end
156
+
157
+ specify "should handle errors on radio buttons for boolean fields if :as=>:radio is used" do
158
+ @ab.errors.add(:platinum, 'foo')
159
+ @b.input(:platinum, :as=>:radio).to_s.should == 'Platinum: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input checked="checked" class="error" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label><span class="error_message">foo</span>'
160
+ end
161
+
162
+ specify "should handle Raw :label options if :as=>:radio is used" do
163
+ @b.input(:platinum, :as=>:radio, :label=>'Foo:<br />'.extend(Forme::Raw)).to_s.should == 'Foo:<br /><label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label>'
164
+ @b.input(:platinum, :as=>:radio, :label=>'Foo:<br />').to_s.should == 'Foo:&lt;br /&gt;: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label>'
165
+ end
166
+
167
+ specify "should respect :true_label and :false_label options for boolean fields if :as=>:radio is used" do
168
+ @b.input(:platinum, :as=>:radio, :true_label=>"Foo", :false_label=>"Bar").to_s.should == 'Platinum: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Foo</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> Bar</label>'
169
+ end
170
+
171
+ specify "should respect :true_value and :false_value options for boolean fields if :as=>:radio is used" do
172
+ @b.input(:platinum, :as=>:radio, :true_value=>"Foo", :false_value=>"Bar").to_s.should == 'Platinum: <label><input id="album_platinum_yes" name="album[platinum]" type="radio" value="Foo"/> Yes</label><label><input checked="checked" id="album_platinum_no" name="album[platinum]" type="radio" value="Bar"/> No</label>'
173
+ end
174
+
142
175
  specify "should use a select box for many_to_one associations" do
143
176
  @b.input(:artist).to_s.should == '<label>Artist: <select id="album_artist_id" name="album[artist_id]"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label>'
144
177
  @c.input(:artist).to_s.should == '<label>Artist: <select id="album_artist_id" name="album[artist_id]"><option value=""></option><option value="1">a</option><option selected="selected" value="2">d</option></select></label>'
145
178
  end
146
179
 
180
+ specify "should allow overriding default input type using a :type option" do
181
+ @b.input(:artist, :type=>:string, :value=>nil).to_s.should == '<label>Artist: <input id="album_artist" name="album[artist]" type="text"/></label>'
182
+ end
183
+
147
184
  specify "should use a required wrapper tag for many_to_one required associations" do
148
185
  @b.input(:artist, :required=>true, :wrapper=>:li).to_s.should == '<li class="many_to_one required"><label>Artist<abbr title="required">*</abbr>: <select id="album_artist_id" name="album[artist_id]" required="required"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label></li>'
149
186
  end
@@ -153,6 +190,11 @@ describe "Forme Sequel::Model forms" do
153
190
  @c.input(:artist, :as=>:radio).to_s.should == 'Artist: <label><input name="album[artist_id]" type="radio" value="1"/> a</label><label><input checked="checked" name="album[artist_id]" type="radio" value="2"/> d</label>'
154
191
  end
155
192
 
193
+ specify "should handle Raw label for many_to_one associations with :as=>:radio option" do
194
+ @b.input(:artist, :as=>:radio, :label=>'Foo:<br />'.extend(Forme::Raw)).to_s.should == 'Foo:<br /><label><input checked="checked" name="album[artist_id]" type="radio" value="1"/> a</label><label><input name="album[artist_id]" type="radio" value="2"/> d</label>'
195
+ @b.input(:artist, :as=>:radio, :label=>'Foo<br />').to_s.should == 'Foo&lt;br /&gt;: <label><input checked="checked" name="album[artist_id]" type="radio" value="1"/> a</label><label><input name="album[artist_id]" type="radio" value="2"/> d</label>'
196
+ end
197
+
156
198
  specify "should correctly use the forms wrapper for wrapping radio buttons for many_to_one associations with :as=>:radio option" do
157
199
  @b = Forme::Form.new(@ab, :wrapper=>:li)
158
200
  @b.input(:artist, :as=>:radio).to_s.should == '<li class="many_to_one">Artist: <label><input checked="checked" name="album[artist_id]" type="radio" value="1"/> a</label><label><input name="album[artist_id]" type="radio" value="2"/> d</label></li>'
@@ -221,6 +263,11 @@ describe "Forme Sequel::Model forms" do
221
263
  @c.input(:tags, :as=>:checkbox).to_s.should == 'Tags: <label><input name="album[tag_pks][]" type="checkbox" value="1"/> s</label><label><input checked="checked" name="album[tag_pks][]" type="checkbox" value="2"/> t</label><label><input name="album[tag_pks][]" type="checkbox" value="3"/> u</label>'
222
264
  end
223
265
 
266
+ specify "should handle Raw label for associations with :as=>:checkbox" do
267
+ @b.input(:tracks, :as=>:checkbox, :label=>'Foo<br />:'.extend(Forme::Raw)).to_s.should == 'Foo<br />:<label><input checked="checked" name="album[track_pks][]" type="checkbox" value="1"/> m</label><label><input checked="checked" name="album[track_pks][]" type="checkbox" value="2"/> n</label><label><input name="album[track_pks][]" type="checkbox" value="3"/> o</label>'
268
+ @b.input(:tracks, :as=>:checkbox, :label=>'Foo<br />').to_s.should == 'Foo&lt;br /&gt;: <label><input checked="checked" name="album[track_pks][]" type="checkbox" value="1"/> m</label><label><input checked="checked" name="album[track_pks][]" type="checkbox" value="2"/> n</label><label><input name="album[track_pks][]" type="checkbox" value="3"/> o</label>'
269
+ end
270
+
224
271
  specify "should correctly use the forms wrapper for wrapping radio buttons for one_to_many associations with :as=>:checkbox option" do
225
272
  @b = Forme::Form.new(@ab, :wrapper=>:li)
226
273
  @b.input(:tracks, :as=>:checkbox).to_s.should == '<li class="one_to_many">Tracks: <label><input checked="checked" name="album[track_pks][]" type="checkbox" value="1"/> m</label><label><input checked="checked" name="album[track_pks][]" type="checkbox" value="2"/> n</label><label><input name="album[track_pks][]" type="checkbox" value="3"/> o</label></li>'
@@ -236,14 +283,29 @@ describe "Forme Sequel::Model forms" do
236
283
  @c.input(:artist_name).to_s.should == '<label>Artist name: <input id="album_artist_name" name="album[artist_name]" type="text" value="d"/></label>'
237
284
  end
238
285
 
286
+ specify "should handle errors on methods not backed by columns" do
287
+ @ab.errors.add(:artist_name, 'foo')
288
+ @b.input(:artist_name).to_s.should == '<label>Artist name: <input class="error" id="album_artist_name" name="album[artist_name]" type="text" value="a"/></label><span class="error_message">foo</span>'
289
+ end
290
+
291
+ specify "should respect a :type option with a schema type as the input type for methods not backed by columns" do
292
+ def @ab.foo; false end
293
+ @b.input(:foo, :type=>:boolean, :as=>:select).to_s.should == '<label>Foo: <select id="album_foo" name="album[foo]"><option value=""></option><option value="t">True</option><option selected="selected" value="f">False</option></select></label>'
294
+ end
295
+
296
+ specify "should respect a :type option with an input type as the input type for methods not backed by columns" do
297
+ def @ab.foo; "bar" end
298
+ @b.input(:foo, :type=>:phone).to_s.should == '<label>Foo: <input id="album_foo" name="album[foo]" type="phone" value="bar"/></label>'
299
+ end
300
+
239
301
  specify "should correctly show an error message if there is one" do
240
302
  @ab.errors.add(:name, 'tis not valid')
241
- @b.input(:name).to_s.should == '<label>Name: <input class="error" id="album_name" name="album[name]" type="text" value="b"/><span class="error_message">tis not valid</span></label>'
303
+ @b.input(:name).to_s.should == '<label>Name: <input class="error" id="album_name" name="album[name]" type="text" value="b"/></label><span class="error_message">tis not valid</span>'
242
304
  end
243
305
 
244
306
  specify "should correctly show an error message for many_to_one associations if there is one" do
245
307
  @ab.errors.add(:artist_id, 'tis not valid')
246
- @b.input(:artist).to_s.should == '<label>Artist: <select class="error" id="album_artist_id" name="album[artist_id]"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select><span class="error_message">tis not valid</span></label>'
308
+ @b.input(:artist).to_s.should == '<label>Artist: <select class="error" id="album_artist_id" name="album[artist_id]"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label><span class="error_message">tis not valid</span>'
247
309
  end
248
310
 
249
311
  specify "should raise an error for unhandled associations" do
@@ -252,10 +314,23 @@ describe "Forme Sequel::Model forms" do
252
314
  proc{Forme::Form.new(al.new).input(:tags)}.should raise_error(Forme::Error)
253
315
  end
254
316
 
255
- specify "should raise an error for unhandled fields" do
317
+ specify "should raise an error for unhandled fields with no :type option" do
256
318
  proc{@b.input(:foo)}.should raise_error(Forme::Error)
257
319
  end
258
320
 
321
+ specify "should respect a :type option with a schema type as the input type for unhandled fields" do
322
+ @b.input(:foo, :type=>:string).to_s.should == '<label>Foo: <input id="album_foo" name="album[foo]" type="text"/></label>'
323
+ @b.input(:password, :type=>:string).to_s.should == '<label>Password: <input id="album_password" name="album[password]" type="password"/></label>'
324
+ end
325
+
326
+ specify "should respect a :type option with an input type as the input type for unhandled fields" do
327
+ @b.input(:foo, :type=>:phone).to_s.should == '<label>Foo: <input id="album_foo" name="album[foo]" type="phone"/></label>'
328
+ end
329
+
330
+ specify "should respect a :multiple option for the name attribute for unhandled fields" do
331
+ @b.input(:foo, :type=>:phone, :multiple=>true).to_s.should == '<label>Foo: <input id="album_foo" name="album[foo][]" type="phone"/></label>'
332
+ end
333
+
259
334
  specify "should add required attribute if the column doesn't support nil values" do
260
335
  def @ab.db_schema; h = super.dup; h[:name] = h[:name].merge(:allow_null=>false); h end
261
336
  @b.input(:name).to_s.should == '<label>Name<abbr title="required">*</abbr>: <input id="album_name" name="album[name]" required="required" type="text" value="b"/></label>'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jeremy Evans
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-01 00:00:00 -07:00
18
+ date: 2011-08-01 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21