easy_callbacks 0.1.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b09b4fff39b736c6bc599a4fb61b0e54d8c7f8dd
4
- data.tar.gz: 250aa6be5312574c712c17d4a42275327f0a84ae
3
+ metadata.gz: b9ce7df274e4dff1affe27fa7d7b1bf71b6411c4
4
+ data.tar.gz: a55360bfebf3f88130a858cb48bfea028a5d5107
5
5
  SHA512:
6
- metadata.gz: 808b9a22c807276a1fca19634eb5b7ad731f69a9e1538d5b63b712fec636092ea08934856dc5e66e09f0f2bbb1f842732f1533ab4de9a7d4dc8853530b2f84ce
7
- data.tar.gz: 1fcad291d78710340a367b33557f57b8bb6bc5c5ca4921ca36c3aa9bd55a03be763acc2f4fa3cbc73b794f3ccae5f7b05caca599706da571943260c13dc4b80e
6
+ metadata.gz: d6a48def8a8b217b9425dd879766619b74214df262a9d70db9b802ebc1a6ea43574229fb28f8fb441419eed5a7739aa63200566ebe0367214f3327a0cd93acac
7
+ data.tar.gz: 6ff374249befe64bfb279dc2c0d18134ba3f2b55de961c25cdd2c992cc39807743bcd30e12255486c0d409cb37e4e0a003b25134653fbda4a15571d34fd2f1c9
data/README.rdoc CHANGED
@@ -1,115 +1,144 @@
1
1
  = Easy Callbacks
2
2
 
3
- Provide callbacks support for Ruby classes.
3
+ Provides callback support for Ruby classes.
4
4
 
5
5
  == Example
6
6
 
7
+ For a given class:
8
+
7
9
  class SomeClass
8
10
 
9
- def some_method(some_arg)
10
- puts some_arg
11
- end
11
+ def some_method(some_arg)
12
+ puts "some_method: #{some_arg}"
13
+ end
12
14
 
13
- include EasyCallbacks::Base
15
+ def before_some_method(some_arg)
16
+ puts "before_some_method: #{some_arg}"
17
+ end
14
18
 
15
- # named callbacks
16
- before :some_method, :do_it_before
17
- around :some_method, :do_it_around
18
- after :some_method, :do_it_after
19
+ def around_some_method(some_arg)
20
+ puts "around_some_method: #{some_arg}"
21
+ end
19
22
 
20
- # anonymous callbacks
21
- before :some_method do |some_arg, callback_details|
22
- # ...
23
- end
23
+ end
24
24
 
25
- def do_it_before(some_arg, callback_details)
26
- # ...
27
- end
25
+ EasyCallbacks.configure(SomeClass) do
28
26
 
29
- def do_it_around(some_arg, callback_details)
30
- # ...
31
- end
27
+ # named callback
28
+ before :some_method, :before_some_method
32
29
 
33
- def do_it_after(some_arg, callback_details)
34
- # ...
35
- end
30
+ # named callback
31
+ around :some_method, :around_some_method
32
+
33
+ # anonymous callback
34
+ after :some_method do
35
+ puts "after_some_method: #{call_args[0]}"
36
+ end
36
37
 
37
38
  end
38
39
 
39
- === Callback Details
40
+ This call:
40
41
 
41
- The second argument is a Hash containing some callback call details:
42
+ SomeClass.new.some_method :some_arg
42
43
 
43
- For named callbacks:
44
+ Produces this output:
44
45
 
45
- {
46
- class: SomeClass,
47
- target: :some_method,
48
- type: :before,
49
- callback_name: :do_it_before,
50
- proc: nil
51
- }
46
+ before_some_method: hue
47
+ some_method: hue
48
+ around_some_method: hue
49
+ after_some_method: hue
52
50
 
53
- For anonymous callbacks:
51
+ == Helper Methods
54
52
 
55
- {
56
- class: SomeClass,
57
- object: #<SomeClass:0x00000002b65ab0>,
58
- target: :some_method,
59
- type: :before,
60
- callback_name: nil,
61
- proc: #<Proc:0x00000002655a20@...>
62
- }
53
+ Inside a callback block/method, you can call three helper methods:
63
54
 
64
- For around callbacks (with success):
55
+ call_args # returns original arguments given to the call
56
+ call_block # returns original block given to the call
57
+ callback_details # returns details of callback execution
65
58
 
66
- {
67
- class: SomeClass,
68
- target: :some_method,
69
- type: :around,
70
- callback_name: :do_it_around,
71
- proc: nil,
72
- return_type: :success,
73
- return_object: nil
74
- }
59
+ === Callback Details
75
60
 
76
- For around callbacks (with error):
61
+ The `callback_details` helper method will return:
77
62
 
78
63
  {
79
- class: SomeClass,
80
- target: :some_method,
81
- type: :around,
82
- callback_name: :do_it_around,
83
- proc: nil,
84
- return_type: :error,
85
- return_object: #<StandardError: StandardError>
64
+ target_class: SomeClass,
65
+ callback_type: :around,
66
+ target_method_name: :some_method,
67
+ callback_method_name: :around_some_method,
68
+ callback_block: nil,
69
+ return_type: :success, # exclusive for `around` callbacks
70
+ return_object: nil # exclusive for `around` callbacks
86
71
  }
