columbo-rails-client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d296dcf93560f489fb7ab4229d254e02cecaeab8
4
+ data.tar.gz: 457c85d4e67981f40d76d3f8c66f22f3200891e2
5
+ SHA512:
6
+ metadata.gz: c53d6c3b1e43a65a34c5f8d6d525a6369e235d565dd564d26f2327c17894aa43ac441ecfc256202584dc487ad879ca166af96d814d60acf864e70d3f15a8a799
7
+ data.tar.gz: 0af15c9a0706ec4bec34428dbb5974ed03b221af8c94718a41f45a62a11ba5a609e2c01f327383b368da866b9783fde5767eace77d956288bae85e5c7ec53f25
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Etienne Bazin
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,305 @@
1
+ # Columbo Rails client
2
+
3
+ This gem provides Rails integrations for Columbo:
4
+
5
+ * easily plugable to ActiveModel and automatically crafts the
6
+ Columbo payload.
7
+ * offers to your models a way to publish events to Columbo.
8
+ * automatic publishings hooked on ActiveRecord Callbacks.
9
+
10
+ ## Installation
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'columbo-rails-client'
15
+ ```
16
+
17
+ And then execute:
18
+ ```bash
19
+ $ bundle
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ `columbo-rails-client` uses `columbo-ruby-client` gem for configuration. See the advanced configuration of the latest [here](https://github.com/wifirst-lab/columbo-ruby-client).
25
+
26
+ For the next examples, the Columbo client is initiliazed like this:
27
+
28
+ ```ruby
29
+ # config/initializers/columbo.rb
30
+
31
+ Columbo.configure do |config|
32
+ config.system.uid = 'crm.my-company.com'
33
+ config.system.label = "My Company's CRM"
34
+ config.system.type = 'CRM'
35
+
36
+ config.client = Columbo::Client::HTTP.new('http://my-company.com/push')
37
+ end
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ### Simplest examples
43
+
44
+ #### Minimal code for publication
45
+
46
+ In each model you want to activate event publication, you must at least:
47
+
48
+ * include module `Columbo::Resource`
49
+ * define the `columbo_actor` method which returns a `Hash` with {:uid, :type, :label} keys.
50
+
51
+ ```ruby
52
+ # app/models/contract.rb
53
+
54
+ class Contract < ApplicationRecord
55
+ include Columbo::Resource
56
+
57
+ def columbo_actor
58
+ { uid: 34, type: "commercial", label: "commercial@my-company.com" }
59
+ end
60
+ end
61
+ ```
62
+
63
+ The next snippet:
64
+
65
+ ```ruby
66
+ c = Contract.new(signed: false)
67
+ c.sign!
68
+
69
+ # Publish an event of type "contract.signed"
70
+ c.columbo.publish('signed')
71
+ ```
72
+
73
+ will publish the next event:
74
+
75
+ ```json
76
+ {
77
+ "system": {
78
+ "uid": "crm.my-company.com",
79
+ "label": "My Company's CRM",
80
+ "type": "CRM"
81
+ },
82
+ "actor": {
83
+ "uid": 34,
84
+ "label": "commercial@my-company.com",
85
+ "type": "commercial"
86
+ },
87
+ "resource": {
88
+ "uid": 1,
89
+ "type": "contract",
90
+ "label": "contract#1",
91
+ "attributes": {
92
+ "id": 1,
93
+ "signed": true,
94
+ "created_at": "2017-01-03T13:08:28.429Z",
95
+ "updated_at": "2017-01-03T13:08:28.429Z"
96
+ }
97
+ },
98
+ "related_resources": null,
99
+ "timestamp": "2017-01-03T13:16:32Z",
100
+ "action": "contract.signed"
101
+ }
102
+ ```
103
+
104
+ The `publish` method returns `true` or `false` if the operation succeeded or not. You can also use the `publish!` method if you want to raise an error if the operation fails.
105
+
106
+ ##### Note on AMQP client
107
+
108
+ If you use the AMQP client, the `publish` method accepts a second option parameter which fits the options `Hash` understable by `Bunny` gem. Values for these options are available [here](http://reference.rubybunny.info/Bunny/Exchange.html#publish-instance_method).
109
+
110
+ For example, the default `routing_key` for the previous event shown above is 'contract.signed' (equal to the action). You could override the `routing_key` by giving it as an option entry in the `publish` method:
111
+
112
+ ```ruby
113
+ c.columbo.publish('signed', routing_key: 'contract.approved')
114
+ ```
115
+
116
+ #### Automatic callbacks
117
+
118
+ You can include `Columbo::Resource::Callbacks` in your models to
119
+ automatically hook publishings on the next three Rails callbacks :
120
+
121
+ * `create`
122
+ * `update`
123
+ * `destroy`
124
+
125
+ For example, for the next model:
126
+
127
+ ```ruby
128
+ class Contract < ApplicationRecord
129
+ include Columbo::Resource
130
+ include Columbo::Resource::Callbacks
131
+ end
132
+ ```
133
+
134
+ Respectively on `after_create`, `after_update` and `after_destroy` callbacks, any `Contract` record will publish an event with these actions names:
135
+
136
+ * `contract.created`
137
+ * `contract.updated`
138
+ * `contract.destroyed`
139
+
140
+ ### Override default values of the event payload
141
+
142
+ #### Override at the instance level
143
+
144
+ As seen above, the event is automatically crafted from the model included the `Columbo::Resource` module. You can override some parts of the crafted event by implemented in your model:
145
+
146
+ * `columbo_payload` method to override the attributes of the resource.
147
+ * `columbo_resource_label` method to override the label of the resource.
148
+ * `columbo_related_resources` method to override the related resources array.
149
+
150
+ ```ruby
151
+ class Contract < ApplicationRecord
152
+
153
+ include Columbo::Resource
154
+ include Columbo::Resource::Callbacks
155
+
156
+ has_one :client
157
+
158
+ # This method is called to create the attributes of the resources Columbo event hash.
159
+ # It should return a hash which fits the mapping you provided to Columbo for this resource.
160
+ # Here we add an extra info attribute to the payload sent to Columbo
161
+ def columbo_payload
162
+ as_json.merge({ client: client.id })
163
+ end
164
+
165
+ # this method is called to override the label of the resource Columbo event.
166
+ def columbo_resource_label
167
+ if signed?
168
+ 'Unsigned contract'
169
+ else
170
+ 'Signed contract'
171
+ end
172
+ end
173
+
174
+ # this method is called to create the related_resources array
175
+ def related_resources
176
+ [{ uid: client.id, type: 'client' }]
177
+ end
178
+
179
+ # compulsory method, see the previous example
180
+ def columbo_actor
181
+ { uid: 34, type: "commercial", label: "commercial@my-company.com" }
182
+ end
183
+ end
184
+ ```
185
+
186
+ The next snippet:
187
+
188
+ ```ruby
189
+ Contract.create(signed: false, client: Client.find(4))
190
+ ```
191
+
192
+ will publish the next event:
193
+
194
+ ```json
195
+ {
196
+ "system": {
197
+ "uid": "crm.my-company.com",
198
+ "label": "My Company's CRM",
199
+ "type": "CRM"
200
+ },
201
+ "actor": {
202
+ "uid": 34,
203
+ "type": "commercial",
204
+ "label": "commercial@my-company.com"
205
+ },
206
+ "resource": {
207
+ "uid": 3,
208
+ "type": "contract",
209
+ "label": "Unsigned contract",
210
+ "attributes": {
211
+ "id": 3,
212
+ "signed": false,
213
+ "created_at": "2017-01-03T13:08:28.429Z",
214
+ "updated_at": "2017-01-03T13:08:28.429Z",
215
+ "client": 4
216
+ }
217
+ },
218
+ "related_resources": [{"uid": 5, "type": "commercial_office"}],
219
+ "timestamp": "2017-01-03T15:57:37Z",
220
+ "action": "contract.created"
221
+ }
222
+ ```
223
+
224
+ #### Override at publish time
225
+
226
+ `publish` and `publish!` methods can take a block as 3rd parameter to locally override a part of the event Columbo payload. The next table gathers all parts of the payload you can override:
227
+
228
+ |Name |Expected values|
229
+ |---- |---------------|
230
+ |actor| Hash with 3 keys: (:uid, :label, :type)|
231
+ |system| Hash with 3 keys: (:uid, :label, :type)|
232
+ |resource| Hash with one of these keys: (:uid, :label, :type, :attributes)|
233
+ |related_resources|Array of Hash with 2 keys: (:uid, :type) or nil|
234
+ |action| the action name (string)|
235
+ |timestamp| DateTime in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string format (UTC)|
236
+
237
+ The next snippet:
238
+
239
+ ```ruby
240
+ c = Contract.find(3)
241
+ c.complete!
242
+
243
+ c.columbo.publish 'completed' do |info|
244
+ info.system = { uid: 'accounting.my-company.com', label: "My Company's Accounting", type: 'Accounting' }
245
+ info.actor = { uid: 30, label: 'accountant@my-company.com', type: 'accountant'}
246
+ end
247
+ ```
248
+
249
+ will publish the next event:
250
+
251
+ ```json
252
+ {
253
+ "system": {
254
+ "uid": "accounting.my-company.com",
255
+ "label": "My Company's Accounting",
256
+ "type": "Accounting"
257
+ },
258
+ "actor": {
259
+ "uid": 30,
260
+ "label": "accountant@my-company.com",
261
+ "type": "accountant"
262
+ },
263
+ "resource": {
264
+ "uid": 3,
265
+ "type": "contract",
266
+ "label": "Signed contract",
267
+ "client": 7,
268
+ "attributes": {
269
+ "id": 3,
270
+ "signed": true,
271
+ "created_at": "2017-01-03T13:08:28.429Z",
272
+ "updated_at": "2017-01-03T13:08:28.429Z"
273
+ }
274
+ },
275
+ "related_resources": [{"uid": 5, "type": "commercial_office"}],
276
+ "timestamp": "2017-01-03T15:51:49Z",
277
+ "action": "contract.completed"
278
+ }
279
+ ```
280
+
281
+ You can still pass `options` to the publisher:
282
+
283
+ ```ruby
284
+ c = Contract.create(signed: false)
285
+
286
+ c.columbo.publish 'completed', routing_key: 'contract.closed' do |info|
287
+ info.system = { uid: 'accounting.my-company.com', label: "My Company's Accounting", type: 'Accounting' }
288
+ info.actor = { uid: 30, label: 'accountant@my-company.com', type: 'accountant'}
289
+ end
290
+ ```
291
+
292
+ ## Test your app with this gem
293
+
294
+ ### With Rspec
295
+
296
+ In your rails application spec/rails_helper.rb, you can easily silent
297
+ the publish method with:
298
+
299
+ ```ruby
300
+ RSpec.configure do |config|
301
+ config.before(:suite) do
302
+ allow_any_instance_of(Columbo::Resource::Publisher).to receive(:publish)
303
+ end
304
+ end
305
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ require 'columbo-client'
2
+ require 'columbo_rails_client/publisher'
3
+ require 'columbo_rails_client/resource'
4
+ require 'columbo_rails_client/callbacks'
@@ -0,0 +1,20 @@
1
+ module Columbo
2
+ module Resource
3
+ module Callbacks
4
+ def self.included(base)
5
+ base.class_eval do
6
+ after_create :publish_create_event
7
+ after_update :publish_update_event
8
+ after_destroy :publish_destroy_event
9
+ end
10
+ end
11
+
12
+ %w(create update destroy).each do |action|
13
+ define_method("publish_#{action}_event") do
14
+ action_name = action == 'destroy' ? "#{action}ed" : "#{action}d"
15
+ self.columbo.publish("#{action_name}")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,85 @@
1
+ module Columbo
2
+ module Resource
3
+ class Publisher
4
+
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def publish(event_type, options = {}, &block)
10
+ begin
11
+ publish_event(event_type, options, &block)
12
+ rescue Exception => e
13
+ Columbo.logger.warn(e.message)
14
+ false
15
+ end
16
+ end
17
+
18
+ def publish!(event_type, options = {}, &block)
19
+ publish_event(event_type, options, &block)
20
+ end
21
+
22
+ private
23
+
24
+ def publish_event(event_type, options, &block)
25
+ @payload = OpenStruct.new(resource: {})
26
+ block.call(@payload) if block_given?
27
+
28
+ if Columbo.client.is_a? Columbo::Client::AMQP
29
+ options = { routing_key: "#{@object.class.name.underscore}.#{event_type}" }.merge(options)
30
+ end
31
+
32
+ Columbo.client.publish(build_event(event_type), options)
33
+ end
34
+
35
+ def resource
36
+ resource_label = @payload.resource[:label]
37
+ if resource_label.nil?
38
+ resource_label = @object.respond_to?(:columbo_resource_label) ? @object.columbo_resource_label : default_resource_label
39
+ end
40
+
41
+ resource_attributes = @payload.resource[:attributes]
42
+ if resource_attributes.nil?
43
+ resource_attributes = @object.respond_to?(:columbo_payload) ? @object.columbo_payload : @object.as_json
44
+ end
45
+
46
+ {
47
+ uid: @payload.resource[:uid] || @object.id,
48
+ type: @payload.resource[:type] || @object.class.name.underscore,
49
+ label: resource_label,
50
+ attributes: resource_attributes
51
+ }
52
+ end
53
+
54
+ def system
55
+ @payload.system || Columbo.configuration.system.to_h
56
+ end
57
+
58
+ def actor
59
+ @payload.actor || @object.columbo_actor
60
+ end
61
+
62
+ def related_resources
63
+ related_resources = @payload.related_resources
64
+ if related_resources.nil?
65
+ related_resources = @object.respond_to?(:columbo_related_resources) ? @object.columbo_related_resources : nil
66
+ end
67
+ end
68
+
69
+ def default_resource_label
70
+ "#{@object.class.name.underscore}##{@object.id}"
71
+ end
72
+
73
+ def build_event(event_type)
74
+ {
75
+ system: system,
76
+ actor: actor,
77
+ resource: resource,
78
+ related_resources: related_resources,
79
+ timestamp: @payload.timestamp || DateTime.now.utc.to_formatted_s(:iso8601),
80
+ action: @payload.action || "#{@object.class.name.underscore}.#{event_type}"
81
+ }
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,7 @@
1
+ module Columbo
2
+ module Resource
3
+ def columbo
4
+ ::Columbo::Resource::Publisher.new(self)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Columbo
2
+ module ResourcePublisher
3
+ VERSION = '0.1.1'
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :columbo_rails_client do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: columbo-rails-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Wifirst
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: columbo-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A simple Rails client for Columbo, easely plugable to ActiveRecord
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - MIT-LICENSE
76
+ - README.md
77
+ - Rakefile
78
+ - lib/columbo-rails-client.rb
79
+ - lib/columbo_rails_client/callbacks.rb
80
+ - lib/columbo_rails_client/publisher.rb
81
+ - lib/columbo_rails_client/resource.rb
82
+ - lib/columbo_rails_client/version.rb
83
+ - lib/tasks/columbo_rails_client_tasks.rake
84
+ homepage: https://github.com/wifirst-lab/columbo-ruby-client
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.5.1
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: A simple Rails client for Columbo, easely plugable to ActiveRecord
108
+ test_files: []