rails-observers-0.1.2/ 0000755 0000041 0000041 00000000000 12250222654 014664 5 ustar www-data www-data rails-observers-0.1.2/rails-observers.gemspec.erb 0000644 0000041 0000041 00000002254 12250222654 022125 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require File.expand_path('../lib/rails/observers/version', __FILE__)
Gem::Specification.new do |s|
s.name = "rails-observers"
s.authors = ["Rafael Mendonça França", "Steve Klabnik"]
s.email = ["rafaelmfranca@gmail.com", "steve@steveklabnik.com"]
s.description = %q{Rails observer (removed from core in Rails 4.0)}
s.summary = %q{ActiveModel::Observer, ActiveRecord::Observer and ActionController::Caching::Sweeper extracted from Rails.}
s.homepage = "https://github.com/rails/rails-observers"
s.version = Rails::Observers::VERSION
s.files = [<%= files.map(&:inspect).join ',' %>]
s.test_files = [<%= test_files.map(&:inspect).join ',' %>]
s.executables = [<%= executables.map(&:inspect).join ',' %>]
s.require_paths = ["lib"]
s.add_dependency 'activemodel', '~> 4.0'
s.add_development_dependency 'minitest', '>= 3'
s.add_development_dependency 'railties', '~> 4.0'
s.add_development_dependency 'activerecord', '~> 4.0'
s.add_development_dependency 'actionmailer', '~> 4.0'
s.add_development_dependency 'actionpack', '~> 4.0'
s.add_development_dependency 'sqlite3', '~> 1.3'
end
rails-observers-0.1.2/Rakefile 0000644 0000041 0000041 00000001507 12250222654 016334 0 ustar www-data www-data #!/usr/bin/env rake
require "bundler/gem_tasks"
require 'rake/testtask'
Rake::TestTask.new("test:regular") do |t|
t.libs = ["test"]
t.pattern = "test/*_test.rb"
t.ruby_opts = ['-w']
end
Rake::TestTask.new("test:generators") do |t|
t.libs = ["test"]
t.pattern = "test/generators/*_test.rb"
t.ruby_opts = ['-w']
end
task :default => :test
task :test => ['test:regular', 'test:generators']
specname = "rails-observers.gemspec"
deps = `git ls-files`.split("\n") - [specname]
file specname => deps do
files = `git ls-files`.split("\n")
test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
require 'erb'
File.open specname, 'w:utf-8' do |f|
f.write ERB.new(File.read("#{specname}.erb")).result(binding)
end
end
rails-observers-0.1.2/Gemfile 0000644 0000041 0000041 00000000260 12250222654 016155 0 ustar www-data www-data source 'https://rubygems.org'
# Specify your gem's dependencies in active_record-observers.gemspec
gemspec
gem 'activerecord-deprecated_finders'
gem 'mocha', require: false
rails-observers-0.1.2/.travis.yml 0000644 0000041 0000041 00000000351 12250222654 016774 0 ustar www-data www-data language: ruby
rvm:
- 1.9.3
before_install: gem install bundler
script: bundle exec rake test
notifications:
email: false
irc:
on_success: change
on_failure: always
channels:
- "irc.freenode.org#rails-contrib"
rails-observers-0.1.2/lib/ 0000755 0000041 0000041 00000000000 12250222654 015432 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/ 0000755 0000041 0000041 00000000000 12250222654 017603 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/test_unit/ 0000755 0000041 0000041 00000000000 12250222654 021621 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/test_unit/observer/ 0000755 0000041 0000041 00000000000 12250222654 023450 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/test_unit/observer/templates/ 0000755 0000041 0000041 00000000000 12250222654 025446 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/test_unit/observer/templates/unit_test.rb 0000644 0000041 0000041 00000000263 12250222654 030012 0 ustar www-data www-data require 'test_helper'
<% module_namespacing do -%>
class <%= class_name %>ObserverTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
<% end -%>
rails-observers-0.1.2/lib/generators/test_unit/observer/observer_generator.rb 0000644 0000041 0000041 00000000577 12250222654 027703 0 ustar www-data www-data require 'rails/generators/test_unit'
module TestUnit
module Generators
class ObserverGenerator < Base
check_class_collision :suffix => "ObserverTest"
source_root File.expand_path("../templates", __FILE__)
def create_test_files
template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_observer_test.rb")
end
end
end
end
rails-observers-0.1.2/lib/generators/active_record/ 0000755 0000041 0000041 00000000000 12250222654 022414 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/active_record/observer/ 0000755 0000041 0000041 00000000000 12250222654 024243 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/active_record/observer/templates/ 0000755 0000041 0000041 00000000000 12250222654 026241 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/active_record/observer/templates/observer.rb 0000644 0000041 0000041 00000000145 12250222654 030415 0 ustar www-data www-data <% module_namespacing do -%>
class <%= class_name %>Observer < ActiveRecord::Observer
end
<% end -%>
rails-observers-0.1.2/lib/generators/active_record/observer/observer_generator.rb 0000644 0000041 0000041 00000000641 12250222654 030466 0 ustar www-data www-data require 'rails/generators/active_record'
module ActiveRecord
module Generators
class ObserverGenerator < Base
check_class_collision :suffix => "Observer"
source_root File.expand_path("../templates", __FILE__)
def create_observer_file
template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb")
end
hook_for :test_framework
end
end
end
rails-observers-0.1.2/lib/generators/rails/ 0000755 0000041 0000041 00000000000 12250222654 020715 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/rails/observer/ 0000755 0000041 0000041 00000000000 12250222654 022544 5 ustar www-data www-data rails-observers-0.1.2/lib/generators/rails/observer/USAGE 0000644 0000041 0000041 00000000614 12250222654 023334 0 ustar www-data www-data Description:
Stubs out a new observer. Pass the observer name, either CamelCased or
under_scored, as an argument.
This generator only invokes your ORM and test framework generators.
Example:
`rails generate observer Account`
For ActiveRecord and TestUnit it creates:
Observer: app/models/account_observer.rb
TestUnit: test/unit/account_observer_test.rb
rails-observers-0.1.2/lib/generators/rails/observer/observer_generator.rb 0000644 0000041 0000041 00000000221 12250222654 026761 0 ustar www-data www-data module Rails
module Generators
class ObserverGenerator < NamedBase #metagenerator
hook_for :orm, :required => true
end
end
end
rails-observers-0.1.2/lib/rails-observers.rb 0000644 0000041 0000041 00000000126 12250222654 021100 0 ustar www-data www-data require 'rails/observers/railtie' if defined? Rails
require 'rails/observers/version'
rails-observers-0.1.2/lib/rails/ 0000755 0000041 0000041 00000000000 12250222654 016544 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/ 0000755 0000041 0000041 00000000000 12250222654 020556 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/activerecord/ 0000755 0000041 0000041 00000000000 12250222654 023230 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/activerecord/observer.rb 0000644 0000041 0000041 00000011120 12250222654 025377 0 ustar www-data www-data module ActiveRecord
# = Active Record Observer
#
# Observer classes respond to life cycle callbacks to implement trigger-like
# behavior outside the original class. This is a great way to reduce the
# clutter that normally comes when the model class is burdened with
# functionality that doesn't pertain to the core responsibility of the
# class. Example:
#
# class CommentObserver < ActiveRecord::Observer
# def after_save(comment)
# Notifications.comment("admin@do.com", "New comment was posted", comment).deliver
# end
# end
#
# This Observer sends an email when a Comment#save is finished.
#
# class ContactObserver < ActiveRecord::Observer
# def after_create(contact)
# contact.logger.info('New contact added!')
# end
#
# def after_destroy(contact)
# contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
# end
# end
#
# This Observer uses logger to log when specific callbacks are triggered.
#
# == Observing a class that can't be inferred
#
# Observers will by default be mapped to the class with which they share a name. So CommentObserver will
# be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
# differently than the class you're interested in observing, you can use the Observer.observe class method which takes
# either the concrete class (Product) or a symbol for that class (:product):
#
# class AuditObserver < ActiveRecord::Observer
# observe :account
#
# def after_update(account)
# AuditTrail.new(account, "UPDATED")
# end
# end
#
# If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
#
# class AuditObserver < ActiveRecord::Observer
# observe :account, :balance
#
# def after_update(record)
# AuditTrail.new(record, "UPDATED")
# end
# end
#
# The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
#
# == Available callback methods
#
# The observer can implement callback methods for each of the methods described in the Callbacks module.
#
# == Storing Observers in Rails
#
# If you're using Active Record within Rails, observer classes are usually stored in app/models with the
# naming convention of app/models/audit_observer.rb.
#
# == Configuration
#
# In order to activate an observer, list it in the config.active_record.observers configuration
# setting in your config/application.rb file.
#
# config.active_record.observers = :comment_observer, :signup_observer
#
# Observers will not be invoked unless you define these in your application configuration.
#
# If you are using Active Record outside Rails, activate the observers explicitly in a configuration or
# environment file:
#
# ActiveRecord::Base.add_observer CommentObserver.instance
# ActiveRecord::Base.add_observer SignupObserver.instance
#
# == Loading
#
# Observers register themselves in the model class they observe, since it is the class that
# notifies them of events when they occur. As a side-effect, when an observer is loaded its
# corresponding model class is loaded.
#
# Up to (and including) Rails 2.0.2 observers were instantiated between plugins and
# application initializers. Now observers are loaded after application initializers,
# so observed models can make use of extensions.
#
# If by any chance you are using observed models in the initialization you can still
# load their observers by calling ModelObserver.instance before. Observers are
# singletons and that call instantiates and registers them.
#
class Observer < ActiveModel::Observer
protected
def observed_classes
klasses = super
klasses + klasses.map { |klass| klass.descendants }.flatten
end
def add_observer!(klass)
super
define_callbacks klass
end
def define_callbacks(klass)
observer = self
observer_name = observer.class.name.underscore.gsub('/', '__')
ActiveRecord::Callbacks::CALLBACKS.each do |callback|
next unless respond_to?(callback)
callback_meth = :"_notify_#{observer_name}_for_#{callback}"
unless klass.respond_to?(callback_meth)
klass.send(:define_method, callback_meth) do |&block|
observer.update(callback, self, &block)
end
klass.send(callback, callback_meth)
end
end
end
end
end
rails-observers-0.1.2/lib/rails/observers/activerecord/active_record.rb 0000644 0000041 0000041 00000000203 12250222654 026361 0 ustar www-data www-data require 'rails/observers/activerecord/base'
module ActiveRecord
autoload :Observer, 'rails/observers/activerecord/observer'
end
rails-observers-0.1.2/lib/rails/observers/activerecord/base.rb 0000644 0000041 0000041 00000000263 12250222654 024470 0 ustar www-data www-data require 'rails/observers/active_model/active_model'
module ActiveRecord
class Base
extend ActiveModel::Observing::ClassMethods
include ActiveModel::Observing
end
end
rails-observers-0.1.2/lib/rails/observers/version.rb 0000644 0000041 0000041 00000000100 12250222654 022557 0 ustar www-data www-data module Rails
module Observers
VERSION = "0.1.2"
end
end
rails-observers-0.1.2/lib/rails/observers/active_model.rb 0000644 0000041 0000041 00000000064 12250222654 023536 0 ustar www-data www-data require 'rails/observers/active_model/active_model'
rails-observers-0.1.2/lib/rails/observers/action_controller/ 0000755 0000041 0000041 00000000000 12250222654 024276 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/action_controller/caching.rb 0000644 0000041 0000041 00000000560 12250222654 026220 0 ustar www-data www-data module ActionController #:nodoc:
module Caching
extend ActiveSupport::Autoload
eager_autoload do
autoload :Sweeper, 'rails/observers/action_controller/caching/sweeping'
autoload :Sweeping, 'rails/observers/action_controller/caching/sweeping'
end
ActionController::Base.extend Sweeping::ClassMethods if defined?(ActiveRecord)
end
end
rails-observers-0.1.2/lib/rails/observers/action_controller/caching/ 0000755 0000041 0000041 00000000000 12250222654 025672 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/action_controller/caching/sweeping.rb 0000644 0000041 0000041 00000010125 12250222654 030037 0 ustar www-data www-data module ActionController #:nodoc:
module Caching
# Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
# They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
#
# class ListSweeper < ActionController::Caching::Sweeper
# observe List, Item
#
# def after_save(record)
# list = record.is_a?(List) ? record : record.list
# expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
# expire_action(:controller => "lists", :action => "all")
# list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
# end
# end
#
# The sweeper is assigned in the controllers that wish to have its job performed using the cache_sweeper class method:
#
# class ListsController < ApplicationController
# caches_action :index, :show, :public, :feed
# cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
# end
#
# In the example above, four actions are cached and three actions are responsible for expiring those caches.
#
# You can also name an explicit class in the declaration of a sweeper, which is needed if the sweeper is in a module:
#
# class ListsController < ApplicationController
# caches_action :index, :show, :public, :feed
# cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
# end
module Sweeping
module ClassMethods #:nodoc:
def cache_sweeper(*sweepers)
configuration = sweepers.extract_options!
sweepers.each do |sweeper|
ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(sweeper.to_s.classify) : sweeper).instance
if sweeper_instance.is_a?(Sweeper)
around_filter(sweeper_instance, :only => configuration[:only])
else
after_filter(sweeper_instance, :only => configuration[:only])
end
end
end
end
end
if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
class Sweeper < ActiveRecord::Observer #:nodoc:
attr_accessor :controller
def initialize(*args)
super
@controller = nil
end
def before(controller)
self.controller = controller
callback(:before) if controller.perform_caching
true # before method from sweeper should always return true
end
def after(controller)
self.controller = controller
callback(:after) if controller.perform_caching
end
def around(controller)
before(controller)
yield
after(controller)
ensure
clean_up
end
protected
# gets the action cache path for the given options.
def action_path_for(options)
Actions::ActionCachePath.new(controller, options).path
end
# Retrieve instance variables set in the controller.
def assigns(key)
controller.instance_variable_get("@#{key}")
end
private
def clean_up
# Clean up, so that the controller can be collected after this request
self.controller = nil
end
def callback(timing)
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
__send__(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
__send__(action_callback_method_name) if respond_to?(action_callback_method_name, true)
end
def method_missing(method, *arguments, &block)
return super unless @controller
@controller.__send__(method, *arguments, &block)
end
end
end
end
end
rails-observers-0.1.2/lib/rails/observers/active_model/ 0000755 0000041 0000041 00000000000 12250222654 023211 5 ustar www-data www-data rails-observers-0.1.2/lib/rails/observers/active_model/observing.rb 0000644 0000041 0000041 00000027213 12250222654 025541 0 ustar www-data www-data require 'singleton'
require 'rails/observers/active_model/observer_array'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/object/try'
require 'active_support/descendants_tracker'
module ActiveModel
# == Active Model Observers Activation
module Observing
extend ActiveSupport::Concern
included do
extend ActiveSupport::DescendantsTracker
end
module ClassMethods
# Activates the observers assigned.
#
# class ORM
# include ActiveModel::Observing
# end
#
# # Calls PersonObserver.instance
# ORM.observers = :person_observer
#
# # Calls Cacher.instance and GarbageCollector.instance
# ORM.observers = :cacher, :garbage_collector
#
# # Same as above, just using explicit class references
# ORM.observers = Cacher, GarbageCollector
#
# Note: Setting this does not instantiate the observers yet.
# instantiate_observers is called during startup, and before
# each development request.
def observers=(*values)
observers.replace(values.flatten)
end
# Gets an array of observers observing this model. The array also provides
# +enable+ and +disable+ methods that allow you to selectively enable and
# disable observers (see ActiveModel::ObserverArray.enable and
# ActiveModel::ObserverArray.disable for more on this).
#
# class ORM
# include ActiveModel::Observing
# end
#
# ORM.observers = :cacher, :garbage_collector
# ORM.observers # => [:cacher, :garbage_collector]
# ORM.observers.class # => ActiveModel::ObserverArray
def observers
@observers ||= ObserverArray.new(self)
end
# Returns the current observer instances.
#
# class Foo
# include ActiveModel::Observing
#
# attr_accessor :status
# end
#
# class FooObserver < ActiveModel::Observer
# def on_spec(record, *args)
# record.status = true
# end
# end
#
# Foo.observers = FooObserver
# Foo.instantiate_observers
#
# Foo.observer_instances # => [#]
def observer_instances
@observer_instances ||= []
end
# Instantiate the global observers.
#
# class Foo
# include ActiveModel::Observing
#
# attr_accessor :status
# end
#
# class FooObserver < ActiveModel::Observer
# def on_spec(record, *args)
# record.status = true
# end
# end
#
# Foo.observers = FooObserver
#
# foo = Foo.new
# foo.status = false
# foo.notify_observers(:on_spec)
# foo.status # => false
#
# Foo.instantiate_observers # => [FooObserver]
#
# foo = Foo.new
# foo.status = false
# foo.notify_observers(:on_spec)
# foo.status # => true
def instantiate_observers
observers.each { |o| instantiate_observer(o) }
end
# Add a new observer to the pool. The new observer needs to respond to
# update, otherwise it raises an +ArgumentError+ exception.
#
# class Foo
# include ActiveModel::Observing
# end
#
# class FooObserver < ActiveModel::Observer
# end
#
# Foo.add_observer(FooObserver.instance)
#
# Foo.observers_instance
# # => [#]
def add_observer(observer)
unless observer.respond_to? :update
raise ArgumentError, "observer needs to respond to 'update'"
end
observer_instances << observer
end
# Fires notifications to model's observers.
#
# def save
# notify_observers(:before_save)
# ...
# notify_observers(:after_save)
# end
#
# Custom notifications can be sent in a similar fashion:
#
# notify_observers(:custom_notification, :foo)
#
# This will call custom_notification, passing as arguments
# the current object and :foo.
def notify_observers(*args)
observer_instances.each { |observer| observer.update(*args) }
end
# Returns the total number of instantiated observers.
#
# class Foo
# include ActiveModel::Observing
#
# attr_accessor :status
# end
#
# class FooObserver < ActiveModel::Observer
# def on_spec(record, *args)
# record.status = true
# end
# end
#
# Foo.observers = FooObserver
# Foo.observers_count # => 0
# Foo.instantiate_observers
# Foo.observers_count # => 1
def observers_count
observer_instances.size
end
# count_observers is deprecated. Use #observers_count.
def count_observers
msg = "count_observers is deprecated in favor of observers_count"
ActiveSupport::Deprecation.warn(msg)
observers_count
end
protected
def instantiate_observer(observer) #:nodoc:
# string/symbol
if observer.respond_to?(:to_sym)
observer = observer.to_s.camelize.constantize
end
if observer.respond_to?(:instance)
observer.instance
else
raise ArgumentError,
"#{observer} must be a lowercase, underscored class name (or " +
"the class itself) responding to the method :instance. " +
"Example: Person.observers = :big_brother # calls " +
"BigBrother.instance"
end
end
# Notify observers when the observed class is subclassed.
def inherited(subclass) #:nodoc:
super
notify_observers :observed_class_inherited, subclass
end
end
# Notify a change to the list of observers.
#
# class Foo
# include ActiveModel::Observing
#
# attr_accessor :status
# end
#
# class FooObserver < ActiveModel::Observer
# def on_spec(record, *args)
# record.status = true
# end
# end
#
# Foo.observers = FooObserver
# Foo.instantiate_observers # => [FooObserver]
#
# foo = Foo.new
# foo.status = false
# foo.notify_observers(:on_spec)
# foo.status # => true
#
# See ActiveModel::Observing::ClassMethods.notify_observers for more
# information.
def notify_observers(method, *extra_args)
self.class.notify_observers(method, self, *extra_args)
end
end
# == Active Model Observers
#
# Observer classes respond to life cycle callbacks to implement trigger-like
# behavior outside the original class. This is a great way to reduce the
# clutter that normally comes when the model class is burdened with
# functionality that doesn't pertain to the core responsibility of the
# class.
#
# class CommentObserver < ActiveModel::Observer
# def after_save(comment)
# Notifications.comment('admin@do.com', 'New comment was posted', comment).deliver
# end
# end
#
# This Observer sends an email when a Comment#save is finished.
#
# class ContactObserver < ActiveModel::Observer
# def after_create(contact)
# contact.logger.info('New contact added!')
# end
#
# def after_destroy(contact)
# contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
# end
# end
#
# This Observer uses logger to log when specific callbacks are triggered.
#
# == Observing a class that can't be inferred
#
# Observers will by default be mapped to the class with which they share a
# name. So CommentObserver will be tied to observing Comment,
# ProductManagerObserver to ProductManager, and so on. If
# you want to name your observer differently than the class you're interested
# in observing, you can use the Observer.observe class method which
# takes either the concrete class (Product) or a symbol for that
# class (:product):
#
# class AuditObserver < ActiveModel::Observer
# observe :account
#
# def after_update(account)
# AuditTrail.new(account, 'UPDATED')
# end
# end
#
# If the audit observer needs to watch more than one kind of object, this can
# be specified with multiple arguments:
#
# class AuditObserver < ActiveModel::Observer
# observe :account, :balance
#
# def after_update(record)
# AuditTrail.new(record, 'UPDATED')
# end
# end
#
# The AuditObserver will now act on both updates to Account
# and Balance by treating them both as records.
#
# If you're using an Observer in a Rails application with Active Record, be
# sure to read about the necessary configuration in the documentation for
# ActiveRecord::Observer.
class Observer
include Singleton
extend ActiveSupport::DescendantsTracker
class << self
# Attaches the observer to the supplied model classes.
#
# class AuditObserver < ActiveModel::Observer
# observe :account, :balance
# end
#
# AuditObserver.observed_classes # => [Account, Balance]
def observe(*models)
models.flatten!
models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
singleton_class.redefine_method(:observed_classes) { models }
end
# Returns an array of Classes to observe.
#
# AccountObserver.observed_classes # => [Account]
#
# You can override this instead of using the +observe+ helper.
#
# class AuditObserver < ActiveModel::Observer
# def self.observed_classes
# [Account, Balance]
# end
# end
def observed_classes
Array(observed_class)
end
# Returns the class observed by default. It's inferred from the observer's
# class name.
#
# PersonObserver.observed_class # => Person
# AccountObserver.observed_class # => Account
def observed_class
name[/(.*)Observer/, 1].try :constantize
end
end
# Start observing the declared classes and their subclasses.
# Called automatically by the instance method.
def initialize #:nodoc:
observed_classes.each { |klass| add_observer!(klass) }
end
def observed_classes #:nodoc:
self.class.observed_classes
end
# Send observed_method(object) if the method exists and
# the observer is enabled for the given object's class.
def update(observed_method, object, *extra_args, &block) #:nodoc:
return if !respond_to?(observed_method) || disabled_for?(object)
send(observed_method, object, *extra_args, &block)
end
# Special method sent by the observed class when it is inherited.
# Passes the new subclass.
def observed_class_inherited(subclass) #:nodoc:
self.class.observe(observed_classes + [subclass])
add_observer!(subclass)
end
protected
def add_observer!(klass) #:nodoc:
klass.add_observer(self)
end
# Returns true if notifications are disabled for this object.
def disabled_for?(object) #:nodoc:
klass = object.class
return false unless klass.respond_to?(:observers)
klass.observers.disabled_for?(self)
end
end
end
rails-observers-0.1.2/lib/rails/observers/active_model/observer_array.rb 0000644 0000041 0000041 00000011016 12250222654 026562 0 ustar www-data www-data require 'set'
module ActiveModel
# Stores the enabled/disabled state of individual observers for
# a particular model class.
class ObserverArray < Array
attr_reader :model_class
def initialize(model_class, *args) #:nodoc:
@model_class = model_class
super(*args)
end
# Returns +true+ if the given observer is disabled for the model class,
# +false+ otherwise.
def disabled_for?(observer) #:nodoc:
disabled_observers.include?(observer.class)
end
# Disables one or more observers. This supports multiple forms:
#
# ORM.observers.disable :all
# # => disables all observers for all models subclassed from
# # an ORM base class that includes ActiveModel::Observing
# # e.g. ActiveRecord::Base
#
# ORM.observers.disable :user_observer
# # => disables the UserObserver
#
# User.observers.disable AuditTrail
# # => disables the AuditTrail observer for User notifications.
# # Other models will still notify the AuditTrail observer.
#
# ORM.observers.disable :observer_1, :observer_2
# # => disables Observer1 and Observer2 for all models.
#
# User.observers.disable :all do
# # all user observers are disabled for
# # just the duration of the block
# end
def disable(*observers, &block)
set_enablement(false, observers, &block)
end
# Enables one or more observers. This supports multiple forms:
#
# ORM.observers.enable :all
# # => enables all observers for all models subclassed from
# # an ORM base class that includes ActiveModel::Observing
# # e.g. ActiveRecord::Base
#
# ORM.observers.enable :user_observer
# # => enables the UserObserver
#
# User.observers.enable AuditTrail
# # => enables the AuditTrail observer for User notifications.
# # Other models will not be affected (i.e. they will not
# # trigger notifications to AuditTrail if previously disabled)
#
# ORM.observers.enable :observer_1, :observer_2
# # => enables Observer1 and Observer2 for all models.
#
# User.observers.enable :all do
# # all user observers are enabled for
# # just the duration of the block
# end
#
# Note: all observers are enabled by default. This method is only
# useful when you have previously disabled one or more observers.
def enable(*observers, &block)
set_enablement(true, observers, &block)
end
protected
def disabled_observers #:nodoc:
@disabled_observers ||= Set.new
end
def observer_class_for(observer) #:nodoc:
return observer if observer.is_a?(Class)
if observer.respond_to?(:to_sym) # string/symbol
observer.to_s.camelize.constantize
else
raise ArgumentError, "#{observer} was not a class or a " +
"lowercase, underscored class name as expected."
end
end
def start_transaction #:nodoc:
disabled_observer_stack.push(disabled_observers.dup)
each_subclass_array do |array|
array.start_transaction
end
end
def disabled_observer_stack #:nodoc:
@disabled_observer_stack ||= []
end
def end_transaction #:nodoc:
@disabled_observers = disabled_observer_stack.pop
each_subclass_array do |array|
array.end_transaction
end
end
def transaction #:nodoc:
start_transaction
begin
yield
ensure
end_transaction
end
end
def each_subclass_array #:nodoc:
model_class.descendants.each do |subclass|
yield subclass.observers
end
end
def set_enablement(enabled, observers) #:nodoc:
if block_given?
transaction do
set_enablement(enabled, observers)
yield
end
else
observers = ActiveModel::Observer.descendants if observers == [:all]
observers.each do |obs|
klass = observer_class_for(obs)
unless klass < ActiveModel::Observer
raise ArgumentError.new("#{obs} does not refer to a valid observer")
end
if enabled
disabled_observers.delete(klass)
else
disabled_observers << klass
end
end
each_subclass_array do |array|
array.set_enablement(enabled, observers)
end
end
end
end
end
rails-observers-0.1.2/lib/rails/observers/active_model/active_model.rb 0000644 0000041 0000041 00000000226 12250222654 026171 0 ustar www-data www-data module ActiveModel
autoload :Observer, 'rails/observers/active_model/observing'
autoload :Observing, 'rails/observers/active_model/observing'
end
rails-observers-0.1.2/lib/rails/observers/railtie.rb 0000644 0000041 0000041 00000001723 12250222654 022537 0 ustar www-data www-data require 'rails/railtie'
module Rails
module Observers
class Railtie < ::Rails::Railtie
initializer "active_record.observer", :before => "active_record.set_configs" do |app|
ActiveSupport.on_load(:active_record) do
require "rails/observers/activerecord/active_record"
if observers = app.config.respond_to?(:active_record) && app.config.active_record.delete(:observers)
send :observers=, observers
end
end
end
initializer "action_controller.caching.sweepers" do
ActiveSupport.on_load(:action_controller) do
require "rails/observers/action_controller/caching"
end
end
config.after_initialize do |app|
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.instantiate_observers
ActionDispatch::Reloader.to_prepare do
ActiveRecord::Base.instantiate_observers
end
end
end
end
end
end
rails-observers-0.1.2/metadata.yml 0000644 0000041 0000041 00000013011 12250222654 017163 0 ustar www-data www-data --- !ruby/object:Gem::Specification
name: rails-observers
version: !ruby/object:Gem::Version
version: 0.1.2
platform: ruby
authors:
- Rafael Mendonça França
- Steve Klabnik
autorequire:
bindir: bin
cert_chain: []
date: 2013-07-19 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: activemodel
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
- !ruby/object:Gem::Dependency
name: minitest
requirement: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '3'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '3'
- !ruby/object:Gem::Dependency
name: railties
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
- !ruby/object:Gem::Dependency
name: activerecord
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
- !ruby/object:Gem::Dependency
name: actionmailer
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
- !ruby/object:Gem::Dependency
name: actionpack
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '4.0'
- !ruby/object:Gem::Dependency
name: sqlite3
requirement: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '1.3'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ~>
- !ruby/object:Gem::Version
version: '1.3'
description: Rails observer (removed from core in Rails 4.0)
email:
- rafaelmfranca@gmail.com
- steve@steveklabnik.com
executables: []
extensions: []
extra_rdoc_files: []
files:
- .gitignore
- .travis.yml
- Gemfile
- LICENSE
- README.md
- Rakefile
- lib/generators/active_record/observer/observer_generator.rb
- lib/generators/active_record/observer/templates/observer.rb
- lib/generators/rails/observer/USAGE
- lib/generators/rails/observer/observer_generator.rb
- lib/generators/test_unit/observer/observer_generator.rb
- lib/generators/test_unit/observer/templates/unit_test.rb
- lib/rails-observers.rb
- lib/rails/observers/action_controller/caching.rb
- lib/rails/observers/action_controller/caching/sweeping.rb
- lib/rails/observers/active_model.rb
- lib/rails/observers/active_model/active_model.rb
- lib/rails/observers/active_model/observer_array.rb
- lib/rails/observers/active_model/observing.rb
- lib/rails/observers/activerecord/active_record.rb
- lib/rails/observers/activerecord/base.rb
- lib/rails/observers/activerecord/observer.rb
- lib/rails/observers/railtie.rb
- lib/rails/observers/version.rb
- rails-observers.gemspec
- rails-observers.gemspec.erb
- test/configuration_test.rb
- test/console_test.rb
- test/fixtures/developers.yml
- test/fixtures/minimalistics.yml
- test/fixtures/topics.yml
- test/generators/generators_test_helper.rb
- test/generators/namespaced_generators_test.rb
- test/generators/observer_generator_test.rb
- test/helper.rb
- test/isolation/abstract_unit.rb
- test/lifecycle_test.rb
- test/models/observers.rb
- test/observer_array_test.rb
- test/observing_test.rb
- test/rake_test.rb
- test/sweeper_test.rb
- test/transaction_callbacks_test.rb
homepage: https://github.com/rails/rails-observers
licenses: []
metadata: {}
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
rubygems_version: 2.0.2
signing_key:
specification_version: 4
summary: ActiveModel::Observer, ActiveRecord::Observer and ActionController::Caching::Sweeper
extracted from Rails.
test_files:
- test/configuration_test.rb
- test/console_test.rb
- test/fixtures/developers.yml
- test/fixtures/minimalistics.yml
- test/fixtures/topics.yml
- test/generators/generators_test_helper.rb
- test/generators/namespaced_generators_test.rb
- test/generators/observer_generator_test.rb
- test/helper.rb
- test/isolation/abstract_unit.rb
- test/lifecycle_test.rb
- test/models/observers.rb
- test/observer_array_test.rb
- test/observing_test.rb
- test/rake_test.rb
- test/sweeper_test.rb
- test/transaction_callbacks_test.rb
rails-observers-0.1.2/test/ 0000755 0000041 0000041 00000000000 12250222654 015643 5 ustar www-data www-data rails-observers-0.1.2/test/helper.rb 0000644 0000041 0000041 00000003202 12250222654 017444 0 ustar www-data www-data require 'minitest/autorun'
require 'active_record'
require 'rails/observers/activerecord/active_record'
FIXTURES_ROOT = File.expand_path(File.dirname(__FILE__)) + "/fixtures"
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
self.fixture_path = FIXTURES_ROOT
self.use_instantiated_fixtures = false
self.use_transactional_fixtures = true
end
ActiveRecord::Base.configurations = { "test" => { adapter: 'sqlite3', database: ':memory:' } }
ActiveRecord::Base.establish_connection(:test)
ActiveRecord::Schema.verbose = false
ActiveRecord::Schema.define do
create_table :topics do |t|
t.string :title
t.string :author_name
t.string :author_email_address
t.datetime :written_on
t.time :bonus_time
t.date :last_read
t.text :content
t.text :important
t.boolean :approved, :default => true
t.integer :replies_count, :default => 0
t.integer :parent_id
t.string :parent_title
t.string :type
t.string :group
t.timestamps
end
create_table :comments do |t|
t.string :title
end
create_table :minimalistics do |t|
end
create_table :developers do |t|
t.string :name
t.integer :salary
end
end
class Topic < ActiveRecord::Base
has_many :replies, dependent: :destroy, foreign_key: "parent_id"
end
class Reply < Topic
belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
end
class Comment < ActiveRecord::Base
def self.lol
"lol"
end
end
class Developer < ActiveRecord::Base
end
class Minimalistic < ActiveRecord::Base
end
ActiveSupport::Deprecation.silence do
require 'active_record/test_case'
end
rails-observers-0.1.2/test/sweeper_test.rb 0000644 0000041 0000041 00000004106 12250222654 020702 0 ustar www-data www-data require 'minitest/autorun'
require 'action_controller'
require 'active_record'
require 'rails/observers/activerecord/active_record'
require 'rails/observers/action_controller/caching'
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
class AppSweeper < ActionController::Caching::Sweeper; end
class SweeperTestController < ActionController::Base
include SharedTestRoutes.url_helpers
cache_sweeper :app_sweeper
def show
render text: 'hello world'
end
def error
raise StandardError.new
end
end
class SweeperTest < ActionController::TestCase
def setup
@routes = SharedTestRoutes
@routes.draw do
get ':controller(/:action)'
end
super
end
def test_sweeper_should_not_ignore_no_method_error
sweeper = ActionController::Caching::Sweeper.send(:new)
assert_raise NoMethodError do
sweeper.send_not_defined
end
end
def test_sweeper_should_not_block_rendering
response = test_process(SweeperTestController)
assert_equal 'hello world', response.body
end
def test_sweeper_should_clean_up_if_exception_is_raised
assert_raise StandardError do
test_process(SweeperTestController, 'error')
end
assert_nil AppSweeper.instance.controller
end
def test_before_method_of_sweeper_should_always_return_true
sweeper = ActionController::Caching::Sweeper.send(:new)
assert sweeper.before(SweeperTestController.new)
end
def test_after_method_of_sweeper_should_always_return_nil
sweeper = ActionController::Caching::Sweeper.send(:new)
assert_nil sweeper.after(SweeperTestController.new)
end
def test_sweeper_should_not_ignore_unknown_method_calls
sweeper = ActionController::Caching::Sweeper.send(:new)
assert_raise NameError do
sweeper.instance_eval do
some_method_that_doesnt_exist
end
end
end
private
def test_process(controller, action = "show")
@controller = controller.is_a?(Class) ? controller.new : controller
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
process(action)
end
end
rails-observers-0.1.2/test/fixtures/ 0000755 0000041 0000041 00000000000 12250222654 017514 5 ustar www-data www-data rails-observers-0.1.2/test/fixtures/minimalistics.yml 0000644 0000041 0000041 00000000017 12250222654 023102 0 ustar www-data www-data first:
id: 1
rails-observers-0.1.2/test/fixtures/topics.yml 0000644 0000041 0000041 00000001532 12250222654 021541 0 ustar www-data www-data first:
id: 1
title: The First Topic
author_name: David
author_email_address: david@loudthinking.com
written_on: 2003-07-16t15:28:11.2233+01:00
last_read: 2004-04-15
bonus_time: 2005-01-30t15:28:00.00+01:00
content: Have a nice day
approved: false
replies_count: 1
second:
id: 2
title: The Second Topic of the day
author_name: Mary
written_on: 2004-07-15t15:28:00.0099+01:00
content: Have a nice day
approved: true
replies_count: 0
parent_id: 1
type: Reply
third:
id: 3
title: The Third Topic of the day
author_name: Carl
written_on: 2012-08-12t20:24:22.129346+00:00
content: I'm a troll
approved: true
replies_count: 1
fourth:
id: 4
title: The Fourth Topic of the day
author_name: Carl
written_on: 2006-07-15t15:28:00.0099+01:00
content: Why not?
approved: true
type: Reply
parent_id: 3
rails-observers-0.1.2/test/fixtures/developers.yml 0000644 0000041 0000041 00000000055 12250222654 022407 0 ustar www-data www-data david:
id: 1
name: David
salary: 80000
rails-observers-0.1.2/test/lifecycle_test.rb 0000644 0000041 0000041 00000014253 12250222654 021173 0 ustar www-data www-data require 'helper'
class SpecialDeveloper < Developer; end
class DeveloperObserver < ActiveRecord::Observer
def calls
@calls ||= []
end
def before_save(developer)
calls << developer
end
end
class SalaryChecker < ActiveRecord::Observer
observe :special_developer
attr_accessor :last_saved
def before_save(developer)
return developer.salary > 80000
end
module Implementation
def after_save(developer)
self.last_saved = developer
end
end
include Implementation
end
class TopicaAuditor < ActiveRecord::Observer
observe :topic
attr_reader :topic
def after_find(topic)
@topic = topic
end
end
class TopicObserver < ActiveRecord::Observer
attr_reader :topic
def after_find(topic)
@topic = topic
end
# Create an after_save callback, so a notify_observer hook is created
# on :topic.
def after_save(nothing)
end
end
class MinimalisticObserver < ActiveRecord::Observer
attr_reader :minimalistic
def after_find(minimalistic)
@minimalistic = minimalistic
end
end
class MultiObserver < ActiveRecord::Observer
attr_reader :record
def self.observed_class() [ Topic, Developer ] end
cattr_reader :last_inherited
@@last_inherited = nil
def observed_class_inherited_with_testing(subclass)
observed_class_inherited_without_testing(subclass)
@@last_inherited = subclass
end
alias_method_chain :observed_class_inherited, :testing
def after_find(record)
@record = record
end
end
class ValidatedComment < Comment
attr_accessor :callers
before_validation :record_callers
after_validation do
record_callers
end
def record_callers
callers << self.class if callers
end
end
class ValidatedCommentObserver < ActiveRecord::Observer
attr_accessor :callers
def after_validation(model)
callers << self.class if callers
end
end
class AroundTopic < Topic
end
class AroundTopicObserver < ActiveRecord::Observer
observe :around_topic
def topic_ids
@topic_ids ||= []
end
def around_save(topic)
topic_ids << topic.id
yield(topic)
topic_ids << topic.id
end
end
class LifecycleTest < ActiveRecord::TestCase
fixtures :topics, :developers, :minimalistics
def test_before_destroy
topic = Topic.find(1)
assert_difference 'Topic.count', -(1 + topic.replies.size) do
topic.destroy
end
end
def test_auto_observer
topic_observer = TopicaAuditor.instance
assert_nil TopicaAuditor.observed_class
assert_equal [Topic], TopicaAuditor.observed_classes.to_a
topic = Topic.find(1)
assert_equal topic.title, topic_observer.topic.title
end
def test_inferred_auto_observer
topic_observer = TopicObserver.instance
assert_equal Topic, TopicObserver.observed_class
topic = Topic.find(1)
assert_equal topic.title, topic_observer.topic.title
end
def test_observing_two_classes
multi_observer = MultiObserver.instance
topic = Topic.find(1)
assert_equal topic.title, multi_observer.record.title
developer = Developer.find(1)
assert_equal developer.name, multi_observer.record.name
end
def test_observing_subclasses
multi_observer = MultiObserver.instance
developer = SpecialDeveloper.find(1)
assert_equal developer.name, multi_observer.record.name
klass = Class.new(Developer)
assert_equal klass, multi_observer.last_inherited
developer = klass.find(1)
assert_equal developer.name, multi_observer.record.name
end
def test_after_find_can_be_observed_when_its_not_defined_on_the_model
observer = MinimalisticObserver.instance
assert_equal Minimalistic, MinimalisticObserver.observed_class
minimalistic = Minimalistic.find(1)
assert_equal minimalistic, observer.minimalistic
end
def test_after_find_can_be_observed_when_its_defined_on_the_model
observer = TopicObserver.instance
assert_equal Topic, TopicObserver.observed_class
topic = Topic.find(1)
assert_equal topic, observer.topic
end
def test_invalid_observer
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
end
test "model callbacks fire before observers are notified" do
callers = []
comment = ValidatedComment.new
comment.callers = ValidatedCommentObserver.instance.callers = callers
comment.valid?
assert_equal [ValidatedComment, ValidatedComment, ValidatedCommentObserver], callers,
"model callbacks did not fire before observers were notified"
end
test "able to save developer" do
SalaryChecker.instance # activate
developer = SpecialDeveloper.new :name => 'Roger', :salary => 100000
assert developer.save, "developer with normal salary failed to save"
end
test "unable to save developer with low salary" do
SalaryChecker.instance # activate
developer = SpecialDeveloper.new :name => 'Rookie', :salary => 50000
assert !developer.save, "allowed to save a developer with too low salary"
end
test "able to call methods defined with included module" do # https://rails.lighthouseapp.com/projects/8994/tickets/6065-activerecordobserver-is-not-aware-of-method-added-by-including-modules
SalaryChecker.instance # activate
developer = SpecialDeveloper.create! :name => 'Roger', :salary => 100000
assert_equal developer, SalaryChecker.instance.last_saved
end
test "around filter from observer should accept block" do
observer = AroundTopicObserver.instance
topic = AroundTopic.new
topic.save
assert_nil observer.topic_ids.first
assert_not_nil observer.topic_ids.last
end
test "able to disable observers" do
observer = DeveloperObserver.instance # activate
observer.calls.clear
ActiveRecord::Base.observers.disable DeveloperObserver do
Developer.create! :name => 'Ancestor', :salary => 100000
SpecialDeveloper.create! :name => 'Descendent', :salary => 100000
end
assert_equal [], observer.calls
end
def test_observer_is_called_once
observer = DeveloperObserver.instance # activate
observer.calls.clear
developer = Developer.create! :name => 'Ancestor', :salary => 100000
special_developer = SpecialDeveloper.create! :name => 'Descendent', :salary => 100000
assert_equal [developer, special_developer], observer.calls
end
end
rails-observers-0.1.2/test/observer_array_test.rb 0000644 0000041 0000041 00000017003 12250222654 022255 0 ustar www-data www-data require 'minitest/autorun'
require 'active_model'
require 'rails/observers/active_model/active_model'
require 'models/observers'
class ObserverArrayTest < ActiveModel::TestCase
def teardown
ORM.observers.enable :all
Budget.observers.enable :all
Widget.observers.enable :all
end
def assert_observer_notified(model_class, observer_class)
observer_class.instance.before_save_invocations.clear
model_instance = model_class.new
model_instance.save
assert_equal [model_instance], observer_class.instance.before_save_invocations
end
def assert_observer_not_notified(model_class, observer_class)
observer_class.instance.before_save_invocations.clear
model_instance = model_class.new
model_instance.save
assert_equal [], observer_class.instance.before_save_invocations
end
test "all observers are enabled by default" do
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can disable individual observers using a class constant" do
ORM.observers.disable WidgetObserver
assert_observer_not_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can enable individual observers using a class constant" do
ORM.observers.disable :all
ORM.observers.enable AuditTrail
assert_observer_not_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can disable individual observers using a symbol" do
ORM.observers.disable :budget_observer
assert_observer_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can enable individual observers using a symbol" do
ORM.observers.disable :all
ORM.observers.enable :audit_trail
assert_observer_not_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can disable multiple observers at a time" do
ORM.observers.disable :widget_observer, :budget_observer
assert_observer_not_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can enable multiple observers at a time" do
ORM.observers.disable :all
ORM.observers.enable :widget_observer, :budget_observer
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_not_notified Budget, AuditTrail
end
test "can disable all observers using :all" do
ORM.observers.disable :all
assert_observer_not_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_not_notified Budget, AuditTrail
end
test "can enable all observers using :all" do
ORM.observers.disable :all
ORM.observers.enable :all
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can disable observers on individual models without affecting those observers on other models" do
Widget.observers.disable :all
assert_observer_not_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can enable observers on individual models without affecting those observers on other models" do
ORM.observers.disable :all
Budget.observers.enable AuditTrail
assert_observer_not_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can disable observers for the duration of a block" do
yielded = false
ORM.observers.disable :budget_observer do
yielded = true
assert_observer_notified Widget, WidgetObserver
assert_observer_not_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
assert yielded
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "can enable observers for the duration of a block" do
yielded = false
Widget.observers.disable :all
Widget.observers.enable :all do
yielded = true
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
assert yielded
assert_observer_not_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "raises an appropriate error when a developer accidentally enables or disables the wrong class (i.e. Widget instead of WidgetObserver)" do
assert_raise ArgumentError do
ORM.observers.enable :widget
end
assert_raise ArgumentError do
ORM.observers.enable Widget
end
assert_raise ArgumentError do
ORM.observers.disable :widget
end
assert_raise ArgumentError do
ORM.observers.disable Widget
end
end
test "allows #enable at the superclass level to override #disable at the subclass level when called last" do
Widget.observers.disable :all
ORM.observers.enable :all
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
test "allows #disable at the superclass level to override #enable at the subclass level when called last" do
Budget.observers.enable :audit_trail
ORM.observers.disable :audit_trail
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_not_notified Budget, AuditTrail
end
test "can use the block form at different levels of the hierarchy" do
yielded = false
Widget.observers.disable :all
ORM.observers.enable :all do
yielded = true
assert_observer_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
assert yielded
assert_observer_not_notified Widget, WidgetObserver
assert_observer_notified Budget, BudgetObserver
assert_observer_not_notified Widget, AuditTrail
assert_observer_notified Budget, AuditTrail
end
end
rails-observers-0.1.2/test/generators/ 0000755 0000041 0000041 00000000000 12250222654 020014 5 ustar www-data www-data rails-observers-0.1.2/test/generators/observer_generator_test.rb 0000644 0000041 0000041 00000002026 12250222654 025275 0 ustar www-data www-data require 'generators/generators_test_helper'
require 'generators/rails/observer/observer_generator'
class ObserverGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::ObserverGenerator
destination File.expand_path("../../tmp", __FILE__)
arguments %w(account)
def setup
super
prepare_destination
end
def test_invokes_default_orm
run_generator
assert_file "app/models/account_observer.rb", /class AccountObserver < ActiveRecord::Observer/
end
def test_invokes_default_orm_with_class_path
run_generator ["admin/account"]
assert_file "app/models/admin/account_observer.rb", /class Admin::AccountObserver < ActiveRecord::Observer/
end
def test_invokes_default_test_framework
run_generator
assert_file "test/unit/account_observer_test.rb", /class AccountObserverTest < ActiveSupport::TestCase/
end
def test_logs_if_the_test_framework_cannot_be_found
content = run_generator ["account", "--test-framework=rspec"]
assert_match(/rspec \[not found\]/, content)
end
end
rails-observers-0.1.2/test/generators/namespaced_generators_test.rb 0000644 0000041 0000041 00000002067 12250222654 025736 0 ustar www-data www-data require 'generators/generators_test_helper'
require 'generators/rails/observer/observer_generator'
class NamespacedObserverGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::ObserverGenerator
arguments %w(account)
destination File.expand_path("../../tmp", __FILE__)
def setup
super
prepare_destination
Rails::Generators.namespace = TestApp
end
def teardown
super
Rails::Generators.namespace = nil
end
def test_invokes_default_orm
run_generator
assert_file "app/models/test_app/account_observer.rb", /module TestApp/, / class AccountObserver < ActiveRecord::Observer/
end
def test_invokes_default_orm_with_class_path
run_generator ["admin/account"]
assert_file "app/models/test_app/admin/account_observer.rb", /module TestApp/, / class Admin::AccountObserver < ActiveRecord::Observer/
end
def test_invokes_default_test_framework
run_generator
assert_file "test/unit/test_app/account_observer_test.rb", /module TestApp/, / class AccountObserverTest < ActiveSupport::TestCase/
end
end
rails-observers-0.1.2/test/generators/generators_test_helper.rb 0000644 0000041 0000041 00000000521 12250222654 025106 0 ustar www-data www-data require 'minitest/autorun'
require 'fileutils'
require 'rails/all'
require 'rails/generators'
require 'rails/generators/test_case'
module TestApp
class Application < Rails::Application
end
end
# Call configure to load the settings from
# Rails.application.config.generators to Rails::Generators
Rails.application.load_generators
rails-observers-0.1.2/test/transaction_callbacks_test.rb 0000644 0000041 0000041 00000023162 12250222654 023557 0 ustar www-data www-data require "helper"
class TransactionCallbacksTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
fixtures :topics
class TopicWithCallbacks < ActiveRecord::Base
self.table_name = :topics
after_commit{|record| record.send(:do_after_commit, nil)}
after_commit(:on => :create){|record| record.send(:do_after_commit, :create)}
after_commit(:on => :update){|record| record.send(:do_after_commit, :update)}
after_commit(:on => :destroy){|record| record.send(:do_after_commit, :destroy)}
after_rollback{|record| record.send(:do_after_rollback, nil)}
after_rollback(:on => :create){|record| record.send(:do_after_rollback, :create)}
after_rollback(:on => :update){|record| record.send(:do_after_rollback, :update)}
after_rollback(:on => :destroy){|record| record.send(:do_after_rollback, :destroy)}
def history
@history ||= []
end
def after_commit_block(on = nil, &block)
@after_commit ||= {}
@after_commit[on] ||= []
@after_commit[on] << block
end
def after_rollback_block(on = nil, &block)
@after_rollback ||= {}
@after_rollback[on] ||= []
@after_rollback[on] << block
end
def do_after_commit(on)
blocks = @after_commit[on] if defined?(@after_commit)
blocks.each{|b| b.call(self)} if blocks
end
def do_after_rollback(on)
blocks = @after_rollback[on] if defined?(@after_rollback)
blocks.each{|b| b.call(self)} if blocks
end
end
def setup
@first, @second = TopicWithCallbacks.find(1, 3).sort_by { |t| t.id }
end
def test_call_after_commit_after_transaction_commits
@first.after_commit_block{|r| r.history << :after_commit}
@first.after_rollback_block{|r| r.history << :after_rollback}
@first.save!
assert_equal [:after_commit], @first.history
end
def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@first.save!
assert_equal [:commit_on_update], @first.history
end
def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@first.destroy
assert_equal [:commit_on_destroy], @first.history
end
def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record
@new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
@new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@new_record.save!
assert_equal [:commit_on_create], @new_record.history
end
def test_call_after_rollback_after_transaction_rollsback
@first.after_commit_block{|r| r.history << :after_commit}
@first.after_rollback_block{|r| r.history << :after_rollback}
Topic.transaction do
@first.save!
raise ActiveRecord::Rollback
end
assert_equal [:after_rollback], @first.history
end
def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@first.save!
raise ActiveRecord::Rollback
end
assert_equal [:rollback_on_update], @first.history
end
def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_update}
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@first.destroy
raise ActiveRecord::Rollback
end
assert_equal [:rollback_on_destroy], @first.history
end
def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record
@new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
@new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
@new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
@new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@new_record.save!
raise ActiveRecord::Rollback
end
assert_equal [:rollback_on_create], @new_record.history
end
def test_call_after_rollback_when_commit_fails
TopicWithCallbacks.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction)
begin
TopicWithCallbacks.connection.class.class_eval do
def commit_db_transaction; raise "boom!"; end
end
@first.after_commit_block{|r| r.history << :after_commit}
@first.after_rollback_block{|r| r.history << :after_rollback}
assert !@first.save rescue nil
assert_equal [:after_rollback], @first.history
ensure
TopicWithCallbacks.connection.class.send(:remove_method, :commit_db_transaction)
TopicWithCallbacks.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
end
end
def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint
def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
@first.after_rollback_block{|r| r.rollbacks(1)}
@first.after_commit_block{|r| r.commits(1)}
def @second.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
def @second.commits(i=0); @commits ||= 0; @commits += i if i; end
@second.after_rollback_block{|r| r.rollbacks(1)}
@second.after_commit_block{|r| r.commits(1)}
Topic.transaction do
@first.save!
Topic.transaction(:requires_new => true) do
@second.save!
raise ActiveRecord::Rollback
end
end
assert_equal 1, @first.commits
assert_equal 0, @first.rollbacks
assert_equal 0, @second.commits
assert_equal 1, @second.rollbacks
end
def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails
def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
@first.after_rollback_block{|r| r.rollbacks(1)}
@first.after_commit_block{|r| r.commits(1)}
Topic.transaction do
@first.save
Topic.transaction(:requires_new => true) do
@first.save!
raise ActiveRecord::Rollback
end
Topic.transaction(:requires_new => true) do
@first.save!
raise ActiveRecord::Rollback
end
end
assert_equal 1, @first.commits
assert_equal 2, @first.rollbacks
end
def test_after_transaction_callbacks_should_prevent_callbacks_from_being_called
def @first.last_after_transaction_error=(e); @last_transaction_error = e; end
def @first.last_after_transaction_error; @last_transaction_error; end
@first.after_commit_block{|r| r.last_after_transaction_error = :commit; raise "fail!";}
@first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";}
@second.after_commit_block{|r| r.history << :after_commit}
@second.after_rollback_block{|r| r.history << :after_rollback}
Topic.transaction do
@first.save!
@second.save!
end
assert_equal :commit, @first.last_after_transaction_error
assert_equal [:after_commit], @second.history
@second.history.clear
Topic.transaction do
@first.save!
@second.save!
raise ActiveRecord::Rollback
end
assert_equal :rollback, @first.last_after_transaction_error
assert_equal [:after_rollback], @second.history
end
end
rails-observers-0.1.2/test/configuration_test.rb 0000644 0000041 0000041 00000001375 12250222654 022104 0 ustar www-data www-data require 'isolation/abstract_unit'
require 'rails-observers'
class ConfigurationTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
def teardown
teardown_app
end
test "config.active_record.observers" do
add_to_config <<-RUBY
config.active_record.observers = :foo_observer
RUBY
app_file 'app/models/foo.rb', <<-RUBY
class Foo < ActiveRecord::Base
end
RUBY
app_file 'app/models/foo_observer.rb', <<-RUBY
class FooObserver < ActiveRecord::Observer
end
RUBY
require "#{app_path}/config/environment"
_ = ActiveRecord::Base
assert defined?(FooObserver)
end
end
rails-observers-0.1.2/test/isolation/ 0000755 0000041 0000041 00000000000 12250222654 017644 5 ustar www-data www-data rails-observers-0.1.2/test/isolation/abstract_unit.rb 0000644 0000041 0000041 00000006146 12250222654 023042 0 ustar www-data www-data # Note:
# It is important to keep this file as light as possible
# the goal for tests that require this is to test booting up
# rails from an empty state, so anything added here could
# hide potential failures
#
# It is also good to know what is the bare minimum to get
# Rails booted up.
require 'fileutils'
require 'bundler/setup'
require 'minitest/autorun'
require 'active_support/test_case'
# These files do not require any others and are needed
# to run the tests
require "active_support/testing/isolation"
require "active_support/core_ext/kernel/reporting"
require 'tmpdir'
module TestHelpers
module Paths
def app_template_path
File.join Dir.tmpdir, 'app_template'
end
def tmp_path(*args)
@tmp_path ||= File.realpath(Dir.mktmpdir)
File.join(@tmp_path, *args)
end
def app_path(*args)
tmp_path(*%w[app] + args)
end
def rails_root
app_path
end
end
module Generation
# Build an application by invoking the generator and going through the whole stack.
def build_app(options = {})
@prev_rails_env = ENV['RAILS_ENV']
ENV['RAILS_ENV'] = 'development'
FileUtils.rm_rf(app_path)
FileUtils.cp_r(app_template_path, app_path)
# Delete the initializers unless requested
unless options[:initializers]
Dir["#{app_path}/config/initializers/*.rb"].each do |initializer|
File.delete(initializer)
end
end
gemfile_path = "#{app_path}/Gemfile"
if options[:gemfile].blank? && File.exist?(gemfile_path)
File.delete gemfile_path
end
routes = File.read("#{app_path}/config/routes.rb")
if routes =~ /(\n\s*end\s*)\Z/
File.open("#{app_path}/config/routes.rb", 'w') do |f|
f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', :via => :all\n" + $1
end
end
add_to_config <<-RUBY
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
config.session_store :cookie_store, :key => "_myapp_session"
config.active_support.deprecation = :log
config.action_controller.allow_forgery_protection = false
config.eager_load = false
RUBY
end
def teardown_app
ENV['RAILS_ENV'] = @prev_rails_env if @prev_rails_env
end
def add_to_config(str)
environment = File.read("#{app_path}/config/application.rb")
if environment =~ /(\n\s*end\s*end\s*)\Z/
File.open("#{app_path}/config/application.rb", 'w') do |f|
f.puts $` + "\n#{str}\n" + $1
end
end
end
def app_file(path, contents)
FileUtils.mkdir_p File.dirname("#{app_path}/#{path}")
File.open("#{app_path}/#{path}", 'w') do |f|
f.puts contents
end
end
def boot_rails
require 'rubygems' unless defined? Gem
require 'bundler'
Bundler.setup
end
end
end
class ActiveSupport::TestCase
include TestHelpers::Paths
include TestHelpers::Generation
end
Module.new do
extend TestHelpers::Paths
# Build a rails app
FileUtils.rm_rf(app_template_path)
FileUtils.mkdir(app_template_path)
`rails new #{app_template_path} --skip-gemfile`
end
rails-observers-0.1.2/test/console_test.rb 0000644 0000041 0000041 00000001473 12250222654 020676 0 ustar www-data www-data require 'isolation/abstract_unit'
require 'rails-observers'
class ConsoleTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
boot_rails
end
def teardown
teardown_app
end
def load_environment
require "#{rails_root}/config/environment"
Rails.application.sandbox = false
Rails.application.load_console
end
def test_active_record_does_not_panic_when_referencing_an_observed_constant
add_to_config "config.active_record.observers = :user_observer"
app_file "app/models/user.rb", <<-MODEL
class User < ActiveRecord::Base
end
MODEL
app_file "app/models/user_observer.rb", <<-MODEL
class UserObserver < ActiveRecord::Observer
end
MODEL
load_environment
assert_nothing_raised { User }
end
end
rails-observers-0.1.2/test/observing_test.rb 0000644 0000041 0000041 00000012035 12250222654 021226 0 ustar www-data www-data require 'minitest/autorun'
require 'active_model'
require 'rails/observers/active_model/active_model'
class ObservedModel
include ActiveModel::Observing
class Observer
end
end
class FooObserver < ActiveModel::Observer
class << self
public :new
end
attr_accessor :stub
def on_spec(record, *args)
stub.event_with(record, *args) if stub
end
def around_save(record)
yield :in_around_save
end
end
class Foo
include ActiveModel::Observing
end
class ObservingTest < ActiveModel::TestCase
def setup
ObservedModel.observers.clear
end
test "initializes model with no cached observers" do
assert ObservedModel.observers.empty?, "Not empty: #{ObservedModel.observers.inspect}"
end
test "stores cached observers in an array" do
ObservedModel.observers << :foo
assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
end
test "flattens array of assigned cached observers" do
ObservedModel.observers = [[:foo], :bar]
assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
assert ObservedModel.observers.include?(:bar), ":bar not in #{ObservedModel.observers.inspect}"
end
test "uses an ObserverArray so observers can be disabled" do
ObservedModel.observers = [:foo, :bar]
assert ObservedModel.observers.is_a?(ActiveModel::ObserverArray)
end
test "instantiates observer names passed as strings" do
ObservedModel.observers << 'foo_observer'
FooObserver.expects(:instance)
ObservedModel.instantiate_observers
end
test "instantiates observer names passed as symbols" do
ObservedModel.observers << :foo_observer
FooObserver.expects(:instance)
ObservedModel.instantiate_observers
end
test "instantiates observer classes" do
ObservedModel.observers << ObservedModel::Observer
ObservedModel::Observer.expects(:instance)
ObservedModel.instantiate_observers
end
test "raises an appropriate error when a developer accidentally adds the wrong class (i.e. Widget instead of WidgetObserver)" do
assert_raise ArgumentError do
ObservedModel.observers = ['string']
ObservedModel.instantiate_observers
end
assert_raise ArgumentError do
ObservedModel.observers = [:string]
ObservedModel.instantiate_observers
end
assert_raise ArgumentError do
ObservedModel.observers = [String]
ObservedModel.instantiate_observers
end
end
test "passes observers to subclasses" do
FooObserver.instance
bar = Class.new(Foo)
assert_equal Foo.observers_count, bar.observers_count
end
end
class ObserverTest < ActiveModel::TestCase
def setup
ObservedModel.observers = :foo_observer
FooObserver.singleton_class.instance_eval do
alias_method :original_observed_classes, :observed_classes
end
end
def teardown
FooObserver.singleton_class.instance_eval do
undef_method :observed_classes
alias_method :observed_classes, :original_observed_classes
end
end
test "guesses implicit observable model name" do
assert_equal Foo, FooObserver.observed_class
end
test "tracks implicit observable models" do
instance = FooObserver.new
assert_equal [Foo], instance.observed_classes
end
test "tracks explicit observed model class" do
FooObserver.observe ObservedModel
instance = FooObserver.new
assert_equal [ObservedModel], instance.observed_classes
end
test "tracks explicit observed model as string" do
FooObserver.observe 'observed_model'
instance = FooObserver.new
assert_equal [ObservedModel], instance.observed_classes
end
test "tracks explicit observed model as symbol" do
FooObserver.observe :observed_model
instance = FooObserver.new
assert_equal [ObservedModel], instance.observed_classes
end
test "calls existing observer event" do
foo = Foo.new
FooObserver.instance.stub = stub
FooObserver.instance.stub.expects(:event_with).with(foo)
Foo.notify_observers(:on_spec, foo)
end
test "calls existing observer event from the instance" do
foo = Foo.new
FooObserver.instance.stub = stub
FooObserver.instance.stub.expects(:event_with).with(foo)
foo.notify_observers(:on_spec)
end
test "passes extra arguments" do
foo = Foo.new
FooObserver.instance.stub = stub
FooObserver.instance.stub.expects(:event_with).with(foo, :bar)
Foo.send(:notify_observers, :on_spec, foo, :bar)
end
test "skips nonexistent observer event" do
foo = Foo.new
Foo.notify_observers(:whatever, foo)
end
test "update passes a block on to the observer" do
yielded_value = nil
FooObserver.instance.update(:around_save, Foo.new) do |val|
yielded_value = val
end
assert_equal :in_around_save, yielded_value
end
test "observe redefines observed_classes class method" do
class BarObserver < ActiveModel::Observer
observe :foo
end
assert_equal [Foo], BarObserver.observed_classes
BarObserver.observe(ObservedModel)
assert_equal [ObservedModel], BarObserver.observed_classes
end
end
rails-observers-0.1.2/test/models/ 0000755 0000041 0000041 00000000000 12250222654 017126 5 ustar www-data www-data rails-observers-0.1.2/test/models/observers.rb 0000644 0000041 0000041 00000001016 12250222654 021463 0 ustar www-data www-data class ORM
include ActiveModel::Observing
def save
notify_observers :before_save
end
class Observer < ActiveModel::Observer
def before_save_invocations
@before_save_invocations ||= []
end
def before_save(record)
before_save_invocations << record
end
end
end
class Widget < ORM; end
class Budget < ORM; end
class WidgetObserver < ORM::Observer; end
class BudgetObserver < ORM::Observer; end
class AuditTrail < ORM::Observer
observe :widget, :budget
end
ORM.instantiate_observers
rails-observers-0.1.2/test/rake_test.rb 0000644 0000041 0000041 00000001725 12250222654 020156 0 ustar www-data www-data require 'isolation/abstract_unit'
require 'rails-observers'
module ApplicationTests
class RakeTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
def teardown
teardown_app
end
def test_load_activerecord_base_when_we_use_observers
Dir.chdir(app_path) do
`bundle exec rails g model user;
bundle exec rake db:migrate;
bundle exec rails g observer user;`
add_to_config "config.active_record.observers = :user_observer"
assert_equal "0", `bundle exec rails r "puts User.count"`.strip
app_file "lib/tasks/count_user.rake", <<-RUBY
namespace :user do
task :count => :environment do
puts User.count
end
end
RUBY
assert_equal "0", `bundle exec rake user:count`.strip
end
end
end
end
rails-observers-0.1.2/.gitignore 0000644 0000041 0000041 00000000250 12250222654 016651 0 ustar www-data www-data *.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
.ruby-version
rails-observers-0.1.2/LICENSE 0000644 0000041 0000041 00000002110 12250222654 015663 0 ustar www-data www-data Copyright (c) 2012 Steve Klabnik, Rafael Mendonça França
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
rails-observers-0.1.2/rails-observers.gemspec 0000644 0000041 0000041 00000006042 12250222654 021355 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require File.expand_path('../lib/rails/observers/version', __FILE__)
Gem::Specification.new do |s|
s.name = "rails-observers"
s.authors = ["Rafael Mendonça França", "Steve Klabnik"]
s.email = ["rafaelmfranca@gmail.com", "steve@steveklabnik.com"]
s.description = %q{Rails observer (removed from core in Rails 4.0)}
s.summary = %q{ActiveModel::Observer, ActiveRecord::Observer and ActionController::Caching::Sweeper extracted from Rails.}
s.homepage = "https://github.com/rails/rails-observers"
s.version = Rails::Observers::VERSION
s.files = [".gitignore",".travis.yml","Gemfile","LICENSE","README.md","Rakefile","lib/generators/active_record/observer/observer_generator.rb","lib/generators/active_record/observer/templates/observer.rb","lib/generators/rails/observer/USAGE","lib/generators/rails/observer/observer_generator.rb","lib/generators/test_unit/observer/observer_generator.rb","lib/generators/test_unit/observer/templates/unit_test.rb","lib/rails-observers.rb","lib/rails/observers/action_controller/caching.rb","lib/rails/observers/action_controller/caching/sweeping.rb","lib/rails/observers/active_model.rb","lib/rails/observers/active_model/active_model.rb","lib/rails/observers/active_model/observer_array.rb","lib/rails/observers/active_model/observing.rb","lib/rails/observers/activerecord/active_record.rb","lib/rails/observers/activerecord/base.rb","lib/rails/observers/activerecord/observer.rb","lib/rails/observers/railtie.rb","lib/rails/observers/version.rb","rails-observers.gemspec","rails-observers.gemspec.erb","test/configuration_test.rb","test/console_test.rb","test/fixtures/developers.yml","test/fixtures/minimalistics.yml","test/fixtures/topics.yml","test/generators/generators_test_helper.rb","test/generators/namespaced_generators_test.rb","test/generators/observer_generator_test.rb","test/helper.rb","test/isolation/abstract_unit.rb","test/lifecycle_test.rb","test/models/observers.rb","test/observer_array_test.rb","test/observing_test.rb","test/rake_test.rb","test/sweeper_test.rb","test/transaction_callbacks_test.rb"]
s.test_files = ["test/configuration_test.rb","test/console_test.rb","test/fixtures/developers.yml","test/fixtures/minimalistics.yml","test/fixtures/topics.yml","test/generators/generators_test_helper.rb","test/generators/namespaced_generators_test.rb","test/generators/observer_generator_test.rb","test/helper.rb","test/isolation/abstract_unit.rb","test/lifecycle_test.rb","test/models/observers.rb","test/observer_array_test.rb","test/observing_test.rb","test/rake_test.rb","test/sweeper_test.rb","test/transaction_callbacks_test.rb"]
s.executables = []
s.require_paths = ["lib"]
s.add_dependency 'activemodel', '~> 4.0'
s.add_development_dependency 'minitest', '>= 3'
s.add_development_dependency 'railties', '~> 4.0'
s.add_development_dependency 'activerecord', '~> 4.0'
s.add_development_dependency 'actionmailer', '~> 4.0'
s.add_development_dependency 'actionpack', '~> 4.0'
s.add_development_dependency 'sqlite3', '~> 1.3'
end
rails-observers-0.1.2/checksums.yaml.gz 0000444 0000041 0000041 00000000414 12250222654 020151 0 ustar www-data www-data ɳQe;R0D"c}mIq(aԨvr~}rdžjG\ĸG.I*<=WAfd1AeS7tH8