forme 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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