pliable 0.1.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.
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