surveillance_authority 0.0.1
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.
- data/.document +11 -0
- data/.gitignore +45 -0
- data/Gemfile +15 -0
- data/LICENSE +20 -0
- data/README.rdoc +81 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/lib/surveillance_authority.rb +91 -0
- data/spec/.rspec +1 -0
- data/spec/hook_creation_spec.rb +177 -0
- data/spec/method_concatenation_spec.rb +38 -0
- data/spec/plugin_tests_spec.rb +84 -0
- data/spec/spec_helper.rb +31 -0
- data/surveillance_authority.gemspec +92 -0
- metadata +263 -0
data/.document
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# .document is used by rdoc and yard to know how to generate documentation
|
2
|
+
# for example, it can be used to control how rdoc gets built when you do `gem install foo`
|
3
|
+
|
4
|
+
README.rdoc
|
5
|
+
lib/**/*.rb
|
6
|
+
bin/*
|
7
|
+
|
8
|
+
# Files below this - are treated as 'extra files', and aren't parsed for ruby code
|
9
|
+
-
|
10
|
+
features/**/*.feature
|
11
|
+
LICENSE
|
data/.gitignore
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
|
14
|
+
# jeweler generated
|
15
|
+
pkg
|
16
|
+
|
17
|
+
# rvm config
|
18
|
+
.rvmrc
|
19
|
+
|
20
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
21
|
+
#
|
22
|
+
# * Create a file at ~/.gitignore
|
23
|
+
# * Include files you want ignored
|
24
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
25
|
+
#
|
26
|
+
# After doing this, these files will be ignored in all your git projects,
|
27
|
+
# saving you from having to 'pollute' every project you touch with them
|
28
|
+
#
|
29
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
30
|
+
#
|
31
|
+
# For MacOS:
|
32
|
+
#
|
33
|
+
#.DS_Store
|
34
|
+
#
|
35
|
+
# For TextMate
|
36
|
+
#*.tmproj
|
37
|
+
#tmtags
|
38
|
+
#
|
39
|
+
# For emacs:
|
40
|
+
#*~
|
41
|
+
#\#*
|
42
|
+
#.\#*
|
43
|
+
#
|
44
|
+
# For vim:
|
45
|
+
#*.swp
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", ">= 2.0.0.beta.19"
|
10
|
+
gem "yard", "~> 0.6.0"
|
11
|
+
gem "bundler", "~> 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.5.0.pre3"
|
13
|
+
gem "rcov", ">= 0"
|
14
|
+
gem "reek", "~> 1.2.8"
|
15
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Daniel Bornkessel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= surveillance_authority
|
2
|
+
|
3
|
+
== Introduction
|
4
|
+
|
5
|
+
This gem provides a dsl to easily write observers in one or more centralized files.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
Install surveillance_authority by adding
|
10
|
+
|
11
|
+
gem 'surveillance_authority'
|
12
|
+
|
13
|
+
to your Gemfile or install it using
|
14
|
+
|
15
|
+
gem install surveillance_authority
|
16
|
+
|
17
|
+
== Integration into your project
|
18
|
+
|
19
|
+
In
|
20
|
+
|
21
|
+
config/initializers
|
22
|
+
|
23
|
+
create one or more ruby files in which you can define your surveillance rules. For example:
|
24
|
+
|
25
|
+
SurveillanceAuthority.observe do
|
26
|
+
# Do something after a new movie was created
|
27
|
+
after "Movie#create" do |movie|
|
28
|
+
# ... do stuff
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Do something before a User gets updated
|
33
|
+
before "User#update" do |user|
|
34
|
+
# ... do stuff
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
== Uhm ...so what?
|
39
|
+
|
40
|
+
surveillance_authority is meant to be used together with some plugins. One of those is varnish_sweeper, which invalidates certain routes.
|
41
|
+
|
42
|
+
== Writing plugins for surveillance_authority
|
43
|
+
|
44
|
+
In order to write a plugin for surveillance_authority, simply create a class that inherits from
|
45
|
+
|
46
|
+
SurveillanceAuthority::Sanctions
|
47
|
+
|
48
|
+
all public methods of that class will be available in the blocks. E.g.
|
49
|
+
|
50
|
+
class VarnishSweeper < SurveillanceAuthority::Sanctions
|
51
|
+
def sweep(url, options = {})
|
52
|
+
options.reverse_merge(
|
53
|
+
:method => :invalidate
|
54
|
+
}
|
55
|
+
|
56
|
+
options[:method] == :purge ? purge_url(url) : invalidate(url)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def purge_url(url)
|
61
|
+
...
|
62
|
+
end
|
63
|
+
|
64
|
+
def invalidate(url)
|
65
|
+
...
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
will make the sweep method available:
|
70
|
+
|
71
|
+
SurveillanceAuthority.observe do
|
72
|
+
# Do something after a new movie was created
|
73
|
+
after "Movie#create" do |movie|
|
74
|
+
sweep movie_path(movie), :method => :invalidate
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
== Copyright
|
80
|
+
|
81
|
+
Copyright (c) 2010 Daniel Bornkessel. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "surveillance_authority"
|
16
|
+
gem.summary = %Q{Write centralized model observers in a simple DSL}
|
17
|
+
gem.description = %Q{Write centralized model observers in a simple DSL}
|
18
|
+
gem.email = "github@bornkessel.com"
|
19
|
+
gem.homepage = "http://github.com/kesselborn/surveillance_authority"
|
20
|
+
gem.authors = ["Daniel Bornkessel"]
|
21
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
22
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
23
|
+
# spec.add_runtime_dependency 'jabber4r', '> 0.1'
|
24
|
+
# spec.add_development_dependency 'rspec', '> 1.2.3'
|
25
|
+
gem.add_development_dependency "rspec", ">= 2.0.0.beta.19"
|
26
|
+
gem.add_development_dependency "yard", "~> 0.6.0"
|
27
|
+
gem.add_development_dependency "bundler", "~> 1.0.0"
|
28
|
+
gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
|
29
|
+
gem.add_development_dependency "rcov", ">= 0"
|
30
|
+
gem.add_development_dependency "reek", "~> 1.2.8"
|
31
|
+
end
|
32
|
+
Jeweler::RubygemsDotOrgTasks.new
|
33
|
+
|
34
|
+
require 'rspec/core'
|
35
|
+
require 'rspec/core/rake_task'
|
36
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
37
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
38
|
+
end
|
39
|
+
|
40
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
41
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
42
|
+
spec.rcov = true
|
43
|
+
end
|
44
|
+
|
45
|
+
require 'reek/rake/task'
|
46
|
+
Reek::Rake::Task.new do |t|
|
47
|
+
t.fail_on_error = true
|
48
|
+
t.verbose = false
|
49
|
+
t.source_files = 'lib/**/*.rb'
|
50
|
+
end
|
51
|
+
|
52
|
+
task :default => :spec
|
53
|
+
|
54
|
+
require 'yard'
|
55
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
|
4
|
+
class SurveillanceAuthority
|
5
|
+
|
6
|
+
class Sanction
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
VALID_HOOKS = [:validation, :validation_on_create, :save, :create]
|
10
|
+
@@plugins = []
|
11
|
+
|
12
|
+
# register plugins (== SurveillanceAuthority::Sanction Sub-Classes) automatically when they get defined
|
13
|
+
def self.inherited(c)
|
14
|
+
c.class_eval do
|
15
|
+
include Singleton
|
16
|
+
end
|
17
|
+
|
18
|
+
@@plugins << c
|
19
|
+
end
|
20
|
+
|
21
|
+
# build a hash containing all available public plugin methods
|
22
|
+
def plugins_methods
|
23
|
+
# caching with @plugins_methods ||= ... does not work here
|
24
|
+
@plugins_methods = @@plugins.inject({}) do |hash, plugin_class|
|
25
|
+
plugin_class.instance_methods(false).each do |method_name|
|
26
|
+
raise "plugin method name clash ... \"#{method_name}\" is defined in \"#{plugin_class.name}\" and \"#{hash[method_name.to_sym].owner.name}\"!" if hash[method_name.to_sym]
|
27
|
+
hash[method_name.to_sym] = plugin_class.instance.method( method_name )
|
28
|
+
end
|
29
|
+
hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing( method_name, *args )
|
34
|
+
@plugins_methods ||= {}
|
35
|
+
|
36
|
+
if @plugins_methods[method_name.to_sym] || plugins_methods[method_name.to_sym]
|
37
|
+
plugins_methods[method_name.to_sym].call( *args )
|
38
|
+
else
|
39
|
+
raise "no method called #{method_name}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
# this creates the sweeper model and its methods. It creates exactly one sweeper model per observed model, regardless if you
|
46
|
+
# observe one or n methods from that model.
|
47
|
+
[:after, :before].each do |hook|
|
48
|
+
define_method hook do |*observed_methods, &block|
|
49
|
+
observed_methods.each do |observed_method|
|
50
|
+
model, method_name = observed_method.split('#')
|
51
|
+
observer_class_name = :"SurveillanceObserverFor#{model}"
|
52
|
+
observer_method_name = :"#{hook}_#{method_name}"
|
53
|
+
|
54
|
+
|
55
|
+
raise "there is no observer callback called \"#{hook}_#{method_name}\"" unless VALID_HOOKS.include?(method_name.to_sym)
|
56
|
+
|
57
|
+
# define sweeper class if it is not defined yet
|
58
|
+
unless Object.const_defined?( observer_class_name )
|
59
|
+
c = Object.const_set( observer_class_name, Class.new(ActionController::Caching::Sweeper) )
|
60
|
+
c.class_exec do
|
61
|
+
observe model.downcase.to_sym
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
observer_class = Object.const_get( observer_class_name )
|
66
|
+
|
67
|
+
# concat old method implementation with block that is passed in if the method is already defined
|
68
|
+
if observer_class.instance_methods(false).include?( observer_method_name )
|
69
|
+
|
70
|
+
old_implementation = observer_class.instance_method( observer_method_name )
|
71
|
+
|
72
|
+
# concatenate the new block and the old implementation
|
73
|
+
observer_class.send :define_method, observer_method_name, lambda{ |param|
|
74
|
+
block.call(param)
|
75
|
+
old_implementation.bind(self).call(param)
|
76
|
+
}
|
77
|
+
else
|
78
|
+
|
79
|
+
# otherwise simply define method
|
80
|
+
observer_class.send :define_method, observer_method_name, lambda{|param| block.call(param) }
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.observe(&block)
|
89
|
+
SurveillanceAuthority::Sanction.instance.instance_eval(&block)
|
90
|
+
end
|
91
|
+
end
|
data/spec/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "BasicHookTests: hook creation" do
|
4
|
+
it "should create sweeper class" do
|
5
|
+
SurveillanceAuthority.observe do
|
6
|
+
after "BasicHookTests1#create" do
|
7
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Object.const_defined?(:SurveillanceObserverForBasicHookTests1).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
it "should add the observe method with the respective class" do
|
16
|
+
Object.should_receive(:const_defined?).with(:SurveillanceObserverForBasicHookTests2)
|
17
|
+
ActionController::Caching::Sweeper.should_receive(:observe)
|
18
|
+
|
19
|
+
SurveillanceAuthority.observe do
|
20
|
+
after "BasicHookTests2#create" do
|
21
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should create an after create hook" do
|
28
|
+
SurveillanceAuthority.observe do
|
29
|
+
after "BasicHookTests3#create" do
|
30
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
SurveillanceObserverForBasicHookTests3.instance_methods(false).include?(:after_create).should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to create create multiple hooks on one class" do
|
38
|
+
SurveillanceAuthority.observe do
|
39
|
+
after "BasicHookTests4#create" do
|
40
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
41
|
+
end
|
42
|
+
|
43
|
+
before "BasicHookTests4#save" do
|
44
|
+
# ... me neither
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
SurveillanceObserverForBasicHookTests4.instance_methods(false).include?(:after_create).should be_true
|
51
|
+
SurveillanceObserverForBasicHookTests4.instance_methods(false).include?(:before_save).should be_true
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should throw an exception when invalid hoods are getting defined" do
|
56
|
+
lambda {
|
57
|
+
SurveillanceAuthority.observe do
|
58
|
+
after "BasicHookTests5#nonexistanthook" do
|
59
|
+
# ...
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}.should raise_exception
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "MultipleHooksSameModelTests: multiple hooks with one specification" do
|
68
|
+
it "should create sweeper class" do
|
69
|
+
SurveillanceAuthority.observe do
|
70
|
+
after "MultipleHooksSameModelTests1#create", "MultipleHooksSameModelTests1#save" do
|
71
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
Object.const_defined?(:SurveillanceObserverForMultipleHooksSameModelTests1).should be_true
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "should add the observe method with the respective class" do
|
80
|
+
ActionController::Caching::Sweeper.should_receive(:observe).once
|
81
|
+
|
82
|
+
SurveillanceAuthority.observe do
|
83
|
+
after "MultipleHooksSameModelTests2#create", "MultipleHooksSameModelTests2#save" do
|
84
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should create an after create hook" do
|
91
|
+
SurveillanceAuthority.observe do
|
92
|
+
after "MultipleHooksSameModelTests3#create", "MultipleHooksSameModelTests3#save" do
|
93
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
SurveillanceObserverForMultipleHooksSameModelTests3.instance_methods(false).include?(:after_create).should be_true
|
98
|
+
SurveillanceObserverForMultipleHooksSameModelTests3.instance_methods(false).include?(:after_save).should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should be able to create create multiple hooks on one class" do
|
102
|
+
SurveillanceAuthority.observe do
|
103
|
+
after "MultipleHooksSameModelTests4#create", "MultipleHooksSameModelTests4#save" do
|
104
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
105
|
+
end
|
106
|
+
|
107
|
+
before "MultipleHooksSameModelTests4#create", "MultipleHooksSameModelTests4#save" do
|
108
|
+
# ... me neither
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
SurveillanceObserverForMultipleHooksSameModelTests4.instance_methods(false).include?(:after_create).should be_true
|
115
|
+
SurveillanceObserverForMultipleHooksSameModelTests4.instance_methods(false).include?(:after_save).should be_true
|
116
|
+
SurveillanceObserverForMultipleHooksSameModelTests4.instance_methods(false).include?(:before_create).should be_true
|
117
|
+
SurveillanceObserverForMultipleHooksSameModelTests4.instance_methods(false).include?(:before_save).should be_true
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
describe "MultipleHooksDifferentModelTests: multiple hooks with one specification" do
|
124
|
+
it "should create sweeper class" do
|
125
|
+
SurveillanceAuthority.observe do
|
126
|
+
after "MultipleHooksDifferentModelTests1_1#create", "MultipleHooksDifferentModelTests1_2#save" do
|
127
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
Object.const_defined?(:SurveillanceObserverForMultipleHooksDifferentModelTests1_1).should be_true
|
132
|
+
Object.const_defined?(:SurveillanceObserverForMultipleHooksDifferentModelTests1_2).should be_true
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
it "should add the observe method with the respective class" do
|
137
|
+
ActionController::Caching::Sweeper.should_receive(:observe).twice
|
138
|
+
|
139
|
+
SurveillanceAuthority.observe do
|
140
|
+
after "MultipleHooksDifferentModelTests2_1#create", "MultipleHooksDifferentModelTests2_2#save" do
|
141
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should create an after create hook" do
|
148
|
+
SurveillanceAuthority.observe do
|
149
|
+
after "MultipleHooksDifferentModelTests3_1#create", "MultipleHooksDifferentModelTests3_2#save" do
|
150
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests3_1.instance_methods(false).include?(:after_create).should be_true
|
155
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests3_2.instance_methods(false).include?(:after_save).should be_true
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should be able to create create multiple hooks on one class" do
|
159
|
+
SurveillanceAuthority.observe do
|
160
|
+
after "MultipleHooksDifferentModelTests4_1#create", "MultipleHooksDifferentModelTests4_2#save" do
|
161
|
+
# hahaha ... I don't do nothing -- YOU FOOL
|
162
|
+
end
|
163
|
+
|
164
|
+
before "MultipleHooksDifferentModelTests4_1#create", "MultipleHooksDifferentModelTests4_2#save" do
|
165
|
+
# ... me neither
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests4_1.instance_methods(false).include?(:after_create).should be_true
|
172
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests4_2.instance_methods(false).include?(:after_save).should be_true
|
173
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests4_1.instance_methods(false).include?(:before_create).should be_true
|
174
|
+
SurveillanceObserverForMultipleHooksDifferentModelTests4_2.instance_methods(false).include?(:before_save).should be_true
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class Plugin1 < SurveillanceAuthority::Sanction
|
4
|
+
def plugin1_method(object)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Plugin2 < SurveillanceAuthority::Sanction
|
9
|
+
def plugin2_method(object)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Plugin3 < SurveillanceAuthority::Sanction
|
14
|
+
def plugin3_method(object)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "Concatenate blocks into one method" do
|
19
|
+
it "should make plugin methods in available in the observer blocks" do
|
20
|
+
SurveillanceAuthority.observe do
|
21
|
+
after "ConcatenateTest1#create" do |object|
|
22
|
+
plugin1_method object
|
23
|
+
end
|
24
|
+
after "ConcatenateTest1#create" do |object|
|
25
|
+
plugin2_method object
|
26
|
+
end
|
27
|
+
after "ConcatenateTest1#create" do |object|
|
28
|
+
plugin3_method object
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Plugin1.instance.should_receive(:plugin1_method).with("They set us up the bomb!")
|
33
|
+
Plugin2.instance.should_receive(:plugin2_method).with("They set us up the bomb!")
|
34
|
+
Plugin3.instance.should_receive(:plugin3_method).with("They set us up the bomb!")
|
35
|
+
SurveillanceObserverForConcatenateTest1.new.after_create("They set us up the bomb!")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class Notify < SurveillanceAuthority::Sanction
|
4
|
+
def notify(message)
|
5
|
+
puts message
|
6
|
+
end
|
7
|
+
|
8
|
+
def notify2(message1, message2, message3)
|
9
|
+
puts message1
|
10
|
+
puts message2
|
11
|
+
puts message3
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "avoid ambigous plugin method names" do
|
16
|
+
it "should throw an exception if a new plugin wants to use a method name that is already used" do
|
17
|
+
C = Class.new(SurveillanceAuthority::Sanction)
|
18
|
+
lambda {
|
19
|
+
C.class_exec {
|
20
|
+
def notify
|
21
|
+
end
|
22
|
+
}
|
23
|
+
SurveillanceAuthority.observe do
|
24
|
+
after "DoubleHappinesTest#create" do |param|
|
25
|
+
notify "huhu"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
SurveillanceObserverForDoubleHappinesTest.new.after_create(nil)
|
29
|
+
}.should raise_exception
|
30
|
+
C.class_exec {
|
31
|
+
undef notify
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "SimplePluginsTests: simple plugins" do
|
37
|
+
it "should make plugin methods in available in the observer blocks" do
|
38
|
+
SurveillanceAuthority.observe do
|
39
|
+
after "SimplePluginsTests1#create" do
|
40
|
+
notify "hihihihi ... I was called"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Notify.instance.should_receive(:notify).with("hihihihi ... I was called")
|
45
|
+
SurveillanceObserverForSimplePluginsTests1.new.after_create(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should pass parameters on to plugin methods" do
|
49
|
+
SurveillanceAuthority.observe do
|
50
|
+
after "SimplePluginsTests2#create" do |param|
|
51
|
+
notify param
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Notify.instance.should_receive(:notify).with("I was called with a param")
|
56
|
+
SurveillanceObserverForSimplePluginsTests2.new.after_create("I was called with a param")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should pass multiple parameters on to plugin methods" do
|
60
|
+
SurveillanceAuthority.observe do
|
61
|
+
after "SimplePluginsTests3#create" do |param|
|
62
|
+
notify2 "lala", "lulu", param
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Notify.instance.should_receive(:notify2).with("lala", "lulu", "pipi")
|
67
|
+
SurveillanceObserverForSimplePluginsTests3.new.after_create("pipi")
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# ... this currently fails and says that notify2 does not get called ... which is not true
|
72
|
+
# it "should be able to call multiple methods" do
|
73
|
+
# SurveillanceAuthority.observe do
|
74
|
+
# after "SimplePluginsTests3#create" do |param|
|
75
|
+
# notify param
|
76
|
+
# notify2 param
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# Notify.instance.should_receive(:notify).with("I was called with a param")
|
81
|
+
# Notify.instance.should_receive(:notify2).with("I was called with a param")
|
82
|
+
# SurveillanceObserverForSimplePluginsTests3.new.after_create("I was called with a param")
|
83
|
+
# end
|
84
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
10
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
11
|
+
require 'surveillance_authority'
|
12
|
+
require 'rspec'
|
13
|
+
|
14
|
+
# Requires supporting files with custom matchers and macros, etc,
|
15
|
+
# in ./support/ and its subdirectories.
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
17
|
+
|
18
|
+
class ActionController
|
19
|
+
class Caching
|
20
|
+
class Sweeper
|
21
|
+
def self.observe(model)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
RSpec.configure do |config|
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{surveillance_authority}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Bornkessel"]
|
12
|
+
s.date = %q{2010-09-27}
|
13
|
+
s.description = %q{Write centralized model observers in a simple DSL}
|
14
|
+
s.email = %q{github@bornkessel.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/surveillance_authority.rb",
|
28
|
+
"spec/.rspec",
|
29
|
+
"spec/hook_creation_spec.rb",
|
30
|
+
"spec/method_concatenation_spec.rb",
|
31
|
+
"spec/plugin_tests_spec.rb",
|
32
|
+
"spec/spec_helper.rb",
|
33
|
+
"surveillance_authority.gemspec"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/kesselborn/surveillance_authority}
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{Write centralized model observers in a simple DSL}
|
39
|
+
s.test_files = [
|
40
|
+
"spec/hook_creation_spec.rb",
|
41
|
+
"spec/method_concatenation_spec.rb",
|
42
|
+
"spec/plugin_tests_spec.rb",
|
43
|
+
"spec/spec_helper.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
52
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
53
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
54
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
55
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
57
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
58
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
59
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
61
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
65
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
68
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
69
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
70
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
71
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
74
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
76
|
+
end
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
79
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
80
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
81
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
82
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
83
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
84
|
+
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
|
85
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
86
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
87
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
|
88
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
89
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: surveillance_authority
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Bornkessel
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-27 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
- beta
|
32
|
+
- 19
|
33
|
+
version: 2.0.0.beta.19
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: yard
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
- 6
|
47
|
+
- 0
|
48
|
+
version: 0.6.0
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: bundler
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 1
|
61
|
+
- 0
|
62
|
+
- 0
|
63
|
+
version: 1.0.0
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: jeweler
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 1
|
76
|
+
- 5
|
77
|
+
- 0
|
78
|
+
- pre3
|
79
|
+
version: 1.5.0.pre3
|
80
|
+
type: :development
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rcov
|
85
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: *id005
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: reek
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 1
|
105
|
+
- 2
|
106
|
+
- 8
|
107
|
+
version: 1.2.8
|
108
|
+
type: :development
|
109
|
+
prerelease: false
|
110
|
+
version_requirements: *id006
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
segments:
|
119
|
+
- 2
|
120
|
+
- 0
|
121
|
+
- 0
|
122
|
+
- beta
|
123
|
+
- 19
|
124
|
+
version: 2.0.0.beta.19
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: *id007
|
128
|
+
- !ruby/object:Gem::Dependency
|
129
|
+
name: yard
|
130
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ~>
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
- 6
|
138
|
+
- 0
|
139
|
+
version: 0.6.0
|
140
|
+
type: :development
|
141
|
+
prerelease: false
|
142
|
+
version_requirements: *id008
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: bundler
|
145
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ~>
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
segments:
|
151
|
+
- 1
|
152
|
+
- 0
|
153
|
+
- 0
|
154
|
+
version: 1.0.0
|
155
|
+
type: :development
|
156
|
+
prerelease: false
|
157
|
+
version_requirements: *id009
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: jeweler
|
160
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
segments:
|
166
|
+
- 1
|
167
|
+
- 5
|
168
|
+
- 0
|
169
|
+
- pre3
|
170
|
+
version: 1.5.0.pre3
|
171
|
+
type: :development
|
172
|
+
prerelease: false
|
173
|
+
version_requirements: *id010
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: rcov
|
176
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
segments:
|
182
|
+
- 0
|
183
|
+
version: "0"
|
184
|
+
type: :development
|
185
|
+
prerelease: false
|
186
|
+
version_requirements: *id011
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: reek
|
189
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
190
|
+
none: false
|
191
|
+
requirements:
|
192
|
+
- - ~>
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
segments:
|
195
|
+
- 1
|
196
|
+
- 2
|
197
|
+
- 8
|
198
|
+
version: 1.2.8
|
199
|
+
type: :development
|
200
|
+
prerelease: false
|
201
|
+
version_requirements: *id012
|
202
|
+
description: Write centralized model observers in a simple DSL
|
203
|
+
email: github@bornkessel.com
|
204
|
+
executables: []
|
205
|
+
|
206
|
+
extensions: []
|
207
|
+
|
208
|
+
extra_rdoc_files:
|
209
|
+
- LICENSE
|
210
|
+
- README.rdoc
|
211
|
+
files:
|
212
|
+
- .document
|
213
|
+
- .gitignore
|
214
|
+
- Gemfile
|
215
|
+
- LICENSE
|
216
|
+
- README.rdoc
|
217
|
+
- Rakefile
|
218
|
+
- VERSION
|
219
|
+
- lib/surveillance_authority.rb
|
220
|
+
- spec/.rspec
|
221
|
+
- spec/hook_creation_spec.rb
|
222
|
+
- spec/method_concatenation_spec.rb
|
223
|
+
- spec/plugin_tests_spec.rb
|
224
|
+
- spec/spec_helper.rb
|
225
|
+
- surveillance_authority.gemspec
|
226
|
+
has_rdoc: true
|
227
|
+
homepage: http://github.com/kesselborn/surveillance_authority
|
228
|
+
licenses: []
|
229
|
+
|
230
|
+
post_install_message:
|
231
|
+
rdoc_options: []
|
232
|
+
|
233
|
+
require_paths:
|
234
|
+
- lib
|
235
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
236
|
+
none: false
|
237
|
+
requirements:
|
238
|
+
- - ">="
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
hash: -1802489470036143465
|
241
|
+
segments:
|
242
|
+
- 0
|
243
|
+
version: "0"
|
244
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
245
|
+
none: false
|
246
|
+
requirements:
|
247
|
+
- - ">="
|
248
|
+
- !ruby/object:Gem::Version
|
249
|
+
segments:
|
250
|
+
- 0
|
251
|
+
version: "0"
|
252
|
+
requirements: []
|
253
|
+
|
254
|
+
rubyforge_project:
|
255
|
+
rubygems_version: 1.3.7
|
256
|
+
signing_key:
|
257
|
+
specification_version: 3
|
258
|
+
summary: Write centralized model observers in a simple DSL
|
259
|
+
test_files:
|
260
|
+
- spec/hook_creation_spec.rb
|
261
|
+
- spec/method_concatenation_spec.rb
|
262
|
+
- spec/plugin_tests_spec.rb
|
263
|
+
- spec/spec_helper.rb
|