ShadowBelmolve-formtastic 0.1.6 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
- module JustinFrench
2
- module Formtastic
3
- class SemanticFormBuilder < ::Formtastic::SemanticFormBuilder
1
+ module JustinFrench #:nodoc:
2
+ module Formtastic #:nodoc:
3
+ class SemanticFormBuilder < ::Formtastic::SemanticFormBuilder #:nodoc:
4
4
  def initialize(*args)
5
5
  ::ActiveSupport::Deprecation.warn("JustinFrench::Formtastic::SemanticFormBuilder is deprecated. User Formtastic::SemanticFormBuilder instead", caller)
6
6
  super
@@ -62,7 +62,7 @@ describe 'Formtastic' do
62
62
  @fred.stub!(:login).and_return('fred_smith')
63
63
  @fred.stub!(:id).and_return(37)
64
64
  @fred.stub!(:new_record?).and_return(false)
65
- @fred.stub!(:errors).and_return(mock('errors', :on => nil))
65
+ @fred.stub!(:errors).and_return(mock('errors', :[] => nil))
66
66
 
67
67
  @bob = mock('user')
68
68
  @bob.stub!(:class).and_return(Author)
@@ -72,20 +72,20 @@ describe 'Formtastic' do
72
72
  @bob.stub!(:posts).and_return([])
73
73
  @bob.stub!(:post_ids).and_return([])
74
74
  @bob.stub!(:new_record?).and_return(false)
75
- @bob.stub!(:errors).and_return(mock('errors', :on => nil))
75
+ @bob.stub!(:errors).and_return(mock('errors', :[] => nil))
76
76
 
77
77
  Author.stub!(:find).and_return([@fred, @bob])
78
78
  Author.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
79
79
  Author.stub!(:human_name).and_return('Author')
80
80
  Author.stub!(:reflect_on_all_validations).and_return([])
81
- Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :klass => Post, :macro => :has_many) if column_name == :posts }
81
+ Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Post, :macro => :has_many) if column_name == :posts }
82
82
 
83
83
  # Sometimes we need a mock @post object and some Authors for belongs_to
84
84
  @new_post = mock('post')
85
85
  @new_post.stub!(:class).and_return(Post)
86
86
  @new_post.stub!(:id).and_return(nil)
87
87
  @new_post.stub!(:new_record?).and_return(true)
88
- @new_post.stub!(:errors).and_return(mock('errors', :on => nil))
88
+ @new_post.stub!(:errors).and_return(mock('errors', :[] => nil))
89
89
  @new_post.stub!(:author).and_return(nil)
90
90
 
91
91
  @freds_post = mock('post')
@@ -97,7 +97,7 @@ describe 'Formtastic' do
97
97
  @freds_post.stub!(:authors).and_return([@fred])
98
98
  @freds_post.stub!(:author_ids).and_return([@fred.id])
99
99
  @freds_post.stub!(:new_record?).and_return(false)
100
- @freds_post.stub!(:errors).and_return(mock('errors', :on => nil))
100
+ @freds_post.stub!(:errors).and_return(mock('errors', :[] => nil))
101
101
  @fred.stub!(:posts).and_return([@freds_post])
102
102
  @fred.stub!(:post_ids).and_return([@freds_post.id])
103
103
 
@@ -106,10 +106,10 @@ describe 'Formtastic' do
106
106
  Post.stub!(:reflect_on_all_validations).and_return([])
107
107
  Post.stub!(:reflect_on_association).and_return do |column_name|
108
108
  case column_name
109
- when :author
110
- mock('reflection', :klass => Author, :macro => :belongs_to)
109
+ when :author, :author_status
110
+ mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to)
111
111
  when :authors
112
- mock('reflection', :klass => Author, :macro => :has_and_belongs_to_many)
112
+ mock('reflection', :options => {}, :klass => Author, :macro => :has_and_belongs_to_many)
113
113
  end
114
114
  end
115
115
  Post.stub!(:find).and_return([@freds_post])
@@ -234,6 +234,10 @@ describe 'Formtastic' do
234
234
  @new_post.stub!(:body)
235
235
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
236
236
  end
237
+
238
+ after do
239
+ Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
240
+ end
237
241
 
238
242
  it "can be overridden" do
239
243
 
@@ -286,6 +290,103 @@ describe 'Formtastic' do
286
290
  end
287
291
  end
288
292
 
293
+ describe '#label' do
294
+ it 'should humanize the given attribute' do
295
+ semantic_form_for(@new_post) do |builder|
296
+ builder.label(:login).should have_tag('label', :with => /Login/)
297
+ end
298
+ end
299
+
300
+ it 'should be printed as span' do
301
+ semantic_form_for(@new_post) do |builder|
302
+ builder.label(:login, nil, { :required => true, :as_span => true }).should have_tag('span.label abbr')
303
+ end
304
+ end
305
+
306
+ describe 'when required is given' do
307
+ it 'should append a required note' do
308
+ semantic_form_for(@new_post) do |builder|
309
+ builder.label(:login, nil, :required => true).should have_tag('label abbr')
310
+ end
311
+ end
312
+
313
+ it 'should allow require option to be given as second argument' do
314
+ semantic_form_for(@new_post) do |builder|
315
+ builder.label(:login, :required => true).should have_tag('label abbr')
316
+ end
317
+ end
318
+ end
319
+
320
+ describe 'when label is given' do
321
+ it 'should allow the text to be given as label option' do
322
+ semantic_form_for(@new_post) do |builder|
323
+ builder.label(:login, :required => true, :label => 'My label').should have_tag('label', :with => /My label/)
324
+ end
325
+ end
326
+
327
+ it 'should return nil if label is false' do
328
+ semantic_form_for(@new_post) do |builder|
329
+ builder.label(:login, :label => false).should be_blank
330
+ end
331
+ end
332
+ end
333
+ end
334
+
335
+ describe '#errors_on' do
336
+ before(:each) do
337
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
338
+ @errors = mock('errors')
339
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
340
+ @errors.stub!(:[]).with(:body).and_return(nil)
341
+ @new_post.stub!(:errors).and_return(@errors)
342
+ end
343
+
344
+ describe 'and the errors will be displayed as a sentence' do
345
+ it 'should render a paragraph with the errors joined into a sentence' do
346
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
347
+ semantic_form_for(@new_post) do |builder|
348
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.to_sentence)
349
+ end
350
+ end
351
+ end
352
+
353
+ describe 'and the errors will be displayed as a list' do
354
+ it 'should render an unordered list with the class errors' do
355
+ Formtastic::SemanticFormBuilder.inline_errors = :list
356
+ semantic_form_for(@new_post) do |builder|
357
+ builder.errors_on(:title).should have_tag('ul.errors')
358
+ end
359
+ end
360
+
361
+ it 'should include a list element for each of the errors within the unordered list' do
362
+ Formtastic::SemanticFormBuilder.inline_errors = :list
363
+ semantic_form_for(@new_post) do |builder|
364
+ @title_errors.each do |error|
365
+ builder.errors_on(:title).should have_tag('ul.errors li', error)
366
+ end
367
+ end
368
+ end
369
+ end
370
+
371
+ describe 'but the errors will not be shown' do
372
+ it 'should return nil' do
373
+ Formtastic::SemanticFormBuilder.inline_errors = :none
374
+ semantic_form_for(@new_post) do |builder|
375
+ builder.errors_on(:title).should be_nil
376
+ end
377
+ end
378
+ end
379
+
380
+ describe 'and no error is found on the method' do
381
+ it 'should return nil' do
382
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
383
+ semantic_form_for(@new_post) do |builder|
384
+ builder.errors_on(:body).should be_nil
385
+ end
386
+ end
387
+ end
388
+ end
389
+
289
390
  describe '#input' do
