form_cutter 1.0.0

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/README.rdoc ADDED
@@ -0,0 +1,107 @@
1
+ == FormCutter
2
+
3
+ The default rails form builder is great but it is so tedious to change the html that goes around it.
4
+ This gem wraps *your* html around the form elements. So all you have to do is this:
5
+
6
+ <%= f.text_field :name %>
7
+
8
+ And add your html template in <tt>app/views/forms/text_field.html.erb</tt> like this:
9
+
10
+ <div class="forms">
11
+ <%= label(object_name, method, label_name) %><em><%= required %></em><br/>
12
+ <%= text_field(object_name, method, options) %>
13
+ <% if hint.present? %><p><%= hint %></p><% end %>
14
+ </div>
15
+
16
+ == Installation
17
+
18
+ Install the gem:
19
+
20
+ gem install form_cutter
21
+
22
+ Add it to your Gemfile:
23
+
24
+ gem "form_cutter"
25
+
26
+ Run the generator:
27
+
28
+ rails generate form_cutter:install
29
+
30
+ == Usage
31
+
32
+ Use the form builders normally, except don't add any markup (unless you want to).
33
+
34
+ <%= form_for @post do |f| %>
35
+ <fieldset>
36
+ <%= f.text_field :title %>
37
+ <%= f.text_area :body %>
38
+ <%= f.select :section, choices %>
39
+ <%= f.radio_button :am_fm %>
40
+ <%= f.check_box :terms_and_conditions %>
41
+ </fieldset>
42
+ <div class="buttons">
43
+ <%= f.sumbit 'Save' %>
44
+ </div>
45
+ <% end %>
46
+
47
+ The form builders will now wrap all form helper methods with *your* html.
48
+
49
+ You're done.
50
+
51
+ === Customization
52
+
53
+ There will always be an exception to the rule. So there are 2 ways to change the html wrapper.
54
+ 1. Like a resource - by creating a directory inside forms/, <tt>app/views/forms/blog/</tt>.
55
+ 2. Passing the :template option - either false or the '<tt>path/to/template</tt>'.
56
+
57
+ It will render the first erb template that it finds. If you use <tt><%= f.text_field :title, :template => 'custom' %></tt> for the @blog model, it looks in this order:
58
+ * forms/blog/custom.html.erb
59
+ * forms/custom.html.erb
60
+ * forms/custom/title.html.erb
61
+ * forms/custom/text_field.html.erb
62
+ * forms/custom/default.html.erb
63
+ * forms/title.html.erb
64
+ * forms/blog/text_field.html.erb
65
+ * forms/text_field.html.erb
66
+ * forms/default.html.erb
67
+
68
+ === One more thing
69
+
70
+ You can pass <tt>:report => true</tt> and you get an instant view page.
71
+
72
+ This will search in app/views/reports/ instead of app/views/forms/.
73
+
74
+ <%= f.text_field(:title, :report => true) %>
75
+
76
+ ==== Other options
77
+ You can pass any options to the helper methods. These will become availble in the.
78
+
79
+ <%= f.text_field(:title, :hint => 'This is a field hint', :anything => 'anything you want') %>
80
+
81
+ Will give you:
82
+
83
+ <%= hint %>
84
+ => 'This is a field hint'
85
+
86
+ <%= options[:anything] %>
87
+ => 'anything you want'
88
+
89
+ FormCutter has several configuration values. You can read and change them in the initializer created by FormCutter, so if you haven't executed the command below yet, please do:
90
+
91
+ rails generate form_cutter:install
92
+
93
+ == TODO
94
+
95
+ Please refer to TODO file.
96
+
97
+ == Maintainers
98
+
99
+ * Benjamin Lewis (http://github.com/23inhouse)
100
+
101
+ == Bugs and Feedback
102
+
103
+ If you discover any bugs or want to drop a line, feel free to create an issue on GitHub.
104
+
105
+ http://github.com/23inhouse/form_cutter/issues
106
+
107
+ MIT License. Copyright 2010 23inhouse. http://23inhouse.com
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'form_cutter'
@@ -0,0 +1,21 @@
1
+ module FormCutter
2
+ module ActionViewExtensions
3
+ module Builder
4
+ def self.included(base)
5
+ base.send(:alias_method, :objectify_options_original, :objectify_options)
6
+ base.send(:remove_method, :objectify_options)
7
+ end
8
+
9
+ private
10
+ def objectify_options(options)
11
+ extended_options = {}
12
+ extended_options.merge!(:report => @options[:report]) unless @options[:report].nil?
13
+ extended_options.merge!(:template => @options[:template]) unless @options[:template].nil?
14
+ extended_options.merge!(options)
15
+ objectify_options_original(extended_options)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ ActionView::Helpers::FormBuilder.send :include, FormCutter::ActionViewExtensions::Builder
@@ -0,0 +1,90 @@
1
+ module FormCutter
2
+ module ActionViewExtensions
3
+ module FormHelper
4
+ different_methods = ['form_for', 'apply_form_for_options!', 'fields_for', 'label', 'check_box', 'radio_button']
5
+ (ActionView::Helpers::FormHelper.instance_method_names - different_methods).each do |helper_method_name|
6
+ module_eval <<-METHOD, __FILE__, __LINE__ + 1
7
+ def #{helper_method_name}(object_name, method, options = {})
8
+ begin
9
+ raise template_error if !template?(options) || caller.first.include?("/app/views/"+base_template_path(options))
10
+ render(:template => template_file(object_name, method, options, '#{helper_method_name}'), :locals => locals(object_name, method, '#{helper_method_name}', options))
11
+ rescue ActionView::MissingTemplate
12
+ super
13
+ end
14
+ end
15
+ METHOD
16
+ end
17
+
18
+ def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
19
+ begin
20
+ raise template_error if !template?(options) || caller.first.include?("/app/views/"+base_template_path(options))
21
+ render(:template => template_file(object_name, method, options, :check_box), :locals => locals(object_name, method, :check_box, options))
22
+ rescue ActionView::MissingTemplate
23
+ super
24
+ end
25
+ end
26
+
27
+ def radio_button(object_name, method, tag_value, options = {})
28
+ begin
29
+ raise template_error if !template?(options) || caller.first.include?("/app/views/"+base_template_path(options))
30
+ render(:template => template_file(object_name, method, options, :radio_button), :locals => locals(object_name, method, :radio_button, options))
31
+ rescue ActionView::MissingTemplate
32
+ super
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def locals(object_name, method, helper_method_name, options, content = nil)
39
+ options[:required] = options[:object].class.validators_on(method).map(&:class).include? ActiveModel::Validations::PresenceValidator if options[:required].nil?
40
+ options[:required] = (options[:required] == true) ? I18n.t(:"form_cutter.required.mark", :default => '*') : ''
41
+
42
+ locals = { :object => options[:object], :object_name => object_name, :method => method, :helper_method_name => helper_method_name, :options => options }
43
+ locals.merge!({:hint => (options.delete(:hint) || '').html_safe})
44
+ locals.merge!({:label_name => options.delete(:label)})
45
+ locals.merge!({:report => options.delete(:report)})
46
+ locals.merge!({:required => options.delete(:required)})
47
+ locals.merge!({:template => options.delete(:template)})
48
+ locals
49
+ end
50
+
51
+ def template_file(object_name, method, options, helper_method_name)
52
+ resource = options[:object].class.to_s.pluralize.downcase
53
+ template = options.delete(:template) || '..'
54
+
55
+ template_path = ActionView::PathSet.new(Array.wrap('app/views'))
56
+ details = {:locale => [:en, :en], :formats => [:html], :handlers => [:erb, :rjs, :builder, :rhtml, :rxml]}
57
+ path = base_template_path(options)
58
+ [
59
+ [path, resource, template].join('/'), # forms/blog/custom.html.erb
60
+ [path, template].join('/'), # forms/custom.html.erb
61
+ [path, template, method.to_s].join('/'), # forms/custom/title.html.erb
62
+ [path, template, helper_method_name].join('/'), # forms/custom/text_field.html.erb
63
+ [path, template, 'default'].join('/'), # forms/custom/default.html.erb
64
+ [path, resource, method.to_s].join('/'), # forms/title.html.erb
65
+ [path, resource, helper_method_name].join('/'), # forms/blog/text_field.html.erb
66
+ [path, helper_method_name].join('/'), # forms/text_field.html.erb
67
+ [path, 'default'].join('/') # forms/default.html.erb
68
+ ].find { |template_file| template_path.exists?(template_file, '', false, details) } || '..'
69
+ end
70
+
71
+ def base_template_path(options)
72
+ report?(options) ? FormCutter.reports_path : FormCutter.forms_path
73
+ end
74
+
75
+ def report?(options)
76
+ options[:report]
77
+ end
78
+
79
+ def template?(options)
80
+ !(options[:template] == false)
81
+ end
82
+
83
+ def template_error
84
+ ActionView::MissingTemplate.new([], '1', '2', '3') # this will never be shown, it will be rescued by super
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ ActionView::Base.send :include, FormCutter::ActionViewExtensions::FormHelper
@@ -0,0 +1,3 @@
1
+ module FormCutter
2
+ VERSION = "1.0.0".freeze
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'action_view'
2
+ require 'form_cutter/action_view_extensions/form_helper'
3
+ require 'form_cutter/action_view_extensions/builder'
4
+
5
+ module FormCutter
6
+ # Default form and report template paths
7
+ mattr_accessor :forms_path
8
+ @@forms_path = 'forms'
9
+
10
+ mattr_accessor :reports_path
11
+ @@reports_path = 'reports'
12
+
13
+ # Default way to setup FormCutter. Run rails generate form_cutter:install
14
+ # to create a fresh initializer with all configuration values.
15
+ def self.setup
16
+ yield self
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ To copy a FormCutter initializer to your Rails App, with some configuration values, just do:
2
+
3
+ rails generate form_cutter:install
@@ -0,0 +1,26 @@
1
+ module FormCutter
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ desc "Copy FormCutter default files"
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ class_option :template_engine
7
+
8
+ def copy_initializers
9
+ copy_file 'form_cutter.rb', 'config/initializers/form_cutter.rb'
10
+ end
11
+
12
+ def copy_templates
13
+ copy_file 'default.html.erb', 'app/views/forms/default.html.erb'
14
+ end
15
+
16
+ def copy_locale_file
17
+ copy_file 'en.yml', 'config/locales/form_cutter.en.yml'
18
+ end
19
+
20
+ def copy_scaffold_template
21
+ engine = options[:template_engine]
22
+ copy_file "_form.html.#{engine}", "lib/templates/#{engine}/scaffold/_form.html.#{engine}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ <%%= form_for(@<%= singular_name %>) do |f| %>
2
+ <%%= f.error_notification %>
3
+
4
+ <div class="inputs">
5
+ <%- attributes.each do |attribute| -%>
6
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
7
+ <%- end -%>
8
+ </div>
9
+
10
+ <div class="actions">
11
+ <%%= f.button :submit %>
12
+ </div>
13
+ <%% end %>
@@ -0,0 +1,18 @@
1
+ = form_cutter_for(@<%= singular_name %>) do |f|
2
+ - if @<%= singular_name %>.errors.any?
3
+ #error_explanation
4
+ %h2
5
+ = pluralize(@<%= singular_name %>.errors.count, "error")
6
+ prohibited this <%= singular_name %> from being saved:
7
+
8
+ %ul
9
+ - @<%= singular_name %>.errors.full_messages.each do |msg|
10
+ %li= msg
11
+
12
+ .inputs
13
+ <%- attributes.each do |attribute| -%>
14
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
15
+ <%- end -%>
16
+
17
+ .actions
18
+ = f.button :submit
@@ -0,0 +1,5 @@
1
+ <div class="forms">
2
+ <%= label(object_name, method, label_name) %><em><%= required %></em><br/>
3
+ <%= send(helper_method_name, object_name, method, options) %>
4
+ <% if hint.present? %><p><%= hint %></p><% end %>
5
+ </div>
@@ -0,0 +1,4 @@
1
+ en:
2
+ form_cutter:
3
+ required:
4
+ mark: '*'
@@ -0,0 +1,6 @@
1
+ # Use this setup block to configure all options available in FormCutter.
2
+ FormCutter.setup do |config|
3
+ # template paths
4
+ config.forms_path = 'forms' # app/views/forms
5
+ config.reports_path = 'reports' # app/views/reports
6
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ class FormHelperTest < ActionView::TestCase
4
+
5
+ test 'a template was rendered' do
6
+ concat(form_for(:user, :url => '/account', :html => { :id => 'my_form' }) do |f|
7
+ f.text_field(:name)
8
+ end)
9
+ assert_template 'hi/there'
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class FormCutterTest < ActiveSupport::TestCase
4
+ test 'setup block yields self' do
5
+ FormCutter.setup do |config|
6
+ assert_equal FormCutter, config
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ module MiscHelpers
2
+ def store_translations(locale, translations, &block)
3
+ begin
4
+ I18n.backend.store_translations locale, translations
5
+ yield
6
+ ensure
7
+ I18n.reload!
8
+ end
9
+ end
10
+
11
+ def assert_no_select(selector, value = nil)
12
+ assert_select(selector, :text => value, :count => 0)
13
+ end
14
+
15
+ def swap(object, new_values)
16
+ old_values = {}
17
+ new_values.each do |key, value|
18
+ old_values[key] = object.send key
19
+ object.send :"#{key}=", value
20
+ end
21
+ yield
22
+ ensure
23
+ old_values.each do |key, value|
24
+ object.send :"#{key}=", value
25
+ end
26
+ end
27
+
28
+ def with_concat_form_for(object, &block)
29
+ concat form_cutter_for(object, &block)
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ class MockController
2
+ attr_accessor :action_name
3
+
4
+ def _routes
5
+ self
6
+ end
7
+
8
+ def action_name
9
+ @action_name || "edit"
10
+ end
11
+
12
+ def url_for(*args)
13
+ "http://example.com"
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class MockResponse
2
+
3
+ def initialize(test_case)
4
+ @test_case = test_case
5
+ end
6
+
7
+ def content_type
8
+ 'text/html'
9
+ end
10
+
11
+ def body
12
+ @test_case.send :output_buffer
13
+ end
14
+ end
@@ -0,0 +1,133 @@
1
+ require 'ostruct'
2
+
3
+ Column = Struct.new(:name, :type, :limit)
4
+ Association = Struct.new(:klass, :name, :macro, :options)
5
+
6
+ class Company < Struct.new(:id, :name)
7
+ extend ActiveModel::Naming
8
+ include ActiveModel::Conversion
9
+
10
+ def self.all(options={})
11
+ all = (1..3).map{|i| Company.new(i, "Company #{i}")}
12
+ return [all.first] if options[:conditions].present?
13
+ return [all.last] if options[:order].present?
14
+ return all[0..1] if options[:include].present?
15
+ return all[1..2] if options[:joins].present?
16
+ all
17
+ end
18
+
19
+ def self.merge_conditions(a, b)
20
+ (a || {}).merge(b || {})
21
+ end
22
+
23
+ def persisted?
24
+ true
25
+ end
26
+ end
27
+
28
+ class Tag < Company
29
+ extend ActiveModel::Naming
30
+ include ActiveModel::Conversion
31
+
32
+ def self.all(options={})
33
+ (1..3).map{|i| Tag.new(i, "Tag #{i}")}
34
+ end
35
+ end
36
+
37
+ class User
38
+ extend ActiveModel::Naming
39
+ include ActiveModel::Conversion
40
+
41
+ attr_accessor :id, :name, :company, :company_id, :time_zone, :active, :description, :created_at, :updated_at,
42
+ :credit_limit, :age, :password, :delivery_time, :born_at, :special_company_id, :country, :url, :tag_ids,
43
+ :avatar, :email, :status, :residence_country, :phone_number
44
+
45
+ def initialize(options={})
46
+ options.each do |key, value|
47
+ send("#{key}=", value)
48
+ end if options
49
+ end
50
+
51
+ def new_record!
52
+ @new_record = true
53
+ end
54
+
55
+ def persisted?
56
+ !(@new_record || false)
57
+ end
58
+
59
+ def company_attributes=(*)
60
+ end
61
+
62
+ def column_for_attribute(attribute)
63
+ column_type, limit = case attribute.to_sym
64
+ when :name, :status, :password then [:string, 100]
65
+ when :description then :text
66
+ when :age then :integer
67
+ when :credit_limit then [:decimal, 15]
68
+ when :active then :boolean
69
+ when :born_at then :date
70
+ when :delivery_time then :time
71
+ when :created_at then :datetime
72
+ when :updated_at then :timestamp
73
+ end
74
+ Column.new(attribute, column_type, limit)
75
+ end
76
+
77
+ def self.human_attribute_name(attribute)
78
+ case attribute
79
+ when 'name'
80
+ 'Super User Name!'
81
+ when 'description'
82
+ 'User Description!'
83
+ when 'company'
84
+ 'Company Human Name!'
85
+ else
86
+ attribute.humanize
87
+ end
88
+ end
89
+
90
+ def self.reflect_on_association(association)
91
+ case association
92
+ when :company
93
+ Association.new(Company, association, :belongs_to, {})
94
+ when :tags
95
+ Association.new(Tag, association, :has_many, {})
96
+ when :first_company
97
+ Association.new(Company, association, :has_one, {})
98
+ when :special_company
99
+ Association.new(Company, association, :belongs_to, { :conditions => { :id => 1 } })
100
+ end
101
+ end
102
+
103
+ def errors
104
+ @errors ||= begin
105
+ hash = Hash.new { |h,k| h[k] = [] }
106
+ hash.merge!(
107
+ :name => ["can't be blank"],
108
+ :description => ["must be longer than 15 characters"],
109
+ :age => ["is not a number", "must be greater than 18"],
110
+ :company => ["company must be present"],
111
+ :company_id => ["must be valid"]
112
+ )
113
+ end
114
+ end
115
+ end
116
+
117
+ class ValidatingUser < User
118
+ include ActiveModel::Validations
119
+ validates :name, :presence => true
120
+ validates :company, :presence => true
121
+ validates_numericality_of :age,
122
+ :greater_than_or_equal_to => 18,
123
+ :less_than_or_equal_to => 99,
124
+ :only_integer => true
125
+ end
126
+
127
+ class OtherValidatingUser < User
128
+ include ActiveModel::Validations
129
+ validates_numericality_of :age,
130
+ :greater_than => 17,
131
+ :less_than => 100,
132
+ :only_integer => true
133
+ end
@@ -0,0 +1,88 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup
5
+
6
+ require 'test/unit'
7
+ require 'mocha'
8
+
9
+ require 'active_model'
10
+ require 'action_controller'
11
+ require 'action_view'
12
+ require 'action_view/template'
13
+ require 'action_view/test_case'
14
+
15
+ $:.unshift File.expand_path("../../lib", __FILE__)
16
+ require 'form_cutter'
17
+
18
+ Dir["#{File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
19
+ I18n.default_locale = :en
20
+
21
+ country_select = "#{File.dirname(__FILE__)}/support/country_select/lib"
22
+
23
+ # if File.exists?(country_select)
24
+ # $:.unshift country_select
25
+ # require 'country_select'
26
+ # else
27
+ # raise "Could not find country_select plugin in test/support. Please execute git submodule update --init."
28
+ # end
29
+
30
+ class FormCutter::FormBuilder
31
+ attr_accessor :attribute_name, :column, :reflection, :input_type, :options
32
+ end
33
+
34
+ class ActionView::TestCase
35
+ include MiscHelpers
36
+ include FormCutter::ActionViewExtensions::FormHelper
37
+
38
+ setup :set_controller
39
+ setup :set_response
40
+ setup :setup_new_user
41
+
42
+ def set_controller
43
+ @controller = MockController.new
44
+ end
45
+
46
+ def set_response
47
+ @response = MockResponse.new(self)
48
+ end
49
+
50
+ def setup_new_user(options={})
51
+ @user = User.new({
52
+ :id => 1,
53
+ :name => 'New in Form Cutter!',
54
+ :description => 'Hello!',
55
+ :created_at => Time.now
56
+ }.merge(options))
57
+
58
+ @validating_user = ValidatingUser.new({
59
+ :id => 1,
60
+ :name => 'New in Form Cutter!',
61
+ :description => 'Hello!',
62
+ :created_at => Time.now,
63
+ :age => 19,
64
+ :company => 1
65
+ }.merge(options))
66
+
67
+ @other_validating_user = OtherValidatingUser.new({
68
+ :id => 1,
69
+ :name => 'New in Form Cutter!',
70
+ :description => 'Hello!',
71
+ :created_at => Time.now,
72
+ :age => 19,
73
+ :company => 1
74
+ }.merge(options))
75
+ end
76
+
77
+ def protect_against_forgery?
78
+ false
79
+ end
80
+
81
+ def user_path(*args)
82
+ '/users'
83
+ end
84
+ alias :users_path :user_path
85
+ alias :super_user_path :user_path
86
+ alias :validating_user_path :user_path
87
+ alias :other_validating_user_path :user_path
88
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: form_cutter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Benjamin Lewis
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-22 00:00:00 +10:30
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Lets you wrap your form helper methods is custom html
22
+ email: 23inhouse@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - init.rb
31
+ - lib/form_cutter.rb
32
+ - lib/form_cutter/action_view_extensions/builder.rb
33
+ - lib/form_cutter/action_view_extensions/form_helper.rb
34
+ - lib/form_cutter/version.rb
35
+ - lib/generators/form_cutter/USAGE
36
+ - lib/generators/form_cutter/install_generator.rb
37
+ - lib/generators/form_cutter/templates/_form.html.erb
38
+ - lib/generators/form_cutter/templates/_form.html.haml
39
+ - lib/generators/form_cutter/templates/default.html.erb
40
+ - lib/generators/form_cutter/templates/en.yml
41
+ - lib/generators/form_cutter/templates/form_cutter.rb
42
+ - README.rdoc
43
+ - test/action_view_extensions/form_helper_test.rb
44
+ - test/form_cutter_test.rb
45
+ - test/support/misc_helpers.rb
46
+ - test/support/mock_controller.rb
47
+ - test/support/mock_response.rb
48
+ - test/support/models.rb
49
+ - test/test_helper.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/23inhouse/form_cutter
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.7
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Forms made templatable!
82
+ test_files:
83
+ - test/action_view_extensions/form_helper_test.rb
84
+ - test/form_cutter_test.rb
85
+ - test/support/misc_helpers.rb
86
+ - test/support/mock_controller.rb
87
+ - test/support/mock_response.rb
88
+ - test/support/models.rb
89
+ - test/test_helper.rb