la_maquina 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3e37589f3930b79eecc19e0743e9b6b1fcf1d9f
4
- data.tar.gz: c332e847878318ab3db7c764f7f19738b41d2338
3
+ metadata.gz: cfe629f6f7df101c2c54c842e0fdbd8c05e0f663
4
+ data.tar.gz: 0f7cacda20c45ae5a0bad8db868cecc60ad4a455
5
5
  SHA512:
6
- metadata.gz: 22aad45ed90d3542aedb927e47399297c0369fd17fcf6b786958704a75a62c1382832f99525987c477856c24f595e95c1ee9ad2b2bbc6a094a4e70c0ff0885ab
7
- data.tar.gz: ae9ddc8d32213ca73d940d3eea5abb1dce9e984f4423be28bf4750d432c0d4a03d53e5b4db7f8f9bc6b5b5adfce687e44873dba279735036b7b883a872fa54a0
6
+ metadata.gz: 18482c2158276e90c16d474ae744f2431d6ced0a3a2ff4111914016becf9fdbd2330ba86837fdf732ce14b793cdb7bebe7c482916a26a8330dbaea8f983e1458
7
+ data.tar.gz: 7b2626cbb36fac8bed0e69b4418a33be3a63d5f996cefb924b616d7ac3f21ce7e343a8907005454a7b62a7f98c548c87a98116372accab23bbb077084adb1355
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- la_maquina (0.0.3)
4
+ la_maquina (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,31 +1,96 @@
1
1
  # La Maquina
2
2
 
3
- Model graph traversal
3
+ Non-database-based arbitrary updates of `belongs_to` associated ActiveRecord models.
4
4
 
5
- ## Installation
5
+ Let's say you have 2 models
6
+ ```ruby
7
+ class DannyTrejo < ActiveRecord::Base
8
+ has_many :machetes
9
+ end
10
+ ```
11
+ and
12
+ ```ruby
13
+ class Machete < ActiveRecord::Base
14
+ belongs_to :danny_trejo
15
+ end
16
+ ```
17
+ and you want to let `DannyTrejo` know when a `Machete` has been updated, but you don't want to use `ActiveRecord`'s `touch`, you can use this gem to execute arbitrary code when `Machete` updates.
6
18
 
7
- Add this line to your application's Gemfile:
19
+ ## Example
8
20
 
9
- gem 'la_maquina'
21
+ Using the example above, let's say that when a `Machete` is added, we want its corresponding `DannyTrejo` object to be reindexed by Solr, using the Sunspot interface. With a little bit of config magic, described at the end of this document, we have this:
10
22
 
11
- And then execute:
23
+ ```ruby
24
+ class DannyTrejo < ActiveRecord::Base
25
+ has_many :machetes
12
26
 
13
- $ bundle
27
+ searchable do
28
+ double :machete_sharpness, multiple: true do
29
+ machetes.map(&:sharpness)
30
+ end
31
+ end
32
+ end
33
+ ```
14
34
 
15
- Or install it yourself as:
35
+ ```ruby
36
+ class Machete < ActiveRecord::Base
37
+ belongs_to :danny_trejo
16
38
 
17
- $ gem install la_maquina
39
+ include LaMaquina::Notifier
40
+ notifies_about :danny_trejo
41
+ end
42
+ ```
18
43
 
19
44
  ## Usage
20
45
 
46
+ There are 4 main components to this gem:
47
+
48
+ * `notifies_about`: defines the association (eg `Machete` -> `DannyTrejo`)
49
+ * Pistons: the plugins that define the behavior (eg `DannyTrejo.find(id).solr_index!`)
50
+ * ErrorNotifier: defines what you do with the errors once they come up
51
+ * DependencyMap: define the mapping between the notifier and notified classes. *OPTIONAL*
21
52
 
53
+ ### notifies_about options
54
+
55
+ `notifies_about target, options ` is an interface that and mirrors ActiveRecord associations.
56
+ to use it, in your `ActiveRecord::Base` model
57
+ ```ruby
58
+ include LaMaquina::Notifier
59
+ ```
60
+ It can either notify LaMaquina about the object itself with `notifies_about :self`, or about a `belongs_to` association with the following options:
61
+
62
+ * `:through`: same as rails. Note: expects the through object belongs_to the target object
63
+ * `:polymorphic`: same as rails. Note: expects rails default target `_type` and targe `_id` fields to be present
64
+ * `:class_name`: takes a modulized camelcased string name of the target class
65
+ * `:class`: takes a class constant of the target class type
66
+ * `:using`: this allows you to send update messages through a ruby interface (eg [JsonApiClient](https://github.com/chingor13/json_api_client)). The interface has to respond to `notify( params = {} )`.
67
+ The params are as follows:
68
+ * `:notified_class`: demodulized snake_cased name of class that is notified about (eg "danny_trejo")
69
+ * `notified_id`: the id of thje object that's being notified about. So if `Machete`(8) belongs to `DannyTrejo`(1), it will be 1
70
+ * `notifier_class`: demodulized snake_cased name of the notifier class (eg "machete")
71
+ **Note:** This requires the receiving side to call `LaMaquina::Engine.notify( notifier_class, id, notified_class = "" )`, so you'll have something like
72
+ ```ruby
73
+ class LaMaquinaController < ApplicationController
74
+ def notify
75
+ notified_class = params[:notified_class]
76
+ notified_id = params[:notified_id]
77
+ notifier_class = params[:notifier_class]
78
+
79
+ LaMaquina::Engine.notify notifier_class, id, notified_class
80
+
81
+ render json: {success: true}
82
+ end
83
+ end
84
+ ```
85
+ Note: `class` and `class_name` options aren't stricly checked; they're formatted and sent through
22
86
 
23
87
  ### Pistons
24
88
 
25
- Once the `Engine` is called it fires the `Piston`s, the behavior of which is entirely up to you.
89
+ A piston is a plugin that can be fired on update.
26
90
 
27
- So, let's say, we have a couple objects that look like:
91
+ Once a model with a `notifies_about :whatever` gets updated and a commit happens, it will fire off a call to wherever LaMaquina is installed (either locally, or on another server if you're notifying through `JsonApiClient` or similar). Once LaMaquina::Engine receives the call it will fire all of its pistons in no particualr order.
28
92
 
93
+ So using the example from above:
29
94
  ```ruby
30
95
  class DannyTrejo < ActiveRecord::Base
31
96
  has_many :machetes
@@ -45,15 +110,14 @@ class Machete < ActiveRecord::Base
45
110
  notifies_about :danny_trejo
46
111
  end
47
112
  ```
48
- and we want to let `DannyTrejo` know when his `Machete` has been updated so that we can reindex him.
113
+ We want to set up a piston that will reindex `DannyTrejo` on `Machete` update.
49
114
 
50
- `Machete` is set up to fire on update, so we'll set up a listener Piston that looks like this:
51
115
 
52
116
  ```ruby
53
117
  class SunspotPiston < LaMaquina::Piston::Base
54
118
  class << self
55
119
  def fire!( notified_class, id, notifier_class = "" )
56
- indexed_class(notified_class).find(id).index!
120
+ indexed_class(notified_class).find(id).solr_index!
57
121
  end
58
122
 
59
123
  private
@@ -65,26 +129,78 @@ class SunspotPiston < LaMaquina::Piston::Base
65
129
  end
66
130
 
67
131
  ```
68
- Which finds the klass, does a find on it and fires off [Sunspot](https://github.com/sunspot/sunspot#reindexing-objects) `index!`
132
+ All it needs to do is respond ot `fire!( notified_class, id, notifier_class = "" )` and what happend from there is entirely up to you.
69
133
 
70
- ### Setup
71
134
 
72
- The setup is pretty straightforward: you do all the setting up in `config/initializers/la_maquina.rb`.
135
+ The piston above doesn't use `notifier_class`, but that comes in quite handy should you want to do complex manipulations.For example, if you have a model that has several associations that respond to `complex_code` and you want to cache that code under a composite cache key of "#{top_object}/#{association}:#{id}", you can do something like:
136
+
137
+ ```ruby
138
+ class CompositeCachePison < LaMaquina::Piston::Base
139
+ class << self
140
+ class_attribute :redis, :map
141
+
142
+ def fire!( notified_class, id, notifier_class )
143
+ key = "#{notified_class}/#{notifier_class}:#{id}"
144
+
145
+ klass = map.mapping_for notified_class
146
+ object = klass.find(id)
73
147
 
74
- The 3 things you have to do are: set up the pistons(if they need configuring), install them, and configure the error_handler.
75
- For example, if you're using the CachePiston and need to set up Redis, here's how your `la_maquina.rb` will look
148
+ # because notifier_class is already snaked we can just send it as an association
149
+ result = object.send(notifier_class).complex_code
150
+
151
+ redis.set key, result
152
+ end
153
+
154
+ # explained below
155
+ self.map = LaMaquina::DependencyMap::ConstantMap.new
156
+ end
157
+ ```
158
+
159
+ ### DependencyMap
160
+
161
+ `DependencyMap` is a way to abstract away the dependency structure from the gem and the piston (like you have in the first piston example).
162
+
163
+ The interface looks like
76
164
 
77
165
  ```ruby
78
- LaMaquina::Piston::CachePiston.redis = Redis::Namespace.new(:cache_piston, redis: Redis.new)
79
- LaMaquina::Engine.install LaMaquina::Piston::CachePiston, TestPiston
80
- LaMaquina.error_notifier = LaMaquina::ErrorNotifier::HoneybadgerNotifier
166
+ class Map < LaMaquina::DependencyMap::Base
167
+ # defined in Base
168
+ # initialize( yaml_path = nil)
169
+
170
+ def mapping_for(*args)
171
+ # your code here
172
+ end
173
+
174
+ # also defined in Base
175
+ # attr_accessor :map
176
+ end
177
+ ```
178
+ LaMaquina comes with 2 default maps: `ConstantMap` and `YamlMap`.
179
+
180
+ `LaMaquina::DependencyMap::ConstantMap` takes a string and tries to constantize it. It's not strictly speaking a map, but it works as you would expect:
181
+ ```ruby
182
+ map = LaMaquina::DependencyMap::ConstantMap.new
183
+ map.mapping_for "danny_trejo" # => DannyTrejo(id: integer, ...)
184
+ ```
185
+ `LaMaquina::DependencyMap::YamlMap` get initialized with a yaml path, parses the yaml and spits out a dependency at any depth, meaning:
186
+ ```yml
187
+ # map.yml
188
+ danny_trejo:
189
+ machete:
190
+ 1: favorite
191
+ 2: dull
81
192
  ```
82
- #### ErrorNotifier
83
- LaMaquina by default comes with an `ErrorNotifier::Base` that will explode in a very unhelpful manner. To override it, you need to change it in the config above and roll a new `ErrorNotifier` that responds to `notify(error, details)`. For example, if you're using Honeybadger, you can use the included `LaMaquina::ErrorNotifiers::HoneybadgerNotifier, which looks like:
193
+ ```ruby
194
+ map = LaMaquina::DependencyMap::YamlMap.new "#{Rail.root}/config/map.yml"
195
+ map.mapping_for "danny_trejo", "machete", 1 # => "favorite"
196
+ ```
197
+
198
+ ### ErrorNotifier
199
+ LaMaquina by default comes with an `ErrorNotifier::Base` that will explode in a very unhelpful manner. To override it, you need to change it in the config above and roll a new `ErrorNotifier` that responds to `notify(error, details)`. For example, if you're using Honeybadger, you can use the included `LaMaquina::ErrorNotifiers::HoneybadgerNotifier`, which looks like:
84
200
  ```ruby
85
201
  class HoneybadgerNotifier < LaMaquina::ErrorNotifier::Base
86
202
  self.notify(error = nil, details = {})
87
- Honeybadger.notify( :error_class => "CacheMachineError: #{error.class.name}",
203
+ Honeybadger.notify( :error_class => "LaMaquinaError: #{error.class.name}",
88
204
  :error_message => error.message,
89
205
  :parameters => details
90
206
  )
@@ -96,6 +212,39 @@ If you *don't* care about your exceptions and want to ignore them, there's a not
96
212
  LaMaquina::Cinegual.error_notifier = LaMaquina::ErrorNotifier::SilentNotifier
97
213
  ```
98
214
 
215
+ ## Setup
216
+
217
+ The setup is pretty straightforward: you do all the setting up in `config/initializers/la_maquina.rb`.
218
+
219
+ The things you have to do are: set up the pistons(if they need configuring), install them, and configure the error_handler.
220
+ For example, if you're using the CompositeCachePison and need to set up Redis, here's how your `la_maquina.rb` will look
221
+
222
+ ```ruby
223
+ CompositeCachePison.redis = Redis::Namespace.new(:cache_piston, redis: Redis.new)
224
+ # you would initialize the map here, not in the piston
225
+ CompositeCachePison.map = LaMaquina::DependencyMap::ConstantMap.new
226
+
227
+ LaMaquina::Engine.install CompositeCachePison
228
+
229
+ LaMaquina.error_notifier = LaMaquina::ErrorNotifier::HoneybadgerNotifier
230
+ ```
231
+
232
+
233
+ ## Installation
234
+
235
+ Add this line to your application's Gemfile:
236
+
237
+ gem 'la_maquina'
238
+
239
+ And then execute:
240
+
241
+ $ bundle
242
+
243
+ Or install it yourself as:
244
+
245
+ $ gem install la_maquina
246
+
247
+
99
248
  ## Contributing
100
249
 
101
250
  1. Fork it ( https://github.com/[my-github-username]/la_maquina/fork )
@@ -2,7 +2,7 @@ module LaMaquina
2
2
  module ErrorNotifier
3
3
  class HoneybadgerNotifier < LaMaquina::ErrorNotifier::Base
4
4
  def notify(error, details = {})
5
- Honeybadger.notify( :error_class => "CacheMachineError: #{error.class.name}",
5
+ Honeybadger.notify( :error_class => "LaMaquinaError: #{error.class.name}",
6
6
  :error_message => error.message,
7
7
  :parameters => details
8
8
  )
@@ -1,3 +1,3 @@
1
1
  module LaMaquina
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,7 @@
1
+ admin:
2
+ trait: trait
3
+
4
+ guest:
5
+ trait:
6
+ - a
7
+ - b
Binary file
@@ -23,4 +23,10 @@ class YamlMapTest < ActiveSupport::TestCase
23
23
  assert 'admin', @map.mapping_for(:admin)
24
24
  assert :admin, @map.mapping_for(:admin)
25
25
  end
26
+
27
+ def test_can_go_to_any_depth
28
+ map = LaMaquina::DependencyMap::YamlMap.new( Rails.root + 'config/la_maquina/dependency_maps/deep_map.yml' )
29
+ assert_equal "trait", map.mapping_for( "admin", "trait" )
30
+ assert_equal "b", map.mapping_for( "guest", "trait", 1 )
31
+ end
26
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: la_maquina
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Orlov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-04 00:00:00.000000000 Z
11
+ date: 2015-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -113,6 +113,7 @@ files:
113
113
  - test/dummy/config/initializers/session_store.rb
114
114
  - test/dummy/config/initializers/wrap_parameters.rb
115
115
  - test/dummy/config/la_maquina/dependency_maps/bad_map.yml
116
+ - test/dummy/config/la_maquina/dependency_maps/deep_map.yml
116
117
  - test/dummy/config/la_maquina/dependency_maps/sunspot_piston.yml
117
118
  - test/dummy/config/locales/en.yml
118
119
  - test/dummy/config/routes.rb
@@ -206,6 +207,7 @@ test_files:
206
207
  - test/dummy/config/initializers/session_store.rb
207
208
  - test/dummy/config/initializers/wrap_parameters.rb
208
209
  - test/dummy/config/la_maquina/dependency_maps/bad_map.yml
210
+ - test/dummy/config/la_maquina/dependency_maps/deep_map.yml
209
211
  - test/dummy/config/la_maquina/dependency_maps/sunspot_piston.yml
210
212
  - test/dummy/config/locales/en.yml
211
213
  - test/dummy/config/routes.rb