290
391
 
291
392
  before do
@@ -472,13 +573,22 @@ describe 'Formtastic' do
472
573
 
473
574
  describe 'when not provided' do
474
575
 
475
- it 'should default to a string for forms without objects' do
576
+ it 'should default to a string for forms without objects unless column is password' do
476
577
  semantic_form_for(:project, :url => 'http://test.host') do |builder|
477
578
  concat(builder.input(:anything))
478
579
  end
479
580
  output_buffer.should have_tag('form li.string')
480
581
  end
481
582
 
583
+ it 'should default to password for forms without objects if column is password' do
584
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
585
+ concat(builder.input(:password))
586
+ concat(builder.input(:password_confirmation))
587
+ concat(builder.input(:confirm_password))
588
+ end
589
+ output_buffer.should have_tag('form li.password', :count => 3)
590
+ end
591
+
482
592
  it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
483
593
  @new_post.stub!(:method_without_a_database_column)
484
594
  @new_post.stub!(:column_for_attribute).and_return(nil)
@@ -538,6 +648,10 @@ describe 'Formtastic' do
538
648
  default_input_type(:float).should == :numeric
539
649
  default_input_type(:decimal).should == :numeric
540
650
  end
651
+
652
+ it 'should default to :country for :string columns named country' do
653
+ default_input_type(:string, :country).should == :country
654
+ end
541
655
 
542
656
  describe 'defaulting to file column' do
543
657
  Formtastic::SemanticFormBuilder.file_methods.each do |method|
@@ -561,7 +675,7 @@ describe 'Formtastic' do
561
675
  end
562
676
 
563
677
  it 'should call the corresponding input method' do
564
- [:select, :time_zone, :radio, :date, :datetime, :time, :boolean].each do |input_style|
678
+ [:select, :time_zone, :radio, :date, :datetime, :time, :boolean, :check_boxes, :hidden].each do |input_style|
565
679
  @new_post.stub!(:generic_column_name)
566
680
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
567
681
  semantic_form_for(@new_post) do |builder|
@@ -583,9 +697,8 @@ describe 'Formtastic' do
583
697
  end
584
698
 
585
699
  describe ':label option' do
586
-
700
+
587
701
  describe 'when provided' do
588
-
589
702
  it 'should be passed down to the label tag' do
590
703
  semantic_form_for(@new_post) do |builder|
591
704
  concat(builder.input(:title, :label => "Kustom"))
@@ -593,35 +706,89 @@ describe 'Formtastic' do
593
706
  output_buffer.should have_tag("form li label", /Kustom/)
594
707
  end
595
708
 
709
+ it 'should not generate a label if false' do
710
+ semantic_form_for(@new_post) do |builder|
711
+ concat(builder.input(:title, :label => false))
712
+ end
713
+ output_buffer.should_not have_tag("form li label")
714
+ end
715
+
716
+ it 'should be dupped if frozen' do
717
+ semantic_form_for(@new_post) do |builder|
718
+ concat(builder.input(:title, :label => "Kustom".freeze))
719
+ end
720
+ output_buffer.should have_tag("form li label", /Kustom/)
721
+ end
596
722
  end
597
723
 
598
724
  describe 'when not provided' do
599
- describe 'and object is not given' do
600
- it 'should default the humanized method name, passing it down to the label tag' do
601
- Formtastic::SemanticFormBuilder.label_str_method = :humanize
602
-
603
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
604
- concat(builder.input(:meta_description))
725
+ describe 'when localized label is NOT provided' do
726
+ describe 'and object is not given' do
727
+ it 'should default the humanized method name, passing it down to the label tag' do
728
+ Formtastic::SemanticFormBuilder.label_str_method = :humanize
729
+
730
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
731
+ concat(builder.input(:meta_description))
732
+ end
733
+
734
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
735
+ end
736
+ end
737
+
738
+ describe 'and object is given' do
739
+ it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
740
+ @new_post.stub!(:meta_description) # a two word method name
741
+ @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
742
+
743
+ semantic_form_for(@new_post) do |builder|
744
+ concat(builder.input(:meta_description))
745
+ end
746
+
747
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
605
748
  end
606
-
607
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
608
749
  end
609
750
  end
610
-
611
- describe 'and object is given' do
612
- it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
613
- @new_post.stub!(:meta_description) # a two word method name
614
- @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
615
-
751
+
752
+ describe 'when localized label is provided' do
753
+ before do
754
+ @localized_label_text = 'Localized title'
755
+ @default_localized_label_text = 'Default localized title'
756
+ ::I18n.backend.store_translations :en,
757
+ :formtastic => {
758
+ :labels => {
759
+ :title => @default_localized_label_text,
760
+ :post => {
761
+ :title => @localized_label_text
762
+ }
763
+ }
764
+ }
765
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
766
+ end
767
+
768
+ it 'should render a label with localized label (I18n)' do
616
769
  semantic_form_for(@new_post) do |builder|
617
- concat(builder.input(:meta_description))
770
+ concat(builder.input(:title, :label => true))
618
771
  end
619
-
620
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
772
+ output_buffer.should have_tag('form li label', @localized_label_text)
773
+ end
774
+
775
+ it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
776
+ ::I18n.backend.store_translations :en,
777
+ :formtastic => {
778
+ :labels => {
779
+ :post => {
780
+ :title => nil
781
+ }
782
+ }
783
+ }
784
+ semantic_form_for(@new_post) do |builder|
785
+ concat(builder.input(:title, :label => true))
786
+ end
787
+ output_buffer.should have_tag('form li label', @default_localized_label_text)
621
788
  end
622
789
  end
623
790
  end
624
-
791
+
625
792
  end
626
793
 
627
794
  describe ':hint option' do
@@ -637,12 +804,104 @@ describe 'Formtastic' do
637
804
  end
638
805
 
639
806
  describe 'when not provided' do
