pliable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.bundle/install.log +1575 -0
  2. data/.document +3 -0
  3. data/.travis.yml +16 -0
  4. data/.yardopts +1 -0
  5. data/ChangeLog.md +4 -0
  6. data/Gemfile +7 -0
  7. data/Gemfile.lock +134 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.md +287 -0
  10. data/Rakefile +39 -0
  11. data/lib/generators/pliable/model_generator.rb +40 -0
  12. data/lib/generators/pliable/templates/migration.rb +24 -0
  13. data/lib/pliable/configure.rb +12 -0
  14. data/lib/pliable/ply.rb +89 -0
  15. data/lib/pliable/ply_relation.rb +4 -0
  16. data/lib/pliable/text_helper.rb +3 -0
  17. data/lib/pliable/version.rb +4 -0
  18. data/lib/pliable.rb +17 -0
  19. data/pliable.gemspec +35 -0
  20. data/spec/.DS_Store +0 -0
  21. data/spec/dummy/README.rdoc +261 -0
  22. data/spec/dummy/Rakefile +7 -0
  23. data/spec/dummy/app/models/.gitkeep +0 -0
  24. data/spec/dummy/app/models/invoice.rb +6 -0
  25. data/spec/dummy/app/models/line_item.rb +5 -0
  26. data/spec/dummy/app/models/merchandise.rb +5 -0
  27. data/spec/dummy/app/models/ply.rb +7 -0
  28. data/spec/dummy/config/application.rb +65 -0
  29. data/spec/dummy/config/boot.rb +10 -0
  30. data/spec/dummy/config/database.yml +19 -0
  31. data/spec/dummy/config/environment.rb +5 -0
  32. data/spec/dummy/config/environments/development.rb +37 -0
  33. data/spec/dummy/config/environments/production.rb +67 -0
  34. data/spec/dummy/config/environments/test.rb +37 -0
  35. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  36. data/spec/dummy/config/initializers/inflections.rb +15 -0
  37. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  38. data/spec/dummy/config/initializers/pliable.rb +5 -0
  39. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  40. data/spec/dummy/config/initializers/session_store.rb +8 -0
  41. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  42. data/spec/dummy/config/locales/en.yml +5 -0
  43. data/spec/dummy/config/routes.rb +58 -0
  44. data/spec/dummy/config.ru +4 -0
  45. data/spec/dummy/db/migrate/.DS_Store +0 -0
  46. data/spec/dummy/db/migrate/20140117210156_create_plies_and_ply_relations.rb +23 -0
  47. data/spec/dummy/db/migration_helper.rb +42 -0
  48. data/spec/dummy/db/schema.rb +39 -0
  49. data/spec/dummy/db/seeds.rb +17 -0
  50. data/spec/dummy/db/static/bottles.csv +201 -0
  51. data/spec/dummy/db/static/varietal_aliases.csv +433 -0
  52. data/spec/dummy/db/static/varietals.csv +295 -0
  53. data/spec/dummy/lib/assets/.gitkeep +0 -0
  54. data/spec/dummy/log/.gitkeep +0 -0
  55. data/spec/dummy/log/development.log +63 -0
  56. data/spec/dummy/log/test.log +2339 -0
  57. data/spec/dummy/public/404.html +26 -0
  58. data/spec/dummy/public/422.html +26 -0
  59. data/spec/dummy/public/500.html +25 -0
  60. data/spec/dummy/public/favicon.ico +0 -0
  61. data/spec/dummy/script/rails +6 -0
  62. data/spec/dummy/spec/fixtures/varietals.yml +2135 -0
  63. data/spec/dummy/spec/models/.DS_Store +0 -0
  64. data/spec/dummy/spec/models/fake_ply_test.rb +12 -0
  65. data/spec/dummy/spec/models/ply_relation_spec.rb +12 -0
  66. data/spec/dummy/spec/pliable_integartion_spec.rb +48 -0
  67. data/spec/dummy/spec/tmp/app/models/foo_alias.rb +4 -0
  68. data/spec/spec_helper.rb +36 -0
  69. data/sub +4 -0
  70. metadata +389 -0
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
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
@@ -0,0 +1,4 @@
1
+ ### 0.1 / 2014-01-17
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'kramdown'
7
+ end
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
@@ -0,0 +1,12 @@
1
+ module Pliable
2
+ module Configure
3
+
4
+ def configure
5
+ yield self if block_given?
6
+ end
7
+
8
+ def added_scrubber(&block)
9
+ Pliable::Ply.send(:define_method, :added_scrubber, &block)
10
+ end
11
+ end
12
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ class PlyRelation < ActiveRecord::Base
2
+ belongs_to :parent, class_name: 'Ply'
3
+ belongs_to :child, class_name: 'Ply'
4
+ end
@@ -0,0 +1,3 @@
1
+ module TextHelper
2
+ extend ActiveSupport::Inflector
3
+ end