mongoid-observers 0.1.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: 97a99e1dcf3791371c919044d09c214b1ac22bc8
4
+ data.tar.gz: 26f5fd4d534d5eaf1ac0285ad0fc515d66e93b4e
5
+ SHA512:
6
+ metadata.gz: efd60e17bff3b6f9644b1ae730f2aaca2246c63e988b269e8f6e830e6238951e148bb1c6dc80c48ef42ffcf2ab6851b66f6861f3e4e63f73e7d6430273c77ebf
7
+ data.tar.gz: 2de69d89aa581ad857c323dcf67ccae78cc2ad38a5b1a539d43cc33d5e4b374b28adf679f389e8a888cee44e5510f6cdd2c6d4c15e7e8844352cd735d47e502a
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: rr717xFYVzxOS32gtsbWXR5QaxG4CBpIr
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
+ spec/tmp
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ mongoid-observers
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1.1
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ services: mongodb
2
+ language: ruby
3
+ script: "bundle exec rake spec"
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - 2.1.1
9
+ env:
10
+ - CODECLIMATE_REPO_TOKEN=f506e465f1ed0571aeaa5e1cb9c14214c9f7567a92d1af70903f3d0bc8015ed6
11
+ notifications:
12
+ email: false
13
+ addons:
14
+ code_climate:
15
+ repo_token: f506e465f1ed0571aeaa5e1cb9c14214c9f7567a92d1af70903f3d0bc8015ed6
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "bundler", "~> 1.5.3"
4
+ gem "rake", "~> 10.2.2"
5
+ gem "rspec", "~> 2.14.1"
6
+ gem "pry", "~> 0.9.12.6"
7
+ gem "simplecov", "~> 0.8.2"
8
+ gem "coveralls", "~> 0.7.0", require: false
9
+ gem "codeclimate-test-reporter"
10
+ gem "ammeter", "~> 1.0.0"
11
+ gem "railties"
12
+
13
+ # Specify your gem's dependencies in mongoid-observers.gemspec
14
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Chamnap Chhorn
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,141 @@
1
+ # Mongoid::Observers [![Build Status](https://travis-ci.org/chamnap/mongoid-observers.svg?branch=master)](https://travis-ci.org/chamnap/mongoid-observers)[![Code Climate](https://codeclimate.com/github/chamnap/mongoid-observers.png)](https://codeclimate.com/github/chamnap/mongoid-observers)[![Coverage Status](https://coveralls.io/repos/chamnap/mongoid-observers/badge.png?branch=master)](https://coveralls.io/r/chamnap/mongoid-observers?branch=master)[![Dependency Status](https://gemnasium.com/chamnap/mongoid-observers.svg)](https://gemnasium.com/chamnap/mongoid-observers)
2
+
3
+ Mongoid Observers (removed from core in Mongoid 4.0). Because this gem doesn't exist and I need to use it very often. Therefore, I extract the code from mongoid on my own. It's basically the same code from mongoid before it's removed.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mongoid-observers'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mongoid-observers
18
+
19
+ ## Usage
20
+
21
+ Observer classes respond to life cycle callbacks to implement trigger-like
22
+ behavior outside the original class. This is a great way to reduce the
23
+ clutter that normally comes when the model class is burdened with
24
+ functionality that doesn't pertain to the core responsibility of the
25
+ class. Mongoid's observers work similar to ActiveRecord's. Example:
26
+
27
+ ```ruby
28
+ class CommentObserver < Mongoid::Observer
29
+ def after_save(comment)
30
+ Notifications.comment(
31
+ "admin@do.com", "New comment was posted", comment
32
+ ).deliver
33
+ end
34
+ end
35
+ ```
36
+
37
+ This Observer sends an email when a Comment#save is finished.
38
+
39
+ ```ruby
40
+ class ContactObserver < Mongoid::Observer
41
+ def after_create(contact)
42
+ contact.logger.info('New contact added!')
43
+ end
44
+
45
+ def after_destroy(contact)
46
+ contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
47
+ end
48
+ end
49
+ ```
50
+
51
+ This Observer uses logger to log when specific callbacks are triggered.
52
+
53
+ #### Observing a class that can't be inferred
54
+
55
+ Observers will by default be mapped to the class with which they share a
56
+ name. So CommentObserver will be tied to observing Comment,
57
+ ProductManagerObserver to ProductManager, and so on. If you want to
58
+ name your observer differently than the class you're interested in
59
+ observing, you can use the Observer.observe class method which takes
60
+ either the concrete class (Product) or a symbol for that class (:product):
61
+
62
+ ```ruby
63
+ class AuditObserver < Mongoid::Observer
64
+ observe :account
65
+
66
+ def after_update(account)
67
+ AuditTrail.new(account, "UPDATED")
68
+ end
69
+ end
70
+ ```
71
+
72
+ If the audit observer needs to watch more than one kind of object,
73
+ this can be specified with multiple arguments:
74
+
75
+ ```ruby
76
+ class AuditObserver < Mongoid::Observer
77
+ observe :account, :balance
78
+
79
+ def after_update(record)
80
+ AuditTrail.new(record, "UPDATED")
81
+ end
82
+ end
83
+ ```
84
+
85
+ The AuditObserver will now act on both updates to Account and Balance
86
+ by treating them both as records.
87
+
88
+ #### Available callback methods
89
+
90
+ * after_initialize
91
+ * before_validation
92
+ * after_validation
93
+ * before_create
94
+ * around_create
95
+ * after_create
96
+ * before_update
97
+ * around_update
98
+ * after_update
99
+ * before_upsert
100
+ * around_upsert
101
+ * after_upsert
102
+ * before_save
103
+ * around_save
104
+ * after_save
105
+ * before_destroy
106
+ * around_destroy
107
+ * after_destroy
108
+
109
+ #### Storing Observers in Rails
110
+
111
+ If you're using Mongoid within Rails, observer classes are usually stored
112
+ in `app/models` with the naming convention of `app/models/audit_observer.rb`.
113
+
114
+ #### Configuration
115
+
116
+ In order to activate an observer, list it in the `config.mongoid.observers`
117
+ configuration setting in your `config/application.rb` file.
118
+
119
+ ```ruby
120
+ config.mongoid.observers = :comment_observer, :signup_observer
121
+ ```
122
+
123
+ Observers will not be invoked unless you define them in your
124
+ application configuration.
125
+
126
+ #### Loading
127
+
128
+ Observers register themselves with the model class that they observe,
129
+ since it is the class that notifies them of events when they occur.
130
+ As a side-effect, when an observer is loaded, its corresponding model
131
+ class is loaded.
132
+
133
+ Observers are loaded after the application initializers, so that
134
+ observed models can make use of extensions. If by any chance you are
135
+ using observed models in the initialization, you can
136
+ still load their observers by calling `ModelObserver.instance` before.
137
+ Observers are singletons and that call instantiates and registers them.
138
+
139
+ ## Authors
140
+
141
+ * [Chamnap Chhorn](https://github.com/chamnap)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList["spec/**/*_spec.rb"]
8
+ end
9
+
10
+ task :default => "spec"
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ require "rails/generators"
3
+ require "rails/generators/mongoid_generator"
4
+
5
+ module Mongoid
6
+ module Generators
7
+ class ObserverGenerator < Base
8
+ check_class_collision suffix: "Observer"
9
+
10
+ def self.source_root
11
+ File.expand_path("../templates", __FILE__)
12
+ end
13
+
14
+ def create_observer_file
15
+ template "observer.rb.tt", File.join("app/models", class_path, "#{file_name}_observer.rb")
16
+ end
17
+
18
+ hook_for :test_framework
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Observer < Mongoid::Observer
3
+ end
4
+ <% end -%>
@@ -0,0 +1,15 @@
1
+ require "active_support"
2
+ require "rails/observers/active_model"
3
+
4
+ require "mongoid"
5
+ require "mongoid/observers/config"
6
+ require "mongoid/observers/interceptable"
7
+ require "mongoid/observers/railtie" if defined? Rails
8
+ require "mongoid/observer"
9
+
10
+ module Mongoid
11
+ include ActiveModel::Observing
12
+
13
+ delegate(*ActiveModel::Observing::ClassMethods.public_instance_methods(false) <<
14
+ { to: Config })
15
+ end
@@ -0,0 +1,186 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+
4
+ # Observer classes respond to life cycle callbacks to implement trigger-like
5
+ # behavior outside the original class. This is a great way to reduce the
6
+ # clutter that normally comes when the model class is burdened with
7
+ # functionality that doesn't pertain to the core responsibility of the
8
+ # class. Mongoid's observers work similar to ActiveRecord's. Example:
9
+ #
10
+ # class CommentObserver < Mongoid::Observer
11
+ # def after_save(comment)
12
+ # Notifications.comment(
13
+ # "admin@do.com", "New comment was posted", comment
14
+ # ).deliver
15
+ # end
16
+ # end
17
+ #
18
+ # This Observer sends an email when a Comment#save is finished.
19
+ #
20
+ # class ContactObserver < Mongoid::Observer
21
+ # def after_create(contact)
22
+ # contact.logger.info('New contact added!')
23
+ # end
24
+ #
25
+ # def after_destroy(contact)
26
+ # contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
27
+ # end
28
+ # end
29
+ #
30
+ # This Observer uses logger to log when specific callbacks are triggered.
31
+ #
32
+ # == Observing a class that can't be inferred
33
+ #
34
+ # Observers will by default be mapped to the class with which they share a
35
+ # name. So CommentObserver will be tied to observing Comment,
36
+ # ProductManagerObserver to ProductManager, and so on. If you want to
37
+ # name your observer differently than the class you're interested in
38
+ # observing, you can use the Observer.observe class method which takes
39
+ # either the concrete class (Product) or a symbol for that class (:product):
40
+ #
41
+ # class AuditObserver < Mongoid::Observer
42
+ # observe :account
43
+ #
44
+ # def after_update(account)
45
+ # AuditTrail.new(account, "UPDATED")
46
+ # end
47
+ # end
48
+ #
49
+ # If the audit observer needs to watch more than one kind of object,
50
+ # this can be specified with multiple arguments:
51
+ #
52
+ # class AuditObserver < Mongoid::Observer
53
+ # observe :account, :balance
54
+ #
55
+ # def after_update(record)
56
+ # AuditTrail.new(record, "UPDATED")
57
+ # end
58
+ # end
59
+ #
60
+ # The AuditObserver will now act on both updates to Account and Balance
61
+ # by treating them both as records.
62
+ #
63
+ # == Available callback methods
64
+ #
65
+ # * after_initialize
66
+ # * before_validation
67
+ # * after_validation
68
+ # * before_create
69
+ # * around_create
70
+ # * after_create
71
+ # * before_update
72
+ # * around_update
73
+ # * after_update
74
+ # * before_upsert
75
+ # * around_upsert
76
+ # * after_upsert
77
+ # * before_save
78
+ # * around_save
79
+ # * after_save
80
+ # * before_destroy
81
+ # * around_destroy
82
+ # * after_destroy
83
+ #
84
+ # == Storing Observers in Rails
85
+ #
86
+ # If you're using Mongoid within Rails, observer classes are usually stored
87
+ # in +app/models+ with the naming convention of +app/models/audit_observer.rb+.
88
+ #
89
+ # == Configuration
90
+ #
91
+ # In order to activate an observer, list it in the +config.mongoid.observers+
92
+ # configuration setting in your +config/application.rb+ file.
93
+ #
94
+ # config.mongoid.observers = :comment_observer, :signup_observer
95
+ #
96
+ # Observers will not be invoked unless you define them in your
97
+ # application configuration.
98
+ #
99
+ # == Loading
100
+ #
101
+ # Observers register themselves with the model class that they observe,
102
+ # since it is the class that notifies them of events when they occur.
103
+ # As a side-effect, when an observer is loaded, its corresponding model
104
+ # class is loaded.
105
+ #
106
+ # Observers are loaded after the application initializers, so that
107
+ # observed models can make use of extensions. If by any chance you are
108
+ # using observed models in the initialization, you can
109
+ # still load their observers by calling +ModelObserver.instance+ before.
110
+ # Observers are singletons and that call instantiates and registers them.
111
+ class Observer < ActiveModel::Observer
112
+
113
+ private
114
+
115
+ # Adds the specified observer to the class.
116
+ #
117
+ # @example Add the observer.
118
+ # observer.add_observer!(Document)
119
+ #
120
+ # @param [ Class ] klass The child observer to add.
121
+ def add_observer!(klass)
122
+ super and define_callbacks(klass)
123
+ end
124
+
125
+ # Defines all the callbacks for each observer of the model.
126
+ #
127
+ # @example Define all the callbacks.
128
+ # observer.define_callbacks(Document)
129
+ #
130
+ # @param [ Class ] klass The model to define them on.
131
+ def define_callbacks(klass)
132
+ observer = self
133
+ observer_name = observer.class.name.underscore.gsub('/', '__')
134
+ Mongoid::Interceptable.observables.each do |callback|
135
+ next unless respond_to?(callback)
136
+ callback_meth = :"_notify_#{observer_name}_for_#{callback}"
137
+ unless klass.respond_to?(callback_meth)
138
+ klass.send(:define_method, callback_meth) do |&block|
139
+ if value = observer.update(callback, self, &block)
140
+ value
141
+ else
142
+ block.call if block
143
+ end
144
+ end
145
+ klass.send(callback, callback_meth)
146
+ end
147
+ end
148
+ self
149
+ end
150
+
151
+ # Are the observers disabled for the object?
152
+ #
153
+ # @api private
154
+ #
155
+ # @example If the observer disabled?
156
+ # Observer.disabled_for(band)
157
+ #
158
+ # @param [ Document ] object The model instance.
159
+ #
160
+ # @return [ true, false ] If the observer is disabled.
161
+ def disabled_for?(object)
162
+ klass = object.class
163
+ return false unless klass.respond_to?(:observers)
164
+ klass.observers.disabled_for?(self) || Mongoid.observers.disabled_for?(self)
165
+ end
166
+
167
+ class << self
168
+
169
+ # Attaches the observer to the specified classes.
170
+ #
171
+ # @example Attach the BandObserver to the class Artist.
172
+ # class BandObserver < Mongoid::Observer
173
+ # observe :artist
174
+ # end
175
+ #
176
+ # @param [ Array<Symbol> ] models The names of the models.
177
+ def observe(*models)
178
+ models.flatten!
179
+ models.collect! do |model|
180
+ model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model
181
+ end
182
+ singleton_class.redefine_method(:observed_classes) { models }
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module Config
3
+ include ActiveModel::Observing
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ module Mongoid
2
+ module Interceptable
3
+ include ActiveModel::Observing
4
+
5
+ class << self
6
+
7
+ # Get all callbacks that can be observed.
8
+ #
9
+ # @example Get the observables.
10
+ # Interceptable.observables
11
+ #
12
+ # @return [ Array<Symbol> ] The names of the observables.
13
+ def observables
14
+ CALLBACKS + registered_observables
15
+ end
16
+
17
+ # Get all registered callbacks that can be observed, not included in
18
+ # Mongoid's defaults.
19
+ #
20
+ # @example Get the observables.
21
+ # Interceptable.registered_observables
22
+ #
23
+ # @return [ Array<Symbol> ] The names of the registered observables.
24
+ def registered_observables
25
+ @registered_observables ||= []
26
+ end
27
+ end
28
+
29
+ module ClassMethods
30
+
31
+ # Set a custom callback as able to be observed.
32
+ #
33
+ # @example Set a custom callback as observable.
34
+ # class Band
35
+ # include Mongoid::Document
36
+ #
37
+ # define_model_callbacks :notification
38
+ # observable :notification
39
+ # end
40
+ #
41
+ # @param [ Array<Symbol> ] args The names of the observable callbacks.
42
+ #
43
+ # @since 3.0.1
44
+ def observable(*args)
45
+ observables = args.flat_map do |name|
46
+ [ :"before_#{name}", :"after_#{name}", :"around_#{name}" ]
47
+ end
48
+ Interceptable.registered_observables.concat(observables).uniq
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,27 @@
1
+ require "rails/railtie"
2
+
3
+ module Mongoid
4
+ module Observers
5
+ class Railtie < ::Rails::Railtie
6
+ initializer "mongoid.observer" do |app|
7
+ ActiveSupport.on_load(:mongoid) do
8
+ if app.config.respond_to?(:mongoid)
9
+ ::Mongoid.observers = app.config.mongoid.observers
10
+ end
11
+ end
12
+ end
13
+
14
+ # Instantitate any registered observers after Rails initialization and
15
+ # instantiate them after being reloaded in the development environment
16
+ config.after_initialize do |app|
17
+ ActiveSupport.on_load(:mongoid) do
18
+ ::Mongoid::instantiate_observers
19
+
20
+ ActionDispatch::Reloader.to_prepare do
21
+ ::Mongoid.instantiate_observers
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module Observers
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mongoid/observers/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mongoid-observers"
8
+ spec.version = Mongoid::Observers::VERSION
9
+ spec.authors = ["Chamnap Chhorn"]
10
+ spec.email = ["chamnapchhorn@gmail.com"]
11
+ spec.summary = %q{Mongoid observer (removed in Mongoid 4.0)}
12
+ spec.description = %q{Mongoid::Observer removed from Mongoid 4.0}
13
+ spec.homepage = "https://github.com/chamnap/mongoid-observer"
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
+
21
+ spec.add_dependency "rails-observers", "~> 0.1.2"
22
+ spec.add_dependency "mongoid", "~> 4.0.0.beta1"
23
+ end
@@ -0,0 +1,14 @@
1
+ class Actor
2
+ include Mongoid::Document
3
+ field :name
4
+ field :after_custom_count, type: Integer, default: 0
5
+
6
+ define_model_callbacks :custom
7
+ observable :custom
8
+
9
+ def do_something
10
+ run_callbacks(:custom) do
11
+ self.name = "custom"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class ActorObserver < Mongoid::Observer
2
+ attr_reader :last_after_create_record
3
+
4
+ def after_create(record)
5
+ @last_after_create_record = record
6
+ end
7
+
8
+ def after_custom(record)
9
+ record.after_custom_count += 1
10
+ end
11
+
12
+ def before_custom(record)
13
+ @after_custom_called = true
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ class Actress < Actor
2
+ end
@@ -0,0 +1,25 @@
1
+ class CallbackRecorder < Mongoid::Observer
2
+ observe :actor
3
+
4
+ attr_reader :last_callback, :call_count, :last_record
5
+
6
+ def initialize
7
+ reset
8
+ super
9
+ end
10
+
11
+ def reset
12
+ @last_callback = nil
13
+ @call_count = Hash.new(0)
14
+ @last_record = {}
15
+ end
16
+
17
+ Mongoid::Interceptable.observables.each do |callback|
18
+ define_method(callback) do |record, &block|
19
+ @last_callback = callback
20
+ @call_count[callback] += 1
21
+ @last_record[callback] = record
22
+ block ? block.call : true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ class Person
2
+ include Mongoid::Document
3
+
4
+ field :username, default: -> { "arthurnn#{rand(0..10)}" }
5
+ field :title
6
+ field :terms, type: Boolean
7
+ field :pets, type: Boolean, default: false
8
+ field :age, type: Integer, default: "100"
9
+ field :dob, type: Date
10
+ field :employer_id
11
+ field :lunch_time, type: Time
12
+ field :aliases, type: Array
13
+ field :map, type: Hash
14
+ field :map_with_default, type: Hash, default: {}
15
+ field :score, type: Integer
16
+ field :blood_alcohol_content, type: Float, default: ->{ 0.0 }
17
+ field :last_drink_taken_at, type: Date, default: ->{ 1.day.ago.in_time_zone("Alaska") }
18
+ field :ssn
19
+ field :owner_id, type: Integer
20
+ field :security_code
21
+ field :reading, type: Object
22
+ field :bson_id, type: BSON::ObjectId
23
+ field :pattern, type: Regexp
24
+ field :override_me, type: Integer
25
+ field :at, as: :aliased_timestamp, type: Time
26
+ field :t, as: :test, type: String
27
+ field :i, as: :inte, type: Integer
28
+ field :a, as: :array, type: Array
29
+ field :desc, localize: true
30
+
31
+
32
+ embeds_many :phone_numbers, class_name: "Phone", validate: false
33
+
34
+ end
@@ -0,0 +1,11 @@
1
+ class Phone
2
+ include Mongoid::Document
3
+
4
+ attr_accessor :number_in_observer
5
+
6
+ field :_id, type: String, default: ->{ number }
7
+
8
+ field :number
9
+ embeds_one :country_code
10
+ embedded_in :person
11
+ end
@@ -0,0 +1,6 @@
1
+ class PhoneObserver < Mongoid::Observer
2
+
3
+ def after_save(phone)
4
+ phone.number_in_observer = phone.number
5
+ end
6
+ end
@@ -0,0 +1,42 @@
1
+ class Record
2
+ include Mongoid::Document
3
+ field :name, type: String
4
+
5
+ field :before_create_called, type: Boolean, default: false
6
+ field :before_save_called, type: Boolean, default: false
7
+ field :before_update_called, type: Boolean, default: false
8
+ field :before_validation_called, type: Boolean, default: false
9
+ field :before_destroy_called, type: Boolean, default: false
10
+
11
+ before_create :before_create_stub
12
+ before_save :before_save_stub
13
+ before_update :before_update_stub
14
+ before_validation :before_validation_stub
15
+ before_destroy :before_destroy_stub
16
+
17
+ after_destroy :access_band
18
+
19
+ def before_create_stub
20
+ self.before_create_called = true
21
+ end
22
+
23
+ def before_save_stub
24
+ self.before_save_called = true
25
+ end
26
+
27
+ def before_update_stub
28
+ self.before_update_called = true
29
+ end
30
+
31
+ def before_validation_stub
32
+ self.before_validation_called = true
33
+ end
34
+
35
+ def before_destroy_stub
36
+ self.before_destroy_called = true
37
+ end
38
+
39
+ def access_band
40
+ band.name
41
+ end
42
+ end
@@ -0,0 +1,6 @@
1
+ test:
2
+ sessions:
3
+ default:
4
+ database: mongoid_observers_test
5
+ hosts:
6
+ - localhost:27017
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ # Generators are not automatically loaded by Rails
4
+ require "generators/mongoid/observer/observer_generator"
5
+
6
+ describe Mongoid::Generators::ObserverGenerator do
7
+ # Tell the generator where to put its output (what it thinks of as Rails.root)
8
+ destination File.expand_path("../../../../../spec/tmp", __FILE__)
9
+
10
+ before do
11
+ prepare_destination
12
+ end
13
+
14
+ it "observer without namespace" do
15
+ run_generator %w(product)
16
+ expect(file("app/models/product_observer.rb")).to exist
17
+ expect(file("app/models/product_observer.rb")).to contain(/class ProductObserver < Mongoid::Observer/)
18
+ end
19
+
20
+ it "observer with namespace" do
21
+ run_generator %w(admin/account)
22
+ expect(file("app/models/admin/account_observer.rb")).to exist
23
+ expect(file("app/models/admin/account_observer.rb")).to contain(/class Admin::AccountObserver < Mongoid::Observer/)
24
+ end
25
+ end
@@ -0,0 +1,290 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Observer do
4
+
5
+ let(:recorder) do
6
+ CallbackRecorder.instance
7
+ end
8
+
9
+ after do
10
+ recorder.reset
11
+ end
12
+
13
+ it "is an instance of an active model observer" do
14
+ ActorObserver.instance.should be_a_kind_of(ActiveModel::Observer)
15
+ end
16
+
17
+ context "when the oberserver observes a different class" do
18
+
19
+ before(:all) do
20
+ class BandObserver < Mongoid::Observer
21
+ observe :record
22
+ end
23
+ end
24
+
25
+ after(:all) do
26
+ Object.send(:remove_const, :BandObserver)
27
+ end
28
+
29
+ it "returns the proper observed classes" do
30
+ BandObserver.observed_classes.should eq([ Record ])
31
+ end
32
+ end
33
+
34
+ context "when the observer is for an embedded document" do
35
+
36
+ before do
37
+ PhoneObserver.instance
38
+ end
39
+
40
+ let(:person) do
41
+ Person.create
42
+ end
43
+
44
+ let!(:phone) do
45
+ person.phone_numbers.create(number: "0152-1111-1111")
46
+ end
47
+
48
+ context "when updating the embedded document" do
49
+
50
+ before do
51
+ phone.update_attribute(:number, "0152-2222-2222")
52
+ end
53
+
54
+ it "contains the updated value in the observer" do
55
+ phone.number_in_observer.should eq("0152-2222-2222")
56
+ end
57
+ end
58
+ end
59
+
60
+ context "when the observer has descendants" do
61
+
62
+ let!(:observer) do
63
+ ActorObserver.instance
64
+ end
65
+
66
+ let!(:actress) do
67
+ Actress.create!(name: "Tina Fey")
68
+ end
69
+
70
+ it "observes descendent class" do
71
+ observer.last_after_create_record.try(:name).should eq(actress.name)
72
+ end
73
+ end
74
+
75
+ context "when the observer is disabled" do
76
+
77
+ let!(:observer) do
78
+ ActorObserver.instance
79
+ end
80
+
81
+ let(:actor) do
82
+ Actor.create!(name: "Johnny Depp")
83
+ end
84
+
85
+ it "does not fire the observer" do
86
+ Actor.observers.disable(:all) do
87
+ actor and observer.last_after_create_record.should_not eq(actor)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "when all observers are disabled" do
93
+
94
+ let!(:observer) do
95
+ ActorObserver.instance
96
+ end
97
+
98
+ let(:actor) do
99
+ Actor.create!(name: "Johnny Depp")
100
+ end
101
+
102
+ it "does not fire the observer" do
103
+ Mongoid.observers.disable(:all) do
104
+ actor and observer.last_after_create_record.should_not eq(actor)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "when the document is new" do
110
+
111
+ let!(:actor) do
112
+ Actor.new
113
+ end
114
+
115
+ it "observes after initialize" do
116
+ recorder.last_callback.should eq(:after_initialize)
117
+ end
118
+
119
+ it "calls after initialize once" do
120
+ recorder.call_count[:after_initialize].should eq(1)
121
+ end
122
+
123
+ it "contains the model of the callback" do
124
+ recorder.last_record[:after_initialize].should eq(actor)
125
+ end
126
+ end
127
+
128
+ context "when the document is being created" do
129
+
130
+ let!(:actor) do
131
+ Actor.create!
132
+ end
133
+
134
+ [ :before_create,
135
+ :after_create,
136
+ :around_create,
137
+ :before_save,
138
+ :after_save,
139
+ :around_save ].each do |callback|
140
+
141
+ it "observes #{callback}" do
142
+ recorder.call_count[callback].should eq(1)
143
+ end
144
+
145
+ it "contains the model of the callback" do
146
+ recorder.last_record[callback].should eq(actor)
147
+ end
148
+ end
149
+ end
150
+
151
+ context "when the document is being updated" do
152
+
153
+ let!(:actor) do
154
+ Actor.create!
155
+ end
156
+
157
+ [ :before_update,
158
+ :after_update,
159
+ :around_update,
160
+ :before_save,
161
+ :after_save,
162
+ :around_save ].each do |callback|
163
+
164
+ before do
165
+ recorder.reset
166
+ actor.update_attributes!(name: "Johnny Depp")
167
+ end
168
+
169
+ it "observes #{callback}" do
170
+ recorder.call_count[callback].should eq(1)
171
+ end
172
+
173
+ it "contains the model of the callback" do
174
+ recorder.last_record[callback].should eq(actor)
175
+ end
176
+ end
177
+ end
178
+
179
+ context "when the document is being upserted" do
180
+
181
+ let!(:actor) do
182
+ Actor.create!
183
+ end
184
+
185
+ [ :before_upsert,
186
+ :after_upsert,
187
+ :around_upsert ].each do |callback|
188
+
189
+ before do
190
+ recorder.reset
191
+ actor.upsert
192
+ end
193
+
194
+ it "observes #{callback}" do
195
+ recorder.call_count[callback].should eq(1)
196
+ end
197
+
198
+ it "contains the model of the callback" do
199
+ recorder.last_record[callback].should eq(actor)
200
+ end
201
+ end
202
+ end
203
+
204
+ context "when custom callbacks are being fired" do
205
+
206
+ let!(:actor) do
207
+ Actor.create!
208
+ end
209
+
210
+ [ :before_custom,
211
+ :after_custom,
212
+ :around_custom ].each do |callback|
213
+
214
+ before do
215
+ recorder.reset
216
+ actor.run_callbacks(:custom) do
217
+ end
218
+ end
219
+
220
+ it "observes #{callback}" do
221
+ recorder.call_count[callback].should eq(1)
222
+ end
223
+
224
+ it "contains the model of the callback" do
225
+ recorder.last_record[callback].should eq(actor)
226
+ end
227
+ end
228
+ end
229
+
230
+ context "when the document is being destroyed" do
231
+
232
+ let!(:actor) do
233
+ Actor.create!
234
+ end
235
+
236
+ [ :before_destroy, :after_destroy, :around_destroy ].each do |callback|
237
+
238
+ before do
239
+ recorder.reset
240
+ actor.destroy
241
+ end
242
+
243
+ it "observes #{callback}" do
244
+ recorder.call_count[callback].should eq(1)
245
+ end
246
+
247
+ it "contains the model of the callback" do
248
+ recorder.last_record[callback].should eq(actor)
249
+ end
250
+ end
251
+ end
252
+
253
+ context "when the document is being validated" do
254
+
255
+ let!(:actor) do
256
+ Actor.new
257
+ end
258
+
259
+ [:before_validation, :after_validation].each do |callback|
260
+
261
+ before do
262
+ recorder.reset
263
+ actor.valid?
264
+ end
265
+
266
+ it "observes #{callback}" do
267
+ recorder.call_count[callback].should eq(1)
268
+ end
269
+
270
+ it "contains the model of the callback" do
271
+ recorder.last_record[callback].should eq(actor)
272
+ end
273
+ end
274
+ end
275
+
276
+ context "when using a custom callback" do
277
+
278
+ let(:actor) do
279
+ Actor.new
280
+ end
281
+
282
+ before do
283
+ actor.do_something
284
+ end
285
+
286
+ it "notifies the observers once" do
287
+ actor.after_custom_count.should eq(1)
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,40 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ require "codeclimate-test-reporter"
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ Coveralls::SimpleCov::Formatter,
7
+ SimpleCov::Formatter::HTMLFormatter,
8
+ CodeClimate::TestReporter::Formatter
9
+ ]
10
+
11
+ SimpleCov.start do
12
+ add_filter "/spec/"
13
+ end
14
+
15
+ MODELS = File.join(File.dirname(__FILE__), "app/models")
16
+ $LOAD_PATH.unshift(MODELS)
17
+
18
+ require "pry"
19
+ require "rails"
20
+ require "mongoid-observers"
21
+ require "ammeter/init"
22
+
23
+ # mongoid connection
24
+ Mongoid.load! File.dirname(__FILE__) + "/config/mongoid.yml", :test
25
+
26
+ # Autoload every model for the test suite that sits in spec/app/models.
27
+ Dir[ File.join(MODELS, "*.rb") ].sort.each do |file|
28
+ name = File.basename(file, ".rb")
29
+ autoload name.camelize.to_sym, name
30
+ end
31
+
32
+ RSpec.configure do |config|
33
+ config.filter_run focus: true
34
+ config.run_all_when_everything_filtered = true
35
+ config.treat_symbols_as_metadata_keys_with_true_values = true
36
+
37
+ config.before(:each) do
38
+ Mongoid.purge!
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-observers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chamnap Chhorn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails-observers
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: mongoid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 4.0.0.beta1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 4.0.0.beta1
41
+ description: Mongoid::Observer removed from Mongoid 4.0
42
+ email:
43
+ - chamnapchhorn@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".coveralls.yml"
49
+ - ".gitignore"
50
+ - ".rspec"
51
+ - ".ruby-gemset"
52
+ - ".ruby-version"
53
+ - ".travis.yml"
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/generators/mongoid/observer/observer_generator.rb
59
+ - lib/generators/mongoid/observer/templates/observer.rb.tt
60
+ - lib/mongoid-observers.rb
61
+ - lib/mongoid/observer.rb
62
+ - lib/mongoid/observers/config.rb
63
+ - lib/mongoid/observers/interceptable.rb
64
+ - lib/mongoid/observers/railtie.rb
65
+ - lib/mongoid/observers/version.rb
66
+ - mongoid-observers.gemspec
67
+ - spec/app/models/actor.rb
68
+ - spec/app/models/actor_observer.rb
69
+ - spec/app/models/actress.rb
70
+ - spec/app/models/callback_recorder.rb
71
+ - spec/app/models/person.rb
72
+ - spec/app/models/phone.rb
73
+ - spec/app/models/phone_observer.rb
74
+ - spec/app/models/record.rb
75
+ - spec/config/mongoid.yml
76
+ - spec/generators/mongoid/observer/observer_generator_spec.rb
77
+ - spec/mongoid/observer_spec.rb
78
+ - spec/spec_helper.rb
79
+ homepage: https://github.com/chamnap/mongoid-observer
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.2.2
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Mongoid observer (removed in Mongoid 4.0)
103
+ test_files:
104
+ - spec/app/models/actor.rb
105
+ - spec/app/models/actor_observer.rb
106
+ - spec/app/models/actress.rb
107
+ - spec/app/models/callback_recorder.rb
108
+ - spec/app/models/person.rb
109
+ - spec/app/models/phone.rb
110
+ - spec/app/models/phone_observer.rb
111
+ - spec/app/models/record.rb
112
+ - spec/config/mongoid.yml
113
+ - spec/generators/mongoid/observer/observer_generator_spec.rb
114
+ - spec/mongoid/observer_spec.rb
115
+ - spec/spec_helper.rb