640
- it 'should not render a hint paragraph' do
641
- hint_text = "this is the title of the post"
807
+ describe 'when localized hint (I18n) is provided' do
808
+ before do
809
+ @localized_hint_text = "This is the localized hint."
810
+ @default_localized_hint_text = "This is the default localized hint."
811
+ ::I18n.backend.store_translations :en,
812
+ :formtastic => {
813
+ :hints => {
814
+ :title => @default_localized_hint_text,
815
+ :post => {
816
+ :title => @localized_hint_text
817
+ }
818
+ }
819
+ }
820
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
821
+ end
822
+
823
+ describe 'when provided value (hint value) is set to TRUE' do
824
+ it 'should render a hint paragraph containing a localized hint (I18n)' do
825
+ semantic_form_for(@new_post) do |builder|
826
+ concat(builder.input(:title, :hint => true))
827
+ end
828
+ output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
829
+ end
830
+
831
+ it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
832
+ ::I18n.backend.store_translations :en,
833
+ :formtastic => {
834
+ :hints => {
835
+ :post => {
836
+ :title => nil
837
+ }
838
+ }
839
+ }
840
+ semantic_form_for(@new_post) do |builder|
841
+ concat(builder.input(:title, :hint => true))
842
+ end
843
+ output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
844
+ end
845
+ end
846
+
847
+ describe 'when provided value (label value) is set to FALSE' do
848
+ it 'should not render a hint paragraph' do
849
+ semantic_form_for(@new_post) do |builder|
850
+ concat(builder.input(:title, :hint => false))
851
+ end
852
+ output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
853
+ end
854
+ end
855
+ end
856
+
857
+ describe 'when localized hint (I18n) is not provided' do
858
+ it 'should not render a hint paragraph' do
859
+ semantic_form_for(@new_post) do |builder|
860
+ concat(builder.input(:title))
861
+ end
862
+ output_buffer.should_not have_tag('form li p.inline-hints')
863
+ end
864
+ end
865
+ end
866
+
867
+ end
868
+
869
+ describe ':wrapper_html option' do
870
+
871
+ describe 'when provided' do
872
+ it 'should be passed down to the li tag' do
873
+ semantic_form_for(@new_post) do |builder|
874
+ concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
875
+ end
876
+ output_buffer.should have_tag("form li#another_id")
877
+ end
878
+
879
+ it 'should append given classes to li default classes' do
880
+ semantic_form_for(@new_post) do |builder|
881
+ concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
882
+ end
883
+ output_buffer.should have_tag("form li.string")
884
+ output_buffer.should have_tag("form li.required")
885
+ output_buffer.should have_tag("form li.another_class")
886
+ end
887
+
888
+ it 'should allow classes to be an array' do
889
+ semantic_form_for(@new_post) do |builder|
890
+ concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
891
+ end
892
+ output_buffer.should have_tag("form li.string")
893
+ output_buffer.should have_tag("form li.my_class")
894
+ output_buffer.should have_tag("form li.another_class")
895
+ end
896
+ end
897
+
898
+ describe 'when not provided' do
899
+ it 'should use default id and class' do
642
900
  semantic_form_for(@new_post) do |builder|
643
901
  concat(builder.input(:title))
644
902
  end
645
- output_buffer.should_not have_tag("form li p.inline-hints")
903
+ output_buffer.should have_tag("form li#post_title_input")
904
+ output_buffer.should have_tag("form li.string")
646
905
  end
647
906
  end
648
907
 
@@ -660,11 +919,10 @@ describe 'Formtastic' do
660
919
  end
661
920
 
662
921
  describe 'when there are errors on the object for this method' do
663
-
664
922
  before do
665
923
  @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
666
924
  @errors = mock('errors')
667
- @errors.stub!(:on).with('title').and_return(@title_errors)
925
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
668
926
  @new_post.stub!(:errors).and_return(@errors)
669
927
  end
670
928
 
@@ -682,65 +940,24 @@ describe 'Formtastic' do
682
940
  output_buffer.should_not have_tag('div.fieldWithErrors')
683
941
  end
684
942
 
685
- describe 'and the errors will be displayed as a sentence' do
686
-
687
- before do
688
- Formtastic::SemanticFormBuilder.inline_errors = :sentence
689
- semantic_form_for(@new_post) do |builder|
690
- concat(builder.input(:title))
691
- end
692
- end
693
-
694
- it 'should render a paragraph with the errors joined into a sentence' do
695
- output_buffer.should have_tag('form li.error p.inline-errors', @title_errors.to_sentence)
696
- end
697
-
698
- end
699
-
700
- describe 'and the errors will be displayed as a list' do
701
-
702
- before do
703
- Formtastic::SemanticFormBuilder.inline_errors = :list
704
- semantic_form_for(@new_post) do |builder|
705
- concat(builder.input(:title))
706
- end
707
- end
708
-
709
- it 'should render an unordered list with the class errors' do
710
- output_buffer.should have_tag('form li.error ul.errors')
711
- end
712
-
713
- it 'should include a list element for each of the errors within the unordered list' do
714
- @title_errors.each do |error|
715
- output_buffer.should have_tag('form li.error ul.errors li', error)
716
- end
943
+ it 'should render a paragraph for the errors' do
944
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
945
+ semantic_form_for(@new_post) do |builder|
946
+ concat(builder.input(:title))
717
947
  end
718
-
948
+ output_buffer.should have_tag('form li.error p.inline-errors')
719
949
  end
720
950
 
721
- describe 'but the errors will not be shown' do
722
-
723
- before do
724
- Formtastic::SemanticFormBuilder.inline_errors = :none
725
- semantic_form_for(@new_post) do |builder|
726
- concat(builder.input(:title))
727
- end
728
- end
729
-
730
- it 'should not display an error sentence' do
731
- output_buffer.should_not have_tag('form li.error p.inline-errors')
732
- end
733
-
734
- it 'should not display an error list' do
735
- output_buffer.should_not have_tag('form li.error ul.errors')
951
+ it 'should not display an error list' do
952
+ Formtastic::SemanticFormBuilder.inline_errors = :list
953
+ semantic_form_for(@new_post) do |builder|
954
+ concat(builder.input(:title))
736
955
  end
737
-
956
+ output_buffer.should have_tag('form li.error ul.errors')
738
957
  end
739
-
740
958
  end
741
959
 
742
960
  describe 'when there are no errors on the object for this method' do
743
-
744
961
  before do
745
962
  semantic_form_for(@new_post) do |builder|
746
963
  concat(builder.input(:title))
@@ -758,11 +975,9 @@ describe 'Formtastic' do
758
975
  it 'should not display an error list' do
759
976
  output_buffer.should_not have_tag('form li.error ul.errors')
760
977
  end
761
-
762
978
  end
763
979
 
764
980
  describe 'when no object is provided' do
765
-
766
981
  before do
767
982
  semantic_form_for(:project, :url => 'http://test.host') do |builder|
768
983
  concat(builder.input(:title))
@@ -780,7 +995,6 @@ describe 'Formtastic' do
780
995
  it 'should not display an error list' do
781
996
  output_buffer.should_not have_tag('form li.error ul.errors')
782
997
  end
783
-
784
998
  end
785
999
  end
786
1000
 
@@ -821,31 +1035,33 @@ describe 'Formtastic' do
821
1035
  output_buffer.should have_tag("form li input[@name=\"post[title]\"]")
822
1036
  end
823
1037
 
824
- it 'should have a maxlength matching the column limit' do
825
- @new_post.column_for_attribute(:title).limit.should == 50
826
- output_buffer.should have_tag("form li input[@maxlength='50']")
827
- end
1038
+ unless type == :numeric
1039
+ it 'should have a maxlength matching the column limit' do
1040
+ @new_post.column_for_attribute(:title).limit.should == 50
1041
+ output_buffer.should have_tag("form li input[@maxlength='50']")
1042
+ end
828
1043
 
829
- it 'should use default_text_field_size for columns longer than default_text_field_size' do
830
- default_size = Formtastic::SemanticFormBuilder.default_text_field_size
831
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
1044
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
1045
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
1046
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
832
1047
 
833
- semantic_form_for(@new_post) do |builder|
834
- concat(builder.input(:title, :as => type))
1048
+ semantic_form_for(@new_post) do |builder|
1049
+ concat(builder.input(:title, :as => type))
1050
+ end
1051
+
1052
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
835
1053
  end