87
72
 
73
+ == Module inclusion
74
+
75
+ You can call `before`, `around` and `after` methods directly instead of calling them inside of `EasyCallbacks.configure` block. Just include `EasyCallbacks` module:
76
+
77
+ class SomeClass
78
+
79
+ def some_method(some_arg)
80
+ puts "some_method: #{some_arg}"
81
+ end
82
+
83
+ def before_some_method(some_arg)
84
+ puts "before_some_method: #{some_arg}"
85
+ end
86
+
87
+ def around_some_method(some_arg)
88
+ puts "around_some_method: #{some_arg}"
89
+ end
90
+
91
+ include EasyCallbacks
92
+
93
+ before :some_method, :before_some_method
94
+
95
+ around :some_method, :around_some_method
96
+
97
+ after :some_method do
98
+ puts "after_some_method: #{call_args[0]}"
99
+ end
100
+
101
+ end
102
+
88
103
  == Singleton Classes Support
89
104
 
90
105
  It works too:
91
106
 
92
107
  class SomeClass
93
108
 
94
- class << self
109
+ class << self
95
110
 
96
- def some_method(some_arg)
97
- puts some_arg
98
- end
111
+ def some_method(some_arg)
112
+ puts "some_method: #{some_arg}"
113
+ end
99
114
 
100
- include EasyCallbacks::Base
115
+ def before_some_method(some_arg)
116
+ puts "before_some_method: #{some_arg}"
117
+ end
101
118
 
102
- # ...
119
+ def around_some_method(some_arg)
120
+ puts "around_some_method: #{some_arg}"
121
+ end
103
122
 
123
+ include EasyCallbacks
124
+
125
+ before :some_method, :before_some_method
126
+
127
+ around :some_method, :around_some_method
128
+
129
+ after :some_method do
130
+ puts "after_some_method: #{call_args[0]}"
104
131
  end
105
132
 
133
+ end
134
+
106
135
  end
107
136
 
108
- SomeClass.some_method 'some arg'
137
+ SomeClass.some_method :hue
109
138
 
110
- == Changelog
139
+ == More
111
140
 
