fhwang-wisper-mongoid 0.2.0

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: e37dcd3e930ce14156e0a47db00a2c91c42904bd
4
+ data.tar.gz: 1177c7a81f51e1662868be879e057f3a8084b13e
5
+ SHA512:
6
+ metadata.gz: d7ae1facc4341726c82bdbf53f1d1c12e61bfb0ef6a828e7c4972db25b77ed41f6f0732355288a0cda47dfe052ff5e1f2fec875951e3e766fd36dfdff00aa3d7
7
+ data.tar.gz: da5c17d2b99d9ef44aa1d006b45ad8934a09608bbdd1789f3e4c53caf129a69b9ca923b6f8d54462d621c0d1eb8ccb5511079efb1988b42898cf1b369ff30487
data/.gitignore ADDED
@@ -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
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
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
12
+ services:
13
+ - mongodb
data/CHANGELOG.md ADDED
@@ -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,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rubysl', '~> 2.0', platforms: :rbx
6
+
7
+ gem 'bundler'
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'pry'
11
+
12
+ group :metrics do
13
+ gem 'flay'
14
+ end
data/LICENSE.txt ADDED
@@ -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.
data/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # Wisper::Mongoid
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/fhwang-wisper-mongoid.png)](http://badge.fury.io/rb/fhwang-wisper-mongoid)
4
+
5
+ Transparently publish model lifecycle events to subscribers.
6
+
7
+ Using Wisper events is a better alternative to Mongoid callbacks and Observers.
8
+
9
+ Listeners are subscribed to models at runtime.
10
+
11
+ ## Installation
12
+
13
+ ```ruby
14
+ gem 'fhwang-wisper-mongoid'
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Setup a publisher
20
+
21
+ ```ruby
22
+ class Meeting
23
+ include Mongoid::Document
24
+ include Wisper.model
25
+
26
+ # ...
27
+ end
28
+ ```
29
+
30
+ If you wish all models to broadcast events without having to explicitly include
31
+ `Wisper.model` add the following to an initializer:
32
+
33
+ ```ruby
34
+ Wisper::Mongoid.extend_all
35
+ ```
36
+
37
+ ### Subscribing
38
+
39
+ Subscribe a listener to model instances:
40
+
41
+ ```ruby
42
+ meeting = Meeting.new
43
+ meeting.subscribe(Auditor.new)
44
+ ```
45
+
46
+ Subscribe a block to model instances:
47
+
48
+ ```ruby
49
+ meeting.on(:create_meeting_successful) { |meeting| ... }
50
+ ```
51
+
52
+ Subscribe a listener to _all_ instances of a model:
53
+
54
+ ```ruby
55
+ Meeting.subscribe(Auditor.new)
56
+ ```
57
+
58
+ Please refer to the [Wisper README](https://github.com/krisleech/wisper) for full details about subscribing.
59
+
60
+ The events which are automatically broadcast are:
61
+
62
+ * `after_create`
63
+ * `after_destroy`
64
+ * `create_<model_name>_{successful, failed}`
65
+ * `update_<model_name>_{successful, failed}`
66
+ * `destroy_<model_name>_successful`
67
+
68
+ ### Reacting to Events
69
+
70
+ To receive an event the listener must implement a method matching the name of
71
+ the event with a single argument, the instance of the model.
72
+
73
+ ```ruby
74
+ def create_meeting_successful(meeting)
75
+ # ...
76
+ end
77
+ ```
78
+
79
+ ## Example
80
+
81
+ ### Controller
82
+
83
+ ```ruby
84
+ class MeetingsController < ApplicationController
85
+ def new
86
+ @meeting = Meeting.new
87
+ end
88
+
89
+ def create
90
+ @meeting = Meeting.new(params[:meeting])
91
+ @meeting.subscribe(Auditor.instance)
92
+ @meeting.on(:meeting_create_successful) { redirect_to meeting_path }
93
+ @meeting.on(:meeting_create_failed) { render action: :new }
94
+ @meeting.save
95
+ end
96
+
97
+ def edit
98
+ @meeting = Meeting.find(params[:id])
99
+ end
100
+
101
+ def update
102
+ @meeting = Meeting.find(params[:id])
103
+ @meeting.subscribe(Auditor.instance)
104
+ @meeting.on(:meeting_update_successful) { redirect_to meeting_path }
105
+ @meeting.on(:meeting_update_failed) { render :action => :edit }
106
+ @meeting.update_attributes(params[:meeting])
107
+ end
108
+ end
109
+ ```
110
+
111
+ Using `on` to subscribe a block to handle the response is optional,
112
+ you can still use `if @meeting.save` if you prefer.
113
+
114
+ ### Listener
115
+
116
+ **Which simply records an audit in memory**
117
+
118
+ ```ruby
119
+ class Auditor
120
+ include Singleton
121
+
122
+ attr_accessor :audit
123
+
124
+ def initialize
125
+ @audit = []
126
+ end
127
+
128
+ def after_create(subject)
129
+ push_audit_for('create', subject)
130
+ end
131
+
132
+ def after_update(subject)
133
+ push_audit_for('update', subject)
134
+ end
135
+
136
+ def after_destroy(subject)
137
+ push_audit_for('destroy', subject)
138
+ end
139
+
140
+ def self.audit
141
+ instance.audit
142
+ end
143
+
144
+ private
145
+
146
+ def push_audit_for(action, subject)
147
+ audit.push(audit_for(action, subject))
148
+ end
149
+
150
+ def audit_for(action, subject)
151
+ {
152
+ action: action,
153
+ subject_id: subject.id,
154
+ subject_class: subject.class.to_s,
155
+ changes: subject.previous_changes,
156
+ created_at: Time.now
157
+ }
158
+ end
159
+ end
160
+ ```
161
+
162
+ **Do some CRUD**
163
+
164
+ ```ruby
165
+ Meeting.create(:description => 'Team Retrospective', :starts_at => Time.now + 2.days)
166
+
167
+ meeting = Meeting.find(1)
168
+ meeting.starts_at = Time.now + 2.months
169
+ meeting.save
170
+ ```
171
+
172
+ **And check the audit**
173
+
174
+ ```ruby
175
+ Auditor.audit # => [...]
176
+ ```
177
+
178
+ ## Special Thanks
179
+
180
+ This gem is a fork of the original wisper-mongoid gem by Adrian Perez.
181
+
182
+ The implementation and interface is heavily inspired by krisleech's
183
+ `wisper-activerecord`.
184
+
185
+
186
+ ## Contributing
187
+
188
+ Please submit a Pull Request with specs.
189
+
190
+ ### Running the specs
191
+
192
+ ```
193
+ bundle exec rake
194
+ ```
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: :spec
7
+ rescue LoadError
8
+ end
@@ -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,41 @@
1
+ module Wisper
2
+ module Mongoid
3
+ module Publisher
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ include Wisper::Publisher
7
+
8
+ after_validation :after_validation_broadcast
9
+ after_create :after_create_broadcast, on: :create
10
+ after_update :after_update_broadcast, on: :update
11
+ after_destroy :after_destroy_broadcast, on: :destroy
12
+ end
13
+
14
+ private
15
+
16
+ def after_validation_broadcast
17
+ action = new_record? ? 'create' : 'update'
18
+ broadcast("#{action}_#{broadcast_model_name_key}_failed", self) unless errors.empty?
19
+ end
20
+
21
+ def after_create_broadcast
22
+ broadcast(:after_create, self)
23
+ broadcast("create_#{broadcast_model_name_key}_successful", self)
24
+ end
25
+
26
+ def after_update_broadcast
27
+ broadcast(:after_update, self)
28
+ broadcast("update_#{broadcast_model_name_key}_successful", self)
29
+ end
30
+
31
+ def after_destroy_broadcast
32
+ broadcast(:after_destroy, self)
33
+ broadcast("destroy_#{broadcast_model_name_key}_successful", self)
34
+ end
35
+
36
+ def broadcast_model_name_key
37
+ self.class.model_name.param_key
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,5 @@
1
+ module Wisper
2
+ module Mongoid
3
+ VERSION = '0.2.0'
4
+ end
5
+ end
@@ -0,0 +1,14 @@
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
+ ::Mongoid::Document.class_eval { include Wisper.model }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ begin
2
+ require 'pry'
3
+ rescue LoadError
4
+ end
5
+
6
+ require 'mongoid'
7
+ require 'wisper'
8
+
9
+ puts "Using Mongoid #{Mongoid::VERSION}"
10
+
11
+ Mongoid.load!('spec/support/mongoid.yml', :test)
12
+
13
+ require 'wisper/mongoid'
14
+ require 'support/models'
15
+
16
+ RSpec.configure do |config|
17
+ config.filter_run :focus
18
+ config.run_all_when_everything_filtered = true
19
+
20
+ if config.files_to_run.one?
21
+ config.full_backtrace = true
22
+ config.default_formatter = 'doc'
23
+ end
24
+
25
+ config.profile_examples = 10
26
+
27
+ config.order = :random
28
+
29
+ Kernel.srand config.seed
30
+
31
+ config.expect_with :rspec do |expectations|
32
+ expectations.syntax = :expect
33
+ end
34
+
35
+ config.mock_with :rspec do |mocks|
36
+ mocks.syntax = :expect
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+ 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
+ clients:
3
+ default:
4
+ database: wisper_mongoid_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,11 @@
1
+ describe Wisper::Mongoid::Publisher do
2
+ it 'includes Wisper::Publisher' do
3
+ klass = Class.new do
4
+ include Mongoid::Document
5
+ include Mongoid::Timestamps
6
+ include Wisper::Mongoid::Publisher
7
+ end
8
+
9
+ expect(klass.ancestors).to include Wisper::Publisher
10
+ end
11
+ end
@@ -0,0 +1,25 @@
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 = 'fhwang-wisper-mongoid'
8
+ spec.version = Wisper::Mongoid::VERSION
9
+ spec.authors = ['Francis Hwang', 'Adrian Perez']
10
+ spec.email = ['sera@fhwang.net']
11
+ spec.summary = 'Subscribe to changes on Mongoid models'
12
+ spec.description = 'Subscribe to changes on Mongoid models'
13
+ spec.homepage = 'https://github.com/fhwang/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'
23
+ spec.add_dependency 'mongoid', '>= 6'
24
+ spec.add_development_dependency "rspec"
25
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fhwang-wisper-mongoid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Francis Hwang
8
+ - Adrian Perez
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-03-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: wisper
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: mongoid
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '6'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '6'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Subscribe to changes on Mongoid models
57
+ email:
58
+ - sera@fhwang.net
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - CHANGELOG.md
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - gemfiles/mongoid-3.1
72
+ - gemfiles/mongoid-4.0
73
+ - lib/wisper/mongoid.rb
74
+ - lib/wisper/mongoid/publisher.rb
75
+ - lib/wisper/mongoid/version.rb
76
+ - spec/spec_helper.rb
77
+ - spec/support/models.rb
78
+ - spec/support/mongoid.yml
79
+ - spec/wisper/mongoid_spec.rb
80
+ - spec/wisper/publisher_spec.rb
81
+ - wisper-mongoid.gemspec
82
+ homepage: https://github.com/fhwang/wisper-mongoid
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.9.3
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.6.14
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Subscribe to changes on Mongoid models
106
+ test_files:
107
+ - spec/spec_helper.rb
108
+ - spec/support/models.rb
109
+ - spec/support/mongoid.yml
110
+ - spec/wisper/mongoid_spec.rb
111
+ - spec/wisper/publisher_spec.rb