836
1054
 
837
- output_buffer.should have_tag("form li input[@size='#{default_size}']")
838
- end
1055
+ it 'should use the column size for columns shorter than default_text_field_size' do
1056
+ column_limit_shorted_than_default = 1
1057
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
839
1058
 
840
- it 'should use the column size for columns shorter than default_text_field_size' do
841
- column_limit_shorted_than_default = 1
842
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
1059
+ semantic_form_for(@new_post) do |builder|
1060
+ concat(builder.input(:title, :as => type))
1061
+ end
843
1062
 
844
- semantic_form_for(@new_post) do |builder|
845
- concat(builder.input(:title, :as => type))
1063
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
846
1064
  end
847
-
848
- output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
849
1065
  end
850
1066
 
851
1067
  it 'should use default_text_field_size for methods without database columns' do
@@ -866,6 +1082,13 @@ describe 'Formtastic' do
866
1082
  output_buffer.should have_tag("form li input.myclass")
867
1083
  end
868
1084
 
1085
+ it 'should consider input_html :id in labels' do
1086
+ semantic_form_for(@new_post) do |builder|
1087
+ concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
1088
+ end
1089
+ output_buffer.should have_tag('form li label[@for="myid"]')
1090
+ end
1091
+
869
1092
  it 'should generate input and labels even if no object is given' do
870
1093
  semantic_form_for(:project, :url => 'http://test.host/') do |builder|
871
1094
  concat(builder.input(:title, :as => type))
@@ -947,139 +1170,206 @@ describe 'Formtastic' do
947
1170
 
948
1171
  end
949
1172
 
950
- it 'should generate input and labels even if no object is given' do
951
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
952
- concat(builder.input(:title, :as => type))
1173
+ describe 'when no object is given' do
1174
+ before(:each) do
1175
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1176
+ concat(builder.input(:title, :as => type))
1177
+ end
953
1178
  end
954
1179
 
955
- output_buffer.should have_tag('form li label')
956
- output_buffer.should have_tag('form li label[@for="project_title"')
957
- output_buffer.should have_tag('form li label', /Title/)
1180
+ it 'should generate input' do
1181
+ if template_method.to_s =~ /_field$/ # password_field
1182
+ output_buffer.should have_tag("form li input")
1183
+ output_buffer.should have_tag("form li input#project_title")
1184
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1185
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
1186
+ else
1187
+ output_buffer.should have_tag("form li #{input_type}")
1188
+ output_buffer.should have_tag("form li #{input_type}#project_title")
1189
+ output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
1190
+ end
1191
+ end
958
1192
 
959
- if template_method.to_s =~ /_field$/ # password_field
960
- output_buffer.should have_tag("form li input")
961
- output_buffer.should have_tag("form li input#project_title")
962
- output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
963
- output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
964
- else
965
- output_buffer.should have_tag("form li #{input_type}")
966
- output_buffer.should have_tag("form li #{input_type}#project_title")
967
- output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
1193
+ it 'should generate labels' do
1194
+ output_buffer.should have_tag('form li label')
1195
+ output_buffer.should have_tag('form li label[@for="project_title"')
1196
+ output_buffer.should have_tag('form li label', /Title/)
968
1197
  end
969
1198
  end
970
1199
 
971
1200
  end
972
1201
  end
973
1202
 
1203
+ describe ":as => :hidden" do
1204
+ before do
1205
+ @new_post.stub!(:hidden)
1206
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
974
1207
 
975
- describe ':as => :radio' do
1208
+ semantic_form_for(@new_post) do |builder|
1209
+ concat(builder.input(:hidden, :as => :hidden))
1210
+ end
1211
+ end
976
1212
 
977
- before do
978
- @new_post.stub!(:author).and_return(@bob)
979
- @new_post.stub!(:author_id).and_return(@bob.id)
980
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1213
+ it "should have a hidden class on the wrapper" do
1214
+ output_buffer.should have_tag('form li.hidden')
981
1215
  end
982
1216
 
983
- describe 'for belongs_to association' do
984
- before do
985
- semantic_form_for(@new_post) do |builder|
986
- concat(builder.input(:author, :as => :radio, :value_as_class => true))
987
- end
988
- end
1217
+ it 'should have a post_hidden_input id on the wrapper' do
1218
+ output_buffer.should have_tag('form li#post_hidden_input')
1219
+ end
989
1220
 
990
- it 'should have a radio class on the wrapper' do
991
- output_buffer.should have_tag('form li.radio')
992
- end
1221
+ it 'should not generate a label for the input' do
1222
+ output_buffer.should_not have_tag('form li label')
1223
+ end
993
1224
 
994
- it 'should have a post_author_id_input id on the wrapper' do
995
- output_buffer.should have_tag('form li#post_author_input')
996
- end
1225
+ it "should generate a input field" do
1226
+ output_buffer.should have_tag("form li input#post_hidden")
1227
+ output_buffer.should have_tag("form li input[@type=\"hidden\"]")
1228
+ output_buffer.should have_tag("form li input[@name=\"post[hidden]\"]")
1229
+ end
1230
+ end
997
1231
 
998
- it 'should generate a fieldset and legend containing label text for the input' do
999
- output_buffer.should have_tag('form li fieldset')
1000
- output_buffer.should have_tag('form li fieldset legend')
1001
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1002
- end
1232
+ describe ":as => :time_zone" do
1233
+ before do
1234
+ @new_post.stub!(:time_zone)
1235
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1003
1236
 
1004
- it 'should generate an ordered list with a list item for each choice' do
1005
- output_buffer.should have_tag('form li fieldset ol')
1006
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1237
+ semantic_form_for(@new_post) do |builder|
1238
+ concat(builder.input(:time_zone))
1007
1239
  end
1240
+ end
1008
1241
 
1009
- it 'should have one option with a "selected" attribute' do
1010
- output_buffer.should have_tag('form li input[@checked]', :count => 1)
1011
- end
1242
+ it "should have a time_zone class on the wrapper" do
1243
+ output_buffer.should have_tag('form li.time_zone')
1244
+ end
1012
1245
 
1013
- describe "each choice" do
1246
+ it 'should have a post_title_input id on the wrapper' do
1247
+ output_buffer.should have_tag('form li#post_time_zone_input')
1248
+ end
1014
1249
 
1015
- it 'should contain a label for the radio input with a nested input and label text' do
1016
- Author.find(:all).each do |author|
1017
- output_buffer.should have_tag('form li fieldset ol li label')
1018
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1019
- output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1020
- output_buffer.should have_tag("form li fieldset ol li label input")
1021
- end
1022
- end
1250
+ it 'should generate a label for the input' do
1251
+ output_buffer.should have_tag('form li label')
1252
+ output_buffer.should have_tag('form li label[@for="post_time_zone"')
1253
+ output_buffer.should have_tag('form li label', /Time zone/)
1254
+ end
1023
1255
 
1024
- it 'should use values as li.class when value_as_class is true' do
1025
- Author.find(:all).each do |author|
1026
- output_buffer.should have_tag("form li fieldset ol li.#{author.id} label")
1027
- end
1028
- end
1256
+ it "should generate a select" do
1257
+ output_buffer.should have_tag("form li select")
1258
+ output_buffer.should have_tag("form li select#post_time_zone")
1259
+ output_buffer.should have_tag("form li select[@name=\"post[time_zone]\"]")
1260
+ end
1029
1261
 
