erector-form_for 0.0.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.
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Rakefile +7 -0
- data/form_erector.gemspec +34 -0
- data/lib/erector/form_for/version.rb +3 -0
- data/lib/erector/form_for.rb +204 -0
- data/spec/form_erector_spec.rb +392 -0
- data/spec/spec_helper.rb +58 -0
- metadata +188 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "erector/form_for/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "erector-form_for"
|
7
|
+
s.version = FormErector::VERSION
|
8
|
+
s.authors = ["Macario"]
|
9
|
+
s.email = ["macarui@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/maca/erector-form_for"
|
11
|
+
s.summary = %q{Form helper inspired by erector targeting html5}
|
12
|
+
s.description = %q{Form helper inspired by erector targeting html5}
|
13
|
+
|
14
|
+
s.rubyforge_project = "erector-form_for"
|
15
|
+
|
16
|
+
s.add_dependency 'erector'
|
17
|
+
s.add_dependency 'sinatra'
|
18
|
+
s.add_dependency 'sinatra-trails'
|
19
|
+
s.add_dependency 'i18n'
|
20
|
+
s.add_dependency 'activesupport', '>= 3.0'
|
21
|
+
|
22
|
+
s.add_development_dependency 'rake'
|
23
|
+
s.add_development_dependency 'rspec'
|
24
|
+
s.add_development_dependency 'capybara'
|
25
|
+
s.add_development_dependency 'rack-test'
|
26
|
+
s.add_development_dependency 'rack_csrf'
|
27
|
+
s.add_development_dependency 'sequel'
|
28
|
+
s.add_development_dependency 'sqlite3'
|
29
|
+
|
30
|
+
s.files = `git ls-files`.split("\n")
|
31
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
32
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'sinatra/trails'
|
3
|
+
require "erector"
|
4
|
+
|
5
|
+
libdir = File.dirname( __FILE__)
|
6
|
+
$:.unshift(libdir) unless $:.include?(libdir)
|
7
|
+
require "form_for/version"
|
8
|
+
|
9
|
+
module Erector
|
10
|
+
module FormFor
|
11
|
+
class Form < Erector::InlineWidget
|
12
|
+
attr_reader :object_name
|
13
|
+
needs :action, :method => 'post'
|
14
|
+
|
15
|
+
def initialize app, object, opts, &block
|
16
|
+
assigns = {}
|
17
|
+
@app = app
|
18
|
+
@object = object
|
19
|
+
@opts = opts
|
20
|
+
@object_name = opts.delete(:object_name)
|
21
|
+
assigns[:method] = opts.delete(:method)
|
22
|
+
|
23
|
+
if opts.has_key?(:action)
|
24
|
+
assigns[:action] = opts.delete(:action)
|
25
|
+
end
|
26
|
+
|
27
|
+
if object_is_record?
|
28
|
+
@object_name ||= object.class.table_name.to_s.singularize
|
29
|
+
if object.new_record?
|
30
|
+
assigns[:action] ||= app.path_for("new_#{object_name}") if app.respond_to?(:path_for)
|
31
|
+
assigns[:method] ||= 'post'
|
32
|
+
opts[:id] ||= "new-#{object_name}"
|
33
|
+
else
|
34
|
+
assigns[:action] ||= app.path_for("edit_#{object_name}", object) if app.respond_to?(:path_for)
|
35
|
+
assigns[:method] ||= 'put'
|
36
|
+
opts[:id] ||= "edit-#{object_name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
super assigns, &block
|
41
|
+
|
42
|
+
@method = @method.to_s
|
43
|
+
@action = @app.url @action
|
44
|
+
end
|
45
|
+
|
46
|
+
def fields attrs = {}, &block
|
47
|
+
legend_text = attrs.delete(:legend)
|
48
|
+
fieldset attrs do
|
49
|
+
ol &block
|
50
|
+
legend(legend_text) if legend_text
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def form_input field, attrs = {}
|
55
|
+
widget WrappedInput.new(@object, @object_name, field, attrs)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def content
|
60
|
+
opts = @opts.merge(:method => @method == 'get' ? 'get' : 'post', :action => @action)
|
61
|
+
form opts do
|
62
|
+
input :type => "hidden", :name => "_method", :value => @method unless %(get post).include? @method
|
63
|
+
if @method != 'get' && @app.env['rack.session'] && @app.env['rack.session']['csrf.token']
|
64
|
+
text! Rack::Csrf.csrf_tag(@app.env)
|
65
|
+
end
|
66
|
+
input :type => "hidden", :name => "utf8", :value => '✓'
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def object_is_record?
|
72
|
+
@object.class.respond_to?(:table_name) && @object.respond_to?(:new_record?)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Input < Erector::Widget
|
77
|
+
EQUIVALENCIES = {:string => :text, :datetime_local => :'datetime-local', :phone => :tel, :fax => :tel}
|
78
|
+
attr_reader :id
|
79
|
+
|
80
|
+
def initialize kind, object, object_name, column, opts
|
81
|
+
opts[:name] ||= object_name ? "#{object_name}[#{column}]" : column
|
82
|
+
opts[:id] ||= [object_name, column].compact.join('-').dasherize
|
83
|
+
opts[:value] ||= Hash === object ? object[column] : object.send(column)
|
84
|
+
@type = kind.to_sym
|
85
|
+
@label = opts.delete(:label) || column.to_s.titleize
|
86
|
+
super opts
|
87
|
+
end
|
88
|
+
|
89
|
+
def content
|
90
|
+
case @type
|
91
|
+
when :boolean
|
92
|
+
input :type => :hidden, :value => 0, :name => @name
|
93
|
+
label :for => id do
|
94
|
+
input assigns.merge(:type => :checkbox, :value => 1)
|
95
|
+
text @label
|
96
|
+
end
|
97
|
+
when :text
|
98
|
+
label @label, :for => id
|
99
|
+
textarea @value, assigns
|
100
|
+
when :select
|
101
|
+
label @label, :for => id
|
102
|
+
assigns.delete(:collection) || raise("Missing parameter :collection")
|
103
|
+
assigns.delete(:value)
|
104
|
+
select assigns do
|
105
|
+
@collection.each do |value, text|
|
106
|
+
option text || value, :value => value, :selected => value.to_s == @value.to_s ? 'selected' : nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
when :radio
|
110
|
+
assigns.delete(:collection) || raise("Missing parameter :collection")
|
111
|
+
assigns.delete(:value)
|
112
|
+
fieldset do
|
113
|
+
label @label
|
114
|
+
ol do
|
115
|
+
@collection.each do |value, label_text|
|
116
|
+
li do
|
117
|
+
label do
|
118
|
+
input :value => value, :id => "#{@id}-#{value}".downcase.dasherize, :checked => value.to_s == @value.to_s ? 'checked' : nil
|
119
|
+
text " #{label_text || value}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
else
|
126
|
+
label @label, :for => id
|
127
|
+
input assigns.merge(:type => EQUIVALENCIES[@type] || @type)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class WrappedInput < Erector::Widget
|
133
|
+
needs :as, :id => nil, :required => false
|
134
|
+
|
135
|
+
def initialize object, object_name, column, opts
|
136
|
+
assigns = {}
|
137
|
+
|
138
|
+
[:as, :required].each do |key|
|
139
|
+
opts.has_key?(key) and assigns[key] = opts.delete(key)
|
140
|
+
end
|
141
|
+
|
142
|
+
case column.to_s
|
143
|
+
when /email/
|
144
|
+
assigns[:as] ||= :email
|
145
|
+
when /url/
|
146
|
+
assigns[:as] ||= :url
|
147
|
+
when /password/
|
148
|
+
assigns[:as] ||= :password
|
149
|
+
when /search/, /query/, 'q'
|
150
|
+
assigns[:as] ||= :search
|
151
|
+
when /phone/, /fax/
|
152
|
+
assigns[:as] ||= :tel
|
153
|
+
end
|
154
|
+
|
155
|
+
if Sequel::Model === object
|
156
|
+
column_schema = object.db_schema[column.to_sym]
|
157
|
+
assigns[:required] = !column_schema[:allow_null] unless assigns.has_key?(:required)
|
158
|
+
|
159
|
+
type = column_schema[:db_type]
|
160
|
+
case type
|
161
|
+
when /char/
|
162
|
+
opts[:maxlength] ||= /\d+/.match(type)
|
163
|
+
assigns[:as] ||= :string
|
164
|
+
else
|
165
|
+
assigns[:as] ||= type.downcase
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
super assigns
|
170
|
+
|
171
|
+
case @as = @as.to_sym
|
172
|
+
when :hidden, :string, :text, :boolean, :email, :color, :date, :datetime, :'datetime-local', :datetime_local, :email, :file, :image, :month, :number, :password, :range, :search, :tel, :phone, :fax, :time, :url, :week, :select, :radio
|
173
|
+
@widget = Input.new @as, object, object_name, column, opts.merge(:required => @required)
|
174
|
+
else
|
175
|
+
raise ArgumentError, ":as => #{@as.inspect} is not a valid option"
|
176
|
+
end
|
177
|
+
|
178
|
+
@wrapper_html = {:class => []}
|
179
|
+
@wrapper_html[:id] = "input-#{@widget.id}"
|
180
|
+
@wrapper_html[:class].push(@required ? 'required' : 'optional')
|
181
|
+
@wrapper_html[:class].push @as
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
def content
|
186
|
+
li @wrapper_html do
|
187
|
+
widget @widget
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module Helpers
|
193
|
+
def form_for object, opts = {}, &block
|
194
|
+
Form.new(self, object, opts, &block).to_html
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class << self
|
199
|
+
def extended base
|
200
|
+
base.send :include, Helpers
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,392 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'form erector' do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
include SpecHelper
|
7
|
+
|
8
|
+
describe 'form tag attributes' do
|
9
|
+
describe 'form for record' do
|
10
|
+
describe 'action and method for new record' do
|
11
|
+
before do
|
12
|
+
app.user_form(new_user)
|
13
|
+
get '/users/new'
|
14
|
+
end
|
15
|
+
|
16
|
+
it { page.should have_css "form[action='http://example.org/users/new']" }
|
17
|
+
it { page.should have_css "form[method='post']" }
|
18
|
+
it { page.should have_css "form[id='new-user']" }
|
19
|
+
it { page.should_not have_css "input[name=_method]" }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'action and method for existing record' do
|
23
|
+
before do
|
24
|
+
app.user_form(existing_user)
|
25
|
+
get '/users/new'
|
26
|
+
end
|
27
|
+
|
28
|
+
it { page.should have_css "form[action='http://example.org/users/1/edit']" }
|
29
|
+
it { page.should have_css "form[method='post']" }
|
30
|
+
it { page.should have_css "form[id='edit-user']" }
|
31
|
+
it { page.should have_xpath "//input[@name='_method' and @value='put']" }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'overriding method (get) and action and setting html attributes' do
|
35
|
+
before do
|
36
|
+
app.user_form(existing_user, :action => '/users', :method => :get, :id => 'search-users', :class => 'search-form')
|
37
|
+
get '/users/new'
|
38
|
+
end
|
39
|
+
|
40
|
+
it { page.should have_css "form[action='http://example.org/users']" }
|
41
|
+
it { page.should have_css "form[method='get']" }
|
42
|
+
it { page.should_not have_css "input[name=_method]" }
|
43
|
+
it { page.should have_css "form#search-users" }
|
44
|
+
it { page.should have_css "form.search-form" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'form for hash' do
|
49
|
+
describe 'action and method for new record and defaulting method to post' do
|
50
|
+
before do
|
51
|
+
app.user_form({}, :action => '/search')
|
52
|
+
get '/users/new'
|
53
|
+
end
|
54
|
+
|
55
|
+
it { page.should have_css "form[action='http://example.org/search']" }
|
56
|
+
it { page.should have_css "form[method='post']" }
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should requiere action' do
|
60
|
+
lambda{
|
61
|
+
app.user_form({}, :method => 'post')
|
62
|
+
get '/users/new'
|
63
|
+
}.should raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'csrf' do
|
68
|
+
it 'should have protection protection off' do
|
69
|
+
app.user_form(existing_user)
|
70
|
+
get '/users/new'
|
71
|
+
page.should_not have_xpath "//input[@name='_csrf' and @type='hidden']"
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should have protection on' do
|
75
|
+
app.use Rack::Session::Cookie, :secret => 'my secret'
|
76
|
+
app.use Rack::Csrf
|
77
|
+
app.user_form(existing_user)
|
78
|
+
get '/users/new'
|
79
|
+
page.should have_xpath "//input[@name='_csrf' and @type='hidden']"
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should have protection off for get' do
|
83
|
+
app.use Rack::Session::Cookie, :secret => 'my secret'
|
84
|
+
app.use Rack::Csrf
|
85
|
+
app.user_form(existing_user, :method => :get)
|
86
|
+
get '/users/new'
|
87
|
+
page.should_not have_xpath "//input[@name='_csrf' and @type='hidden']"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should have utf8 field' do
|
92
|
+
app.user_form(existing_user)
|
93
|
+
get '/users/new'
|
94
|
+
page.should have_xpath "//input[@name='utf8' and @type='hidden' and @value='✓']"
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should pass self to block' do
|
98
|
+
app.user_form(new_user) do |form|
|
99
|
+
form.should be_a Erector::FormFor::Form
|
100
|
+
end
|
101
|
+
get '/users/new'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'formfield' do
|
106
|
+
describe 'basic' do
|
107
|
+
before do
|
108
|
+
app.user_form(new_user) do |form|
|
109
|
+
fields
|
110
|
+
end
|
111
|
+
get '/users/new'
|
112
|
+
end
|
113
|
+
it { page.should have_xpath "//form/fieldset" }
|
114
|
+
it { page.should have_xpath "//form/fieldset/ol" }
|
115
|
+
it { page.should_not have_xpath "//form/fieldset/legend" }
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'with legend and attributes' do
|
119
|
+
before do
|
120
|
+
app.user_form(new_user) do |form|
|
121
|
+
fields :legend => 'Basic', :id => 'basic'
|
122
|
+
end
|
123
|
+
get '/users/new'
|
124
|
+
end
|
125
|
+
it { page.should have_xpath "//form/fieldset" }
|
126
|
+
it { page.should have_xpath "//form/fieldset[@id='basic']" }
|
127
|
+
it { page.should have_xpath "//form/fieldset/legend", :text => 'Basic' }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'inputs' do
|
132
|
+
describe 'for record' do
|
133
|
+
describe 'basic' do
|
134
|
+
before do
|
135
|
+
new_user.stub!(:name).and_return('Macario')
|
136
|
+
app.user_form(new_user) do
|
137
|
+
fields do
|
138
|
+
form_input :name
|
139
|
+
form_input :about
|
140
|
+
end
|
141
|
+
end
|
142
|
+
get '/users/new'
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'wrap' do
|
146
|
+
it { page.should have_xpath "//form/fieldset/ol/li" }
|
147
|
+
it { page.should have_css "li#input-user-name" }
|
148
|
+
it { page.should have_css "li#input-user-name.required" }
|
149
|
+
it { page.should have_css "li#input-user-name.string" }
|
150
|
+
it { page.should have_css "li#input-user-about.optional" }
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'input' do
|
154
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input" }
|
155
|
+
it { page.should have_css "input#user-name" }
|
156
|
+
it { page.should have_css "input#user-name[type='text']" }
|
157
|
+
it { page.should have_css "input#user-name[name='user[name]']" }
|
158
|
+
it { page.should have_css "input#user-name[value='Macario']" }
|
159
|
+
it { page.should have_css "input#user-name[maxlength='255']" }
|
160
|
+
it { page.should have_css "input#user-name[required]" }
|
161
|
+
it { page.should_not have_css "input#user-about[required]" }
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'label' do
|
165
|
+
it { page.should have_css "label[for='user-name']" }
|
166
|
+
it { page.should have_css "label[for='user-name']", :text => "Name" }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe 'overriding defaults' do
|
171
|
+
before do
|
172
|
+
new_user.stub!(:name).and_return('Macario')
|
173
|
+
app.user_form(new_user) do
|
174
|
+
fields do
|
175
|
+
form_input :name, :required => false, :value => 'Luis', :id => 'nombre', :name => 'nombre', :maxlength => 100, :label => 'Escriba su nombre', :as => 'email'
|
176
|
+
end
|
177
|
+
end
|
178
|
+
get '/users/new'
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'wrap' do
|
182
|
+
it { page.should have_xpath "//form/fieldset/ol/li" }
|
183
|
+
it { page.should have_css "li#input-nombre" }
|
184
|
+
it { page.should have_css "li#input-nombre.optional" }
|
185
|
+
it { page.should have_css "li#input-nombre.email" }
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'input' do
|
189
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input" }
|
190
|
+
it { page.should have_css "input#nombre" }
|
191
|
+
it { page.should have_css "input#nombre[type='email']" }
|
192
|
+
it { page.should have_css "input#nombre[name='nombre']" }
|
193
|
+
it { page.should have_css "input#nombre[value='Luis']" }
|
194
|
+
it { page.should have_css "input#nombre[maxlength='100']" }
|
195
|
+
end
|
196
|
+
|
197
|
+
describe 'label' do
|
198
|
+
it { page.should have_css "label[for='nombre']" }
|
199
|
+
it { page.should have_css "label[for='nombre']", :text => "Escriba su nombre" }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'for hash' do
|
205
|
+
before do
|
206
|
+
app.user_form({:name => 'Macario', :about => nil}, :action => '/new') do
|
207
|
+
fields do
|
208
|
+
form_input :name, :as => :string, :required => true
|
209
|
+
form_input :about, :as => :string
|
210
|
+
end
|
211
|
+
end
|
212
|
+
get '/users/new'
|
213
|
+
end
|
214
|
+
|
215
|
+
describe 'wrap for required' do
|
216
|
+
it { page.should have_xpath "//form/fieldset/ol/li" }
|
217
|
+
it { page.should have_css "li#input-name" }
|
218
|
+
it { page.should have_css "li#input-name.required" }
|
219
|
+
it { page.should have_css "li#input-name.string" }
|
220
|
+
end
|
221
|
+
|
222
|
+
describe 'wrap for optional' do
|
223
|
+
it { page.should have_css "li#input-about.optional" }
|
224
|
+
end
|
225
|
+
|
226
|
+
describe 'input' do
|
227
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input" }
|
228
|
+
it { page.should have_css "input#name" }
|
229
|
+
it { page.should have_css "input#name[type='text']" }
|
230
|
+
it { page.should have_css "input#name[name='name']" }
|
231
|
+
it { page.should have_css "input#name[value='Macario']" }
|
232
|
+
end
|
233
|
+
|
234
|
+
describe 'label' do
|
235
|
+
it { page.should have_css "label[for='name']" }
|
236
|
+
it { page.should have_css "label[for='name']", :text => "Name" }
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe 'input' do
|
241
|
+
describe 'boolean input with sequel reflection' do
|
242
|
+
before do
|
243
|
+
app.user_form(new_user) do
|
244
|
+
fields { form_input :confirmed }
|
245
|
+
end
|
246
|
+
get '/users/new'
|
247
|
+
end
|
248
|
+
|
249
|
+
it { page.should have_xpath "//form/fieldset/ol/li/label/input[@id='user-confirmed']" }
|
250
|
+
it { page.should have_css "input#user-confirmed[type='checkbox']" }
|
251
|
+
it { page.should have_css "input#user-confirmed[value='1']" }
|
252
|
+
it { page.should have_css "input#user-confirmed[name='user[confirmed]']" }
|
253
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input[@type='hidden' and @name='user[confirmed]']" }
|
254
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input[@type='hidden' and @value='0']" }
|
255
|
+
it { page.should have_xpath "//form/fieldset/ol/li/input[@type='hidden' and @name='user[confirmed]']" }
|
256
|
+
end
|
257
|
+
|
258
|
+
%w(hidden color date datetime datetime-local datetime_local email file image month number password range search tel phone fax time url week).each do |type|
|
259
|
+
describe "#{type} input" do
|
260
|
+
before "should emit type='#{type}'" do
|
261
|
+
app.user_form({}, :action => '/search') do
|
262
|
+
fields { form_input :any, :as => type }
|
263
|
+
end
|
264
|
+
get '/users/new'
|
265
|
+
@type =
|
266
|
+
case type
|
267
|
+
when 'datetime_local' then 'datetime-local'
|
268
|
+
when 'phone', 'fax' then 'tel'
|
269
|
+
else type end
|
270
|
+
end
|
271
|
+
|
272
|
+
it { page.should have_css "input[type='#{@type}']" }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe 'type default by name' do
|
277
|
+
before do
|
278
|
+
app.user_form({}, :action => '/search') do
|
279
|
+
fields do
|
280
|
+
form_input :email
|
281
|
+
form_input :url
|
282
|
+
form_input :password
|
283
|
+
form_input :password_confirmation
|
284
|
+
form_input :search
|
285
|
+
form_input :query
|
286
|
+
form_input :q
|
287
|
+
form_input :phone
|
288
|
+
form_input :request_fax
|
289
|
+
end
|
290
|
+
end
|
291
|
+
get '/users/new'
|
292
|
+
end
|
293
|
+
it { page.should have_css "input#email[type='email']" }
|
294
|
+
it { page.should have_css "input#url[type='url']" }
|
295
|
+
it { page.should have_css "input#password[type='password']" }
|
296
|
+
it { page.should have_css "input#password-confirmation[type='password']" }
|
297
|
+
it { page.should have_css "input#search[type='search']" }
|
298
|
+
it { page.should have_css "input#query[type='search']" }
|
299
|
+
it { page.should have_css "input#q[type='search']" }
|
300
|
+
it { page.should have_css "input#phone[type='tel']" }
|
301
|
+
it { page.should have_css "input#request-fax[type='tel']" }
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe 'text input' do
|
306
|
+
describe 'text input with sequel reflection' do
|
307
|
+
before do
|
308
|
+
new_user.stub!(:bio).and_return('Lorem ipsum...')
|
309
|
+
app.user_form(new_user) do
|
310
|
+
fields { form_input :bio }
|
311
|
+
end
|
312
|
+
get '/users/new'
|
313
|
+
end
|
314
|
+
|
315
|
+
it { page.should have_xpath "//form/fieldset/ol/li/label[@for='user-bio']" }
|
316
|
+
it { page.should have_xpath "//form/fieldset/ol/li/textarea[@id='user-bio']" }
|
317
|
+
it { page.should_not have_css "texarea[value]" }
|
318
|
+
it { page.should have_css "textarea", :text => 'Lorem ipsum...' }
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe 'select input' do
|
323
|
+
describe 'with hash' do
|
324
|
+
before do
|
325
|
+
app.user_form({:quality => 'best'}, :action => '/search') do
|
326
|
+
fields { form_input :quality, :as => :select, :collection => {:worse => 'Worse', :best => 'Best'} }
|
327
|
+
end
|
328
|
+
get '/users/new'
|
329
|
+
end
|
330
|
+
|
331
|
+
it { page.should have_xpath "//form/fieldset/ol/li/label[@for='quality']" }
|
332
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select[@id='quality']" }
|
333
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select[@name='quality']" }
|
334
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='worse']" }
|
335
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='best']" }
|
336
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='worse']", :text => 'Worse' }
|
337
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='best']", :text => 'Best' }
|
338
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='best' and @selected='selected']" }
|
339
|
+
end
|
340
|
+
|
341
|
+
describe 'with multi array' do
|
342
|
+
before do
|
343
|
+
app.user_form({:quality => 'best'}, :action => '/search') do
|
344
|
+
fields { form_input :quality, :as => :select, :collection => [%w(worse Worse), %w(best Best)] }
|
345
|
+
end
|
346
|
+
get '/users/new'
|
347
|
+
end
|
348
|
+
|
349
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='worse']", :text => 'Worse' }
|
350
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='best']", :text => 'Best' }
|
351
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='best' and @selected='selected']" }
|
352
|
+
end
|
353
|
+
|
354
|
+
describe 'with array' do
|
355
|
+
before do
|
356
|
+
app.user_form({:quality => 'Best'}, :action => '/search') do
|
357
|
+
fields { form_input :quality, :as => :select, :collection => %w(Worse Best) }
|
358
|
+
end
|
359
|
+
get '/users/new'
|
360
|
+
end
|
361
|
+
|
362
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='Worse']", :text => 'Worse' }
|
363
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='Best']", :text => 'Best' }
|
364
|
+
it { page.should have_xpath "//form/fieldset/ol/li/select/option[@value='Best' and @selected='selected']" }
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe 'radio buttons' do
|
369
|
+
before do
|
370
|
+
app.user_form({:quality => 'best'}, :action => '/search') do
|
371
|
+
fields { form_input :quality, :as => :radio, :collection => {:worse => 'Worse', :best => 'Best'} }
|
372
|
+
end
|
373
|
+
get '/users/new'
|
374
|
+
end
|
375
|
+
|
376
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset" }
|
377
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/label", :text => 'Quality' }
|
378
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol" }
|
379
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li", :count => 2 }
|
380
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label", :count => 2 }
|
381
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input", :count => 2 }
|
382
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='worse']" }
|
383
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='best']" }
|
384
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='worse' and @id='quality-worse']" }
|
385
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='best']" }
|
386
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='best' and @id='quality-best']" }
|
387
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label", :text => 'Worse' }
|
388
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label", :text => 'Best' }
|
389
|
+
it { page.should have_xpath "//form/fieldset/ol/li/fieldset/ol/li/label/input[@value='best' and @checked='checked']" }
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec'
|
3
|
+
require 'capybara'
|
4
|
+
require 'rack/test'
|
5
|
+
require 'rack/csrf'
|
6
|
+
require 'sqlite3'
|
7
|
+
require 'sequel'
|
8
|
+
|
9
|
+
$:.unshift File.join(File.dirname( __FILE__), '..', 'lib')
|
10
|
+
require 'erector/form_for'
|
11
|
+
|
12
|
+
DB = Sequel.sqlite
|
13
|
+
DB.create_table :users do
|
14
|
+
primary_key :id
|
15
|
+
String :name, :null => false
|
16
|
+
String :about, :fixed => true
|
17
|
+
String :any
|
18
|
+
Text :bio
|
19
|
+
Boolean :confirmed
|
20
|
+
end
|
21
|
+
|
22
|
+
class User < Sequel::Model
|
23
|
+
end
|
24
|
+
|
25
|
+
module SpecHelper
|
26
|
+
def self.included base
|
27
|
+
base.instance_eval do
|
28
|
+
let(:app) do
|
29
|
+
app = Class.new(Sinatra::Base)
|
30
|
+
app.register Sinatra::Trails
|
31
|
+
app.register Erector::FormFor
|
32
|
+
def app.user_form *args, &block
|
33
|
+
resources(:users) do
|
34
|
+
get(new_user){ form_for(*args, &block) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
app.set :environment, :test
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:new_user) do
|
41
|
+
user = User.new
|
42
|
+
user.stub!(:new_record?).and_return(true)
|
43
|
+
user
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:existing_user) do
|
47
|
+
user = User.new
|
48
|
+
user.stub!(:new_record?).and_return(false)
|
49
|
+
user.stub!(:to_param).and_return(1)
|
50
|
+
user
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:page) do
|
54
|
+
Capybara::Node::Simple.new(last_response.body)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: erector-form_for
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Macario
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: erector
|
16
|
+
requirement: &70307239220860 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70307239220860
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sinatra
|
27
|
+
requirement: &70307239220260 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70307239220260
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sinatra-trails
|
38
|
+
requirement: &70307239219560 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70307239219560
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: i18n
|
49
|
+
requirement: &70307239218940 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70307239218940
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: activesupport
|
60
|
+
requirement: &70307239218120 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '3.0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70307239218120
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: &70307239217480 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70307239217480
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
requirement: &70307239201960 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70307239201960
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: capybara
|
93
|
+
requirement: &70307239201400 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70307239201400
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rack-test
|
104
|
+
requirement: &70307239200900 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70307239200900
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rack_csrf
|
115
|
+
requirement: &70307239200360 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70307239200360
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: sequel
|
126
|
+
requirement: &70307239199860 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *70307239199860
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: sqlite3
|
137
|
+
requirement: &70307239199380 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *70307239199380
|
146
|
+
description: Form helper inspired by erector targeting html5
|
147
|
+
email:
|
148
|
+
- macarui@gmail.com
|
149
|
+
executables: []
|
150
|
+
extensions: []
|
151
|
+
extra_rdoc_files: []
|
152
|
+
files:
|
153
|
+
- .gitignore
|
154
|
+
- .rspec
|
155
|
+
- Gemfile
|
156
|
+
- Rakefile
|
157
|
+
- form_erector.gemspec
|
158
|
+
- lib/erector/form_for.rb
|
159
|
+
- lib/erector/form_for/version.rb
|
160
|
+
- spec/form_erector_spec.rb
|
161
|
+
- spec/spec_helper.rb
|
162
|
+
homepage: http://github.com/maca/erector-form_for
|
163
|
+
licenses: []
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project: erector-form_for
|
182
|
+
rubygems_version: 1.8.8
|
183
|
+
signing_key:
|
184
|
+
specification_version: 3
|
185
|
+
summary: Form helper inspired by erector targeting html5
|
186
|
+
test_files:
|
187
|
+
- spec/form_erector_spec.rb
|
188
|
+
- spec/spec_helper.rb
|