112
- See 'changelog.txt' to follow the progress.
141
+ To see more of `EasyCallbacks` usages, please take a look at DummyClass[https://github.com/r4z3c/easy_callbacks/blob/master/spec/support/dummy_class.rb].
113
142
 
114
143
  ===
115
144
 
@@ -19,9 +19,10 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_dependency 'bundler', '~>1'
21
21
  s.add_dependency 'activesupport', '~>4'
22
- s.add_dependency 'method_decorator', '~>1'
22
+ s.add_dependency 'method_decorator', '~>3.0.1'
23
23
 
24
24
  s.add_development_dependency 'rspec', '~>3'
25
25
  s.add_development_dependency 'simplecov', '~>0'
26
26
  s.add_development_dependency 'model-builder', '~>2'
27
+ s.add_development_dependency 'rake'
27
28
  end
@@ -0,0 +1,8 @@
1
+ require 'easy_callbacks/models/target_class'
2
+ require 'easy_callbacks/models/callback'
3
+ require 'easy_callbacks/repositories/base_repository'
4
+ require 'easy_callbacks/repositories/target_classes_repository'
5
+ require 'easy_callbacks/repositories/callbacks_repository'
6
+ require 'easy_callbacks/dsls/target_classes_dsl'
7
+ require 'easy_callbacks/utils/validator'
8
+ require 'easy_callbacks/utils/serializer'
@@ -0,0 +1,77 @@
1
+ require 'method_decorator'
2
+
3
+ module EasyCallbacks
4
+ module Dsls
5
+
6
+ class TargetClassesDsl
7
+
8
+ attr_accessor :target_class_instance
9
+
10
+ def initialize(target_class_instance)
11
+ self.target_class_instance = target_class_instance
12
+ end
13
+
14
+ def before(target_method_name, callback_method_name=nil, &callback_block)
15
+ handle_callback_definition :before, target_method_name, callback_method_name, &callback_block
16
+ end
17
+
18
+ def around(target_method_name, callback_method_name=nil, &callback_block)
19
+ handle_callback_definition :around, target_method_name, callback_method_name, &callback_block
20
+ end
21
+
22
+ def after(target_method_name, callback_method_name=nil, &callback_block)
23
+ handle_callback_definition :after, target_method_name, callback_method_name, &callback_block
24
+ end
25
+
26
+ protected
27
+
28
+ def handle_callback_definition(callback_type, target_method_name, callback_method_name, &callback_block)
29
+ push_callback callback_type, target_method_name, callback_method_name, &callback_block
30
+ decorate_method target_method_name
31
+ end
32
+
33
+ def push_callback(callback_type, target_method_name, callback_method_name, &callback_block)
34
+ target_class_instance.add_callback callback_type, target_method_name, callback_method_name, &callback_block
35
+ end
36
+
37
+ def decorate_method(target_method_name)
38
+ tci = target_class_instance
39
+ MethodDecorator.decorate target_class_instance.target_class, target_method_name do
40
+ EasyCallbacks.execute_callbacks self, tci, :before, target_method_name, nil, call_args, &call_block
41
+
42
+ result = error = nil
43
+ begin
44
+ result = call_original
45
+ rescue => e
46
+ error = e
47
+ end
48
+
49
+ additional_options = error ?
50
+ { return_type: :error, return_object: error } :
51
+ { return_type: :success, return_object: result }
52
+
53
+ EasyCallbacks.execute_callbacks self, tci, :around, target_method_name, additional_options, call_args, &call_block
54
+
55
+ raise error if error
56
+
57
+ EasyCallbacks.execute_callbacks self, tci, :after, target_method_name, nil, call_args, &call_block
58
+
59
+ result
60
+ end
61
+ end
62
+
63
+ def target_class_instance=(target_class_instance)
64
+ validate_target_class_instance target_class_instance
65
+ @target_class_instance = target_class_instance
66
+ end
67
+
68
+ def validate_target_class_instance(target_class_instance)
69
+ Utils::Validator.validate_instance_type! :target_class_instance,
70
+ target_class_instance,
71
+ Models::TargetClass
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,18 @@
1
+ module EasyCallbacks
2
+ module Models
3
+
4
+ class Callback
5
+
6
+ attr_accessor :callback_type, :target_method_name, :callback_method_name, :callback_block
7
+
8
+ def initialize(callback_type, target_method_name, callback_method_name)
9
+ self.callback_type = callback_type
10
+ self.target_method_name = target_method_name
11
+ self.callback_method_name = callback_method_name
12
+ self.callback_block = block_given? ? Proc.new : nil
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+ module EasyCallbacks
2
+ module Models
3
+
4
+ class TargetClass
5
+
6
+ attr_accessor :target_class, :callbacks_repository
7
+
8
+ def initialize(target_class)
9
+ self.target_class = target_class
10
+ self.callbacks_repository = ::EasyCallbacks::Repositories::CallbacksRepository.new self
11
+ end
12
+
13
+ def add_callback(callback_type, target_method_name, callback_method_name, &callback_block)
14
+ callbacks_repository.find_or_add callback_type, target_method_name, callback_method_name, &callback_block
15
+ end
16
+
17
+ def get_callbacks_for(callback_type, target_method_name)
18
+ callbacks_repository.get_callbacks_for callback_type, target_method_name
19
+ end
20
+
21
+ protected
22
+
23
+ def target_class=(target_class)
24
+ validate_target_class target_class
25
+ @target_class = target_class
26
+ end
27
+
28
+ def validate_target_class(target_class)
29
+ Utils::Validator.validate_instance_type! :target_class, target_class, Class
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ module EasyCallbacks
2
+ module Repositories
3
+
4
+ class BaseRepository
5
+
6
+ attr_accessor :list
7
+
8
+ def initialize(*args); self.list = [] end
9
+
10
+ def find_or_add(*args, &block); find(*args) || add(*args, &block) end
11
+
12
+ def add(*args, &block)
13
+ unless exists? *args
14
+ model_instance = block_given? ? model.new(*args, &block) : model.new(*args)
15
+ self.list.push(model_instance)
16
+ model_instance
17
+ end
18
+ end
19
+
20
+ def exists?(*args); not find(*args).nil? end
21
+
22
+ def find(*args); list.find &find_block(*args) end
23
+
24
+ protected
25
+
26
+ def find_block(*args)
27
+ raise NotImplementedError.new("find_block@#{self.class} must overwrite find_block@#{self.class.superclass}")
28
+ end
29
+
30
+ def model
31
+ raise NotImplementedError.new("model@#{self.class} must overwrite model@#{self.class.superclass}")
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ module EasyCallbacks
2
+ module Repositories
3
+
4
+ class CallbacksRepository < BaseRepository
5
+
6
+ attr_accessor :target_class_instance
7
+
8
+ def initialize(target_class_instance)
9
+ super
10
+ self.target_class_instance = target_class_instance
11
+ end
12
+
13
+ def get_callbacks_for(callback_type, target_method_name)
14
+ list.select do |c|
15
+ c.callback_type.eql?(callback_type) and
16
+ c.target_method_name.eql?(target_method_name)
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def find_block(callback_type, target_method_name, callback_method_name)
23
+ Proc.new do |item|
24
+ item.callback_type.eql? callback_type and
25
+ item.target_method_name.eql? target_method_name and
26
+ item.callback_method_name.eql? callback_method_name
27
+ end
28
+ end
29
+
30
+ def model; Models::Callback end
31
+
32
+ def target_class_instance=(target_class_instance)
33
+ validate_target_class_instance target_class_instance
34
+ @target_class_instance = target_class_instance
35
+ end
36
+
37
+ def validate_target_class_instance(target_class_instance)
38
+ Utils::Validator.validate_instance_type! :target_class_instance, target_class_instance, Models::TargetClass
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ module EasyCallbacks
2
+ module Repositories
3
+
4
+ class TargetClassesRepository < BaseRepository
5
+
6
+ protected
7
+
8
+ def find_block(target_class); Proc.new { |item| item.target_class.eql? target_class } end
9
+
10
+ def model; Models::TargetClass end
11
+
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module EasyCallbacks
2
+ module Utils
3
+
4
+ class Serializer
5
+
6
+ class << self
7
+
8
+ def to_h(object, attrs=[])
9
+ attrs = [attrs] unless attrs.is_a? Array
10
+ hash = {}
11
+ attrs.each { |k| hash[k.to_sym] = object.send k }
12
+ hash
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module EasyCallbacks
2
+ module Utils
3
+
4
+ class Validator
5
+
6
+ class << self
7
+
8
+ def validate_instance_type!(attribute_name, instance, desired_type)
9
+ raise TypeError.new("#{attribute_name} must be a #{desired_type}") unless instance.is_a? desired_type
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module EasyCallbacks
2
- VERSION = '0.1.2'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -1,17 +1,69 @@
1
- module EasyCallbacks
1
+ require 'easy_callbacks/all'
2
+ require 'active_support/concern'
2
3
 
3
- ROOT = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ module EasyCallbacks extend ActiveSupport::Concern
4
5
 
5
- class << self
6
+ included do
7
+
8
+ class << self
9
+
10
+ def before(target_method_name, callback_method_name=nil, &callback_block)
11
+ handle_callback_definition :before, target_method_name, callback_method_name, &callback_block
12
+ end
6
13
 
7
- def load_easy_callbacks
8
- Dir[File.expand_path(File.join(ROOT,'lib','easy_callbacks','**/*.rb'))].each do |file|
9
- require file
14
+ def around(target_method_name, callback_method_name=nil, &callback_block)
15
+ handle_callback_definition :around, target_method_name, callback_method_name, &callback_block
10
16
  end
17
+
18
+ def after(target_method_name, callback_method_name=nil, &callback_block)
19
+ handle_callback_definition :after, target_method_name, callback_method_name, &callback_block
20
+ end
21
+
22
+ def handle_callback_definition(callback_type, target_method_name, callback_method_name, &callback_block)
23
+ EasyCallbacks.configure(self) { send callback_type, target_method_name, callback_method_name, &callback_block }
24
+ end
25
+
11
26
  end
12
27
 
13
28
  end
14
29
 
15
- load_easy_callbacks
30
+ class << self
31
+
32
+ attr_writer :target_classes_repository
33
+
34
+ def configure(target_class, &cfg_block)
35
+ target_class_instance = target_classes_repository.find_or_add target_class
36
+ Dsls::TargetClassesDsl.new(target_class_instance).instance_eval &cfg_block
37
+ end
38
+
39
+ def execute_callbacks(context, target_class_instance, callback_type, target_method_name, additional_options, call_args, &call_block)
40
+ validate_target_class_instance target_class_instance
41
+ target_class_instance.get_callbacks_for(callback_type, target_method_name).each do |callback|
42
+ define_callback_details_method additional_options, callback, target_class_instance
43
+ proc = callback.callback_block
44
+ proc.nil? ? context.send(callback.callback_method_name, *call_args, &call_block) : context.instance_eval(&proc)
45
+ end
46
+ end
47
+
48
+ def define_callback_details_method(additional_options, callback, target_class_instance)
49
+ target_class_instance.target_class.send :define_method, :callback_details do
50
+ callback_details = Utils::Serializer.to_h(
51
+ callback, %w(callback_type target_method_name callback_method_name callback_block)
52
+ ).merge(target_class: target_class_instance.target_class)
53
+ additional_options ? callback_details.merge(additional_options) : callback_details
54
+ end
55
+ end
56
+
57
+ protected
58
+
59
+ def validate_target_class_instance(target_class_instance)
60
+ Utils::Validator.validate_instance_type! :target_class_instance, target_class_instance, Models::TargetClass
61
+ end
62
+
63
+ def target_classes_repository
64
+ @target_classes_repository ||= Repositories::TargetClassesRepository.new
65
+ end
66
+
67
+ end
16
68
 
17
69
  end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+ require 'support/dummy_class'
3
+
4
+ describe EasyCallbacks do
5
+
6
+ let(:dummy_arg) { :dummy_arg }
7
+
8
+ context 'when common class as target' do
9
+
10
+ let(:target) { DummyClass }
11
+ let(:target_instance) { target.new }
12
+
13
+ context 'when public method' do
14
+
15
+ context 'when through module singleton method' do
16
+
17
+ before do
18
+ expect(target_instance).to receive(:puts).with("before_a_public_instance_method_with: #{[dummy_arg]}").ordered
19
+ expect(target_instance).to receive(:puts).with("a_public_instance_method_arg: #{dummy_arg}").ordered
20
+ expect(target_instance).to receive(:puts).with("around_a_public_instance_method_with: #{[dummy_arg]}").ordered
21
+ expect(target_instance).to receive(:puts).with("after_a_public_instance_method_with: #{[dummy_arg]}").ordered
22
+ end
23
+
24
+ it { target_instance.a_public_instance_method dummy_arg }
25
+
26
+ end
27
+
28
+ context 'when through module inclusion' do
29
+
30
+ before do
31
+ expect(target_instance).to receive(:puts).with("before_another_public_instance_method_with: #{[dummy_arg]}").ordered
32
+ expect(target_instance).to receive(:puts).with("another_public_instance_method_arg: #{dummy_arg}").ordered
33
+ expect(target_instance).to receive(:puts).with("around_another_public_instance_method_with: #{[dummy_arg]}").ordered
34
+ expect(target_instance).to receive(:puts).with("after_another_public_instance_method_with: #{[dummy_arg]}").ordered
35
+ end
36
+
37
+ it { target_instance.another_public_instance_method dummy_arg }
38
+
39
+ end
40
+
41
+ end
42
+
43
+ context 'when protected method' do
44
+
45
+ context 'when calling protected method deliberately' do
46
+
47
+ it { expect{target_instance.a_protected_instance_method dummy_arg}.to raise_error NoMethodError }
48
+
49
+ end
50
+
51
+ context 'when calling protected method through `send`' do
52
+
53
+ before do
54
+ expect(target_instance).to receive(:puts).with("before_a_protected_instance_method_with: #{[dummy_arg]}").ordered
55
+ expect(target_instance).to receive(:puts).with("a_protected_instance_method_arg: #{dummy_arg}").ordered
56
+ expect(target_instance).to receive(:puts).with("around_a_protected_instance_method_with: #{[dummy_arg]}").ordered
57
+ expect(target_instance).to receive(:puts).with("after_a_protected_instance_method_with: #{[dummy_arg]}").ordered
58
+ end
59
+
60
+ it { target_instance.send :a_protected_instance_method, dummy_arg }
61
+
62
+ end
63
+
64
+ end
65
+
66
+ context 'when private method' do
67
+
68
+ context 'when calling private method deliberately' do
69
+
70
+ it { expect{target_instance.a_private_instance_method dummy_arg}.to raise_error NoMethodError }
71
+
72
+ end
73
+
74
+ context 'when calling private method through `send`' do
75
+
76
+ before do
77
+ expect(target_instance).to receive(:puts).with("before_a_private_instance_method_with: #{[dummy_arg]}").ordered
78
+ expect(target_instance).to receive(:puts).with("a_private_instance_method_arg: #{dummy_arg}").ordered
79
+ expect(target_instance).to receive(:puts).with("around_a_private_instance_method_with: #{[dummy_arg]}").ordered
80
+ expect(target_instance).to receive(:puts).with("after_a_private_instance_method_with: #{[dummy_arg]}").ordered
81
+ end
82
+
83
+ it { target_instance.send :a_private_instance_method, dummy_arg }
84
+
85
+ end
86
+
87
+ end
88
+
89
+ context 'when dealing with around callback error' do
90
+
91
+ let(:error_msg) { 'some runtime error' }
92
+
93
+ before do
94
+ expect(target_instance).to receive(:puts).with("a_public_instance_method_with_error_arg: #{dummy_arg}").ordered
95
+ expect(target_instance).to receive(:puts).with("around_a_public_instance_method_with_error: #{error_msg}").ordered
96
+ end
97
+
98
+ it { expect{target_instance.a_public_instance_method_with_error dummy_arg}.to raise_error(RuntimeError, error_msg) }
99
+
100
+ end
101
+
102
+ end
103
+
104
+ context 'when singleton class as target' do
105
+
106
+ let(:target) { DummyClass.singleton_class }
107
+ let(:target_instance) { DummyClass }
108
+
109
+ context 'when public method' do
110
+
111
+ context 'when through module singleton method' do
112
+
113
+ before do
114
+ expect(target_instance).to receive(:puts).with("before_a_public_singleton_method_with: #{[dummy_arg]}").ordered
115
+ expect(target_instance).to receive(:puts).with("a_public_singleton_method_arg: #{dummy_arg}").ordered
116
+ expect(target_instance).to receive(:puts).with("around_a_public_singleton_method_with: #{[dummy_arg]}").ordered
117
+ expect(target_instance).to receive(:puts).with("after_a_public_singleton_method_with: #{[dummy_arg]}").ordered
118
+ end
119
+
120
+ it { target_instance.a_public_singleton_method dummy_arg }
121
+
122
+ end
123
+
124
+ context 'when through module inclusion' do
125
+
126
+ before do
127
+ expect(target_instance).to receive(:puts).with("before_another_public_singleton_method_with: #{[dummy_arg]}").ordered
128
+ expect(target_instance).to receive(:puts).with("another_public_singleton_method_arg: #{dummy_arg}").ordered
129
+ expect(target_instance).to receive(:puts).with("around_another_public_singleton_method_with: #{[dummy_arg]}").ordered
130
+ expect(target_instance).to receive(:puts).with("after_another_public_singleton_method_with: #{[dummy_arg]}").ordered
131
+ end
132
+
133
+ it { target_instance.another_public_singleton_method dummy_arg }
134
+
135
+ end
136
+
137
+ end
138
+
139
+ context 'when protected method' do
140
+
141
+ context 'when calling protected method deliberately' do
142
+
143
+ it { expect{target_instance.a_protected_singleton_method dummy_arg}.to raise_error NoMethodError }
144
+
145
+ end
146
+
147
+ context 'when calling protected method through `send`' do
148
+
149
+ before do
150
+ expect(target_instance).to receive(:puts).with("before_a_protected_singleton_method_with: #{[dummy_arg]}").ordered
151
+ expect(target_instance).to receive(:puts).with("a_protected_singleton_method_arg: #{dummy_arg}").ordered
152
+ expect(target_instance).to receive(:puts).with("around_a_protected_singleton_method_with: #{[dummy_arg]}").ordered
153
+ expect(target_instance).to receive(:puts).with("after_a_protected_singleton_method_with: #{[dummy_arg]}").ordered
154
+ end
155
+
156
+ it { target_instance.send :a_protected_singleton_method, dummy_arg }
157
+
158
+ end
159
+
160
+ end
161
+
162
+ context 'when private method' do
163
+
164
+ context 'when calling private method deliberately' do
165
+
166
+ it { expect{target_instance.a_private_singleton_method dummy_arg}.to raise_error NoMethodError }
167
+
168
+ end
169
+
170
+ context 'when calling private method through `send`' do
171
+
172
+ before do
173
+ expect(target_instance).to receive(:puts).with("before_a_private_singleton_method_with: #{[dummy_arg]}").ordered
174
+ expect(target_instance).to receive(:puts).with("a_private_singleton_method_arg: #{dummy_arg}").ordered
175
+ expect(target_instance).to receive(:puts).with("around_a_private_singleton_method_with: #{[dummy_arg]}").ordered
176
+ expect(target_instance).to receive(:puts).with("after_a_private_singleton_method_with: #{[dummy_arg]}").ordered
177
+ end
178
+
179
+ it { target_instance.send :a_private_singleton_method, dummy_arg }
180
+
181
+ end
182
+
183
+ end
184
+
185
+ end
186
+
187
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ base_repository = EasyCallbacks::Repositories::BaseRepository
4
+
5
+ describe base_repository do
6
+
7
+ it 'must override base repository `find_block` method' do
8
+ expect{base_repository.new.send :find_block }.to raise_error(NotImplementedError)
9
+ end
10
+
11
+ it 'must override base repository `model` method' do
12
+ expect{base_repository.new.send :model }.to raise_error(NotImplementedError)
13
+ end
14
+
15
+ end
@@ -0,0 +1,160 @@
1
+ class DummyClass
2
+
3
+ def a_public_instance_method(arg)
4
+ puts "a_public_instance_method_arg: #{arg}"
5
+ end
6
+
7
+ def another_public_instance_method(arg)
8
+ puts "another_public_instance_method_arg: #{arg}"
9
+ end
10
+
11
+ def a_public_instance_method_with_error(arg)
12
+ puts "a_public_instance_method_with_error_arg: #{arg}"
13
+ raise 'some runtime error'
14
+ end
15
+
16
+ protected
17
+
18
+ def a_protected_instance_method(arg)
19
+ puts "a_protected_instance_method_arg: #{arg}"
20
+ end
21
+
22
+ private
23
+
24
+ def a_private_instance_method(arg)
25
+ puts "a_private_instance_method_arg: #{arg}"
26
+ end
27
+
28
+ class << self
29
+
30
+ def a_public_singleton_method(arg)
31
+ puts "a_public_singleton_method_arg: #{arg}"
32
+ end
33
+
34
+ def another_public_singleton_method(arg)
35
+ puts "another_public_singleton_method_arg: #{arg}"
36
+ end
37
+
38
+ protected
39
+
40
+ def a_protected_singleton_method(arg)
41
+ puts "a_protected_singleton_method_arg: #{arg}"
42
+ end
43
+
44
+ private
45
+
46
+ def a_private_singleton_method(arg)
47
+ puts "a_private_singleton_method_arg: #{arg}"
48
+ end
49
+
50
+ include EasyCallbacks
51
+
52
+ before :another_public_singleton_method do
53
+ puts "before_another_public_singleton_method_with: #{call_args}"
54
+ end
55
+
56
+ around :another_public_singleton_method do
57
+ puts "around_another_public_singleton_method_with: #{call_args}"
58
+ end
59
+
60
+ after :another_public_singleton_method do
61
+ puts "after_another_public_singleton_method_with: #{call_args}"
62
+ end
63
+
64
+ end
65
+
66
+ include EasyCallbacks
67
+
68
+ before :another_public_instance_method do
69
+ puts "before_another_public_instance_method_with: #{call_args}"
70
+ end
71
+
72
+ around :another_public_instance_method do
73
+ puts "around_another_public_instance_method_with: #{call_args}"
74
+ end
75
+
76
+ after :another_public_instance_method do
77
+ puts "after_another_public_instance_method_with: #{call_args}"
78
+ end
79
+
80
+ end
81
+
82
+ EasyCallbacks.configure(DummyClass) do
83
+ before :a_public_instance_method do
84
+ puts "before_a_public_instance_method_with: #{call_args}"
85
+ end
86
+
87
+ around :a_public_instance_method do
88
+ puts "around_a_public_instance_method_with: #{call_args}"
89
+ end
90
+
91
+ after :a_public_instance_method do
92
+ puts "after_a_public_instance_method_with: #{call_args}"
93
+ end
94
+
95
+ before :a_protected_instance_method do
96
+ puts "before_a_protected_instance_method_with: #{call_args}"
97
+ end
98
+
99
+ around :a_protected_instance_method do
100
+ puts "around_a_protected_instance_method_with: #{call_args}"
101
+ end
102
+
103
+ after :a_protected_instance_method do
104
+ puts "after_a_protected_instance_method_with: #{call_args}"
105
+ end
106
+
107
+ before :a_private_instance_method do
108
+ puts "before_a_private_instance_method_with: #{call_args}"
109
+ end
110
+
111
+ around :a_private_instance_method do
112
+ puts "around_a_private_instance_method_with: #{call_args}"
113
+ end
114
+
115
+ after :a_private_instance_method do
116
+ puts "after_a_private_instance_method_with: #{call_args}"
117
+ end
118
+
119
+ around :a_public_instance_method_with_error do
120
+ puts "around_a_public_instance_method_with_error: #{callback_details[:return_object]}"
121
+ end
122
+ end
123
+
124
+ EasyCallbacks.configure(DummyClass.singleton_class) do
125
+ before :a_public_singleton_method do
126
+ puts "before_a_public_singleton_method_with: #{call_args}"
127
+ end
128
+
129
+ around :a_public_singleton_method do
130
+ puts "around_a_public_singleton_method_with: #{call_args}"
131
+ end
132
+
133
+ after :a_public_singleton_method do
134
+ puts "after_a_public_singleton_method_with: #{call_args}"
135
+ end
136
+
137
+ before :a_protected_singleton_method do
138
+ puts "before_a_protected_singleton_method_with: #{call_args}"
139
+ end
140
+
141
+ around :a_protected_singleton_method do
142
+ puts "around_a_protected_singleton_method_with: #{call_args}"
143
+ end
144
+
145
+ after :a_protected_singleton_method do
146
+ puts "after_a_protected_singleton_method_with: #{call_args}"
147
+ end
148
+
149
+ before :a_private_singleton_method do
150
+ puts "before_a_private_singleton_method_with: #{call_args}"
151
+ end
152
+
153
+ around :a_private_singleton_method do
154
+ puts "around_a_private_singleton_method_with: #{call_args}"
155
+ end
156
+
157
+ after :a_private_singleton_method do
158
+ puts "after_a_private_singleton_method_with: #{call_args}"
159
+ end
160
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_callbacks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - r4z3c
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-24 00:00:00.000000000 Z
11
+ date: 2017-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1'
47
+ version: 3.0.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1'
54
+ version: 3.0.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Provide callbacks support for Ruby classes
98
112
  email:
99
113
  - r4z3c.43@gmail.com
@@ -107,14 +121,22 @@ files:
107
121
  - MIT-LICENSE
108
122
  - README.rdoc
109
123
  - Rakefile
110
- - changelog.txt
111
124
  - easy_callbacks.gemspec
112
125
  - lib/easy_callbacks.rb
113
- - lib/easy_callbacks/base.rb
126
+ - lib/easy_callbacks/all.rb
127
+ - lib/easy_callbacks/dsls/target_classes_dsl.rb
128
+ - lib/easy_callbacks/models/callback.rb
129
+ - lib/easy_callbacks/models/target_class.rb
130
+ - lib/easy_callbacks/repositories/base_repository.rb
131
+ - lib/easy_callbacks/repositories/callbacks_repository.rb
132
+ - lib/easy_callbacks/repositories/target_classes_repository.rb
133
+ - lib/easy_callbacks/utils/serializer.rb
134
+ - lib/easy_callbacks/utils/validator.rb
114
135
  - lib/easy_callbacks/version.rb
115
- - spec/lib/easy_callbacks/base_spec.rb
136
+ - spec/lib/easy_callbacks_spec.rb
137
+ - spec/lib/repositories/base_repository_spec.rb
116
138
  - spec/spec_helper.rb
117
- - spec/support/some_class.rb
139
+ - spec/support/dummy_class.rb
118
140
  homepage: https://github.com/r4z3c/easy_callbacks.git
119
141
  licenses:
120
142
  - MIT
@@ -140,6 +162,7 @@ signing_key:
140
162
  specification_version: 4
141
163
  summary: Set callbacks for Ruby class methods
142
164
  test_files:
143
- - spec/lib/easy_callbacks/base_spec.rb
165
+ - spec/lib/easy_callbacks_spec.rb
166
+ - spec/lib/repositories/base_repository_spec.rb
144
167
  - spec/spec_helper.rb
145
- - spec/support/some_class.rb
168
+ - spec/support/dummy_class.rb
data/changelog.txt DELETED
@@ -1,13 +0,0 @@
1
- # 0.1.2
2
-
3
- - setting 'execute_callbacks_for' (and related methods) as private
4
-
5
- # 0.1.1
6
-
7
- - fixing callbacks initialization bug: when trying to 'execute_callbacks_for' for a type (e.g. 'before') that doesn't
8
- received pushes, it crashes by trying call 'select' to a nil object
9
-
10
- # 0.1.0
11
-
12
- - adding 'object' key to 'callback_details' providing context to anonymous callbacks
13
- - removing 'method_missing' strategy from base module, this isn't strictly necessary
@@ -1,117 +0,0 @@
1
- require 'method_decorator'
2
-
3
- module EasyCallbacks
4
- module Base extend ActiveSupport::Concern
5
-
6
- included do
7
-
8
- include MethodDecorator
9
-
10
- class << self
11
-
12
- attr_accessor :callbacks
13
-
14
- def before(target, callback_name=nil, &block)
15
- handle_callback_definition :before, target, callback_name, &block
16
- end
17
-
18
- def around(target, callback_name=nil, &block)
19
- handle_callback_definition :around, target, callback_name, &block
20
- end
21
-
22
- def after(target, callback_name=nil, &block)
23
- handle_callback_definition :after, target, callback_name, &block
24
- end
25
-
26
- private
27
-
28
- def handle_callback_definition(type, target, callback_name, &block)
29
- push_callback type, target, callback_name, &block
30
- decorate_target target
31
- end
32
-
33
- def push_callback(type, target, callback_name)
34
- initialize_callbacks
35
- self.callbacks[type].push target: target,
36
- callback_name: callback_name,
37
- proc: (block_given? ? Proc.new : nil)
38
- end
39
-
40
- def initialize_callbacks
41
- self.callbacks ||= {}
42
- self.callbacks[:before] ||= []
43
- self.callbacks[:around] ||= []
44
- self.callbacks[:after] ||= []
45
- end
46
-
47
- def decorate_target(target)
48
- decorate_method target do |*args, &block|
49
- execute_callbacks_for :before, target, nil, *args, &block
50
- result, error = execute_original_method target, *args, &block
51
-
52
- additional_options = error ?
53
- { return_type: :error, return_object: error } :
54
- { return_type: :success, return_object: result }
55
-
56
- execute_callbacks_for :around, target, additional_options, *args, &block
57
-
58
- raise error if error
59
-
60
- execute_callbacks_for :after, target, nil, *args, &block
61
-
62
- result
63
- end unless method_defined? original_method_name_for(target)
64
- end
65
-
66
- end
67
-
68
- private
69
-
70
- def execute_callbacks_for(type, target, additional_options, *args, &block)
71
- get_callbacks_for(type).select { |c| c[:target].eql? target }.each do |callback|
72
- cn = callback[:callback_name]
73
- proc = callback[:proc]
74
- t = callback[:target]
75
- arguments = args + [
76
- class: callbacks_holder,
77
- target: t,
78
- type: type,
79
- callback_name: cn,
80
- proc: proc
81
- ];
82
-
83
- arguments.last.merge! additional_options if additional_options
84
-
85
- if proc.nil?
86
- send(cn, *arguments, &block)
87
- else
88
- arguments.last.merge! object: self
89
- proc.call(*arguments, &block)
90
- end
91
- end
92
- end
93
-
94
- def get_callbacks_for(type)
95
- callbacks_holder.callbacks[type]
96
- end
97
-
98
- def callbacks_holder
99
- self.class.eql?(Class) ? self.singleton_class : self.class
100
- end
101
-
102
- def execute_original_method(target, *args, &block)
103
- result = error = nil
104
-
105
- begin
106
- result = call_original_method target, *args, &block
107
- rescue => e
108
- error = e
109
- end
110
-
111
- return result, error
112
- end
113
-
114
- end
115
-
116
- end
117
- end
@@ -1,28 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/some_class'
3
-
4
- describe EasyCallbacks::Base do
5
-
6
- let(:instance) { SomeClass.new }
7
-
8
- it do
9
- expect_instance_for_puts_with('before_1: some_arg')
10
- expect_class_for_puts_with('before_2: some_arg')
11
- expect_instance_for_puts_with('some_method: some_arg')
12
- expect_instance_for_puts_with('around_1: some_arg')
13
- expect_class_for_puts_with('around_2: some_arg')
14
- expect_instance_for_puts_with('after_1: some_arg')
15
- expect_class_for_puts_with('after_2: some_arg')
16
-
17
- instance.some_method(:some_arg)
18
- end
19
-
20
- def expect_instance_for_puts_with(expected)
21
- expect(instance).to receive(:puts).with(expected).ordered
22
- end
23
-
24
- def expect_class_for_puts_with(expected)
25
- expect(SomeClass).to receive(:puts).with(expected).ordered
26
- end
27
-
28
- end
@@ -1,36 +0,0 @@
1
- class SomeClass
2
-
3
- def some_method(some_arg)
4
- puts "some_method: #{some_arg}"
5
- end
6
-
7
- include EasyCallbacks::Base
8
-
9
- before :some_method, :before_1
10
- before :some_method do |some_arg, callback_details|
11
- puts "before_2: #{some_arg}"
12
- end
13
-
14
- around :some_method, :around_1
15
- around :some_method do |some_arg, callback_details|
16
- puts "around_2: #{some_arg}"
17
- end
18
-
19
- after :some_method, :after_1
20
- after :some_method do |some_arg, callback_details|
21
- puts "after_2: #{some_arg}"
22
- end
23
-
24
- def before_1(some_arg, callback_details)
25
- puts "before_1: #{some_arg}"
26
- end
27
-
28
- def around_1(some_arg, callback_details)
29
- puts "around_1: #{some_arg}"
30
- end
31
-
32
- def after_1(some_arg, callback_details)
33
- puts "after_1: #{some_arg}"
34
- end
35
-
36
- end