1030
- it "should have a radio input" do
1031
- Author.find(:all).each do |author|
1032
- output_buffer.should have_tag("form li fieldset ol li label input#post_author_id_#{author.id}")
1033
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1034
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1035
- output_buffer.should have_tag("form li fieldset ol li label input[@name='post[author_id]']")
1036
- end
1262
+ it 'should use input_html to style inputs' do
1263
+ semantic_form_for(@new_post) do |builder|
1264
+ concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
1265
+ end
1266
+ output_buffer.should have_tag("form li select.myclass")
1267
+ end
1268
+
1269
+ describe 'when no object is given' do
1270
+ before(:each) do
1271
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1272
+ concat(builder.input(:time_zone, :as => :time_zone))
1037
1273
  end
1274
+ end
1038
1275
 
1039
- it "should mark input as checked if it's the the existing choice" do
1040
- @new_post.author_id.should == @bob.id
1041
- @new_post.author.id.should == @bob.id
1042
- @new_post.author.should == @bob
1276
+ it 'should generate labels' do
1277
+ output_buffer.should have_tag('form li label')
1278
+ output_buffer.should have_tag('form li label[@for="project_time_zone"')
1279
+ output_buffer.should have_tag('form li label', /Time zone/)
1280
+ end
1043
1281
 
1282
+ it 'should generate select inputs' do
1283
+ output_buffer.should have_tag("form li select")
1284
+ output_buffer.should have_tag("form li select#project_time_zone")
1285
+ output_buffer.should have_tag("form li select[@name=\"project[time_zone]\"]")
1286
+ end
1287
+ end
1288
+ end
1289
+
1290
+ describe ":as => :country" do
1291
+
1292
+ before do
1293
+ @new_post.stub!(:country)
1294
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1295
+ end
1296
+
1297
+ describe "when country_select is not available as a helper from a plugin" do
1298
+
1299
+ it "should raise an error, sugesting the author installs a plugin" do
1300
+ lambda {
1044
1301
  semantic_form_for(@new_post) do |builder|
1045
- concat(builder.input(:author, :as => :radio))
1302
+ concat(builder.input(:country, :as => :country))
1046
1303
  end
1047
-
1048
- output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1049
- end
1304
+ }.should raise_error
1050
1305
  end
1051
-
1052
- it 'should generate a fieldset, legend, labels and inputs even if no object is given' do
1053
- output_buffer.replace ''
1054
-
1055
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1056
- concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1306
+
1307
+ end
1308
+
1309
+ describe "when country_select is available as a helper (from a plugin)" do
1310
+
1311
+ before do
1312
+ semantic_form_for(@new_post) do |builder|
1313
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1314
+ concat(builder.input(:country, :as => :country))
1057
1315
  end
1316
+ end
1317
+
1318
+ it "should have a time_zone class on the wrapper" do
1319
+ output_buffer.should have_tag('form li.country')
1320
+ end
1058
1321
 
1059
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1060
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1322
+ it 'should have a post_title_input id on the wrapper' do
1323
+ output_buffer.should have_tag('form li#post_country_input')
1324
+ end
1061
1325
 
1062
- Author.find(:all).each do |author|
1063
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1064
- output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1326
+ it 'should generate a label for the input' do
1327
+ output_buffer.should have_tag('form li label')
1328
+ output_buffer.should have_tag('form li label[@for="post_country"')
1329
+ output_buffer.should have_tag('form li label', /Country/)
1330
+ end
1065
1331
 
1066
- output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1067
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1068
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1069
- output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1332
+ it "should generate a select" do
1333
+ output_buffer.should have_tag("form li select")
1334
+ end
1335
+
1336
+ end
1337
+
1338
+ describe ":priority_countries option" do
1339
+
1340
+ it "should be passed down to the country_select helper when provided" do
1341
+ priority_countries = ["Foo", "Bah"]
1342
+ semantic_form_for(@new_post) do |builder|
1343
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1344
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1345
+
1346
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
1347
+ end
1348
+ end
1349
+
1350
+ it "should default to the @@priority_countries config when absent" do
1351
+ priority_countries = Formtastic::SemanticFormBuilder.priority_countries
1352
+ priority_countries.should_not be_empty
1353
+ priority_countries.should_not be_nil
1354
+
1355
+ semantic_form_for(@new_post) do |builder|
1356
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1357
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1358
+
1359
+ concat(builder.input(:country, :as => :country))
1070
1360
  end
1071
1361
  end
1072
-
1362
+
1073
1363
  end
1074
-
1364
+
1075
1365
  end
1076
-
1077
- describe ':as => :check_boxes' do
1366
+
1367
+ describe ':as => :radio' do
1078
1368
 
1079
1369
  before do
1080
1370
  @new_post.stub!(:author).and_return(@bob)
1081
1371
  @new_post.stub!(:author_id).and_return(@bob.id)
1082
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1372
+ Post.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to) }
1083
1373
  end
1084
1374
 
1085
1375
  describe 'for belongs_to association' do
@@ -1093,7 +1383,7 @@ describe 'Formtastic' do
1093
1383
  output_buffer.should have_tag('form li.radio')
1094
1384
  end
1095
1385
 
1096
- it 'should have a post_author_id_input id on the wrapper' do
1386
+ it 'should have a post_author_input id on the wrapper' do
1097
1387
  output_buffer.should have_tag('form li#post_author_input')
1098
1388
  end
1099
1389
 
@@ -1108,7 +1398,7 @@ describe 'Formtastic' do
1108
1398
  output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1109
1399
  end
1110
1400
 
1111
- it 'should have one option with a "selected" attribute' do
1401
+ it 'should have one option with a "checked" attribute' do
1112
1402
  output_buffer.should have_tag('form li input[@checked]', :count => 1)
1113
1403
  end
1114
1404
 
@@ -1116,10 +1406,8 @@ describe 'Formtastic' do
1116
1406
 
1117
1407
  it 'should contain a label for the radio input with a nested input and label text' do
1118
1408
  Author.find(:all).each do |author|
1119
- output_buffer.should have_tag('form li fieldset ol li label')
1120
1409
  output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1121
1410
  output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1122
- output_buffer.should have_tag("form li fieldset ol li label input")
1123
1411
  end
1124
1412
  end
1125
1413
 
@@ -1151,29 +1439,39 @@ describe 'Formtastic' do
1151
1439
  end
1152
1440
  end
1153
1441
 
1154
- it 'should generate a fieldset, legend, labels and inputs even if no object is given' do
1155
- output_buffer.replace ''
1442
+ describe 'and no object is given' do
1443
+ before(:each) do
1444
+ output_buffer.replace ''
1445
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1446
+ concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1447
+ end
1448
+ end
1156
1449
 
1157
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1158
- concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1450
+ it 'should generate a fieldset with legend' do
1451
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1159
1452
  end
1160
1453
 
1161
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1162
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1454
+ it 'shold generate an li tag for each item in the collection' do
1455
+ output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1456
+ end
1163
1457
 
1164
- Author.find(:all).each do |author|
1165
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1166
- output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1458
+ it 'should generate labels for each item' do
1459
+ Author.find(:all).each do |author|
1460
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1461
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1462
+ end
1463
+ end
1167
1464
 
