wisper-mongoid 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c417fcf4602a8f9144061fac7f8f77eb490f891a
4
+ data.tar.gz: cb72e823ec94e8202e44f548880390218972e8d1
5
+ SHA512:
6
+ metadata.gz: 0aabd5e0cb1d8c859e348b610890d99acc2406b6af069538c993269a4a5fae814deecf73ec64b17adf6346eb8a564ada07f124411a13d0be91a70a7e8dcced05
7
+ data.tar.gz: e6c541b3b749363dd079d57552297d26f878021ba09422bab0187996b3f88846737729d22e57e17c33f0ece28e1f8e337e9f8b9273e71365468d94551a16e986
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/db.sqlite3
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ bundler_args: --without=metrics
3
+ script: bundle exec rspec spec
4
+ gemfile:
5
+ - gemfiles/mongoid-3.1
6
+ - gemfiles/mongoid-4.0
7
+ rvm:
8
+ - '1.9.3'
9
+ - '2.2.0'
10
+ - jruby
11
+ - rbx-2
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 (24 Mar 2015)
2
+
3
+ * Initial implementation based on krisleech/wisper-activerecord (Adrian Perez / blackxored)
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rubysl', '~> 2.0', :platforms => :rbx
6
+
7
+ gem 'bundler', '~> 1.5'
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'pry'
11
+
12
+ group :metrics do
13
+ gem 'flay'
14
+ gem 'simplecov'
15
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Kris Leech
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,199 @@
1
+ # Wisper::Mongoid
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/wisper-mongoid.png)](http://badge.fury.io/rb/wisper-mongoid)
4
+ [![Code Climate](https://codeclimate.com/github/blackxored/wisper-mongoid.png)](https://codeclimate.com/github/blackxored/wisper-mongoid)
5
+ [![Build Status](https://travis-ci.org/blackxored/wisper-mongoid.png?branch=master)](https://travis-ci.org/blackxored/wisper-mongoid)
6
+
7
+ Transparently publish model lifecycle events to subscribers.
8
+
9
+ Using Wisper events is a better alternative to Mongoid callbacks and Observers.
10
+
11
+ Listeners are subscribed to models at runtime.
12
+
13
+ ## Installation
14
+
15
+ ```ruby
16
+ gem 'wisper-mongoid'
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Setup a publisher
22
+
23
+ ```ruby
24
+ class Meeting
25
+ include Mongoid::Document
26
+ include Wisper.model
27
+
28
+ # ...
29
+ end
30
+ ```
31
+
32
+ If you wish all models to broadcast events without having to explicitly include
33
+ `Wisper.model` add the following to an initializer:
34
+
35
+ ```ruby
36
+ Wisper::Mongoid.extend_all
37
+ ```
38
+
39
+ ### Subscribing
40
+
41
+ Subscribe a listener to model instances:
42
+
43
+ ```ruby
44
+ meeting = Meeting.new
45
+ meeting.subscribe(Auditor.new)
46
+ ```
47
+
48
+ Subscribe a block to model instances:
49
+
50
+ ```ruby
51
+ meeting.on(:create_meeting_successful) { |meeting| ... }
52
+ ```
53
+
54
+ Subscribe a listener to _all_ instances of a model:
55
+
56
+ ```ruby
57
+ Meeting.subscribe(Auditor.new)
58
+ ```
59
+
60
+ Please refer to the [Wisper README](https://github.com/krisleech/wisper) for full details about subscribing.
61
+
62
+ The events which are automatically broadcast are:
63
+
64
+ * `after_create`
65
+ * `after_destroy`
66
+ * `create_<model_name>_{successful, failed}`
67
+ * `update_<model_name>_{successful, failed}`
68
+ * `destroy_<model_name>_successful`
69
+
70
+ ### Reacting to Events
71
+
72
+ To receive an event the listener must implement a method matching the name of
73
+ the event with a single argument, the instance of the model.
74
+
75
+ ```ruby
76
+ def create_meeting_successful(meeting)
77
+ # ...
78
+ end
79
+ ```
80
+
81
+ ## Example
82
+
83
+ ### Controller
84
+
85
+ ```ruby
86
+ class MeetingsController < ApplicationController
87
+ def new
88
+ @meeting = Meeting.new
89
+ end
90
+
91
+ def create
92
+ @meeting = Meeting.new(params[:meeting])
93
+ @meeting.subscribe(Auditor.instance)
94
+ @meeting.on(:meeting_create_successful) { redirect_to meeting_path }
95
+ @meeting.on(:meeting_create_failed) { render action: :new }
96
+ @meeting.save
97
+ end
98
+
99
+ def edit
100
+ @meeting = Meeting.find(params[:id])
101
+ end
102
+
103
+ def update
104
+ @meeting = Meeting.find(params[:id])
105
+ @meeting.subscribe(Auditor.instance)
106
+ @meeting.on(:meeting_update_successful) { redirect_to meeting_path }
107
+ @meeting.on(:meeting_update_failed) { render :action => :edit }
108
+ @meeting.update_attributes(params[:meeting])
109
+ end
110
+ end
111
+ ```
112
+
113
+ Using `on` to subscribe a block to handle the response is optional,
114
+ you can still use `if @meeting.save` if you prefer.
115
+
116
+ ### Listener
117
+
118
+ **Which simply records an audit in memory**
119
+
120
+ ```ruby
121
+ class Auditor
122
+ include Singleton
123
+
124
+ attr_accessor :audit
125
+
126
+ def initialize
127
+ @audit = []
128
+ end
129
+
130
+ def after_create(subject)
131
+ push_audit_for('create', subject)
132
+ end
133
+
134
+ def after_update(subject)
135
+ push_audit_for('update', subject)
136
+ end
137
+
138
+ def after_destroy(subject)
139
+ push_audit_for('destroy', subject)
140
+ end
141
+
142
+ def self.audit
143
+ instance.audit
144
+ end
145
+
146
+ private
147
+
148
+ def push_audit_for(action, subject)
149
+ audit.push(audit_for(action, subject))
150
+ end
151
+
152
+ def audit_for(action, subject)
153
+ {
154
+ action: action,
155
+ subject_id: subject.id,
156
+ subject_class: subject.class.to_s,
157
+ changes: subject.previous_changes,
158
+ created_at: Time.now
159
+ }
160
+ end
161
+ end
162
+ ```
163
+
164
+ **Do some CRUD**
165
+
166
+ ```ruby
167
+ Meeting.create(:description => 'Team Retrospective', :starts_at => Time.now + 2.days)
168
+
169
+ meeting = Meeting.find(1)
170
+ meeting.starts_at = Time.now + 2.months
171
+ meeting.save
172
+ ```
173
+
174
+ **And check the audit**
175
+
176
+ ```ruby
177
+ Auditor.audit # => [...]
178
+ ```
179
+
180
+ ## Compatibility
181
+
182
+ Tested on 1.9.3, 2.x, Rubinius and JRuby for Mongoid ~> 3.1, ~> 4.0
183
+
184
+ See the CI [build status](https://travis-ci.org/blackxored/wisper-mongoid) for more information.
185
+
186
+ ## Special Thanks
187
+
188
+ Special thanks to krisleech for creating `wisper` and `wisper-activerecord`,
189
+ this implementation is heavily based on the later.
190
+
191
+ ## Contributing
192
+
193
+ Please submit a Pull Request with specs.
194
+
195
+ ### Running the specs
196
+
197
+ ```
198
+ bundle exec rspec
199
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rubysl', '~> 2.0', :platforms => :rbx
4
+
5
+ gem 'rspec'
6
+
7
+ gem 'mongoid', '~> 3.1'
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rubysl', '~> 2.0', :platforms => :rbx
4
+
5
+ gem 'rspec'
6
+
7
+ gem 'mongoid', '~> 4.0'
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1 @@
1
+ require "wisper/active_record"
@@ -0,0 +1,15 @@
1
+ require "wisper/mongoid/version"
2
+ require "wisper/mongoid/publisher"
3
+
4
+ module Wisper
5
+ def self.model
6
+ ::Wisper::Mongoid::Publisher
7
+ end
8
+
9
+ module Mongoid
10
+ def self.extend_all
11
+ # TODO: Include model on all mongoid documents
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ module Wisper
2
+ module Mongoid
3
+ module Publisher
4
+ extend ActiveSupport::Concern
5
+ included do
6
+
7
+ include Wisper::Publisher
8
+
9
+ after_validation :after_validation_broadcast
10
+ after_create :after_create_broadcast, on: :create
11
+ after_update :after_update_broadcast, on: :update
12
+ after_destroy :after_destroy_broadcast, on: :destroy
13
+ end
14
+
15
+ def commit(_attributes = nil)
16
+ warn "[DEPRECATED] use save, create, update_attributes as usual"
17
+ assign_attributes(_attributes) if _attributes.present?
18
+ save
19
+ end
20
+
21
+ module ClassMethods
22
+ def commit(_attributes = nil)
23
+ warn "[DEPRECATED] use save, create, update_attributes as usual"
24
+ new(_attributes).save
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def after_validation_broadcast
31
+ action = new_record? ? 'create' : 'update'
32
+ broadcast("#{action}_#{broadcast_model_name_key}_failed", self) unless errors.empty?
33
+ end
34
+
35
+ def after_create_broadcast
36
+ broadcast(:after_create, self)
37
+ broadcast("create_#{broadcast_model_name_key}_successful", self)
38
+ end
39
+
40
+ def after_update_broadcast
41
+ broadcast(:after_update, self)
42
+ broadcast("update_#{broadcast_model_name_key}_successful", self)
43
+ end
44
+
45
+ def after_destroy_broadcast
46
+ broadcast(:after_destroy, self)
47
+ broadcast("destroy_#{broadcast_model_name_key}_successful", self)
48
+ end
49
+
50
+ def broadcast_model_name_key
51
+ self.class.model_name.param_key
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module Wisper
2
+ module Mongoid
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,43 @@
1
+ begin
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ end
6
+ rescue LoadError
7
+ end
8
+
9
+ require 'pry'
10
+ require 'wisper'
11
+ require 'mongoid'
12
+
13
+ puts "Using Mongoid #{Mongoid::VERSION}"
14
+
15
+ Mongoid.load!("spec/support/mongoid.yml", :test)
16
+
17
+ require 'wisper/mongoid'
18
+ require 'support/models'
19
+
20
+ RSpec.configure do |config|
21
+ config.filter_run :focus
22
+ config.run_all_when_everything_filtered = true
23
+
24
+ if config.files_to_run.one?
25
+ config.full_backtrace = true
26
+ config.default_formatter = 'doc'
27
+ end
28
+
29
+ config.profile_examples = 10
30
+
31
+ config.order = :random
32
+
33
+ Kernel.srand config.seed
34
+
35
+ config.expect_with :rspec do |expectations|
36
+ expectations.syntax = :expect
37
+ end
38
+
39
+ config.mock_with :rspec do |mocks|
40
+ mocks.syntax = :expect
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ class Meeting
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include Wisper.model
5
+
6
+ field :title, default: "My Meeting"
7
+ field :location
8
+
9
+ validates :title, presence: true
10
+ end
@@ -0,0 +1,6 @@
1
+ test:
2
+ sessions:
3
+ default:
4
+ database: wisper_test
5
+ hosts:
6
+ - localhost:27017
@@ -0,0 +1,86 @@
1
+ describe 'Mongoid' do
2
+ let(:listener) { double('Listener') }
3
+ let(:model_class) { Meeting }
4
+
5
+ before { Wisper::GlobalListeners.clear }
6
+
7
+ it '.model returns Mongoid module' do
8
+ expect(Wisper.model).to eq(Wisper::Mongoid::Publisher)
9
+ end
10
+
11
+ describe 'when creating' do
12
+ context 'and model is valid' do
13
+ it 'publishes create_<model_name>_successful event to listener' do
14
+ expect(listener).to receive(:create_meeting_successful).with(instance_of(model_class))
15
+ model_class.subscribe(listener)
16
+ model_class.create
17
+ end
18
+ end
19
+
20
+ context 'and model is not valid' do
21
+ it 'publishes create_<model_name>_failed event to listener' do
22
+ expect(listener).to receive(:create_meeting_failed).with(instance_of(model_class))
23
+ model_class.subscribe(listener)
24
+ model_class.create(title: nil)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe 'when updating' do
30
+ before do
31
+ model_class.create!
32
+ end
33
+
34
+ let(:model) { model_class.first }
35
+
36
+ context 'and model is valid' do
37
+ it 'publishes update_<model_name>_successful event to listener' do
38
+ expect(listener).to receive(:update_meeting_successful).with(instance_of(model_class))
39
+ model_class.subscribe(listener)
40
+ model.title = 'foo'
41
+ model.save
42
+ end
43
+ end
44
+
45
+ context 'and model is not valid' do
46
+ it 'publishes update_<model_name>_failed event to listener' do
47
+ expect(listener).to receive(:update_meeting_failed).with(instance_of(model_class))
48
+ model_class.subscribe(listener)
49
+ model.title = nil
50
+ model.save
51
+ end
52
+ end
53
+ end
54
+
55
+ describe 'create' do
56
+ it 'publishes an after_create event to listener' do
57
+ expect(listener).to receive(:after_create).with(instance_of(model_class))
58
+ model_class.subscribe(listener)
59
+ model_class.create
60
+ end
61
+ end
62
+
63
+ describe 'update' do
64
+ before { model_class.create! }
65
+
66
+ let(:model) { model_class.first }
67
+
68
+ it 'publishes an after_update event to listener' do
69
+ expect(listener).to receive(:after_update).with(instance_of(model_class))
70
+ model.subscribe(listener)
71
+ model.update_attributes(title: 'new title')
72
+ end
73
+ end
74
+
75
+ describe 'destroy' do
76
+ before { model_class.create! }
77
+
78
+ let(:model) { model_class.first }
79
+
80
+ it 'publishes an after_destroy event to listener' do
81
+ expect(listener).to receive(:after_destroy).with(instance_of(model_class))
82
+ model_class.subscribe(listener)
83
+ model.destroy
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,12 @@
1
+ describe Wisper::Mongoid::Publisher do
2
+
3
+ it 'includes Wisper::Publisher' do
4
+ klass = Class.new do
5
+ include Mongoid::Document
6
+ include Mongoid::Timestamps
7
+ include Wisper::Mongoid::Publisher
8
+ end
9
+
10
+ expect(klass.ancestors).to include Wisper::Publisher
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wisper/mongoid/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wisper-mongoid"
8
+ spec.version = Wisper::Mongoid::VERSION
9
+ spec.authors = ["Adrian Perez"]
10
+ spec.email = ["adrianperez.deb@gmail.com"]
11
+ spec.summary = %q{Subscribe to changes on Mongoid models}
12
+ spec.description = %q{Subscribe to changes on Mongoid models}
13
+ spec.homepage = "https://github.com/blackxored/wisper-mongoid"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = ">= 1.9.3"
21
+
22
+ spec.add_dependency "wisper", "~> 1.3"
23
+ spec.add_dependency "mongoid", ">= 3.1", "< 5"
24
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wisper-mongoid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adrian Perez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: wisper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mongoid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '5'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '3.1'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '5'
47
+ description: Subscribe to changes on Mongoid models
48
+ email:
49
+ - adrianperez.deb@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - ".gitignore"
55
+ - ".rspec"
56
+ - ".travis.yml"
57
+ - CHANGELOG.md
58
+ - Gemfile
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - gemfiles/mongoid-3.1
63
+ - gemfiles/mongoid-4.0
64
+ - lib/wisper/activerecord.rb
65
+ - lib/wisper/mongoid.rb
66
+ - lib/wisper/mongoid/publisher.rb
67
+ - lib/wisper/mongoid/version.rb
68
+ - spec/spec_helper.rb
69
+ - spec/support/models.rb
70
+ - spec/support/mongoid.yml
71
+ - spec/wisper/mongoid_spec.rb
72
+ - spec/wisper/publisher_spec.rb
73
+ - wisper-mongoid.gemspec
74
+ homepage: https://github.com/blackxored/wisper-mongoid
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.9.3
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.4.5
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Subscribe to changes on Mongoid models
98
+ test_files:
99
+ - spec/spec_helper.rb
100
+ - spec/support/models.rb
101
+ - spec/support/mongoid.yml
102
+ - spec/wisper/mongoid_spec.rb
103
+ - spec/wisper/publisher_spec.rb
104
+ has_rdoc: