formation 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.
@@ -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