flex_fields 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/.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