fhwang-wisper-mongoid 0.2.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.
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