1168
- output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1169
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1170
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1171
- output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1465
+ it 'should generate inputs for each item' do
1466
+ Author.find(:all).each do |author|
1467
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1468
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1469
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1470
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1471
+ end
1172
1472
  end
1173
1473
  end
1174
-
1175
1474
  end
1176
-
1177
1475
  end
1178
1476
 
1179
1477
  describe ':as => :select' do
@@ -1217,9 +1515,13 @@ describe 'Formtastic' do
1217
1515
  it 'should create a select without size' do
1218
1516
  output_buffer.should_not have_tag('form li select[@size]')
1219
1517
  end
1220
-
1518
+
1519
+ it 'should have a blank option' do
1520
+ output_buffer.should have_tag("form li select option[@value='']")
1521
+ end
1522
+
1221
1523
  it 'should have a select option for each Author' do
1222
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size)
1524
+ output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1223
1525
  Author.find(:all).each do |author|
1224
1526
  output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1225
1527
  end
@@ -1228,6 +1530,18 @@ describe 'Formtastic' do
1228
1530
  it 'should have one option with a "selected" attribute' do
1229
1531
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1230
1532
  end
1533
+
1534
+ it 'should not singularize the association name' do
1535
+ @new_post.stub!(:author_status).and_return(@bob)
1536
+ @new_post.stub!(:author_status_id).and_return(@bob.id)
1537
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1538
+
1539
+ semantic_form_for(@new_post) do |builder|
1540
+ concat(builder.input(:author_status, :as => :select))
1541
+ end
1542
+
1543
+ output_buffer.should have_tag('form li select#post_author_status_id')
1544
+ end
1231
1545
  end
1232
1546
 
1233
1547
  describe 'for a has_many association' do
@@ -1247,7 +1561,7 @@ describe 'Formtastic' do
1247
1561
 
1248
1562
  it 'should have a label inside the wrapper' do
1249
1563
  output_buffer.should have_tag('form li label')
1250
- output_buffer.should have_tag('form li label', /Posts/)
1564
+ output_buffer.should have_tag('form li label', /Post/)
1251
1565
  output_buffer.should have_tag("form li label[@for='author_post_ids']")
1252
1566
  end
1253
1567
 
@@ -1266,6 +1580,10 @@ describe 'Formtastic' do
1266
1580
  output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
1267
1581
  end
1268
1582
  end
1583
+
1584
+ it 'should not have a blank option' do
1585
+ output_buffer.should_not have_tag("form li select option[@value='']")
1586
+ end
1269
1587
 
1270
1588
  it 'should have one option with a "selected" attribute' do
1271
1589
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
@@ -1289,7 +1607,7 @@ describe 'Formtastic' do
1289
1607
 
1290
1608
  it 'should have a label inside the wrapper' do
1291
1609
  output_buffer.should have_tag('form li label')
1292
- output_buffer.should have_tag('form li label', /Authors/)
1610
+ output_buffer.should have_tag('form li label', /Author/)
1293
1611
  output_buffer.should have_tag("form li label[@for='post_author_ids']")
1294
1612
  end
1295
1613
 
@@ -1308,42 +1626,179 @@ describe 'Formtastic' do
1308
1626
  output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1309
1627
  end
1310
1628
  end
1629
+
1630
+ it 'should not have a blank option' do
1631
+ output_buffer.should_not have_tag("form li select option[@value='']")
1632
+ end
1311
1633
 
1312
1634
  it 'should have one option with a "selected" attribute' do
1313
1635
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1314
1636
  end
1315
1637
  end
1316
-
1317
- describe 'when :include_blank => true, :prompt => "choose something" is set' do
1638
+
1639
+ describe 'when :include_blank is not set' do
1640
+ before do
1641
+ @new_post.stub!(:author_id).and_return(nil)
1642
+ semantic_form_for(@new_post) do |builder|
1643
+ concat(builder.input(:author, :as => :select))
1644
+ end
1645
+ end
1646
+
1647
+ it 'should have a blank option by default' do
1648
+ output_buffer.should have_tag("form li select option[@value='']", "")
1649
+ end
1650
+ end
1651
+
1652
+ describe 'when :include_blank is set to false' do
1318
1653
  before do
1319
1654
  @new_post.stub!(:author_id).and_return(nil)
1320
1655
  semantic_form_for(@new_post) do |builder|
1321
- concat(builder.input(:author, :as => :select, :include_blank => true, :prompt => "choose author"))
1656
+ concat(builder.input(:author, :as => :select, :include_blank => false))
1322
1657
  end
1323
1658
  end
1659
+
1660
+ it 'should not have a blank option' do
1661
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1662
+ end
1663
+ end
1324
1664
 
1325
- it 'should have a blank select option' do
1326
- output_buffer.should have_tag("form li select option[@value='']", //)
1665
+ describe 'when :prompt => "choose something" is set' do
1666
+ before do
1667
+ @new_post.stub!(:author_id).and_return(nil)
1668
+ semantic_form_for(@new_post) do |builder|
1669
+ concat(builder.input(:author, :as => :select, :prompt => "choose author"))
1670
+ end
1327
1671
  end
1328
1672
 
1329
1673
  it 'should have a select with prompt' do
1330
1674
  output_buffer.should have_tag("form li select option[@value='']", /choose author/)
1331
1675
  end
1676
+
1677
+ it 'should not have a blank select option' do
1678
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1679
+ end
1332
1680
  end
1333
1681
 
1334
- it 'should generate label, select and options even if object is not given' do
1335
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1336
- concat(builder.input(:author, :as => :select, :collection => Author.find(:all)))
1682
+ describe 'when no object is given' do
1683
+ before(:each) do
1684
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1685
+ concat(builder.input(:author, :as => :select, :collection => Author.find(:all)))
1686
+ end
1687
+ end
1688
+
1689
+ it 'should generate label' do
1690
+ output_buffer.should have_tag('form li label', /Author/)
1691
+ output_buffer.should have_tag("form li label[@for='project_author']")
1692
+ end
1693
+
1694
+ it 'should generate select inputs' do
1695
+ output_buffer.should have_tag('form li select#project_author')
1696
+ output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1697
+ end
1698
+
1699
+ it 'should generate an option to each item' do
1700
+ Author.find(:all).each do |author|
1701
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1702
+ end
1703
+ end
1704
+ end
1705
+ end
1706
+
1707
+ describe ':as => :check_boxes' do
1708
+
1709
+ describe 'for a has_many association' do
1710
+ before do
1711
+ semantic_form_for(@fred) do |builder|
1712
+ concat(builder.input(:posts, :as => :check_boxes, :value_as_class => true))
1713
+ end
1714
+ end
1715
+
1716
+ it 'should have a check_boxes class on the wrapper' do
1717
+ output_buffer.should have_tag('form li.check_boxes')
1718
+ end
1719
+
1720
+ it 'should have a author_posts_input id on the wrapper' do
1721
+ output_buffer.should have_tag('form li#author_posts_input')
1722
+ end
1723
+
1724
+ it 'should generate a fieldset and legend containing label text for the input' do
1725
+ output_buffer.should have_tag('form li fieldset')
1726
+ output_buffer.should have_tag('form li fieldset legend')
1727
+ output_buffer.should have_tag('form li fieldset legend', /Posts/)
1728
+ end
1729
+
1730
+ it 'should generate an ordered list with a list item for each choice' do
1731
+ output_buffer.should have_tag('form li fieldset ol')
1732
+ output_buffer.should have_tag('form li fieldset ol li', :count => Post.find(:all).size)
1733
+ end
1734
+
1735
+ it 'should have one option with a "checked" attribute' do
1736
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1737
+ end
1738
+
1739
+ it 'should generate hidden inputs with default value blank' do
1740
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='hidden'][@value='']", :count => Post.find(:all).size)
1741
+ end
1742
+
1743
+ describe "each choice" do
1744
+
1745
+ it 'should contain a label for the radio input with a nested input and label text' do
1746
+ Post.find(:all).each do |post|
1747
+ output_buffer.should have_tag('form li fieldset ol li label', /#{post.to_label}/)
1748
+ output_buffer.should have_tag("form li fieldset ol li label[@for='author_post_ids_#{post.id}']")
1749
+ end
1750
+ end
1751
+
1752
+ it 'should use values as li.class when value_as_class is true' do
1753
+ Post.find(:all).each do |post|
1754
+ output_buffer.should have_tag("form li fieldset ol li.#{post.id} label")
1755
+ end
1756
+ end
1757
+
1758
+ it 'should have a checkbox input for each post' do
1759
+ Post.find(:all).each do |post|
1760
+ output_buffer.should have_tag("form li fieldset ol li label input#author_post_ids_#{post.id}")
1761
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='author[post_ids][]']", :count => 2)
1762
+ end
1763
+ end
1764
+
1765
+ it "should mark input as checked if it's the the existing choice" do
1766
+ Post.find(:all).include?(@fred.posts.first).should be_true
1767
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1768
+ end
1337
1769
  end
