flex_fields 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .DS_Store
2
+ .rvmrc
3
+ .bundle
4
+
5
+ flex_fields*.gem
6
+ *emfile.lock
7
+
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "activerecord", "~> 3.0"
6
+ gem "activesupport", "~> 3.0"
7
+
8
+ group :test do
9
+ gem 'rspec'
10
+ gem "sqlite3"
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ flex_fields (1.0.0)
5
+ activerecord (>= 3.0)
6
+ activesupport (>= 3.0)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ activemodel (3.1.3)
12
+ activesupport (= 3.1.3)
13
+ builder (~> 3.0.0)
14
+ i18n (~> 0.6)
15
+ activerecord (3.1.3)
16
+ activemodel (= 3.1.3)
17
+ activesupport (= 3.1.3)
18
+ arel (~> 2.2.1)
19
+ tzinfo (~> 0.3.29)
20
+ activesupport (3.1.3)
21
+ multi_json (~> 1.0)
22
+ arel (2.2.1)
23
+ builder (3.0.0)
24
+ diff-lcs (1.1.3)
25
+ i18n (0.6.0)
26
+ multi_json (1.0.4)
27
+ rspec (2.8.0)
28
+ rspec-core (~> 2.8.0)
29
+ rspec-expectations (~> 2.8.0)
30
+ rspec-mocks (~> 2.8.0)
31
+ rspec-core (2.8.0)
32
+ rspec-expectations (2.8.0)
33
+ diff-lcs (~> 1.1.2)
34
+ rspec-mocks (2.8.0)
35
+ sqlite3 (1.3.5)
36
+ tzinfo (0.3.31)
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ activerecord (~> 3.0)
43
+ activesupport (~> 3.0)
44
+ flex_fields!
45
+ rspec
46
+ sqlite3
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Kyle Crum (http://kylecrum.wordpress.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,102 @@
1
+ Flex Fields
2
+ ===============
3
+
4
+ Flex Fields allows you to define an arbitrary amount of data to be stored in
5
+ a serialized column. Why? Because sometimes you have data that just doesn't need
6
+ to be in its own column.
7
+
8
+
9
+ ## Examples ##
10
+
11
+ To activate, just need to declare flex_fields in your model.
12
+
13
+ ```
14
+ class MyModel < ActiveRecord::Base
15
+ flex_fields :foo=>String, :bar=>Integer
16
+ end
17
+ ```
18
+
19
+ This gives you two new flex fields: foo and bar
20
+
21
+ ```
22
+ my_model = MyModel.new(:foo=>'foo',:bar=>1)
23
+ my_model.foo
24
+ => 'foo'
25
+ my_model.bar
26
+ => 1
27
+ ```
28
+
29
+ Flex Fields works nicely with inheritance and STI, too, so don't worry about that!
30
+
31
+ ```
32
+ class AnotherModel < MyModel
33
+ flex_fields :more_stuff=>Array
34
+ end
35
+
36
+ another_model = AnotherModel.new
37
+ another_model.foo
38
+ => nil
39
+ another_model.more_stuff
40
+ => []
41
+ ```
42
+
43
+ By default, the data is stored in a serialized Hash in a column called 'flex'
44
+ You can change this by passing in column_name.
45
+
46
+ ```
47
+ class MyModel < ActiveRecord::Base
48
+ flex_fields :column_name=>:data, :foo=>String, :bar=>Integer
49
+ end
50
+ ```
51
+
52
+ Now, everything is stored in a serialized hash in the data column.
53
+
54
+ Just like in ActiveRecord, if you want to override the default getter and setter methods,
55
+ you can. Instead of using write_attribute and read_attribute, use write_flex_field and
56
+ read_flex_field
57
+
58
+ ```
59
+ class MyModel < ActiveRecord::Base
60
+
61
+ flex_fields :foo=>String, :bar=>Integer
62
+
63
+ def foo
64
+ logger.debug("I am accessing foo")
65
+ read_flex_field(:foo)
66
+ end
67
+
68
+ def foo=(new_val)
69
+ logger.debug("I am setting foo to a new value")
70
+ write_flex_field(:foo,new_val)
71
+ end
72
+
73
+ end
74
+ ```
75
+
76
+ ## Conversions ##
77
+
78
+ Flex Attributes will convert the value to the class you specify in the declaration
79
+
80
+ ```
81
+ class MyModel < ActiveRecord::Base
82
+ flex_fields :float_value=>Float, :integer_value=>Integer
83
+ end
84
+
85
+ model = MyModel.new
86
+ model.float_value = '1'
87
+ model.float_value
88
+ => 1.0
89
+ model.integer_value = '1'
90
+ model.integer_value
91
+ => 1
92
+ ```
93
+ Currently, Flex Fields supports these types of fields:
94
+
95
+ Array
96
+ Date
97
+ DateTime
98
+ Float
99
+ Hash
100
+ Integer
101
+ String
102
+ Time
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "flex_fields/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'flex_fields'
7
+ s.version = FlexFields::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = [ 'Kyle Crum' ]
10
+ s.email = [ 'kyle.e.crum@gmail.com' ]
11
+ s.homepage = 'http://github.com/stouset/twitter_bootstrap_form_for'
12
+ s.summary = 'Rails form builder optimized for Twitter Bootstrap'
13
+ s.description = 'A custom Rails FormBuilder that assumes the use of Twitter Bootstrap'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency('activerecord', '>= 3.0')
21
+ s.add_dependency('activesupport', '>= 3.0')
22
+ end
@@ -0,0 +1,86 @@
1
+ module FlexFields
2
+ module Base
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def flex_fields(options={})
11
+
12
+ set_flex_options(options)
13
+
14
+ serialize(self.flex_fields_column, Hash) unless self.serialized_attributes.keys.include?(self.flex_fields_column)
15
+
16
+ include InstanceMethods
17
+ flex_accessor(options)
18
+
19
+ end
20
+
21
+ def set_flex_options(options)
22
+
23
+ class_attribute :flex_fields_column unless self.respond_to?(:flex_fields_column)
24
+ class_attribute :flex_fields_config unless self.respond_to?(:flex_fields_config)
25
+
26
+ self.flex_fields_config ||= {}
27
+
28
+ if !self.flex_fields_column
29
+ column_name = options.delete(:column_name) || :flex
30
+ self.flex_fields_column = column_name.to_sym if column_name
31
+ self.flex_fields_config = options
32
+ else
33
+ self.flex_fields_config = flex_fields_config.merge(options)
34
+ end
35
+ end
36
+
37
+ def flex_accessor(options)
38
+ options.each_pair do |name,type|
39
+ setter = (name.to_s + '=').to_sym
40
+ define_method(name) {self.read_flex_field(name)}
41
+ define_method(setter) {|val| self.write_flex_field(name, val)}
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ module InstanceMethods
48
+
49
+ protected
50
+
51
+ def type_for_flex_field(attribute)
52
+ self.flex_fields_config[attribute]
53
+ end
54
+
55
+ def write_flex_field (attribute, val)
56
+ attribute = attribute.to_sym
57
+ converted_val = convert_to_type(val, type_for_flex_field(attribute))
58
+ self[self.flex_fields_column][attribute] = converted_val
59
+ send("#{flex_fields_column}_will_change!")
60
+ return converted_val
61
+ end
62
+
63
+ def read_flex_field (attribute)
64
+ attribute = attribute.to_sym
65
+ converted_val = convert_to_type(self[self.flex_fields_column][attribute], type_for_flex_field(attribute))
66
+ return converted_val
67
+ end
68
+
69
+ private
70
+
71
+ def convert_to_type(val, type)
72
+ return val if val.kind_of?(type)
73
+
74
+ begin
75
+ converter_class = "FlexAttributes::#{type}Converter".constantize
76
+ rescue #if no converter
77
+ raise ArgumentError.new("Unsupported type #{type}")
78
+ end
79
+
80
+ return converter_class.convert(val)
81
+
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ module FlexAttributes
2
+ class ArrayConverter
3
+
4
+ def self.convert(val=nil)
5
+ return [] if val.nil?
6
+ if val.kind_of?(Array)
7
+ return val
8
+ else
9
+ return [val]
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module FlexAttributes
2
+ class DateConverter
3
+
4
+ def self.convert(val=nil)
5
+
6
+ if val.kind_of?(Date)
7
+ return val
8
+ else
9
+ begin
10
+ return Date.parse(val.to_s, true)
11
+ rescue ArgumentError
12
+ return nil
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module FlexAttributes
2
+ class DateTimeConverter
3
+
4
+ def self.convert(val=nil)
5
+ if val.kind_of?(DateTime)
6
+ return val
7
+ else
8
+ begin
9
+ return DateTime.parse(val.to_s, true)
10
+ rescue ArgumentError
11
+ return nil
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module FlexAttributes
2
+ class FloatConverter
3
+
4
+ def self.convert(val=nil)
5
+ val.to_f
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module FlexAttributes
2
+ class HashConverter
3
+
4
+ def self.convert(val=nil)
5
+ if val.kind_of?(Hash)
6
+ return val
7
+ else
8
+ return nil
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module FlexAttributes
2
+ class IntegerConverter
3
+
4
+ def self.convert(val=nil)
5
+ val.nil? ? nil : val.to_i
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module FlexAttributes
2
+ class StringConverter
3
+
4
+ def self.convert(val=nil)
5
+ val.to_s
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module FlexAttributes
2
+ class TimeConverter
3
+
4
+ def self.convert(val=nil)
5
+ if val.kind_of?(Time)
6
+ return val
7
+ else
8
+ begin
9
+ return Time.parse(val.to_s)
10
+ rescue ArgumentError
11
+ return nil
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module FlexFields
2
+ if defined? Rails::Railtie
3
+ class Railtie < Rails::Railtie
4
+ initializer 'flex_fields.insert_into_active_record' do
5
+ ActiveSupport.on_load :active_record do
6
+ ActiveRecord::Base.send :include, FlexFields::Base
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module FlexFields
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'flex_fields/version'
2
+ require 'flex_fields/base'
3
+ require 'flex_fields/railtie'
4
+ # Load Converters
5
+ Dir.entries("#{File.dirname(__FILE__)}/flex_fields/converter").each do |filename|
6
+ require "flex_fields/converter/#{filename.gsub('.rb', '')}" if filename =~ /\.rb$/
7
+ end
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ describe "FlexAttributes" do
4
+
5
+ it 'is a part of ActiveRecord::Base' do
6
+ SomeModel.should respond_to(:flex_fields)
7
+ end
8
+
9
+ after do
10
+ reset_classes
11
+ end
12
+
13
+ describe 'being declared in the model' do
14
+
15
+ it 'uses a default column called flex' do
16
+ SomeModel.should_receive(:serialize).with(:flex, Hash)
17
+ SomeModel.flex_fields
18
+ SomeModel.flex_fields_column.should == :flex
19
+ end
20
+
21
+ it 'can override the default column' do
22
+ SomeModel.should_receive(:serialize).with(:something, Hash)
23
+ SomeModel.flex_fields :column_name=>'something'
24
+ SomeModel.flex_fields_column.should == :something
25
+ end
26
+
27
+ it 'creates getters and setters for each attribute specified' do
28
+ SomeModel.flex_fields :foo=>String, :bar=>Date
29
+ some_model = SomeModel.new
30
+ some_model.should respond_to(:foo)
31
+ some_model.should respond_to(:foo=)
32
+ some_model.should respond_to(:bar)
33
+ some_model.should respond_to(:bar=)
34
+ end
35
+
36
+ it 'can initialize flex values via the constructor' do
37
+ SomeModel.flex_fields :foo=>String, :bar=>Integer
38
+ model = SomeModel.new(:foo=>'foo',:bar=>1)
39
+ model.foo.should == 'foo'
40
+ model.bar.should == 1
41
+ end
42
+
43
+ it 'should inherit settings for subclasses' do
44
+ SomeModel.flex_fields :foo=>String, :column_name=>:something
45
+ InheritedModel.flex_fields :bar=>Integer
46
+ InheritedModel.flex_fields_column.should == :something
47
+ InheritedModel.flex_fields_config.should == {:foo=>String,:bar=>Integer}
48
+ inherited = InheritedModel.new
49
+ inherited.should respond_to(:foo)
50
+ inherited.should respond_to(:bar)
51
+ end
52
+
53
+ it 'takes the colum name from the base class that calls flex_fields' do
54
+ SomeModel.flex_fields :column_name=>:some_column
55
+ InheritedModel.flex_fields :column_name=>:differet_column
56
+ InheritedModel.flex_fields_column.should == :some_column
57
+ end
58
+
59
+ end
60
+
61
+ describe 'conversions' do
62
+
63
+ before do
64
+ SomeModel.flex_fields
65
+ @model = SomeModel.new
66
+ end
67
+
68
+ it 'can convert arrays' do
69
+ @model.send(:convert_to_type,[1,2,3],Array).should == [1,2,3]
70
+ @model.send(:convert_to_type,1,Array).should == [1]
71
+ end
72
+
73
+ it 'can convert dates' do
74
+ date_string = '1979-12-05'
75
+ date = Date.parse(date_string)
76
+ @model.send(:convert_to_type,date_string,Date).should == date
77
+ @model.send(:convert_to_type,date,Date).should == date
78
+ @model.send(:convert_to_type,'foo',Date).should be_nil
79
+ end
80
+
81
+ it 'can convert date times' do
82
+ date_time_string = '1979-12-05T08:30:45Z'
83
+ date_time = DateTime.parse(date_time_string)
84
+ @model.send(:convert_to_type,date_time_string,DateTime).should == date_time
85
+ @model.send(:convert_to_type,date_time,DateTime).should == date_time
86
+ @model.send(:convert_to_type,'foo',DateTime).should be_nil
87
+ end
88
+
89
+ it 'can convert floats' do
90
+ @model.send(:convert_to_type,3.14159,Float).should == 3.14159
91
+ @model.send(:convert_to_type,'3.14159',Float).should == 3.14159
92
+ end
93
+
94
+ it 'can convert hashes' do
95
+ @model.send(:convert_to_type,{:foo=>'bar'},Hash).should == {:foo=>'bar'}
96
+ @model.send(:convert_to_type,'foobar',Hash).should be_nil
97
+ end
98
+
99
+ it 'can convert integers' do
100
+ @model.send(:convert_to_type,1,Integer).should == 1
101
+ @model.send(:convert_to_type,'1',Integer).should == 1
102
+ end
103
+
104
+ it 'can convert strings' do
105
+ @model.send(:convert_to_type,"string",String).should == "string"
106
+ @model.send(:convert_to_type,3.14159,String).should == "3.14159"
107
+ end
108
+
109
+ it 'can convert times' do
110
+ time_string = "16:30"
111
+ time = Time.parse(time_string)
112
+ @model.send(:convert_to_type,time_string,Time).should == time
113
+ @model.send(:convert_to_type,time,Time).should == time
114
+ @model.send(:convert_to_type,'foo',Time).should be_nil
115
+ end
116
+
117
+ end
118
+
119
+ describe 'instance methods' do
120
+
121
+ before do
122
+ SomeModel.flex_fields :foo=>String, :bar=>Integer, :column_name=>:something
123
+ @model = SomeModel.new
124
+ end
125
+
126
+ it 'should return the flex column' do
127
+ @model.send(:flex_fields_column).should == :something
128
+ end
129
+
130
+ it 'should return the correct flex type for an attribute' do
131
+ @model.send(:type_for_flex_field, :foo).should == String
132
+ end
133
+
134
+ it 'can set and return flex values' do
135
+ @model.foo = "I am a string"
136
+ @model.bar = 5
137
+ @model.foo.should == "I am a string"
138
+ @model.bar.should == 5
139
+ end
140
+
141
+ it 'will save values properly' do
142
+ @model.bar = "6"
143
+ @model.foo = "foo"
144
+ @model.save!
145
+ saved_model = SomeModel.find(@model.id)
146
+ saved_model.bar.should == 6
147
+ saved_model.foo.should == "foo"
148
+ end
149
+
150
+ end
151
+
152
+ end
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'sqlite3'
4
+
5
+ require 'flex_fields'
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts "Run `bundle install` to install missing gems"
11
+ exit e.status_code
12
+ end
13
+
14
+ require 'active_record'
15
+ require 'active_support'
16
+
17
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
18
+ require 'flex_fields'
19
+
20
+ ActiveRecord::Base.configurations = {'sqlite3' => {:adapter => 'sqlite3', :database => ':memory:'}}
21
+ ActiveRecord::Base.establish_connection('sqlite3')
22
+
23
+ ActiveRecord::Schema.define(:version => 0) do
24
+ create_table :some_models do |t|
25
+ t.string :name
26
+ t.string :type
27
+ t.text :flex
28
+ t.text :something
29
+ end
30
+ end
31
+
32
+ ActiveRecord::Base.send(:include, FlexFields::Base)
33
+
34
+ def reset_classes
35
+ Object.send(:remove_const, :SomeModel) rescue nil
36
+ Object.send(:remove_const, :InheritedModel) rescue nil
37
+ Object.const_set(:SomeModel, Class.new(ActiveRecord::Base))
38
+ Object.const_set(:InheritedModel, SomeModel)
39
+ end
40
+
41
+ reset_classes
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flex_fields
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kyle Crum
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-06 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &3744860 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *3744860
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &3744360 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *3744360
36
+ description: A custom Rails FormBuilder that assumes the use of Twitter Bootstrap
37
+ email:
38
+ - kyle.e.crum@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - Gemfile.lock
46
+ - MIT-LICENSE
47
+ - README.markdown
48
+ - flex_fields.gemspec
49
+ - lib/flex_fields.rb
50
+ - lib/flex_fields/base.rb
51
+ - lib/flex_fields/converter/array_converter.rb
52
+ - lib/flex_fields/converter/date_converter.rb
53
+ - lib/flex_fields/converter/date_time_converter.rb
54
+ - lib/flex_fields/converter/float_converter.rb
55
+ - lib/flex_fields/converter/hash_converter.rb
56
+ - lib/flex_fields/converter/integer_converter.rb
57
+ - lib/flex_fields/converter/string_converter.rb
58
+ - lib/flex_fields/converter/time_converter.rb
59
+ - lib/flex_fields/railtie.rb
60
+ - lib/flex_fields/version.rb
61
+ - spec/flex_attributes_spec.rb
62
+ - spec/spec_helper.rb
63
+ homepage: http://github.com/stouset/twitter_bootstrap_form_for
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.14
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Rails form builder optimized for Twitter Bootstrap
87
+ test_files:
88
+ - spec/flex_attributes_spec.rb
89
+ - spec/spec_helper.rb