visionmedia-dm-forms 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.rdoc +4 -0
- data/Manifest +27 -0
- data/README.rdoc +62 -0
- data/Rakefile +16 -0
- data/Todo.rdoc +27 -0
- data/dm-forms.gemspec +37 -0
- data/examples/benchmarks.rb +118 -0
- data/examples/datamapper.rb +37 -0
- data/examples/elements.rb +31 -0
- data/examples/haml.rb +21 -0
- data/examples/login.haml +4 -0
- data/lib/dm-forms/core_ext.rb +39 -0
- data/lib/dm-forms/elements.rb +210 -0
- data/lib/dm-forms/model_elements.rb +33 -0
- data/lib/dm-forms/tag.rb +156 -0
- data/lib/dm-forms/version.rb +9 -0
- data/lib/dm-forms.rb +32 -0
- data/spec/functional/core_ext_spec.rb +56 -0
- data/spec/functional/elements_spec.rb +209 -0
- data/spec/functional/tag_spec.rb +49 -0
- data/spec/integration/datamapper_spec.rb +70 -0
- data/spec/integration/haml_spec.rb +29 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/benchmarks.rake +5 -0
- data/tasks/docs.rake +13 -0
- data/tasks/gemspec.rake +3 -0
- data/tasks/spec.rake +25 -0
- metadata +111 -0
data/lib/dm-forms/tag.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
|
2
|
+
module DataMapper
|
3
|
+
module Form
|
4
|
+
class Tag
|
5
|
+
|
6
|
+
##
|
7
|
+
# Boolean attributes.
|
8
|
+
|
9
|
+
BOOLEAN_ATTRIBUTES = :disabled, :readonly, :multiple, :checked, :selected
|
10
|
+
|
11
|
+
##
|
12
|
+
# Elements which should not include auto-generated classes.
|
13
|
+
|
14
|
+
IGNORE_CLASSES_ON_ELEMENTS = :form, :label, :fieldset, :hidden
|
15
|
+
|
16
|
+
##
|
17
|
+
# Name of element (input, fieldset, etc).
|
18
|
+
|
19
|
+
attr_accessor :name
|
20
|
+
|
21
|
+
##
|
22
|
+
# Options passed to the constructor.
|
23
|
+
|
24
|
+
attr_accessor :options
|
25
|
+
|
26
|
+
##
|
27
|
+
# Attributes pulled from #options.
|
28
|
+
|
29
|
+
attr_accessor :attributes
|
30
|
+
|
31
|
+
##
|
32
|
+
# Markup placed before the element.
|
33
|
+
|
34
|
+
attr_accessor :before
|
35
|
+
|
36
|
+
##
|
37
|
+
# Markup placed after the element.
|
38
|
+
|
39
|
+
attr_accessor :after
|
40
|
+
|
41
|
+
##
|
42
|
+
# Tag's description.
|
43
|
+
|
44
|
+
attr_accessor :description
|
45
|
+
|
46
|
+
def initialize name, options = {}, &block
|
47
|
+
@name, @options, @attributes = name, options, (options[:attributes] ||= {})
|
48
|
+
@before, @after = attribute(:before, ''), attribute(:after, '')
|
49
|
+
@description = Elements.desc(attribute(:description)) || ''
|
50
|
+
@model = attribute :model
|
51
|
+
(@attributes[:value] ||= '') << Elements.capture_elements(@model, &block) if block_given?
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Render final markup of this element or 'tag'.
|
56
|
+
|
57
|
+
def render
|
58
|
+
@attributes[:class] = classes unless classes.blank?
|
59
|
+
prepare_boolean_attributes
|
60
|
+
before << label
|
61
|
+
close = self_closing? ? " />" : ">#{inner_html}</#{@name}>"
|
62
|
+
open = "<#{@name} #{@attributes.to_html_attributes}"
|
63
|
+
tag = before << open << close << description << after << "\n"
|
64
|
+
end
|
65
|
+
alias :to_s :render
|
66
|
+
|
67
|
+
##
|
68
|
+
# Prepare boolean attribute values, so that the user may
|
69
|
+
# utilize :multiple => true, instead of :multiple => :multiple.
|
70
|
+
|
71
|
+
def prepare_boolean_attributes
|
72
|
+
@attributes.each_pair do |key, value|
|
73
|
+
if BOOLEAN_ATTRIBUTES.include? key
|
74
|
+
if value
|
75
|
+
@attributes[key] = key
|
76
|
+
else
|
77
|
+
@attributes.delete key
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Wither or not a tag is self-closing (<br />).
|
85
|
+
|
86
|
+
def self_closing?
|
87
|
+
@options[:self_closing]
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# The inner HTML of this tag, only available for
|
92
|
+
# elements which are not self-closing.
|
93
|
+
|
94
|
+
def inner_html
|
95
|
+
attribute :value, '' unless self_closing?
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Is the element required.
|
100
|
+
|
101
|
+
def required?
|
102
|
+
attribute :required, false
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Generates a label when needed.
|
107
|
+
|
108
|
+
def label
|
109
|
+
@label ||= has_label? ? Elements.label(@attributes.delete(:label), :for => @attributes[:name], :required => required?) : ''
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Wither or not this tag has a label.
|
114
|
+
|
115
|
+
def has_label?
|
116
|
+
!@attributes[:label].blank?
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Returns user generated classes as well as those generated by
|
121
|
+
# dm-forms for styling consistancy.
|
122
|
+
|
123
|
+
def classes
|
124
|
+
@classes ||= [@attributes[:class], generate_classes].join(' ').strip if should_add_classes?
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
##
|
130
|
+
# Generates element class(es) such as form-submit.
|
131
|
+
|
132
|
+
def generate_classes
|
133
|
+
classes = "form-#{@name == :input ? @attributes[:type] : @name}"
|
134
|
+
classes << " form-#{@attributes[:name]}" unless @attributes[:name].blank?
|
135
|
+
classes
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Wither or not classes should be added to this element.
|
140
|
+
|
141
|
+
def should_add_classes?
|
142
|
+
!(IGNORE_CLASSES_ON_ELEMENTS.include? @name or IGNORE_CLASSES_ON_ELEMENTS.include? @attributes[:type])
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Return an +attribute+ or its +default+ value, removing
|
147
|
+
# it from @attributes so that final attributes rendered
|
148
|
+
# within the HTML are not cluttered with ad-hoc keys.
|
149
|
+
|
150
|
+
def attribute attribute, default = nil
|
151
|
+
@attributes.delete(attribute) || default
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/dm-forms.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 TJ Holowaychuk
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
$:.unshift File.dirname(__FILE__)
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'extlib'
|
28
|
+
require 'dm-forms/version'
|
29
|
+
require 'dm-forms/core_ext'
|
30
|
+
require 'dm-forms/tag'
|
31
|
+
require 'dm-forms/elements'
|
32
|
+
require 'dm-forms/model_elements'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
describe "core ext" do
|
4
|
+
|
5
|
+
#--
|
6
|
+
# Humanize
|
7
|
+
#++
|
8
|
+
|
9
|
+
describe "String#humanize" do
|
10
|
+
|
11
|
+
it "should humanize strings" do
|
12
|
+
'im_a_Lame_String.Yeah.with.7.words'.humanize.should == 'im a Lame String Yeah with 7 words'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should humanize symbols" do
|
16
|
+
:some_Cool_symbol.humanize.should == 'some Cool symbol'
|
17
|
+
:login.humanize.should == 'login'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not mess with already human readable strings" do
|
21
|
+
'i am already VERY readable'.humanize.should == 'i am already VERY readable'
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
#--
|
27
|
+
# Indent
|
28
|
+
#++
|
29
|
+
|
30
|
+
describe "String#indent" do
|
31
|
+
|
32
|
+
it "should indent 2 spaces by default" do
|
33
|
+
'meow'.indent.should == ' meow'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should indent variable tab lengths" do
|
37
|
+
'meow'.indent(2).should == ' meow'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should indent multi-line strings" do
|
41
|
+
string = <<-EOF.deindent
|
42
|
+
foo
|
43
|
+
bar
|
44
|
+
EOF
|
45
|
+
string.indent.should == <<-EOF.deindent
|
46
|
+
foo
|
47
|
+
bar
|
48
|
+
EOF
|
49
|
+
string.indent(2).should == <<-EOF.deindent
|
50
|
+
foo
|
51
|
+
bar
|
52
|
+
EOF
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
|
2
|
+
include DataMapper::Form::Elements
|
3
|
+
|
4
|
+
describe DataMapper::Form::Elements do
|
5
|
+
|
6
|
+
#--
|
7
|
+
# Element aspecs
|
8
|
+
#++
|
9
|
+
|
10
|
+
describe "element aspecs" do
|
11
|
+
|
12
|
+
it "should allow descriptions" do
|
13
|
+
s = textarea :comments, :description => 'Please enter your comments.'
|
14
|
+
s.should == <<-HTML.deindent(8)
|
15
|
+
<textarea class="form-textarea form-comments" name="comments"></textarea>
|
16
|
+
<p class="description">Please enter your comments.</p>
|
17
|
+
HTML
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should allow prefixing of arbitrary markup" do
|
21
|
+
s = textarea :comments, :before => "<h1>Comments</h1>\n"
|
22
|
+
s.should == <<-HTML.deindent(8)
|
23
|
+
<h1>Comments</h1>
|
24
|
+
<textarea class="form-textarea form-comments" name="comments"></textarea>
|
25
|
+
HTML
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should allow arbitrary markup after" do
|
29
|
+
s = textarea :comments, :after => "\n<p>Custom markup</p>"
|
30
|
+
s.should == <<-HTML.deindent(8)
|
31
|
+
<textarea class="form-textarea form-comments" name="comments"></textarea>
|
32
|
+
<p>Custom markup</p>
|
33
|
+
HTML
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
#--
|
39
|
+
# Elements
|
40
|
+
#++
|
41
|
+
|
42
|
+
describe "elements" do
|
43
|
+
|
44
|
+
it "should create labels" do
|
45
|
+
s = label 'Email', :for => :email
|
46
|
+
s.should == %(<label for="email">Email:</label>\n)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should create required labels" do
|
50
|
+
s = label 'Email', :for => :email, :required => true
|
51
|
+
s.should == %(<label for="email">Email:<em>*</em></label>\n)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should create textfields" do
|
55
|
+
s = textfield :phone, :value => 'Enter phone number'
|
56
|
+
s.should == %(<input type="textfield" class="form-textfield form-phone" value="Enter phone number" name="phone" />\n)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should create submit buttons" do
|
60
|
+
s = submit :op, :value => 'Submit'
|
61
|
+
s.should == %(<input type="submit" class="form-submit form-op" value="Submit" name="op" />\n)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should create buttons" do
|
65
|
+
s = button :op, :value => 'Edit'
|
66
|
+
s.should == %(<input type="button" class="form-button form-op" value="Edit" name="op" />\n)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should create image buttons" do
|
70
|
+
s = button :op, :value => 'Edit', :src => 'path/to/image.png'
|
71
|
+
s.should == %(<input type="image" class="form-image form-op" value="Edit" name="op" src="path/to/image.png" />\n)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should create a checkbox" do
|
75
|
+
s = checkbox :agree_to_terms, :value => 'Agree to terms', :checked => true
|
76
|
+
s.should == %(<input type="checkbox" class="form-checkbox form-agree_to_terms" value="Agree to terms" name="agree_to_terms" checked="checked" />\n)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should create a file field" do
|
80
|
+
s = file :image
|
81
|
+
s.should == %(<input type="file" class="form-file form-image" name="image" />\n)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should create hidden fields" do
|
85
|
+
s = hidden :_method, :value => 'put'
|
86
|
+
s.should == %(<input type="hidden" value="put" name="_method" />\n)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should create a radio button" do
|
90
|
+
s = radio :sex, :value => 'Male'
|
91
|
+
s.should == %(<input type="radio" class="form-radio form-sex" value="Male" name="sex" />\n)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should create textareas" do
|
95
|
+
s = textarea :comments, :value => 'Enter your comments here', :label => 'Comments'
|
96
|
+
s.should == <<-HTML.deindent(8)
|
97
|
+
<label for="comments">Comments:</label>
|
98
|
+
<textarea class="form-textarea form-comments" name="comments">Enter your comments here</textarea>
|
99
|
+
HTML
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should create fieldsets" do
|
103
|
+
s = fieldset :details, :legend => 'Details', :value => 'WAHOO!'
|
104
|
+
s.should == <<-HTML.deindent(8)
|
105
|
+
<fieldset class="fieldset-details">
|
106
|
+
<legend>Details</legend>WAHOO!</fieldset>
|
107
|
+
HTML
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should create fieldsets with element capturing block" do
|
111
|
+
s = fieldset :details, :id => 'details' do |f|
|
112
|
+
f.button :one
|
113
|
+
f.button :two
|
114
|
+
end
|
115
|
+
s.should == <<-HTML.deindent(8)
|
116
|
+
<fieldset class="fieldset-details" id="details">
|
117
|
+
<legend>Details</legend><input type="button" class="form-button form-one" name="one" />
|
118
|
+
<input type="button" class="form-button form-two" name="two" />
|
119
|
+
</fieldset>
|
120
|
+
HTML
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should create fieldsets without legends, auto-generating them from the fieldset name" do
|
124
|
+
s = fieldset :some_legend, :value => 'WAHOO!'
|
125
|
+
s.should == <<-HTML.deindent(8)
|
126
|
+
<fieldset class="fieldset-some_legend">
|
127
|
+
<legend>Some legend</legend>WAHOO!</fieldset>
|
128
|
+
HTML
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should create select fields" do
|
132
|
+
s = select :color, :options => { :red => 'Red', :green => 'Green', :blue => 'Blue' }
|
133
|
+
s.should == <<-HTML.deindent(8)
|
134
|
+
<select class="form-select form-color" name="color">
|
135
|
+
<option value="blue">Blue</option>
|
136
|
+
<option value="red">Red</option>
|
137
|
+
<option value="green">Green</option>
|
138
|
+
</select>
|
139
|
+
HTML
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should create select fields with block" do
|
143
|
+
s = select :color do |s|
|
144
|
+
s.option :red, 'Red'
|
145
|
+
s.option :green, 'Green'
|
146
|
+
s.option :blue, 'Blue'
|
147
|
+
end
|
148
|
+
s.should == <<-HTML.deindent(8)
|
149
|
+
<select class="form-select form-color" name="color">
|
150
|
+
<option value="red">Red</option>
|
151
|
+
<option value="green">Green</option>
|
152
|
+
<option value="blue">Blue</option>
|
153
|
+
</select>
|
154
|
+
HTML
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
#--
|
160
|
+
# Form specifics
|
161
|
+
#++
|
162
|
+
|
163
|
+
describe "forms" do
|
164
|
+
|
165
|
+
it "should default method to post" do
|
166
|
+
s = form :register
|
167
|
+
s.should == %(<form method="post" id="form-register"></form>\n)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should allow custom methods" do
|
171
|
+
s = form :register, :method => :get
|
172
|
+
s.should == %(<form method="get" id="form-register"></form>\n)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should allow arbitrary inner html" do
|
176
|
+
s = form :register, :method => :get, :value => 'COOKIE!'
|
177
|
+
s.should == %(<form method="get" id="form-register">COOKIE!</form>\n)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should store arbitrary methods in _method" do
|
181
|
+
s = form :login, :method => :put do |f|
|
182
|
+
f.submit :op, :value => 'Submit'
|
183
|
+
end
|
184
|
+
s.should == <<-HTML.deindent(8)
|
185
|
+
<form method="post" id="form-login"><input type="hidden" value="put" name="_method" />
|
186
|
+
<input type="submit" class="form-submit form-op" value="Submit" name="op" />
|
187
|
+
</form>
|
188
|
+
HTML
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should create with a block for inner html" do
|
192
|
+
s = form :login do |f|
|
193
|
+
f.textfield :name, :label => 'Username'
|
194
|
+
f.textfield :pass, :label => 'Password'
|
195
|
+
f.submit :op, :value => 'Login'
|
196
|
+
end
|
197
|
+
s.should == <<-HTML.deindent(8)
|
198
|
+
<form method="post" id="form-login"><label for="name">Username:</label>
|
199
|
+
<input type="textfield" class="form-textfield form-name" name="name" />
|
200
|
+
<label for="pass">Password:</label>
|
201
|
+
<input type="textfield" class="form-textfield form-pass" name="pass" />
|
202
|
+
<input type="submit" class="form-submit form-op" value="Login" name="op" />
|
203
|
+
</form>
|
204
|
+
HTML
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
describe DataMapper::Form::Tag do
|
3
|
+
|
4
|
+
Tag = DataMapper::Form::Tag
|
5
|
+
|
6
|
+
it "should generate classes" do
|
7
|
+
tag = Tag.new :input, :attributes => { :name => 'email', :type => :textfield }
|
8
|
+
tag.send(:classes).should == 'form-textfield form-email'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should generate classes when no name is present" do
|
12
|
+
tag = Tag.new :input, :attributes => { :type => :textfield }
|
13
|
+
tag.send(:classes).should == 'form-textfield'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should auto-assign boolean attributes" do
|
17
|
+
tag = Tag.new :input, :attributes => { :name => 'email', :type => :textfield, :disabled => true }
|
18
|
+
tag.render.should == %(<input disabled="disabled" type="textfield" class="form-textfield form-email" name="email"></input>\n)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should generate and merge classes" do
|
22
|
+
tag = Tag.new :input, :attributes => { :class => 'foo bar', :name => 'email', :type => :textfield }
|
23
|
+
tag.send(:classes).should == 'foo bar form-textfield form-email'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should grab inner html for non self-closing tags" do
|
27
|
+
tag = Tag.new :textarea, :self_closing => false, :attributes => { :value => 'BOOYAH' }
|
28
|
+
tag.inner_html.should == 'BOOYAH'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow descriptions and remove from attributes" do
|
32
|
+
tag = Tag.new :input, :attributes => { :description => 'testing one two three' }
|
33
|
+
tag.description.should == %(\n<p class="description">testing one two three</p>)
|
34
|
+
tag.attributes.has_key?(:description).should be_false
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should allow capturing of elements via block" do
|
38
|
+
tag = Tag.new :fieldset, :attributes => { :id => 'something' } do |f|
|
39
|
+
f.button :one
|
40
|
+
f.button :two
|
41
|
+
end
|
42
|
+
tag.render.should == <<-HTML.deindent
|
43
|
+
<fieldset id="something"><input type="button" class="form-button form-one" name="one" />
|
44
|
+
<input type="button" class="form-button form-two" name="two" />
|
45
|
+
</fieldset>
|
46
|
+
HTML
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
require 'dm-core'
|
3
|
+
require 'dm-validations'
|
4
|
+
|
5
|
+
include DataMapper::Form::ModelElements
|
6
|
+
|
7
|
+
DataMapper.setup :default, 'sqlite3::memory:'
|
8
|
+
|
9
|
+
class User
|
10
|
+
include DataMapper::Resource
|
11
|
+
property :id, Serial
|
12
|
+
property :name, String, :format => /^[\w]+$/
|
13
|
+
property :email, String, :format => :email_address
|
14
|
+
end
|
15
|
+
|
16
|
+
DataMapper.auto_migrate!
|
17
|
+
|
18
|
+
describe DataMapper::Form::ModelElements do
|
19
|
+
|
20
|
+
before :each do
|
21
|
+
@user = User.new :name => 'invalid username', :email => 'is_valid@email.com'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should create a list of errors when a model is invalid" do
|
25
|
+
errors_for(@user).should == <<-HTML.deindent
|
26
|
+
<ul class="messages error">
|
27
|
+
<li>Name has an invalid format</li>
|
28
|
+
</ul>
|
29
|
+
HTML
|
30
|
+
@user.email = 'invalid email@ something.com'
|
31
|
+
errors_for(@user).should == <<-HTML.deindent
|
32
|
+
<ul class="messages error">
|
33
|
+
<li>Name has an invalid format</li>
|
34
|
+
<li>Email has an invalid format</li>
|
35
|
+
</ul>
|
36
|
+
HTML
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should create model specific forms with errors on elements" do
|
40
|
+
results = form_for @user do |f|
|
41
|
+
f.textfield :name
|
42
|
+
f.textfield :email
|
43
|
+
f.submit :op, :value => 'Save'
|
44
|
+
end
|
45
|
+
results.should == <<-HTML.deindent
|
46
|
+
<form method="post" id="form-user"><input type="textfield" class="error form-textfield form-name" name="name" />
|
47
|
+
<input type="textfield" class="form-textfield form-email" name="email" />
|
48
|
+
<input type="submit" class="form-submit form-op" value="Save" name="op" />
|
49
|
+
</form>
|
50
|
+
HTML
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should use _method put for updating records" do
|
54
|
+
@user.name = 'tj'
|
55
|
+
@user.save
|
56
|
+
results = form_for @user, :action => '/register' do |f|
|
57
|
+
f.textfield :name
|
58
|
+
f.textfield :email
|
59
|
+
f.submit :op, :value => 'Save'
|
60
|
+
end
|
61
|
+
results.should == <<-HTML.deindent
|
62
|
+
<form method="post" action="/register" id="form-user"><input type="hidden" value="put" name="_method" />
|
63
|
+
<input type="textfield" class="form-textfield form-name" name="name" />
|
64
|
+
<input type="textfield" class="form-textfield form-email" name="email" />
|
65
|
+
<input type="submit" class="form-submit form-op" value="Save" name="op" />
|
66
|
+
</form>
|
67
|
+
HTML
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'haml'
|
4
|
+
|
5
|
+
include DataMapper::Form::Elements
|
6
|
+
|
7
|
+
describe "Haml + dm-forms" do
|
8
|
+
|
9
|
+
it "should create pretty forms :D" do
|
10
|
+
engine = Haml::Engine.new <<-HAML.deindent
|
11
|
+
.comments
|
12
|
+
%h1 Comments
|
13
|
+
= textfield :name
|
14
|
+
= textfield :email
|
15
|
+
= textarea :comments
|
16
|
+
= submit :op, :value => 'Submit'
|
17
|
+
HAML
|
18
|
+
engine.render.should == <<-HTML.deindent
|
19
|
+
<div class='comments'>
|
20
|
+
<h1>Comments</h1>
|
21
|
+
<input type="textfield" class="form-textfield form-name" name="name" />
|
22
|
+
<input type="textfield" class="form-textfield form-email" name="email" />
|
23
|
+
<textarea class="form-textarea form-comments" name="comments"></textarea>
|
24
|
+
<input type="submit" class="form-submit form-op" value="Submit" name="op" />
|
25
|
+
</div>
|
26
|
+
HTML
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tasks/docs.rake
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
namespace :docs do
|
3
|
+
|
4
|
+
desc 'Remove rdoc products'
|
5
|
+
task :remove => [:clobber_docs]
|
6
|
+
|
7
|
+
desc 'Build docs, and open in browser for viewing (specify BROWSER)'
|
8
|
+
task :open do
|
9
|
+
browser = ENV["BROWSER"] || "safari"
|
10
|
+
sh "open -a #{browser} doc/index.html"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/tasks/gemspec.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc "Run all specifications"
|
5
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
6
|
+
t.libs << "lib"
|
7
|
+
t.spec_opts = ["--color", "--require", "spec/spec_helper.rb"]
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :spec do
|
11
|
+
|
12
|
+
desc "Run all specifications verbosely"
|
13
|
+
Spec::Rake::SpecTask.new(:verbose) do |t|
|
14
|
+
t.libs << "lib"
|
15
|
+
t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run specific specification verbosely (specify SPEC)"
|
19
|
+
Spec::Rake::SpecTask.new(:select) do |t|
|
20
|
+
t.libs << "lib"
|
21
|
+
t.spec_files = [ENV["SPEC"]]
|
22
|
+
t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|