formation 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ coverage
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in formation.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'minitest'
8
+ end
@@ -0,0 +1,22 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/**/*_{test,spec}.rb']
7
+ # t.warning = true
8
+ end
9
+
10
+ begin
11
+ require 'rcov/rcovtask'
12
+ Rcov::RcovTask.new do |t|
13
+ t.test_files = FileList['test/**/*_{test,spec}.rb']
14
+ t.verbose = true
15
+ t.rcov_opts << %w{ --exclude .rvm }
16
+ end
17
+ rescue LoadError
18
+ desc 'Analyze code coverage with tests'
19
+ task :rcov do
20
+ puts "Install rcov"
21
+ end
22
+ end
data/demo.rb ADDED
@@ -0,0 +1,179 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'datamapper'
4
+ require File.expand_path('../lib/formation', __FILE__)
5
+
6
+ class Post
7
+
8
+ include DataMapper::Resource
9
+
10
+ property :id, Serial
11
+ property :title, String
12
+ property :body, Text
13
+ property :created_at, DateTime
14
+
15
+ end
16
+
17
+ class PostForm
18
+
19
+ include Formation::Form
20
+
21
+ resource :post do
22
+ fieldset :legend => 'New Post' do
23
+ field :title, :label => 'Title', :required => true
24
+ field :body, :label => 'Body', :type => :textarea, :required => true
25
+ end
26
+ end
27
+
28
+ def initialize(post)
29
+ @post = post
30
+ end
31
+
32
+ end
33
+
34
+ class RegistrationForm
35
+
36
+ include Formation::Form
37
+
38
+ fieldset :account do
39
+ field :login_name, :required => true
40
+ field :password, :required => true
41
+ end
42
+
43
+ fieldset :address do
44
+ field :address
45
+ field :city
46
+ end
47
+
48
+ end
49
+
50
+ DataMapper.setup :default, 'sqlite::memory:'
51
+ DataMapper.auto_migrate!
52
+
53
+ get '/styles.css' do
54
+ <<-CSS
55
+ *, html {
56
+ font-family: Verdana, Arial, Helvetica, sans-serif;
57
+ }
58
+ body, form, ul, li, p, h2, h3, h4, h5 {
59
+ margin: 0;
60
+ padding: 0;
61
+ }
62
+ body {
63
+ background-color: #606061;
64
+ color: #ffffff;
65
+ }
66
+ img {
67
+ border: none;
68
+ }
69
+ p {
70
+ font-size: 1em;
71
+ margin: 0 0 1em 0;
72
+ }
73
+ h2 {
74
+ font-size: 14px;
75
+ margin: 0 0 12px;
76
+ }
77
+
78
+ form {
79
+ margin: 20px auto;
80
+ width: 610px;
81
+ }
82
+ form fieldset {
83
+ margin: 0 0 20px;
84
+ padding: 20px;
85
+ -webkit-border-radius: 5px;
86
+ -moz-border-radius: 5px;
87
+ border-radius: 5px;
88
+ }
89
+ form ol {
90
+ list-style-type: none;
91
+ padding: 0;
92
+ margin: 0;
93
+ }
94
+ form li {
95
+ margin: 0 0 12px;
96
+ position: relative;
97
+ }
98
+ form label {
99
+ width: 150px;
100
+ display: inline-block;
101
+ vertical-align: top;
102
+ }
103
+ form input, form textarea, form select {
104
+ background: #fff;
105
+ display: inline-block;
106
+ width: 371px;
107
+ border: 1px solid #fff;
108
+ padding: 3px 26px 3px 3px;
109
+ -moz-transition: background-color 1s ease;
110
+ -webkit-transition: background-color 1s ease;
111
+ -o-transition: background-color 1s ease;
112
+ transition: background-color 1s ease;
113
+ -webkit-border-radius: 5px;
114
+ -moz-border-radius: 5px;
115
+ border-radius: 5px;
116
+ }
117
+ CSS
118
+ end
119
+
120
+ get '/register' do
121
+ @form = RegistrationForm.new
122
+ erb :register
123
+ end
124
+
125
+ post '/register' do
126
+ @form = RegistrationForm.new
127
+ @form.submit params
128
+ if @form.valid?
129
+ erb :thanks
130
+ else
131
+ erb :register
132
+ end
133
+ end
134
+
135
+ get '/posts/new' do
136
+ @form = PostForm.new(Post.new)
137
+ erb :new_post
138
+ end
139
+
140
+ post '/posts' do
141
+ @form = PostForm.new(Post.new)
142
+ @form.submit params
143
+ if @form.valid?
144
+ @form.post.save
145
+ raise @form.inspect
146
+ redirect "/posts/#{@form.post.id}"
147
+ else
148
+ erb :new_post
149
+ end
150
+ end
151
+
152
+ __END__
153
+
154
+ @@ layout
155
+ <html>
156
+ <head>
157
+ <link rel="stylesheet" type="text/css" href="/styles.css" media="screen" />
158
+ </head>
159
+ <body>
160
+ <%= yield %>
161
+ </body>
162
+ </html>
163
+
164
+ @@ register
165
+ <h1>Register</h1>
166
+ <form action="/register" method="post">
167
+ <%= Formation::Printer.new(@form).print %>
168
+ <input type="submit" />
169
+ </form>
170
+
171
+ @@ thanks
172
+ <h1>Thanks!</h1>
173
+
174
+ @@ new_post
175
+ <h1>New Post</h1>
176
+ <form action="/posts" method="post">
177
+ <%= Formation::Printer.new(@form).print %>
178
+ <input type="submit" />
179
+ </form>
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "formation/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "formation"
7
+ s.version = Formation::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Chris Gibson']
10
+ s.email = ['chrislgibson@gmail.com']
11
+ s.homepage = "http://github.com/chrisgibson/formation"
12
+ s.summary = %q{first-class ruby forms}
13
+ s.description = %q{first-class ruby forms}
14
+
15
+ # s.rubyforge_project = "formation"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,24 @@
1
+ module Formation
2
+
3
+ module Support
4
+
5
+ end
6
+
7
+ module Types
8
+
9
+ end
10
+
11
+ end
12
+
13
+ require File.expand_path('../formation/util', __FILE__)
14
+ require File.expand_path('../formation/element', __FILE__)
15
+ require File.expand_path('../formation/field', __FILE__)
16
+ require File.expand_path('../formation/fieldset', __FILE__)
17
+ require File.expand_path('../formation/form', __FILE__)
18
+ require File.expand_path('../formation/type', __FILE__)
19
+ require File.expand_path('../formation/types/checkbox', __FILE__)
20
+ require File.expand_path('../formation/types/password', __FILE__)
21
+ require File.expand_path('../formation/types/text', __FILE__)
22
+ require File.expand_path('../formation/types/text_area', __FILE__)
23
+
24
+ require File.expand_path('../formation/printer', __FILE__)
@@ -0,0 +1,9 @@
1
+ class Formation::Element
2
+
3
+ attr_reader :name
4
+
5
+ def field?
6
+ false
7
+ end
8
+
9
+ end
@@ -0,0 +1,32 @@
1
+ class Formation::Field < Formation::Element
2
+
3
+ attr_reader :label, :fieldset, :type
4
+ attr_accessor :value
5
+
6
+ def initialize(name, options = {})
7
+ @name = name
8
+ if @fieldset = options.delete(:fieldset)
9
+ @fieldset.fields << self
10
+ end
11
+ @type = options.delete(:type) || :text
12
+ @type = Formation::Type.create(self, @type)
13
+ @label = options.delete(:label) || Formation::Util.titleize(@name)
14
+ @required = options.delete(:required) || false
15
+
16
+ # Attach any left-over entries as accessors
17
+ options.each do |key, value|
18
+ metaclass = class << self; self; end
19
+ metaclass.send :attr_accessor, key.to_sym
20
+ send "#{key}=", value
21
+ end
22
+ end
23
+
24
+ def field?
25
+ true
26
+ end
27
+
28
+ def required?
29
+ @required
30
+ end
31
+
32
+ end
@@ -0,0 +1,14 @@
1
+ class Formation::Fieldset < Formation::Element
2
+
3
+ attr_reader :legend
4
+
5
+ def initialize(name, options = {})
6
+ @name = name
7
+ @legend = options[:legend] || Formation::Util.titleize(name)
8
+ end
9
+
10
+ def fields
11
+ @fields ||= []
12
+ end
13
+
14
+ end
@@ -0,0 +1,146 @@
1
+ module Formation::Form
2
+
3
+ module ClassMethods
4
+
5
+ def elements
6
+ @elements ||= []
7
+ end
8
+
9
+ def field(name, options = {})
10
+ @_current_resource ||= nil
11
+ @_current_fieldset ||= nil
12
+ if @_current_resource
13
+ name = "#{@_current_resource}[#{name}]"
14
+ else
15
+ name = name.to_s
16
+ end
17
+ fields[name] = Formation::Field.new(name, { :fieldset => @_current_fieldset }.merge(options))
18
+ elements << fields[name] unless @_current_fieldset
19
+ end
20
+
21
+ def fields
22
+ @fields ||= {}
23
+ end
24
+
25
+ def fieldset(name, options = {})
26
+ if name.is_a? Hash
27
+ options = name
28
+ name = Formation::Util.underscore(options[:legend])
29
+ end
30
+ @_current_fieldset = (fieldsets[name] ||= Formation::Fieldset.new(name, options))
31
+ elements << @_current_fieldset
32
+ yield
33
+ @_current_fieldset = nil
34
+ end
35
+
36
+ def fieldsets
37
+ @fieldsets ||= {}
38
+ end
39
+
40
+ def resource(resource)
41
+ resources << resource
42
+ class_eval <<-RUBY
43
+ attr_accessor :#{resource}
44
+ RUBY
45
+ if block_given?
46
+ @_current_resource = resource
47
+ yield
48
+ @_current_resource = nil
49
+ end
50
+ end
51
+
52
+ def resources
53
+ @resources ||= []
54
+ end
55
+
56
+ def validates_with_method(method_name)
57
+ method_name = method_name.to_sym
58
+ validators << method_name
59
+ end
60
+
61
+ def validators
62
+ @validators ||= []
63
+ end
64
+
65
+ end
66
+
67
+ def self.included(base)
68
+ base.extend(ClassMethods)
69
+ end
70
+
71
+ def elements
72
+ self.class.elements
73
+ end
74
+
75
+ def errors
76
+ @errors ||= []
77
+ end
78
+
79
+ def fields
80
+ fields = elements.map do |element|
81
+ element.field? ? element : element.fields
82
+ end
83
+ fields.flatten
84
+ end
85
+
86
+ def submit(params)
87
+ @submitted = true
88
+ errors.clear
89
+ fields.each do |field|
90
+ field.value = extract_value_from_params(field.name, params)
91
+ if field.required? && (field.value.nil? || field.value.empty?)
92
+ errors << "#{field.label} is required"
93
+ end
94
+ end
95
+ validators.each do |validator|
96
+ send "#{validator}"
97
+ end
98
+ self
99
+ end
100
+
101
+ def valid?
102
+ !errors.any?
103
+ end
104
+
105
+ def validators
106
+ self.class.validators
107
+ end
108
+
109
+ def value_for(name)
110
+ @values[name.to_s]
111
+ end
112
+
113
+ def values
114
+ @values ||= {}
115
+ end
116
+
117
+ private
118
+
119
+ def extract_value_from_params(name, params)
120
+ key = %r{([^\[\]=&]+)}.match(name).captures.first
121
+ value = if self.class.resources.include? key.to_sym
122
+ captures = %r{\[([^\[\]=&]+)\]}.match(name).captures
123
+ return nil unless captures.any?
124
+ resource = params.fetch(key, nil)
125
+ return nil unless resource
126
+ actual_value = resource.fetch(captures.first, nil)
127
+ return nil unless actual_value
128
+ send(key).send("#{captures.first}=", actual_value)
129
+ else
130
+ if params[key]
131
+ branch = params[key].dup
132
+ match = %r{\[([^\[\]=&]+)\]}.match(name)
133
+ if match
134
+ match.captures.each do |capture|
135
+ branch = branch[capture]
136
+ end
137
+ end
138
+ branch
139
+ else
140
+ nil
141
+ end
142
+ end
143
+ values[name] = value
144
+ end
145
+
146
+ end
@@ -0,0 +1,52 @@
1
+ class Formation::Printer
2
+
3
+ attr_reader :form
4
+
5
+ def initialize(form)
6
+ @form = form
7
+ end
8
+
9
+ def print
10
+ html = ''
11
+ html << print_errors(form.errors)
12
+ form.elements.each do |element|
13
+ if element.field?
14
+ html << print_field(element)
15
+ else
16
+ html << print_fieldset(element)
17
+ end
18
+ end
19
+ html
20
+ end
21
+
22
+ def print_error(error)
23
+ <<-HTML
24
+ <p style="color: red">#{error}</p>
25
+ HTML
26
+ end
27
+
28
+ def print_errors(errors)
29
+ errors.map { |error| print_error error }.join("\n")
30
+ end
31
+
32
+ def print_field(field)
33
+ <<-HTML
34
+ <li>
35
+ <label>#{field.label}</label>
36
+ #{field.type.to_html}
37
+ </li>
38
+ HTML
39
+ end
40
+
41
+ def print_fieldset(fieldset)
42
+ <<-HTML
43
+ <fieldset>
44
+ <legend>#{fieldset.legend}</legend>
45
+ <ol>
46
+ #{fieldset.fields.map { |f| print_field f }.join("\n")}
47
+ </ol>
48
+ </fieldset>
49
+ HTML
50
+ end
51
+
52
+ end
@@ -0,0 +1,19 @@
1
+ class Formation::Type
2
+
3
+ def self.create(field, type)
4
+ klass = case type.to_sym
5
+ when :checkbox
6
+ Formation::Types::Checkbox
7
+ when :password
8
+ Formation::Types::Password
9
+ when :text
10
+ Formation::Types::Text
11
+ when :textarea
12
+ Formation::Types::TextArea
13
+ else
14
+ raise "Invalid or unsupported field type: #{type}"
15
+ end
16
+ klass.new(field)
17
+ end
18
+
19
+ end
@@ -0,0 +1,15 @@
1
+ class Formation::Types::Checkbox
2
+
3
+ attr_reader :field
4
+
5
+ def initialize(field)
6
+ @field = field
7
+ end
8
+
9
+ def to_html
10
+ <<-HTML.strip
11
+ <input type="checkbox" name="#{field.name}" value="1" checked="#{field.value ? 'checked' : ''}" />
12
+ HTML
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ class Formation::Types::Password
2
+
3
+ attr_reader :field
4
+
5
+ def initialize(field)
6
+ @field = field
7
+ end
8
+
9
+ def to_html
10
+ <<-HTML.strip
11
+ <input type="password" name="#{field.name}" />
12
+ HTML
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ class Formation::Types::Text
2
+
3
+ attr_reader :field
4
+
5
+ def initialize(field)
6
+ @field = field
7
+ end
8
+
9
+ def to_html
10
+ <<-HTML.strip
11
+ <input type="text" name="#{field.name}" value="#{field.value}" />
12
+ HTML
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ class Formation::Types::TextArea
2
+
3
+ attr_reader :field
4
+
5
+ def initialize(field)
6
+ @field = field
7
+ end
8
+
9
+ def to_html
10
+ <<-HTML.strip
11
+ <textarea name="#{field.name}">#{field.value}</textarea>
12
+ HTML
13
+ end
14
+
15
+ end
@@ -0,0 +1,11 @@
1
+ class Formation::Util
2
+
3
+ def self.titleize(string)
4
+ string.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.upcase }
5
+ end
6
+
7
+ def self.underscore(string)
8
+ string.to_s.downcase.gsub(/\s/, '_')
9
+ end
10
+
11
+ end
@@ -0,0 +1,5 @@
1
+ module Formation
2
+
3
+ VERSION = "0.0.1"
4
+
5
+ end
@@ -0,0 +1,61 @@
1
+ Formation
2
+ =========
3
+
4
+ `formation` is a ruby library for building, validating, and extending forms.
5
+
6
+ Simple:
7
+
8
+ class RegistrationForm
9
+
10
+ include Formation::Form
11
+
12
+ fieldset :account do
13
+ field :login_name, :type => :text, :required => true
14
+ field :password, :type => :text, :required => true
15
+ end
16
+
17
+ fieldset :address do
18
+ field :address, :type => :text
19
+ field :city, :type => :text
20
+ end
21
+
22
+ end
23
+
24
+ Model:
25
+
26
+ class Post
27
+
28
+ include DataMapper::Resource
29
+
30
+ property :id, Serial
31
+ property :title, String
32
+ property :body, Text
33
+ property :created_at, DateTime
34
+
35
+ end
36
+
37
+ class PostForm
38
+
39
+ include Formation::Form
40
+
41
+ resource :post do
42
+ fieldset :legend => 'New Post' do
43
+ field :title, :type => :text, :required => true
44
+ field :body, :type => :textarea, :required => true
45
+ end
46
+ end
47
+
48
+ def initialize(post)
49
+ @post = post
50
+ end
51
+
52
+ end
53
+
54
+ ### Validating
55
+ ...
56
+
57
+ ### Printing
58
+ ...
59
+
60
+ ### Extending
61
+ ...
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Formation::Field do
4
+
5
+ describe '.label' do
6
+
7
+ it 'should use the given label, if specified' do
8
+ Formation::Field.new('first_name', :label => 'Name').label.must_equal 'Name'
9
+ end
10
+
11
+ it 'should use the titleized name, if not specified' do
12
+ Formation::Field.new('first_name').label.must_equal 'First Name'
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Formation::Form do
4
+
5
+ describe '#fields' do
6
+
7
+ it 'should have the correct name' do
8
+ SimpleForm.fields['first_name'].name.must_equal 'first_name'
9
+ end
10
+
11
+ it 'should have the label of the fieldset it belongs to (if any)' do
12
+ SimpleForm.fields['address'].fieldset.legend.must_equal 'Address'
13
+ end
14
+
15
+ it 'should pass-through custom attributes' do
16
+ SimpleForm.fields['username'].custom.must_equal 'test'
17
+ end
18
+
19
+ end
20
+
21
+ describe '#fieldsets' do
22
+
23
+ it 'should contain the fields belonging to it' do
24
+ SimpleForm.fieldsets['Address'].fields.map(&:name).must_equal %w{ address city zip_code }
25
+ end
26
+
27
+ end
28
+
29
+ describe 'an instance' do
30
+
31
+ before do
32
+ @simple_form = SimpleForm.new(:first_name => 'Chris')
33
+ @post = OpenStruct.new(:title => 'Test')
34
+ @model_form = PostForm.new(@post)
35
+ end
36
+
37
+ describe '.elements' do
38
+
39
+ it 'should return the elements in the correct order' do
40
+ @simple_form.elements.map(&:name).must_equal %w{ first_name Address login_details }
41
+ end
42
+
43
+ end
44
+
45
+ describe '.submit' do
46
+
47
+ it 'should accept empty params' do
48
+ @simple_form.submit({})
49
+ end
50
+
51
+ it 'should extract values of fields' do
52
+ @simple_form.submit({'first_name' => 'Christopher' })
53
+ @simple_form.values['first_name'].must_equal 'Christopher'
54
+
55
+ @model_form.submit({'post' => { 'title' => 'Testing' }, 'author' => { 'name' => 'Chris'}})
56
+ @model_form.post.title.must_equal 'Testing'
57
+ end
58
+
59
+ it 'should be valid if all required values were provided' do
60
+ @simple_form.submit({'first_name' => 'Christopher', 'zip_code' => '12345' })
61
+ @simple_form.valid?.must_equal true
62
+ end
63
+
64
+ it 'should not be valid if all required values were not provided' do
65
+ @simple_form.submit({})
66
+ @simple_form.valid?.must_equal false
67
+ end
68
+
69
+ it 'should have an error for each missing required value' do
70
+ @simple_form.submit({})
71
+ @simple_form.errors.must_equal ['First Name is required', 'Zip Code is invalid']
72
+ end
73
+
74
+ end
75
+
76
+ describe '.values' do
77
+
78
+ it 'should extract values from resource' do
79
+ @simple_form.values['first_name'].must_equal 'Chris'
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,16 @@
1
+ class PostForm
2
+
3
+ include Formation::Form
4
+
5
+ resource :post do
6
+ field :title
7
+ field :body, :type => :textarea
8
+ end
9
+
10
+ field 'author[name]'
11
+
12
+ def initialize(post)
13
+ @post = post
14
+ end
15
+
16
+ end
@@ -0,0 +1,33 @@
1
+ class SimpleForm
2
+ include Formation::Form
3
+
4
+ field 'first_name', :required => true
5
+
6
+ fieldset 'Address' do
7
+ field 'address', :type => :text
8
+ field 'city', :type => :text
9
+ field 'zip_code', :type => :text
10
+ end
11
+
12
+ fieldset :legend => 'Login Details' do
13
+ field 'username', :custom => 'test'
14
+ end
15
+
16
+ validates_with_method :validate_zip_code
17
+
18
+ def initialize(options = {})
19
+ options.each do |key, value|
20
+ values[key.to_s] = value
21
+ end
22
+ end
23
+
24
+ def validate_zip_code
25
+ if value_for(:zip_code) =~ /^\d{5}$/
26
+ true
27
+ else
28
+ errors << 'Zip Code is invalid'
29
+ false
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'minitest/autorun'
4
+ require 'minitest/pride'
5
+ require 'ostruct'
6
+
7
+ require File.expand_path('../../lib/formation', __FILE__)
8
+ require File.expand_path('../forms/simple_form', __FILE__)
9
+ require File.expand_path('../forms/post_form', __FILE__)
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Formation::Type do
4
+
5
+ describe '#create' do
6
+
7
+ it 'should raise an exception if the type is unsupported' do
8
+ lambda {
9
+ Formation::Type.create(nil, :foo)
10
+ }.must_raise RuntimeError
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe Formation::Types::Checkbox do
4
+
5
+ before do
6
+ @field = Formation::Field.new('remember_me', :type => :checkbox)
7
+ @type = @field.type
8
+ end
9
+
10
+ describe '.to_html' do
11
+
12
+ describe 'with no value' do
13
+
14
+ before do
15
+ @field.value = nil
16
+ end
17
+
18
+ it 'should render correctly' do
19
+ @type.to_html.must_equal <<-HTML.strip
20
+ <input type="checkbox" name="remember_me" value="1" checked="" />
21
+ HTML
22
+ end
23
+
24
+ end
25
+
26
+ describe 'with a false value' do
27
+
28
+ before do
29
+ @field.value = false
30
+ end
31
+
32
+ it 'should render correctly' do
33
+ @type.to_html.must_equal <<-HTML.strip
34
+ <input type="checkbox" name="remember_me" value="1" checked="" />
35
+ HTML
36
+ end
37
+
38
+ end
39
+
40
+ describe 'with a true value' do
41
+
42
+ before do
43
+ @field.value = true
44
+ end
45
+
46
+ it 'should render correctly' do
47
+ @type.to_html.must_equal <<-HTML.strip
48
+ <input type="checkbox" name="remember_me" value="1" checked="checked" />
49
+ HTML
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe Formation::Types::Password do
4
+
5
+ before do
6
+ @field = Formation::Field.new('password', :type => :password)
7
+ @type = @field.type
8
+ end
9
+
10
+ describe '.to_html' do
11
+
12
+ describe 'with no value' do
13
+
14
+ before do
15
+ @field.value = nil
16
+ end
17
+
18
+ it 'should render correctly' do
19
+ @type.to_html.must_equal <<-HTML.strip
20
+ <input type="password" name="password" />
21
+ HTML
22
+ end
23
+
24
+ end
25
+
26
+ describe 'with a value' do
27
+
28
+ before do
29
+ @field.value = 'testing'
30
+ end
31
+
32
+ it 'should render correctly' do
33
+ @type.to_html.must_equal <<-HTML.strip
34
+ <input type="password" name="password" />
35
+ HTML
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe Formation::Types::TextArea do
4
+
5
+ before do
6
+ @field = Formation::Field.new('body', :type => :textarea)
7
+ @type = @field.type
8
+ end
9
+
10
+ describe '.to_html' do
11
+
12
+ describe 'with no value' do
13
+
14
+ before do
15
+ @field.value = nil
16
+ end
17
+
18
+ it 'should render correctly' do
19
+ @type.to_html.must_equal <<-HTML.strip
20
+ <textarea name="body"></textarea>
21
+ HTML
22
+ end
23
+
24
+ end
25
+
26
+ describe 'with a value' do
27
+
28
+ before do
29
+ @field.value = 'Blah, blah, blah'
30
+ end
31
+
32
+ it 'should render correctly' do
33
+ @type.to_html.must_equal <<-HTML.strip
34
+ <textarea name="body">Blah, blah, blah</textarea>
35
+ HTML
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe Formation::Types::Text do
4
+
5
+ before do
6
+ @field = Formation::Field.new('username', :type => :text)
7
+ @type = @field.type
8
+ end
9
+
10
+ describe '.to_html' do
11
+
12
+ describe 'with no value' do
13
+
14
+ before do
15
+ @field.value = nil
16
+ end
17
+
18
+ it 'should render correctly' do
19
+ @type.to_html.must_equal <<-HTML.strip
20
+ <input type="text" name="username" value="" />
21
+ HTML
22
+ end
23
+
24
+ end
25
+
26
+ describe 'with a value' do
27
+
28
+ before do
29
+ @field.value = 'chris'
30
+ end
31
+
32
+ it 'should render correctly' do
33
+ @type.to_html.must_equal <<-HTML.strip
34
+ <input type="text" name="username" value="chris" />
35
+ HTML
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Formation::Util do
4
+
5
+ describe '.titleize' do
6
+
7
+ it 'should handle underscores and case' do
8
+ Formation::Util.titleize('first_name').must_equal 'First Name'
9
+ end
10
+
11
+ end
12
+
13
+ describe '.underscore' do
14
+
15
+ it 'should handle spaces and case' do
16
+ Formation::Util.underscore('First Name').must_equal 'first_name'
17
+ end
18
+
19
+ end
20
+
21
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: formation
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Chris Gibson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-23 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: first-class ruby forms
23
+ email:
24
+ - chrislgibson@gmail.com
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - Rakefile
35
+ - demo.rb
36
+ - formation.gemspec
37
+ - lib/formation.rb
38
+ - lib/formation/element.rb
39
+ - lib/formation/field.rb
40
+ - lib/formation/fieldset.rb
41
+ - lib/formation/form.rb
42
+ - lib/formation/printer.rb
43
+ - lib/formation/type.rb
44
+ - lib/formation/types/checkbox.rb
45
+ - lib/formation/types/password.rb
46
+ - lib/formation/types/text.rb
47
+ - lib/formation/types/text_area.rb
48
+ - lib/formation/util.rb
49
+ - lib/formation/version.rb
50
+ - readme.md
51
+ - test/field_spec.rb
52
+ - test/form_spec.rb
53
+ - test/forms/post_form.rb
54
+ - test/forms/simple_form.rb
55
+ - test/test_helper.rb
56
+ - test/type_spec.rb
57
+ - test/types/checkbox_spec.rb
58
+ - test/types/password_spec.rb
59
+ - test/types/text_area_spec.rb
60
+ - test/types/text_spec.rb
61
+ - test/util_spec.rb
62
+ has_rdoc: true
63
+ homepage: http://github.com/chrisgibson/formation
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.5.3
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: first-class ruby forms
96
+ test_files:
97
+ - test/field_spec.rb
98
+ - test/form_spec.rb
99
+ - test/forms/post_form.rb
100
+ - test/forms/simple_form.rb
101
+ - test/test_helper.rb
102
+ - test/type_spec.rb
103
+ - test/types/checkbox_spec.rb
104
+ - test/types/password_spec.rb
105
+ - test/types/text_area_spec.rb
106
+ - test/types/text_spec.rb
107
+ - test/util_spec.rb