pliable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bundle/install.log +1575 -0
- data/.document +3 -0
- data/.travis.yml +16 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +134 -0
- data/LICENSE.txt +20 -0
- data/README.md +287 -0
- data/Rakefile +39 -0
- data/lib/generators/pliable/model_generator.rb +40 -0
- data/lib/generators/pliable/templates/migration.rb +24 -0
- data/lib/pliable/configure.rb +12 -0
- data/lib/pliable/ply.rb +89 -0
- data/lib/pliable/ply_relation.rb +4 -0
- data/lib/pliable/text_helper.rb +3 -0
- data/lib/pliable/version.rb +4 -0
- data/lib/pliable.rb +17 -0
- data/pliable.gemspec +35 -0
- data/spec/.DS_Store +0 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/invoice.rb +6 -0
- data/spec/dummy/app/models/line_item.rb +5 -0
- data/spec/dummy/app/models/merchandise.rb +5 -0
- data/spec/dummy/app/models/ply.rb +7 -0
- data/spec/dummy/config/application.rb +65 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +19 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/pliable.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/.DS_Store +0 -0
- data/spec/dummy/db/migrate/20140117210156_create_plies_and_ply_relations.rb +23 -0
- data/spec/dummy/db/migration_helper.rb +42 -0
- data/spec/dummy/db/schema.rb +39 -0
- data/spec/dummy/db/seeds.rb +17 -0
- data/spec/dummy/db/static/bottles.csv +201 -0
- data/spec/dummy/db/static/varietal_aliases.csv +433 -0
- data/spec/dummy/db/static/varietals.csv +295 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/log/development.log +63 -0
- data/spec/dummy/log/test.log +2339 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/fixtures/varietals.yml +2135 -0
- data/spec/dummy/spec/models/.DS_Store +0 -0
- data/spec/dummy/spec/models/fake_ply_test.rb +12 -0
- data/spec/dummy/spec/models/ply_relation_spec.rb +12 -0
- data/spec/dummy/spec/pliable_integartion_spec.rb +48 -0
- data/spec/dummy/spec/tmp/app/models/foo_alias.rb +4 -0
- data/spec/spec_helper.rb +36 -0
- data/sub +4 -0
- metadata +389 -0
data/.document
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
|
6
|
+
addons:
|
7
|
+
postgresql: 9.2
|
8
|
+
|
9
|
+
before_script:
|
10
|
+
- psql -c 'create database dummy_test;' -U postgres
|
11
|
+
|
12
|
+
script:
|
13
|
+
- cd spec/dummy/
|
14
|
+
- bundle exec rake db:test:prepare
|
15
|
+
- cd ../..
|
16
|
+
- bundle exec rspec
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "pliable Documentation" --protected
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pliable (0.1)
|
5
|
+
pg
|
6
|
+
rails (>= 4.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (4.0.2)
|
12
|
+
actionpack (= 4.0.2)
|
13
|
+
mail (~> 2.5.4)
|
14
|
+
actionpack (4.0.2)
|
15
|
+
activesupport (= 4.0.2)
|
16
|
+
builder (~> 3.1.0)
|
17
|
+
erubis (~> 2.7.0)
|
18
|
+
rack (~> 1.5.2)
|
19
|
+
rack-test (~> 0.6.2)
|
20
|
+
activemodel (4.0.2)
|
21
|
+
activesupport (= 4.0.2)
|
22
|
+
builder (~> 3.1.0)
|
23
|
+
activerecord (4.0.2)
|
24
|
+
activemodel (= 4.0.2)
|
25
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
26
|
+
activesupport (= 4.0.2)
|
27
|
+
arel (~> 4.0.0)
|
28
|
+
activerecord-deprecated_finders (1.0.3)
|
29
|
+
activesupport (4.0.2)
|
30
|
+
i18n (~> 0.6, >= 0.6.4)
|
31
|
+
minitest (~> 4.2)
|
32
|
+
multi_json (~> 1.3)
|
33
|
+
thread_safe (~> 0.1)
|
34
|
+
tzinfo (~> 0.3.37)
|
35
|
+
arel (4.0.1)
|
36
|
+
atomic (1.1.14)
|
37
|
+
builder (3.1.4)
|
38
|
+
coderay (1.1.0)
|
39
|
+
columnize (0.3.6)
|
40
|
+
database_cleaner (1.0.1)
|
41
|
+
debugger (1.6.5)
|
42
|
+
columnize (>= 0.3.1)
|
43
|
+
debugger-linecache (~> 1.2.0)
|
44
|
+
debugger-ruby_core_source (~> 1.3.1)
|
45
|
+
debugger-linecache (1.2.0)
|
46
|
+
debugger-ruby_core_source (1.3.1)
|
47
|
+
diff-lcs (1.2.5)
|
48
|
+
erubis (2.7.0)
|
49
|
+
hike (1.2.3)
|
50
|
+
i18n (0.6.9)
|
51
|
+
kramdown (1.3.1)
|
52
|
+
mail (2.5.4)
|
53
|
+
mime-types (~> 1.16)
|
54
|
+
treetop (~> 1.4.8)
|
55
|
+
metaclass (0.0.2)
|
56
|
+
method_source (0.8.2)
|
57
|
+
mime-types (1.25.1)
|
58
|
+
minitest (4.7.5)
|
59
|
+
mocha (1.0.0)
|
60
|
+
metaclass (~> 0.0.1)
|
61
|
+
multi_json (1.8.4)
|
62
|
+
pg (0.17.1)
|
63
|
+
polyglot (0.3.3)
|
64
|
+
pry (0.9.12.4)
|
65
|
+
coderay (~> 1.0)
|
66
|
+
method_source (~> 0.8)
|
67
|
+
slop (~> 3.4)
|
68
|
+
pry-debugger (0.2.2)
|
69
|
+
debugger (~> 1.3)
|
70
|
+
pry (~> 0.9.10)
|
71
|
+
rack (1.5.2)
|
72
|
+
rack-test (0.6.2)
|
73
|
+
rack (>= 1.0)
|
74
|
+
rails (4.0.2)
|
75
|
+
actionmailer (= 4.0.2)
|
76
|
+
actionpack (= 4.0.2)
|
77
|
+
activerecord (= 4.0.2)
|
78
|
+
activesupport (= 4.0.2)
|
79
|
+
bundler (>= 1.3.0, < 2.0)
|
80
|
+
railties (= 4.0.2)
|
81
|
+
sprockets-rails (~> 2.0.0)
|
82
|
+
railties (4.0.2)
|
83
|
+
actionpack (= 4.0.2)
|
84
|
+
activesupport (= 4.0.2)
|
85
|
+
rake (>= 0.8.7)
|
86
|
+
thor (>= 0.18.1, < 2.0)
|
87
|
+
rake (0.9.6)
|
88
|
+
rspec (2.14.0)
|
89
|
+
rspec-core (~> 2.14.0)
|
90
|
+
rspec-expectations (~> 2.14.0)
|
91
|
+
rspec-mocks (~> 2.14.0)
|
92
|
+
rspec-core (2.14.7)
|
93
|
+
rspec-expectations (2.14.4)
|
94
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
95
|
+
rspec-mocks (2.14.4)
|
96
|
+
rubygems-tasks (0.2.4)
|
97
|
+
slop (3.4.7)
|
98
|
+
sprockets (2.10.1)
|
99
|
+
hike (~> 1.2)
|
100
|
+
multi_json (~> 1.0)
|
101
|
+
rack (~> 1.0)
|
102
|
+
tilt (~> 1.1, != 1.3.0)
|
103
|
+
sprockets-rails (2.0.1)
|
104
|
+
actionpack (>= 3.0)
|
105
|
+
activesupport (>= 3.0)
|
106
|
+
sprockets (~> 2.8)
|
107
|
+
thor (0.18.1)
|
108
|
+
thread_safe (0.1.3)
|
109
|
+
atomic
|
110
|
+
tilt (1.4.1)
|
111
|
+
treetop (1.4.15)
|
112
|
+
polyglot
|
113
|
+
polyglot (>= 0.3.1)
|
114
|
+
tzinfo (0.3.38)
|
115
|
+
yard (0.8.7.3)
|
116
|
+
|
117
|
+
PLATFORMS
|
118
|
+
ruby
|
119
|
+
|
120
|
+
DEPENDENCIES
|
121
|
+
bundler (~> 1.0)
|
122
|
+
database_cleaner (~> 1.0)
|
123
|
+
kramdown
|
124
|
+
minitest (>= 4.7.5)
|
125
|
+
mocha (~> 1.0.0)
|
126
|
+
pg (~> 0.17.1)
|
127
|
+
pliable!
|
128
|
+
pry (~> 0.9.12)
|
129
|
+
pry-debugger (~> 0.2)
|
130
|
+
rails (>= 4.0)
|
131
|
+
rake (~> 0.8)
|
132
|
+
rspec (~> 2.14)
|
133
|
+
rubygems-tasks (~> 0.2)
|
134
|
+
yard (~> 0.8)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Mike Piccolo
|
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.md
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
pliable
|
2
|
+
============
|
3
|
+
| Project | Gem Release |
|
4
|
+
|------------------------ | ----------------- |
|
5
|
+
| Gem name | pliable |
|
6
|
+
| License | [MIT](LICENSE.txt) |
|
7
|
+
| Version | [![Gem Version](https://badge.fury.io/rb/pliable.png)](http://badge.fury.io/rb/pliable) |
|
8
|
+
| Continuous Integration | [![Build Status](https://travis-ci.org/mfpiccolo/pliable.png?branch=master)](https://travis-ci.org/mfpiccolo/pliable)
|
9
|
+
Z| Grade | [![Code Climate](https://codeclimate.com/github/mfpiccolo/pliable.png)](https://codeclimate.com/github/mfpiccolo/pliable)
|
10
|
+
| Homepage | [http://mfpiccolo.github.io/pliable][homepage] |
|
11
|
+
| Documentation | [http://rdoc.info/github/mfpiccolo/pliable/frames][documentation] |
|
12
|
+
| Issues | [https://github.com/mfpiccolo/pliable/issues][issues] |
|
13
|
+
|
14
|
+
## Description
|
15
|
+
|
16
|
+
Pliable makes integrating a Rails project with Schemaless data not so painful.
|
17
|
+
|
18
|
+
Rolling your own integration with an external service where the schema can change from moment to moment can be tough. Pliable makes it a bit easier by giving you a familiar place to store this data (models backed by postgres) and familiar ways of interacting with it (Active Record objects, complete with associations).
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem "pliable"
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install pliable
|
35
|
+
|
36
|
+
## Features
|
37
|
+
|
38
|
+
Pliable allows you to save individual records from external schemaless databases into your postgres
|
39
|
+
backed rails apps. We store all of the data in a plies table. The Ply model contains logic that allows
|
40
|
+
you to inherit from Ply and then act as if these iherited models are normal Active Record models.
|
41
|
+
|
42
|
+
Here is the Ply model your generator created:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class Ply < Pliable::Ply
|
46
|
+
# Define methods here that you want all you Ply backed models to have.
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Now you can create a model that is backed by Ply.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class Foo < Ply
|
54
|
+
# This is redundant if it is the same name ass the class but required for now.
|
55
|
+
ply_name "Foo"
|
56
|
+
# Define methods that you only want Foo to have.
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
Now lets make another Ply Backed Model.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class Bar < Ply
|
64
|
+
ply_name "Bar"
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
Now you should be able to treat these like any other Active Record object with the added bonus of a
|
69
|
+
few features. You can assign any json data to the data attribute.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
foo = Foo.create(data: {"some" => "json", "other" => "data"})
|
73
|
+
```
|
74
|
+
The nice part is now these json keys are methods.
|
75
|
+
```ruby
|
76
|
+
foo.some => "json"
|
77
|
+
```
|
78
|
+
|
79
|
+
Another nicety is associations. You can associate a Ply inhereted class to another using parent
|
80
|
+
and child relationships and the PlyRelations model
|
81
|
+
```ruby
|
82
|
+
foo = Foo.create
|
83
|
+
bar = Bar.create
|
84
|
+
PlyRealation.create(parent_id: foo.id, parent_type: foo.class.name, child_id: bar, child_type: bar.class.name)
|
85
|
+
|
86
|
+
foo.bars => <#<ActiveRecord::AssociationRelation [#<Pliable::Ply id: 2 otype: "Bar" ...>
|
87
|
+
```
|
88
|
+
|
89
|
+
## Configuration
|
90
|
+
|
91
|
+
To use the generator run:
|
92
|
+
|
93
|
+
$ rails g pliable:model
|
94
|
+
|
95
|
+
This will set up pliable.rb initializer, create the migration and run it and add a Ply model and specs.
|
96
|
+
|
97
|
+
In the initializer, specify any aditional logic you need to prepare the ply_name for pluralization.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
Pliable.configure do |config|
|
101
|
+
# Add logic to this bloc to change the names given by external services so we can pluralize.
|
102
|
+
# For instance if you ply names need to gsub __c of the end do:
|
103
|
+
config.added_scrubber {|name| name.gsub('__c', '') }
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
## Examples
|
108
|
+
|
109
|
+
An example of a salesforce integration:
|
110
|
+
|
111
|
+
Here is your Ply model:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
# Notice it inherits from Pliable::Ply
|
115
|
+
class Ply < Pliable::Ply
|
116
|
+
|
117
|
+
# Define methods here that you want all of your models to have
|
118
|
+
def anything_you_like
|
119
|
+
puts "I can play disco all night"
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
This is an example salesforce Invoice model:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
# Notice it inherits from your apps Ply
|
129
|
+
class Invoice < Ply
|
130
|
+
|
131
|
+
# If you dont put this you will get all Ply records.
|
132
|
+
# This is the name that you have put into the otype attribute.
|
133
|
+
# In this example I just used the exact salesforce api name
|
134
|
+
ply_name "Invoice__c"
|
135
|
+
|
136
|
+
# Add Invoice specific methods here
|
137
|
+
def what_dosnt_gather_moss?
|
138
|
+
"A rolling stone!"
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
Here is an example associated salesforce model:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
class LineItem < Ply
|
148
|
+
|
149
|
+
ply_name "Line_Item__c"
|
150
|
+
|
151
|
+
# You guessed it. LineItem specific methods here.
|
152
|
+
def best_pliable_quote
|
153
|
+
"Facts are stubborn, but statistics are more pliable. - Mark Twain"
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
Here is your PlyRelation model:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# This will probably not be needed in the future and will live in the gem
|
163
|
+
class PlyRelation < ActiveRecord::Base
|
164
|
+
belongs_to :parent, class_name: 'Ply'
|
165
|
+
belongs_to :child, class_name: 'Ply'
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
A service object for pulling salesforce data into your app:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class SalesforceSynch
|
173
|
+
|
174
|
+
attr_reader :user, :client
|
175
|
+
|
176
|
+
def initialize(user)
|
177
|
+
@user = user
|
178
|
+
end
|
179
|
+
|
180
|
+
def call
|
181
|
+
set_clients # Connect to your Salesforce data (i.e. databsedotcom or restforce)
|
182
|
+
create_plys_from_salesforce_records # Create records in your PG database using Ply model
|
183
|
+
create_ply_relations # Dynamically create associations based on the data recieved
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.call
|
187
|
+
new.call
|
188
|
+
end
|
189
|
+
|
190
|
+
def set_clients
|
191
|
+
#Fake service object that sets up a client to connect to databasedotcom
|
192
|
+
@client = ConnectToDatabasedotcom.call(user.salesforce_credentials)
|
193
|
+
end
|
194
|
+
|
195
|
+
def create_plys_from_salesforce_records
|
196
|
+
data = []
|
197
|
+
|
198
|
+
# sf_api model names as strings in array
|
199
|
+
records = []
|
200
|
+
|
201
|
+
# User has_many :plies in this example (i.e. user.plies)
|
202
|
+
client.get_the_records_you_want.each do |record|
|
203
|
+
object = user.plies.find_or_create_by(oid: record.Id)
|
204
|
+
object.update_attributes(
|
205
|
+
# The data attribute is a json column. This is where you store all shcemaless data.
|
206
|
+
data: record.attributes,
|
207
|
+
# Whatever the service calls the object (i.e. Invoice__c for salesforce)
|
208
|
+
otype: record.salesforce_api_name,
|
209
|
+
# Use last_checked and last_modified to know when you need to update a record
|
210
|
+
last_checked: Time.zone.now
|
211
|
+
)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Dynamically deduce if there is a relationship with any of the plys that have been imported.
|
216
|
+
# In the case of saleforce the id of related object is stored by using the name of that
|
217
|
+
# object as a key. (ie "Invoice__c" => "long_uiniq_id"). In this app users choose a few models
|
218
|
+
# that they want to bring over but you could easily just get everything.
|
219
|
+
user.plies.each do |ply|
|
220
|
+
related_model_names = ply.instance_variables.map {|e| e.to_s.gsub("@", "") } & user.model_names
|
221
|
+
related_model_names.each do |name|
|
222
|
+
child = Ply.find_by_oid(ply.send(name.to_sym))
|
223
|
+
unless PlyRelation.where(parent_id: record.id, child_id: child.id).present?
|
224
|
+
ply.children.new(
|
225
|
+
parent_id: ply.id,
|
226
|
+
parent_type: ply.otype,
|
227
|
+
child_id: ply.id,
|
228
|
+
child_type: ply.otype
|
229
|
+
).save # #create does not work yet. Sorry
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
Now with this setup you can run something like this
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
SalesforceSynch.call(@user) # Awesome. You just imported all your salesforce data.
|
241
|
+
|
242
|
+
invoice = Invoice.first => #<Invoice id: 1, user_id: 1, oid: "randomnumber", otype: "Invoice__c",
|
243
|
+
# data: {"Id"=>"a00i000000BbWLvAAN", "OwnerId"=>"005i0000002NdyWAAS", "Owner"=>nil...}...>
|
244
|
+
|
245
|
+
invoice.line_items => #<ActiveRecord::AssociationRelation [#<Pliable::Ply id: 2 ...>
|
246
|
+
|
247
|
+
invoice.line_items.first.invoices.find(invoice.id) === invoice => true
|
248
|
+
|
249
|
+
invoice.SalesForceCustomAttribute__c => Whatever it is in salesforce.
|
250
|
+
|
251
|
+
Invoice.all => #<ActiveRecord::Relation [#<Invoice id: 136, user_id: 1...>
|
252
|
+
|
253
|
+
LineItem.first => #<LineItem id: 145, user_id: 1...>
|
254
|
+
|
255
|
+
Invoice.find_by_oid("random_oid_number") => #<Invoice id: 132, user_id: 1, oid: "rand...">
|
256
|
+
|
257
|
+
# All the normal active-recordy goodness
|
258
|
+
```
|
259
|
+
|
260
|
+
## Requirements
|
261
|
+
|
262
|
+
## Donating
|
263
|
+
Support this project and [others by mfpiccolo][gittip-mfpiccolo] via [gittip][gittip-mfpiccolo].
|
264
|
+
|
265
|
+
[gittip-mfpiccolo]: https://www.gittip.com/mfpiccolo/
|
266
|
+
|
267
|
+
## Copyright
|
268
|
+
|
269
|
+
Copyright (c) 2013 Mike Piccolo
|
270
|
+
|
271
|
+
See [LICENSE.txt](LICENSE.txt) for details.
|
272
|
+
|
273
|
+
## Contributing
|
274
|
+
|
275
|
+
1. Fork it ( http://github.com/<my-github-username>/pliable/fork )
|
276
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
277
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
278
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
279
|
+
5. Create new Pull Request
|
280
|
+
|
281
|
+
[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/e1a155a07163d56ca0c4f246c7aa8766 "githalytics.com")](http://githalytics.com/mfpiccolo/pliable)
|
282
|
+
|
283
|
+
[license]: https://github.com/mfpiccolo/pliable/MIT-LICENSE
|
284
|
+
[homepage]: http://mfpiccolo.github.io/pliable
|
285
|
+
[documentation]: http://rdoc.info/github/mfpiccolo/pliable/frames
|
286
|
+
[issues]: https://github.com/mfpiccolo/pliable/issues
|
287
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rubygems/tasks'
|
24
|
+
Gem::Tasks.new
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
|
28
|
+
Rake::TestTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'yard'
|
35
|
+
YARD::Rake::YardocTask.new
|
36
|
+
task :doc => :yard
|
37
|
+
|
38
|
+
task :default => :test
|
39
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "rails/generators/active_record"
|
2
|
+
|
3
|
+
module Pliable
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
def self.next_migration_number(path)
|
9
|
+
@migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
source_root File.expand_path("../templates", __FILE__)
|
13
|
+
|
14
|
+
def add_initializer
|
15
|
+
create_file "config/initializers/pliable.rb", "Pliable.configure do |config|
|
16
|
+
# define extra scrubbing for ply_name here. This is for the purpose of making scopes.
|
17
|
+
# For instance, if your models ply name is something like 'Invoice__c'
|
18
|
+
# you will need to gsub '__c' off the end:
|
19
|
+
# config.added_scrubber {|name| name.gsub('__c', '') }
|
20
|
+
end"
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_ply_and_relation_model
|
24
|
+
Rails::Generators.invoke("active_record:model", ["Ply", "--parent", "pliable/ply", "--no-migration" ])
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_migration
|
28
|
+
# TODO only run if migration dosn't exist
|
29
|
+
migration_template "migration.rb", "db/migrate/create_plies_and_ply_relations"
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_migrations
|
33
|
+
unless (ActiveRecord::Base.connection.table_exists?('plies') && (ActiveRecord::Base.connection.table_exists? 'ply_relations'))
|
34
|
+
rake("db:migrate db:test:prepare")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreatePliesAndPlyRelations < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :plies do |t|
|
4
|
+
t.integer :user_id
|
5
|
+
t.string :oid
|
6
|
+
t.string :otype
|
7
|
+
t.json :data
|
8
|
+
t.hstore :ohash
|
9
|
+
t.datetime :last_modified
|
10
|
+
t.datetime :last_checked
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :ply_relations do |t|
|
16
|
+
t.integer :parent_id
|
17
|
+
t.string :parent_type
|
18
|
+
t.integer :child_id
|
19
|
+
t.string :child_type
|
20
|
+
|
21
|
+
t.timestamps
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/pliable/ply.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Pliable
|
4
|
+
class Ply < ActiveRecord::Base
|
5
|
+
# TODO move to Dummy
|
6
|
+
|
7
|
+
# Allows an ply to associate another ply as either a parent or child
|
8
|
+
has_many :ply_relations
|
9
|
+
has_many :parent_relations, class_name: "PlyRelation", foreign_key: "child_id"
|
10
|
+
has_many :parents, through: :parent_relations, source: :parent
|
11
|
+
has_many :child_relations, class_name: "PlyRelation", foreign_key: "parent_id"
|
12
|
+
has_many :children, through: :child_relations, source: :child
|
13
|
+
|
14
|
+
after_initialize :set_ply_attributes
|
15
|
+
after_initialize :define_ply_scopes
|
16
|
+
|
17
|
+
def self.oldest_last_checked_time
|
18
|
+
order('last_checked').first.last_checked
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.all
|
22
|
+
if current_scope
|
23
|
+
current_scope.clone
|
24
|
+
else
|
25
|
+
if self.name == "Pliable::Ply"
|
26
|
+
scope = relation
|
27
|
+
else
|
28
|
+
if self.try(:ply_type)
|
29
|
+
scope = relation.where(otype: self.try(:ply_type))
|
30
|
+
else
|
31
|
+
scope = relation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
scope.default_scoped = true
|
35
|
+
scope
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.ply_name(name)
|
40
|
+
define_singleton_method(:ply_type) { name }
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_param
|
44
|
+
oid
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def set_ply_attributes
|
50
|
+
if data.present?
|
51
|
+
data.each do |key,value|
|
52
|
+
instance_variable_set(('@' + key.to_s).to_sym, value)
|
53
|
+
define_singleton_method(key.to_s) { instance_variable_get(('@' + key.to_s).to_sym) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def define_ply_scopes
|
59
|
+
# pluralize is not perfect. ie. Merchandise__c => merchandises
|
60
|
+
child_names = children.pluck(:child_type).uniq
|
61
|
+
parent_names = parents.pluck(:parent_type).uniq
|
62
|
+
|
63
|
+
add_scopes(child_names, parent_names)
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_scopes(child_names, parent_names)
|
67
|
+
child_names.each do |name|
|
68
|
+
define_singleton_method(scrub_for_scope(name)) do
|
69
|
+
children.where(otype: name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
parent_names.each do |name|
|
74
|
+
define_singleton_method(scrub_for_scope(name)) do
|
75
|
+
parents.where(otype: name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# user initializer to overwrite this method
|
81
|
+
def scrub_for_scope(name)
|
82
|
+
if respond_to? :added_scrubber
|
83
|
+
name = added_scrubber(name)
|
84
|
+
end
|
85
|
+
|
86
|
+
TextHelper.pluralize(name.downcase)
|
87
|
+
end
|
88
|
+
end # Ply
|
89
|
+
end # Pliable
|