1338
1770
 
1339
- output_buffer.should have_tag('form li label', /Author/)
1340
- output_buffer.should have_tag("form li label[@for='project_author']")
1771
+ describe 'and no object is given' do
1772
+ before(:each) do
1773
+ output_buffer.replace ''
1774
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1775
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => Author.find(:all)))
1776
+ end
1777
+ end
1778
+
1779
+ it 'should generate a fieldset with legend' do
1780
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1781
+ end
1341
1782
 
1342
- output_buffer.should have_tag('form li select#project_author')
1343
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size)
1783
+ it 'shold generate an li tag for each item in the collection' do
1784
+ output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1785
+ end
1786
+
1787
+ it 'should generate labels for each item' do
1788
+ Author.find(:all).each do |author|
1789
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1790
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1791
+ end
1792
+ end
1344
1793
 
1345
- Author.find(:all).each do |author|
1346
- output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1794
+ it 'should generate inputs for each item' do
1795
+ Author.find(:all).each do |author|
1796
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1797
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='checkbox']")
1798
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1799
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id][]']")
1800
+ end
1801
+ end
1347
1802
  end
1348
1803
  end
1349
1804
  end
@@ -1356,7 +1811,7 @@ describe 'Formtastic' do
1356
1811
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1357
1812
  end
1358
1813
 
1359
- { :select => :option, :radio => :input }.each do |type, countable|
1814
+ { :select => :option, :radio => :input, :check_boxes => :'input[@type="checkbox"]' }.each do |type, countable|
1360
1815
 
1361
1816
  describe ":as => #{type.inspect}" do
1362
1817
  describe 'when the :collection option is not provided' do
@@ -1397,7 +1852,7 @@ describe 'Formtastic' do
1397
1852
  semantic_form_for(@new_post) do |builder|
1398
1853
  concat(builder.input(:author, :as => type, :collection => @authors))
1399
1854
  end
1400
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size)
1855
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size + (type == :select ? 1 : 0))
1401
1856
  end
1402
1857
 
1403
1858
  describe 'and the :collection is an array of strings' do
@@ -1411,9 +1866,9 @@ describe 'Formtastic' do
1411
1866
  concat(builder.input(:category_name, :as => type, :collection => @categories))
1412
1867
  end
1413
1868
 
1414
- @categories.each do |item|
1415
- output_buffer.should have_tag("form li.#{type}", /#{item}/)
1416
- output_buffer.should have_tag("form li.#{type} #{countable}[@value=#{item}]")
1869
+ @categories.each do |value|
1870
+ output_buffer.should have_tag("form li.#{type}", /#{value}/)
1871
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1417
1872
  end
1418
1873
  end
1419
1874
 
@@ -1446,7 +1901,7 @@ describe 'Formtastic' do
1446
1901
 
1447
1902
  @categories.each do |label, value|
1448
1903
  output_buffer.should have_tag("form li.#{type}", /#{label}/)
1449
- output_buffer.should have_tag("form li.#{type} #{countable}[@value=#{value}]")
1904
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1450
1905
  end
1451
1906
  end
1452
1907
  end
@@ -1459,12 +1914,13 @@ describe 'Formtastic' do
1459
1914
 
1460
1915
  it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1461
1916
  semantic_form_for(@new_post) do |builder|
1462
- concat(builder.input(:category_name, :as => :radio, :collection => @categories))
1917
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1463
1918
  end
1464
1919
 
1465
- @categories.each do |label, value|
1466
- output_buffer.should have_tag('form li fieldset ol li label', /#{label}/i)
1467
- output_buffer.should have_tag('form li fieldset ol li label input[@value='+value+']')
1920
+ @categories.each do |text, value|
1921
+ label = type == :select ? :option : :label
1922
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{text}/i)
1923
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1468
1924
  end
1469
1925
  end
1470
1926
  end
@@ -1477,12 +1933,13 @@ describe 'Formtastic' do
1477
1933
 
1478
1934
  it "should use the symbol as the label text and value for each #{countable}" do
1479
1935
  semantic_form_for(@new_post) do |builder|
1480
- concat(builder.input(:category_name, :as => :radio, :collection => @categories))
1936
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1481
1937
  end
1482
1938
 
1483
1939
  @categories.each do |value|
1484
- output_buffer.should have_tag('form li fieldset ol li label', /#{value}/i)
1485
- output_buffer.should have_tag('form li fieldset ol li label input[@value='+value.to_s+']')
1940
+ label = type == :select ? :option : :label
1941
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{value}/i)
1942
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1486
1943
  end
1487
1944
  end
1488
1945
  end
@@ -1539,8 +1996,15 @@ describe 'Formtastic' do
1539
1996
  end
1540
1997
 
1541
1998
  end
1999
+ end
2000
+ end
2001
+
2002
+ describe 'for boolean attributes' do
2003
+
2004
+ { :select => :option, :radio => :input }.each do |type, countable|
2005
+ checked_or_selected = { :select => :selected, :radio => :checked }[type]
1542
2006
 
1543
- describe 'when attribute is a boolean' do
2007
+ describe ":as => #{type.inspect}" do
1544
2008
 
1545
2009
  before do
1546
2010
  @new_post.stub!(:allow_comments)
@@ -1564,7 +2028,7 @@ describe 'Formtastic' do
1564
2028
  end
1565
2029
 
1566
2030
  it "should generate two #{countable}" do
1567
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => 2)
2031
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => (type == :select ? 3 : 2))
1568
2032
  output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"]})
1569
2033
  output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"]})
1570
2034
  end
@@ -1588,8 +2052,6 @@ describe 'Formtastic' do
1588
2052
  end
1589
2053
  end
1590
2054
 
1591
- checked_or_selected = { :select => :selected, :radio => :checked }[type]
1592
-
1593
2055
  describe 'when the value is nil' do
1594
2056
  before do
1595
2057
  @new_post.stub!(:allow_comments).and_return(nil)
@@ -1656,6 +2118,7 @@ describe 'Formtastic' do
1656
2118
  end
1657
2119
  end
1658
2120
  end
2121
+
1659
2122
  end
1660
2123
  end
1661
2124
  end
@@ -1758,24 +2221,21 @@ describe 'Formtastic' do
1758
2221
  end
1759
2222
 
1760
2223
  describe 'when :discard_input => true is set' do
1761
-
1762
2224
  it 'should use default hidden value equals to 1 when attribute returns nil' do
1763
- pending
1764
2225
  semantic_form_for(@new_post) do |builder|
1765
2226
  concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1766
2227
  end
1767
2228
 
1768
- output_buffer.should have_tag("form li fieldset ol input[@type='hidden'][@value='1']")
2229
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='1']")
1769
2230
  end
