Changeset 731
- Timestamp:
- 10/08/07 16:35:13 (1 year ago)
- Files:
-
- plugins/merb_helpers/lib/form_helpers.rb (modified) (2 diffs)
- plugins/merb_helpers/specs/merb_helpers_spec.rb (modified) (2 diffs)
- plugins/merb_helpers/specs/spec_helper.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/merb_helpers/lib/form_helpers.rb
r730 r731 1 class Hash 2 3 def to_html_attributes 4 map do |k,v| 5 "#{k.to_s.camelize.downcase}=\"#{v}\"" 6 end.join(" ") 7 end 8 9 def add_html_class!(html_class) 10 if self[:class] 11 self[:class] = "#{self[:class]} #{html_class}" 12 else 13 self[:class] = html_class 14 end 15 end 16 17 end 18 1 19 module Merb 2 20 module Helpers … … 18 36 end 19 37 20 def form_for(obj, &block) 21 concat("<form>", block.binding) 22 38 def open_tag(name, attrs = nil) 39 "<#{name}#{' ' + attrs.to_html_attributes if attrs}>" 40 end 41 42 def self_closing_tag(name, attrs = nil) 43 "<#{name}#{' ' + attrs.to_html_attributes if attrs}/>" 44 end 45 46 def form_tag(attrs = {}, &block) 47 concat(open_tag("form", attrs), block.binding) 48 concat(capture(&block), block.binding) 49 concat("</form>", block.binding) 50 end 51 52 def form_for(obj, attrs=nil, &block) 53 concat(open_tag("form", attrs), block.binding) 54 fields_for(obj, attrs, &block) 55 concat("</form>", block.binding) 56 end 57 58 def fields_for(obj, attrs=nil, &block) 23 59 old_obj, @_obj = @_obj, instance_variable_get("@#{obj}") 24 60 @_object_name = obj 25 61 old_block, @_block = @_block, block 26 62 27 block.call 28 29 concat("</form>", block.binding) 30 @_obj, @_block = old_obj, old_block 63 concat(capture(&block), block.binding) 64 65 @_obj, @_block = old_obj, old_block 31 66 end 32 67 33 def text_control(col) 34 concat("<input type='text' name='#{@_object_name}[#{col}]' value='#{@_obj.send(col)}'/>", @_block.binding) 68 def name_value(col, attrs) 69 {:name => "#{@_object_name}[#{col}]", :value => "#{@_obj.send(col)}"}.merge(attrs) 70 end 71 72 def text_control(col, attrs = {}) 73 errorify_field(attrs, col) 74 text_field(name_value(col, attrs)) 75 end 76 77 def text_field(attrs = {}) 78 attrs.merge!(:type => "text") 79 self_closing_tag("input", attrs) 80 end 81 82 def checkbox_control(col, attrs = {}) 83 errorify_field(attrs, col) 84 val = @_obj.send(col) 85 attrs.merge!(:value => val ? "1" : "0") 86 attrs.merge!(:checked => "checked") if val 87 checkbox_field(name_value(col, attrs)) 88 end 89 90 def checkbox_field(attrs = {}) 91 attrs.merge!(:type => :checkbox) 92 attrs.add_html_class!("checkbox") 93 self_closing_tag("input", attrs) 94 end 95 96 def hidden_control(col, attrs = {}) 97 errorify_field(attrs, col) 98 hidden_field(name_value(col, attrs)) 99 end 100 101 def hidden_field(attrs = {}) 102 attrs.merge!(:type => :hidden) 103 self_closing_tag("input", attrs) 104 end 105 106 def radio_group_control(col, options = {}, attrs = {}) 107 errorify_field(attrs, col) 108 val = @_obj.send(col) 109 ret = "" 110 options.each do |opt| 111 hash = {:name => "#{@_object_name}[#{col}]", :value => opt} 112 hash.merge!(:selected => "selected") if val.to_s == opt.to_s 113 ret << radio_field(hash) 114 end 115 ret 116 end 117 118 def radio_field(attrs = {}) 119 attrs.merge!(:type => "radio") 120 attrs.add_html_class!("radio") 121 self_closing_tag("input", attrs) 122 end 123 124 def submit_button(contents, attrs = {}) 125 attrs.merge!(:type => "submit") 126 open_tag("button", attrs) + contents + "</button>" 127 end 128 129 def errorify_field(attrs, col) 130 attrs.add_html_class!("error") if !@obj.valid? && @obj.errors.on(col) 35 131 end 36 132 plugins/merb_helpers/specs/merb_helpers_spec.rb
r729 r731 5 5 include Merb::ErubisCaptureMixin 6 6 include Merb::Helpers::Form 7 8 7 9 8 describe "error_messages_for" do … … 37 36 end 38 37 39 class FakeModel 40 def self.columns 41 [FakeColumn.new(:foo, :string), FakeColumn.new(:bar, :integer)] 42 end 38 describe "form_tag" do 39 it_should_behave_like "FakeBufferConsumer" 43 40 44 def foo 45 "foowee" 41 it "should take create a form" do 42 form_tag(:action => "foo", :method => "POST") do 43 _buffer << "Hello" 44 end 45 _buffer.should match_tag(:form, :action => "foo", :method => "POST") 46 _buffer.should include("Hello") 46 47 end 47 48 end 48 49 49 class FakeColumn 50 attr_accessor :name, :type 51 def initialize(name, type) 52 @name, @type = name, type 50 describe "form_for" do 51 it_should_behave_like "FakeBufferConsumer" 52 53 it "should wrap the contents in a form tag" do 54 form_for(:obj) do 55 _buffer("") << "Hello" 56 end 57 _buffer("").should == "<form>Hello</form>" 53 58 end 54 59 end 55 60 56 describe "text_control" do 61 describe "fields_for" do 62 it_should_behave_like "FakeBufferConsumer" 57 63 58 before :each do 59 @obj = FakeModel.new 60 def _buffer(buf) @buffer ||= "" end 64 it "should dump the contents in the context of the object" do 65 fields_for(:obj) do 66 _buffer("") << "Hello" 67 end 68 _buffer("").should == "Hello" 69 end 70 71 it "should be able to modify the context midstream" do 72 @obj2 = FakeModel2.new 73 form_for(:obj) do 74 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee") 75 fields_for(:obj2) do 76 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee2") 77 end 78 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee") 79 end 61 80 end 81 end 82 83 describe "text_field (basic)" do 84 it "should return a basic text field based on the values passed in" do 85 text_field(:name => "foo", :value => "bar").should == "<input type=\"text\" name=\"foo\" value=\"bar\"/>" 86 end 87 end 88 89 describe "text_control (data bound)" do 90 it_should_behave_like "FakeBufferConsumer" 62 91 63 92 it "should take a string object and return a useful text control" do 64 93 f = form_for :obj do 65 text_control(:foo).should == "<form><input type='text' name='obj[foo]' value='foowee'/>"94 text_control(:foo).should match_tag(:input, :type => "text", :name => "obj[foo]", :value => "foowee") 66 95 end 67 f.should == "<form><input type='text' name='obj[foo]' value='foowee'/></form>" 96 end 97 98 it "should take additional attributes and use them" do 99 form_for :obj do 100 text_control(:foo, :bar => "7").should match_tag(:input, :type => "text", :name => "obj[foo]", :value => "foowee", :bar => "7") 101 end 102 end 103 end 104 105 describe "checkbox_field (basic)" do 106 include TagMatchers 107 108 it "should return a basic checkbox based on the values passed in" do 109 checkbox_field(:name => "foo", :checked => "checked").should match_tag(:input, :class => "checkbox", :name => "foo", :checked => "checked") 110 end 111 end 112 113 describe "checkbox_control (data bound)" do 114 it_should_behave_like "FakeBufferConsumer" 115 116 it "should take a string and return a useful checkbox control" do 117 form_for :obj do 118 checkbox_control(:baz).should match_tag(:input, :type =>"checkbox", :name => "obj[baz]", :class => "checkbox", :value => "1", :checked => "checked") 119 checkbox_control(:bat).should match_tag(:input, :type =>"checkbox", :name => "obj[bat]", :class => "checkbox", :value => "0") 120 end 68 121 end 69 122 123 it "should render controls with errors if their attribute contains an error" do 124 form_for :obj do 125 checkbox_control(:bazbad).should match_tag(:input, :type =>"checkbox", :name => "obj[bazbad]", 126 :class => "error checkbox", :value => "1", :checked => "checked") 127 checkbox_control(:batbad).should match_tag(:input, :type =>"checkbox", :name => "obj[batbad]", 128 :class => "error checkbox", :value => "0") 129 end 130 end 131 70 132 end 133 134 describe "hidden_field (basic)" do 135 include TagMatchers 136 137 it "should return a basic checkbox based on the values passed in" do 138 hidden_field(:name => "foo", :value => "bar").should match_tag(:input, :type => "hidden", :name => "foo", :value => "bar") 139 end 140 end 141 142 describe "hidden_control (data bound)" do 143 it_should_behave_like "FakeBufferConsumer" 144 145 it "should take a string and return a useful checkbox control" do 146 form_for :obj do 147 hidden_control(:foo).should match_tag(:input, :type =>"hidden", :name => "obj[foo]", :value => "foowee") 148 end 149 end 150 151 it "should render controls with errors if their attribute contains an error" do 152 form_for :obj do 153 hidden_control(:foobad).should match_tag(:input, :type =>"hidden", :name => "obj[foobad]", :value => "foowee", :class => "error") 154 end 155 end 156 157 end 158 159 describe "radio button (basic)" do 160 include TagMatchers 161 it "should should return a basic radio button based on the values passed in" do 162 radio_field(:name => "foo", :value => "bar").should match_tag(:input, :type => "radio", :name => "foo", :value => "bar") 163 end 164 end 165 166 describe "radio button groups (data bound)" do 167 it_should_behave_like "FakeBufferConsumer" 168 169 it "should return a group of radio buttons" do 170 form_for :obj do 171 radio = radio_group_control(:foo, [:foowee, :baree]).scan(/<[^>]*>/) 172 radio[0].should match_tag(:input, :type => "radio", :name => "obj[foo]", :value => "foowee", :selected => "selected") 173 radio[1].should match_tag(:input, :type => "radio", :name => "obj[foo]", :value => "baree") 174 radio[1].should not_match_tag(:selected => "selected") 175 end 176 end 177 end 178 179 describe "submit_button" do 180 it_should_behave_like "FakeBufferConsumer" 181 182 it "should produce a simple submit button" do 183 submit_button("Foo").should == "<button type=\"submit\">Foo</button>" 184 end 185 end plugins/merb_helpers/specs/spec_helper.rb
r710 r731 3 3 require 'rubygems' 4 4 require 'merb' 5 6 module TagMatchers 7 class MatchTag 8 def initialize(name, attrs) 9 @name, @attrs = name, attrs 10 end 11 12 def matches?(target) 13 @errors = [] 14 unless target.include?("<#{@name}") 15 @errors << "Expected a <#{@name}>, but was #{target}" 16 end 17 @attrs.each do |attr, val| 18 unless target.include?("#{attr}=\"#{val}\"") 19 @errors << "Expected #{attr}=\"#{val}\", but was #{target}" 20 end 21 end 22 @errors.size == 0 23 end 24 25 def failure_message 26 @errors[0] 27 end 28 end 29 30 class NotMatchTag 31 def initialize(attrs) 32 @attrs = attrs 33 end 34 35 def matches?(target) 36 @errors = [] 37 @attrs.each do |attr, val| 38 if target.include?("#{attr}=\"#{val}\"") 39 @errors << "Should not include #{attr}=\"#{val}\", but was #{target}" 40 end 41 end 42 @errors.size == 0 43 end 44 45 def failure_message 46 @errors[0] 47 end 48 end 49 50 def match_tag(name, attrs) 51 MatchTag.new(name, attrs) 52 end 53 def not_match_tag(attrs) 54 NotMatchTag.new(attrs) 55 end 56 end 57 58 class FakeModel 59 def self.columns 60 [FakeColumn.new(:foo, :string), 61 FakeColumn.new(:foobad, :string), 62 FakeColumn.new(:bar, :integer), 63 FakeColumn.new(:barbad, :integer), 64 FakeColumn.new(:baz, :boolean), 65 FakeColumn.new(:bazbad, :boolean), 66 FakeColumn.new(:bat, :boolean), 67 FakeColumn.new(:batbad, :boolean) 68 ] 69 end 70 71 def valid? 72 false 73 end 74 75 def errors 76 FakeErrors.new(self) 77 end 78 79 def foo 80 "foowee" 81 end 82 alias_method :foobad, :foo 83 84 def bar 85 7 86 end 87 alias_method :barbad, :bar 88 89 def baz 90 true 91 end 92 alias_method :bazbad, :baz 93 94 def bat 95 false 96 end 97 alias_method :batbad, :bat 98 end 99 100 class FakeModel2 < FakeModel 101 102 def foo 103 "foowee2" 104 end 105 alias_method :foobad, :foo 106 107 end 108 109 class FakeErrors 110 111 def initialize(model) 112 @model = model 113 end 114 115 def on(name) 116 name.to_s.include?("bad") 117 end 118 119 end 120 121 class FakeColumn 122 attr_accessor :name, :type 123 def initialize(name, type) 124 @name, @type = name, type 125 end 126 end 127 128 describe "FakeBufferConsumer", :shared => true do 129 include TagMatchers 130 131 before :each do 132 @obj = FakeModel.new 133 def _buffer(buf = "") @buffer ||= "" end 134 end 135 end
