flattener 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.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE +22 -0
- data/README.md +99 -0
- data/Rakefile +2 -0
- data/flattener.gemspec +23 -0
- data/lib/flattener/base.rb +13 -0
- data/lib/flattener/configurator.rb +147 -0
- data/lib/flattener/rails.rb +7 -0
- data/lib/flattener/version.rb +3 -0
- data/lib/flattener.rb +12 -0
- data/spec/lib/flattener/base_spec.rb +35 -0
- data/spec/lib/flattener/configurator_spec.rb +120 -0
- data/spec/spec_helper.rb +55 -0
- metadata +121 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Lucas Florio
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Flattener
|
2
|
+
|
3
|
+
Allows to flat an object (ActiveRecord based) into one level.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'flattener'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install flattener
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Say you have something like this:
|
22
|
+
|
23
|
+
class Customer < ActiveRecord::Base
|
24
|
+
has_one :address
|
25
|
+
end
|
26
|
+
|
27
|
+
class Address < ActiveRecord::Base
|
28
|
+
# ... Attributes here
|
29
|
+
end
|
30
|
+
|
31
|
+
You could do something like this:
|
32
|
+
|
33
|
+
class Customer < ActiveRecord::Base
|
34
|
+
|
35
|
+
include Flattener
|
36
|
+
|
37
|
+
has_one :address
|
38
|
+
|
39
|
+
flat :address do
|
40
|
+
attribute :address_line_1
|
41
|
+
attribute :address_line_2
|
42
|
+
attribute :city
|
43
|
+
attribute :state
|
44
|
+
attribute :country
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
and use it like this:
|
50
|
+
|
51
|
+
customer = Customer.new address_line_1: "Av. Santa Fe 1234", country: "Argentina"
|
52
|
+
|
53
|
+
Pretty simple. It support all the basic AR methods, like valid?, save or create.
|
54
|
+
|
55
|
+
I know what you think. "I can do that with a simple delegate call". Indeed, but you can also do this:
|
56
|
+
|
57
|
+
class Payment < ActiveRecord::Base
|
58
|
+
|
59
|
+
include Flattener
|
60
|
+
|
61
|
+
has_one :payment_profile
|
62
|
+
|
63
|
+
flat :payment_profile do
|
64
|
+
|
65
|
+
attributes :credit_card, :expiration_date
|
66
|
+
|
67
|
+
flat :address do
|
68
|
+
attribute :address_line_1
|
69
|
+
attribute :address_line_2
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
And this way getting something really simple:
|
77
|
+
|
78
|
+
payment = Payment.new amount: "23.00", payment_profile_credit_card: "XXXXXXXXXX", expiration_date: "2011/12",
|
79
|
+
payment_profile_address_line_1: "Av. Mongo 1234"
|
80
|
+
|
81
|
+
payment.payment_profile_address_line_1 #=> "Av. Mongo 1234"
|
82
|
+
# and so on.
|
83
|
+
|
84
|
+
# supose you have a validation on Address#address_line_2
|
85
|
+
payment.valid? #=> false
|
86
|
+
payment.errors[:payment_profile_address_line_1] #=> ".... is required, blah..."
|
87
|
+
|
88
|
+
So what is this gem doing?
|
89
|
+
|
90
|
+
* It builds the flattened objects automatically, or the way you want (configuration option).
|
91
|
+
* It overwrites the AR methods in order to call the flattened methods before, so the right validation errors appear in place.
|
92
|
+
|
93
|
+
## Contributing
|
94
|
+
|
95
|
+
1. Fork it
|
96
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
97
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
98
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
99
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/flattener.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/flattener/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Lucas Florio"]
|
6
|
+
gem.email = ["lucasefe@gmail.com"]
|
7
|
+
gem.description = %q{Allows to flat an object and his children (ActiveRecord based) into one level, so you create them all without building a complex form. }
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "flattener"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Flattener::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'activerecord'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'sqlite3'
|
21
|
+
gem.add_development_dependency 'shoulda'
|
22
|
+
gem.add_development_dependency 'guard-rspec'
|
23
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Flattener
|
2
|
+
|
3
|
+
class Configurator
|
4
|
+
|
5
|
+
def self.flat klass, object, options = {}, &block
|
6
|
+
new klass, object, options, &block
|
7
|
+
end
|
8
|
+
|
9
|
+
# # nesting
|
10
|
+
def flat object, options = {}, &block
|
11
|
+
NestedConfigurator.new self, object, options, &block
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :klass, :accessor, :name, :prefix, :options, :attributes
|
15
|
+
|
16
|
+
def initialize(klass, name, options = {}, &block)
|
17
|
+
@klass = klass
|
18
|
+
@name = name
|
19
|
+
@options = options
|
20
|
+
@attributes = {}
|
21
|
+
@prefix = @options[:prefix] || @name.to_s
|
22
|
+
@accessor = @options[:accessor] || @name.to_s
|
23
|
+
prepare!
|
24
|
+
self.instance_eval(&block) if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
def prepare!
|
28
|
+
add_build_method!
|
29
|
+
add_proxy_method!
|
30
|
+
add_validator_method!
|
31
|
+
|
32
|
+
unless klass.respond_to?(:flatteners)
|
33
|
+
klass.class_attribute :flatteners
|
34
|
+
klass.flatteners = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
klass.flatteners[name] = self
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_build_method!
|
41
|
+
unless @klass.instance_methods.include?(build_method_name.to_sym)
|
42
|
+
raise "must specify a build option, or the method named #{build_method_name}" unless @options.has_key?(:build)
|
43
|
+
@klass.send :define_method, build_method_name, &@options[:build]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_proxy_method!
|
48
|
+
code = <<-CODE
|
49
|
+
def #{proxy_method_name}
|
50
|
+
if self.#{accessor_method_name}.nil?
|
51
|
+
#{build_method_name}
|
52
|
+
end
|
53
|
+
self.#{accessor_method_name}
|
54
|
+
end
|
55
|
+
CODE
|
56
|
+
@klass.class_eval code, __FILE__, __LINE__
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_validator_method!
|
60
|
+
if defined?(ActiveRecord::Validations) && @klass.included_modules.include?(ActiveRecord::Validations)
|
61
|
+
code = <<-CODE
|
62
|
+
def #{validate_method_name}
|
63
|
+
unless self.#{accessor_method_name}.blank?
|
64
|
+
self.#{proxy_method_name}.valid?
|
65
|
+
|
66
|
+
self.#{proxy_method_name}.errors.each do |name, message|
|
67
|
+
flattened_name = self.class.flatteners[:#{name}].attributes[name]
|
68
|
+
self.errors.add flattened_name, message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
CODE
|
73
|
+
@klass.class_eval code
|
74
|
+
@klass.validate validate_method_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# How it access the flattened object
|
79
|
+
def accessor_method_name
|
80
|
+
@accessor
|
81
|
+
end
|
82
|
+
|
83
|
+
def proxy_method_name
|
84
|
+
"proxy_#{accessor_method_name}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_method_name
|
88
|
+
"build_#{accessor_method_name}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def validate_method_name
|
92
|
+
"validate_#{accessor_method_name}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def method_name_for(name)
|
96
|
+
if prefix.blank?
|
97
|
+
name.to_sym
|
98
|
+
else
|
99
|
+
"#{prefix}_#{name}".to_sym
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def attribute(name)
|
104
|
+
method_name = method_name_for(name)
|
105
|
+
code = <<-CODE
|
106
|
+
def #{method_name}
|
107
|
+
#{proxy_method_name}.#{name}
|
108
|
+
end
|
109
|
+
|
110
|
+
def #{method_name}=(value)
|
111
|
+
#{proxy_method_name}.#{name} = value
|
112
|
+
end
|
113
|
+
CODE
|
114
|
+
@klass.class_eval code, __FILE__, __LINE__
|
115
|
+
self.attributes[name] = method_name
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class NestedConfigurator < Configurator
|
120
|
+
|
121
|
+
attr_accessor :parent
|
122
|
+
|
123
|
+
def initialize(parent, name, options = {}, &block)
|
124
|
+
@parent = parent
|
125
|
+
options[:prefix] ||= if @parent.prefix.blank?
|
126
|
+
name.to_s
|
127
|
+
else
|
128
|
+
"#{@parent.prefix}_#{name.to_s}"
|
129
|
+
end
|
130
|
+
options[:accessor] ||= "#{parent.accessor_method_name}_#{name}"
|
131
|
+
super(parent.klass, name, options, &block)
|
132
|
+
end
|
133
|
+
|
134
|
+
def prepare!
|
135
|
+
super
|
136
|
+
code = <<-CODE
|
137
|
+
# customer_payment_profile_address
|
138
|
+
|
139
|
+
def #{parent.accessor_method_name}_#{name}
|
140
|
+
#{parent.proxy_method_name}.#{name}
|
141
|
+
end
|
142
|
+
CODE
|
143
|
+
@klass.class_eval code
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
data/lib/flattener.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "flattener/version"
|
2
|
+
require "flattener/configurator"
|
3
|
+
require "flattener/base"
|
4
|
+
require "flattener/Rails" if defined?(Rails)
|
5
|
+
|
6
|
+
module Flattener
|
7
|
+
|
8
|
+
def flat object, options = {}, &block
|
9
|
+
Flattener::Configurator.flat(self, object, options, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class CustomerBuilder < Flattener::Base
|
5
|
+
attr_accessor :customer
|
6
|
+
|
7
|
+
flat :customer, prefix: "", build: proc {self.customer = Customer.new} do
|
8
|
+
|
9
|
+
attribute :name
|
10
|
+
|
11
|
+
flat :payment_profile, build: proc { self.proxy_customer.build_payment_profile } do
|
12
|
+
attribute :uuid
|
13
|
+
|
14
|
+
flat :address, build: proc { self.proxy_customer_payment_profile.build_address } do
|
15
|
+
attribute :city
|
16
|
+
attribute :street_line_1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Flattener::Base do
|
24
|
+
|
25
|
+
it "should work as a class too" do
|
26
|
+
instance = CustomerBuilder.new name: "jose", payment_profile_uuid: "GGG-78979", payment_profile_address_city: "Mongo City"
|
27
|
+
instance.name.should == "jose"
|
28
|
+
instance.customer.name.should == "jose"
|
29
|
+
|
30
|
+
instance.payment_profile_uuid.should == instance.customer.payment_profile.uuid
|
31
|
+
instance.payment_profile_address_city.should == instance.customer.payment_profile.address.city
|
32
|
+
instance.should be_valid
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A flattened object" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@klass = Class.new do
|
7
|
+
extend Flattener
|
8
|
+
attr_accessor :subobject
|
9
|
+
end
|
10
|
+
|
11
|
+
SubClass = Class.new do
|
12
|
+
attr_accessor :name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "configuration" do
|
17
|
+
|
18
|
+
it "should be flattenable" do
|
19
|
+
@klass.should respond_to(:flat)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store the flattened configuration" do
|
23
|
+
@klass.flat :subobject, build: proc { self.subobject = SubClass.new } do
|
24
|
+
attribute :name
|
25
|
+
end
|
26
|
+
|
27
|
+
@klass.should respond_to(:flatteners)
|
28
|
+
@klass.flatteners[:subobject].should_not be_blank
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should keep track of the flattened attributes" do
|
32
|
+
@klass.flat :subobject, build: proc { self.subobject = SubClass.new } do
|
33
|
+
attribute :name
|
34
|
+
end
|
35
|
+
@klass.flatteners[:subobject].attributes.keys.should == [ :name ]
|
36
|
+
@klass.flatteners[:subobject].attributes.values.should == [ :subobject_name ]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
context "basic usage" do
|
43
|
+
|
44
|
+
it "should raise an error if no build option is provided" do
|
45
|
+
lambda {
|
46
|
+
@klass.flat :subobject
|
47
|
+
}.should raise_error(/build/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should flat an extra object attribute" do
|
51
|
+
@klass.flat :subobject, build: proc { self.subobject = SubClass.new } do
|
52
|
+
attribute :name
|
53
|
+
end
|
54
|
+
|
55
|
+
instance = @klass.new
|
56
|
+
instance.should respond_to(:subobject_name)
|
57
|
+
instance.should respond_to(:subobject_name=)
|
58
|
+
instance.subobject_name = "name from hell"
|
59
|
+
instance.subobject.should be_an_instance_of(SubClass)
|
60
|
+
instance.subobject.name.should == "name from hell"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should support to change the prefix (the way the methods are named) " do
|
64
|
+
@klass.flat :subobject, build: proc { self.subobject = SubClass.new }, prefix: "so" do
|
65
|
+
attribute :name
|
66
|
+
end
|
67
|
+
|
68
|
+
instance = @klass.new
|
69
|
+
instance.should respond_to(:so_name)
|
70
|
+
instance.should respond_to(:so_name=)
|
71
|
+
instance.so_name = "name from hell"
|
72
|
+
instance.subobject.should be_an_instance_of(SubClass)
|
73
|
+
instance.subobject.name.should == "name from hell"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "a flattened object with validations" do
|
81
|
+
|
82
|
+
it "jjj" do
|
83
|
+
instance = Customer.new
|
84
|
+
instance.payment_profile_uuid = "GGG-78979"
|
85
|
+
instance.payment_profile_uuid.should == instance.payment_profile.uuid
|
86
|
+
|
87
|
+
instance.should be_valid
|
88
|
+
instance.save.should be_true
|
89
|
+
instance.payment_profile.should_not be_new_record
|
90
|
+
|
91
|
+
instance.payment_profile_uuid = nil
|
92
|
+
instance.should_not be_valid
|
93
|
+
|
94
|
+
instance.errors.should have(1).message
|
95
|
+
instance.errors[:payment_profile_uuid].first.should match(/can't be blank/)
|
96
|
+
|
97
|
+
instance.save.should_not be_true
|
98
|
+
end
|
99
|
+
|
100
|
+
it "nested flattened objects" do
|
101
|
+
instance = Customer.new
|
102
|
+
instance.payment_profile_uuid = "GGG-78979"
|
103
|
+
instance.payment_profile.should respond_to(:build_address)
|
104
|
+
instance.payment_profile_uuid.should == instance.payment_profile.uuid
|
105
|
+
instance.payment_profile_address_city = "Mongo City"
|
106
|
+
instance.payment_profile_address_city.should == instance.payment_profile.address.city
|
107
|
+
instance.should be_valid
|
108
|
+
|
109
|
+
instance.payment_profile_address_city = nil
|
110
|
+
instance.should_not be_valid
|
111
|
+
instance.errors[:payment_profile_address_city].first.should match(/can't be blank/)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "massive assignment" do
|
115
|
+
instance = Customer.new payment_profile_uuid: "GGG-78979", payment_profile_address_city: "Mongo City"
|
116
|
+
instance.payment_profile_uuid.should == instance.payment_profile.uuid
|
117
|
+
instance.payment_profile_address_city.should == instance.payment_profile.address.city
|
118
|
+
instance.should be_valid
|
119
|
+
end
|
120
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'flattener'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
6
|
+
|
7
|
+
ActiveRecord::Schema.define(:version => 1) do
|
8
|
+
create_table :customers, force: true do |t|
|
9
|
+
t.string :name
|
10
|
+
end
|
11
|
+
|
12
|
+
create_table :payment_profiles, force: true do |t|
|
13
|
+
t.integer :customer_id
|
14
|
+
t.string :uuid
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :addresses, force: true do |t|
|
18
|
+
t.integer :payment_profile_id
|
19
|
+
t.string :street_line_1
|
20
|
+
t.string :street_line_2
|
21
|
+
t.string :city
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class Address < ActiveRecord::Base
|
27
|
+
belongs_to :payment_profile
|
28
|
+
|
29
|
+
validates :city, presence: true
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class PaymentProfile < ActiveRecord::Base
|
34
|
+
has_one :address
|
35
|
+
belongs_to :customer
|
36
|
+
|
37
|
+
validates :uuid, presence: true
|
38
|
+
end
|
39
|
+
|
40
|
+
class Customer < ActiveRecord::Base
|
41
|
+
|
42
|
+
has_one :payment_profile
|
43
|
+
|
44
|
+
extend Flattener
|
45
|
+
|
46
|
+
flat :payment_profile do
|
47
|
+
attribute :uuid
|
48
|
+
|
49
|
+
flat :address, build: proc { self.proxy_payment_profile.build_address } do
|
50
|
+
attribute :city
|
51
|
+
attribute :street_line_1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flattener
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lucas Florio
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &70174276620400 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70174276620400
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70174276619820 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70174276619820
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sqlite3
|
38
|
+
requirement: &70174276619140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70174276619140
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: shoulda
|
49
|
+
requirement: &70174276618720 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70174276618720
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: guard-rspec
|
60
|
+
requirement: &70174276618300 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70174276618300
|
69
|
+
description: ! 'Allows to flat an object and his children (ActiveRecord based) into
|
70
|
+
one level, so you create them all without building a complex form. '
|
71
|
+
email:
|
72
|
+
- lucasefe@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .rspec
|
79
|
+
- Gemfile
|
80
|
+
- Guardfile
|
81
|
+
- LICENSE
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- flattener.gemspec
|
85
|
+
- lib/flattener.rb
|
86
|
+
- lib/flattener/base.rb
|
87
|
+
- lib/flattener/configurator.rb
|
88
|
+
- lib/flattener/rails.rb
|
89
|
+
- lib/flattener/version.rb
|
90
|
+
- spec/lib/flattener/base_spec.rb
|
91
|
+
- spec/lib/flattener/configurator_spec.rb
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
homepage: ''
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.15
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Allows to flat an object and his children (ActiveRecord based) into one level,
|
117
|
+
so you create them all without building a complex form.
|
118
|
+
test_files:
|
119
|
+
- spec/lib/flattener/base_spec.rb
|
120
|
+
- spec/lib/flattener/configurator_spec.rb
|
121
|
+
- spec/spec_helper.rb
|