1770
2231
 
1771
2232
  it 'should use default attribute value when it is not nil' do
1772
- pending
1773
2233
  @new_post.stub!(:publish_at).and_return(Date.new(2007,12,27))
1774
2234
  semantic_form_for(@new_post) do |builder|
1775
2235
  concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1776
2236
  end
1777
2237
 
1778
- output_buffer.should have_tag("form li fieldset ol input[@type='hidden'][@value='27']")
2238
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='27']")
1779
2239
  end
1780
2240
  end
1781
2241
 
@@ -1848,16 +2308,25 @@ describe 'Formtastic' do
1848
2308
  end
1849
2309
  end
1850
2310
 
1851
- it 'should have fieldset, legend, label and selects even if object is not given' do
1852
- output_buffer.replace ''
2311
+ describe 'when no object is given' do
2312
+ before(:each) do
2313
+ output_buffer.replace ''
2314
+ semantic_form_for(:project, :url => 'http://test.host') do |@builder|
2315
+ concat(@builder.input(:publish_at, :as => :datetime))
2316
+ end
2317
+ end
1853
2318
 
1854
- semantic_form_for(:project, :url => 'http://test.host') do |@builder|
1855
- concat(@builder.input(:publish_at, :as => :datetime))
2319
+ it 'should have fieldset with legend' do
2320
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1856
2321
  end
1857
2322
 
1858
- output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1859
- output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
1860
- output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2323
+ it 'should have labels for each input' do
2324
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2325
+ end
2326
+
2327
+ it 'should have selects for each inputs' do
2328
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2329
+ end
1861
2330
  end
1862
2331
  end
1863
2332
 
@@ -1885,19 +2354,18 @@ describe 'Formtastic' do
1885
2354
 
1886
2355
  it 'should have an ordered list of two items inside the fieldset' do
1887
2356
  output_buffer.should have_tag('form li.time fieldset ol')
1888
- # output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2357
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
1889
2358
  end
1890
2359
 
1891
2360
  it 'should have five labels for hour and minute' do
1892
- pending
1893
2361
  output_buffer.should have_tag('form li.time fieldset ol li label', :count => 2)
1894
2362
  output_buffer.should have_tag('form li.time fieldset ol li label', /hour/i)
1895
2363
  output_buffer.should have_tag('form li.time fieldset ol li label', /minute/i)
1896
2364
  end
1897
2365
 
1898
- it 'should have five selects for hour and minute' do
1899
- pending
1900
- output_buffer.should have_tag('form li.time fieldset ol li select', :count => 2)
2366
+ it 'should have two selects for hour and minute' do
2367
+ #output_buffer.should have_tag('form li.time fieldset ol li select', :count => 2)
2368
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
1901
2369
  end
1902
2370
  end
1903
2371
 
@@ -1976,7 +2444,6 @@ describe 'Formtastic' do
1976
2444
  end
1977
2445
  end
1978
2446
 
1979
-
1980
2447
  describe '#inputs' do
1981
2448
 
1982
2449
  describe 'with a block' do
@@ -2130,8 +2597,8 @@ describe 'Formtastic' do
2130
2597
  describe 'without a block' do
2131
2598
 
2132
2599
  before do
2133
- Post.stub!(:reflections).and_return({:author => mock('reflection', :macro => :belongs_to),
2134
- :comments => mock('reflection', :macro => :has_many) })
2600
+ Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to),
2601
+ :comments => mock('reflection', :options => {}, :macro => :has_many) })
2135
2602
  Post.stub!(:content_columns).and_return([mock('column', :name => 'title'), mock('column', :name => 'body'), mock('column', :name => 'created_at')])
2136
2603
  Author.stub!(:find).and_return([@fred, @bob])
2137
2604
 
@@ -2436,7 +2903,41 @@ describe 'Formtastic' do
2436
2903
  output_buffer.should have_tag('li.commit input#my_id')
2437
2904
  output_buffer.should have_tag('li.commit input.my_class')
2438
2905
  end
2906
+
2907
+ end
2439
2908
 
2909
+ describe 'when the first option is a string and the second is a hash' do
2910
+
2911
+ before do
2912
+ @new_post.stub!(:new_record?).and_return(false)
2913
+ semantic_form_for(@new_post) do |builder|
2914
+ concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
2915
+ end
2916
+ end
2917
+
2918
+ it "should render the string as the value of the button" do
2919
+ output_buffer.should have_tag('li input[@value="a string"]')
2920
+ end
2921
+
2922
+ it "should deal with the options hash" do
2923
+ output_buffer.should have_tag('li input.pretty')
2924
+ end
2925
+
2926
+ end
2927
+
2928
+ describe 'when the first option is a hash' do
2929
+
2930
+ before do
2931
+ @new_post.stub!(:new_record?).and_return(false)
2932
+ semantic_form_for(@new_post) do |builder|
2933
+ concat(builder.commit_button(:button_html => { :class => "pretty"}))
2934
+ end
2935
+ end
2936
+
2937
+ it "should deal with the options hash" do
2938
+ output_buffer.should have_tag('li input.pretty')
2939
+ end
2940
+
2440
2941
  end
2441
2942
 
2442
2943
  describe 'when used on an existing record' do
@@ -2549,7 +3050,7 @@ describe 'Formtastic' do
2549
3050
  end
2550
3051
  end
2551
3052
 
2552
- output_buffer.should eql("<form action=\"/posts\" class=\"formtastic post\" id=\"new_post\" method=\"post\"><input id=\"post_links__delete\" name=\"post[links][_delete]\" type=\"hidden\" /><a href=\"#\" onclick=\"$(this).parents('.nil_class').hide(); $(this).prev(':input').val('1');; return false;\">Remove</a></form>")
3053
+ output_buffer.should eql("<form action=\"/posts\" class=\"formtastic post\" id=\"new_post\" method=\"post\"><input id=\"post_links__delete\" name=\"post[links][_delete]\" type=\"hidden\" /><a href=\"#\" onclick=\";$(this).parents('.nil_class').hide(); $(this).prev(':input').val('1');; return false;\">Remove</a></form>")
2553
3054
  end
2554
3055
 
2555
3056
  it "should have a show method" do