slayer 0.4.0.beta3 → 0.5.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/release.yml +28 -0
- data/.github/workflows/test.yml +28 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +13 -18
- data/Dockerfile +1 -2
- data/README.md +39 -47
- data/Rakefile +0 -11
- data/lib/slayer/command.rb +65 -8
- data/lib/slayer/compat/compat_040.rb +64 -0
- data/lib/slayer/cops/return_matcher.rb +45 -0
- data/lib/slayer/minitest.rb +6 -7
- data/lib/slayer/result.rb +5 -5
- data/lib/slayer/result_matcher.rb +24 -24
- data/lib/slayer/rspec.rb +20 -4
- data/lib/slayer/version.rb +1 -1
- data/lib/slayer.rb +0 -2
- data/slayer.gemspec +5 -8
- metadata +19 -64
- data/.hound.yml +0 -2
- data/.rubocop_todo.yml +0 -48
- data/.travis.yml +0 -6
- data/CHANGELOG.md +0 -9
- data/lib/slayer/hook.rb +0 -154
- data/lib/slayer/service.rb +0 -136
@@ -10,16 +10,16 @@ module Slayer
|
|
10
10
|
#
|
11
11
|
# == Matching based on success or failure
|
12
12
|
#
|
13
|
-
# The ResultMatcher matches calls to {#
|
14
|
-
# for {Result#
|
15
|
-
# for {Result#
|
13
|
+
# The ResultMatcher matches calls to {#ok} to a {Result} that returns +true+
|
14
|
+
# for {Result#ok?}, calls to {#err} to a {Result} that returns +true+
|
15
|
+
# for {Result#err?}, and calls to {#all} to a {Result} in either state.
|
16
16
|
#
|
17
|
-
# A matching call to {#
|
17
|
+
# A matching call to {#ok} or {#err} takes precedence over matching calls to {#all}
|
18
18
|
#
|
19
19
|
# == Matching based on status
|
20
20
|
#
|
21
21
|
# Additionally, the ResultMatcher can also match by the {Result#status}. If a status
|
22
|
-
# or statuses is passed to {#
|
22
|
+
# or statuses is passed to {#ok}, {#err}, or {#all}, these will only be invoked if the
|
23
23
|
# status of the {Result} matches the passed in status.
|
24
24
|
#
|
25
25
|
# If the default block is the same as the block for one of the statuses the status +:default+
|
@@ -29,11 +29,11 @@ module Slayer
|
|
29
29
|
# == Both pass and fail must be handled
|
30
30
|
#
|
31
31
|
# If the block form of a {Command.call} is invoked, both the block must handle the default
|
32
|
-
# status for both a {Result#
|
32
|
+
# status for both a {Result#ok?} and a {Result#err?}. If both are not handled,
|
33
33
|
# the matching block will not be invoked and a {ResultNotHandledError} will be
|
34
34
|
# raised.
|
35
35
|
#
|
36
|
-
# @example Matcher invokes the matching pass block, with precedence given to {#
|
36
|
+
# @example Matcher invokes the matching pass block, with precedence given to {#ok} and {#err}
|
37
37
|
# # Call produces a successful Result
|
38
38
|
# SuccessCommand.call do |m|
|
39
39
|
# m.pass { puts "Pass!" }
|
@@ -105,8 +105,8 @@ module Slayer
|
|
105
105
|
|
106
106
|
@status = result.status || :default
|
107
107
|
|
108
|
-
@
|
109
|
-
@
|
108
|
+
@handled_default_ok = false
|
109
|
+
@handled_default_err = false
|
110
110
|
|
111
111
|
# These are set to false if they are never set. If they are set to `nil` that
|
112
112
|
# means the block intentionally passed `nil` as the block to be executed.
|
@@ -125,12 +125,12 @@ module Slayer
|
|
125
125
|
# not matched by other matchers.
|
126
126
|
#
|
127
127
|
# If no value is provided for statuses it defaults to +:default+.
|
128
|
-
def
|
128
|
+
def ok(*statuses, &block)
|
129
129
|
statuses << :default if statuses.empty?
|
130
|
-
@
|
130
|
+
@handled_default_ok ||= statuses.include?(:default)
|
131
131
|
|
132
|
-
block_is_match = @result.
|
133
|
-
block_is_default = @result.
|
132
|
+
block_is_match = @result.ok? && statuses.include?(@status)
|
133
|
+
block_is_default = @result.ok? && statuses.include?(:default)
|
134
134
|
|
135
135
|
@matching_block = block if block_is_match
|
136
136
|
@default_block = block if block_is_default
|
@@ -144,19 +144,19 @@ module Slayer
|
|
144
144
|
# not matched by other matchers.
|
145
145
|
#
|
146
146
|
# If no value is provided for statuses it defaults to +:default+.
|
147
|
-
def
|
147
|
+
def err(*statuses, &block)
|
148
148
|
statuses << :default if statuses.empty?
|
149
|
-
@
|
149
|
+
@handled_default_err ||= statuses.include?(:default)
|
150
150
|
|
151
|
-
block_is_match = @result.
|
152
|
-
block_is_default = @result.
|
151
|
+
block_is_match = @result.err? && statuses.include?(@status)
|
152
|
+
block_is_default = @result.err? && statuses.include?(:default)
|
153
153
|
|
154
154
|
@matching_block = block if block_is_match
|
155
155
|
@default_block = block if block_is_default
|
156
156
|
end
|
157
157
|
|
158
158
|
# Provide a block that should be invoked for any {Result}. This has a lower precedence that
|
159
|
-
# either {#
|
159
|
+
# either {#ok} or {#err}.
|
160
160
|
#
|
161
161
|
# @param statuses [Array<status>] Statuses that should be compared to the {Result}. If
|
162
162
|
# any of provided statuses match the {Result} this block will be considered a match.
|
@@ -166,8 +166,8 @@ module Slayer
|
|
166
166
|
# If no value is provided for statuses it defaults to +:default+.
|
167
167
|
def all(*statuses, &block)
|
168
168
|
statuses << :default if statuses.empty?
|
169
|
-
@
|
170
|
-
@
|
169
|
+
@handled_default_ok ||= statuses.include?(:default)
|
170
|
+
@handled_default_err ||= statuses.include?(:default)
|
171
171
|
|
172
172
|
block_is_match = statuses.include?(@status)
|
173
173
|
block_is_default = statuses.include?(:default)
|
@@ -186,7 +186,7 @@ module Slayer
|
|
186
186
|
#
|
187
187
|
# @api private
|
188
188
|
def handled_defaults?
|
189
|
-
return @
|
189
|
+
return @handled_default_ok && @handled_default_err
|
190
190
|
end
|
191
191
|
|
192
192
|
# Executes the provided block that best matched the {Result}. If no block matched
|
@@ -213,8 +213,8 @@ module Slayer
|
|
213
213
|
|
214
214
|
private
|
215
215
|
|
216
|
-
|
217
|
-
|
218
|
-
|
216
|
+
def run_block(block)
|
217
|
+
block&.call(@result.value, @result, @command) # explicit nil should fail this test
|
218
|
+
end
|
219
219
|
end
|
220
220
|
end
|
data/lib/slayer/rspec.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'rspec/expectations'
|
2
|
+
|
2
3
|
# rubocop:disable Metrics/BlockLength
|
3
|
-
RSpec::Matchers.define :
|
4
|
+
RSpec::Matchers.define :be_ok_result do
|
4
5
|
match do |result|
|
5
6
|
status_matches = @status.nil? || @status == result.status
|
6
7
|
message_matches = @message.nil? || @message == result.message
|
7
8
|
value_matches = @value.nil? || @value == result.value
|
8
9
|
|
9
|
-
result.
|
10
|
+
result.ok? && status_matches && message_matches && value_matches
|
10
11
|
end
|
11
12
|
|
12
13
|
chain :with_status do |status|
|
@@ -21,6 +22,12 @@ RSpec::Matchers.define :be_success_result do
|
|
21
22
|
@value = value
|
22
23
|
end
|
23
24
|
|
25
|
+
chain :with do |args|
|
26
|
+
@status = args[:status] if args.key? :status
|
27
|
+
@message = args[:message] if args.key? :message
|
28
|
+
@value = args[:value] if args.key? :value
|
29
|
+
end
|
30
|
+
|
24
31
|
# :nocov:
|
25
32
|
failure_message do |result|
|
26
33
|
return 'expected command to succeed' if @status.nil? && @value.nil? && @message.nil?
|
@@ -33,18 +40,19 @@ RSpec::Matchers.define :be_success_result do
|
|
33
40
|
return "expected command not to have message: #{@message}" if !@message.nil? && result.message == @message
|
34
41
|
return "expected command not to have value: #{@value}" if !@value.nil? && result.value == @value
|
35
42
|
return "expected command not to have status :#{@status}" if !@status.nil? && result.status == @status
|
43
|
+
|
36
44
|
return 'expected command to fail'
|
37
45
|
end
|
38
46
|
# :nocov:
|
39
47
|
end
|
40
48
|
|
41
|
-
RSpec::Matchers.define :
|
49
|
+
RSpec::Matchers.define :be_err_result do
|
42
50
|
match do |result|
|
43
51
|
status_matches = @status.nil? || @status == result.status
|
44
52
|
message_matches = @message.nil? || @message == result.message
|
45
53
|
value_matches = @value.nil? || @value == result.value
|
46
54
|
|
47
|
-
result.
|
55
|
+
result.err? && status_matches && message_matches && value_matches
|
48
56
|
end
|
49
57
|
|
50
58
|
chain :with_status do |status|
|
@@ -59,6 +67,12 @@ RSpec::Matchers.define :be_failed_result do
|
|
59
67
|
@value = value
|
60
68
|
end
|
61
69
|
|
70
|
+
chain :with do |args|
|
71
|
+
@status = args[:status] if args.key? :status
|
72
|
+
@message = args[:message] if args.key? :message
|
73
|
+
@value = args[:value] if args.key? :value
|
74
|
+
end
|
75
|
+
|
62
76
|
# :nocov:
|
63
77
|
failure_message do |result|
|
64
78
|
return 'expected command to fail' if @status.nil? && @value.nil? && @message.nil?
|
@@ -71,8 +85,10 @@ RSpec::Matchers.define :be_failed_result do
|
|
71
85
|
return "expected command to have message: #{@message}" if !@message.nil? && result.message == @message
|
72
86
|
return "expected command to have value: #{@value}" if !@value.nil? && result.value == @value
|
73
87
|
return "expected command to have status :#{@status}" if !@status.nil? && result.status == @status
|
88
|
+
|
74
89
|
return 'expected command to succeed'
|
75
90
|
end
|
76
91
|
# :nocov:
|
77
92
|
end
|
93
|
+
|
78
94
|
# rubocop:enable Metrics/BlockLength
|
data/lib/slayer/version.rb
CHANGED
data/lib/slayer.rb
CHANGED
data/slayer.gemspec
CHANGED
@@ -18,18 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency 'virtus', '~>
|
21
|
+
spec.add_dependency 'virtus', '~> 2.0'
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
24
24
|
spec.add_development_dependency 'byebug', '~> 9.0'
|
25
|
-
spec.add_development_dependency 'chandler'
|
26
|
-
spec.add_development_dependency 'coveralls'
|
27
25
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
28
26
|
spec.add_development_dependency 'minitest-reporters', '~> 1.1'
|
29
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
30
|
-
spec.add_development_dependency '
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency '
|
33
|
-
spec.add_development_dependency 'simplecov', '~> 0.13'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.12'
|
28
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
29
|
+
spec.add_development_dependency 'rubocop', '= 1.38.0'
|
30
|
+
spec.add_development_dependency 'simplecov'
|
34
31
|
spec.add_development_dependency 'yard', '~> 0.9'
|
35
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slayer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wyatt Kirby
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-12-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: virtus
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '2.0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '2.0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: bundler
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,34 +53,6 @@ dependencies:
|
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '9.0'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: chandler
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: coveralls
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
84
56
|
- !ruby/object:Gem::Dependency
|
85
57
|
name: minitest
|
86
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,70 +87,56 @@ dependencies:
|
|
115
87
|
requirements:
|
116
88
|
- - "~>"
|
117
89
|
- !ruby/object:Gem::Version
|
118
|
-
version: '3.
|
119
|
-
type: :development
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - "~>"
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '3.5'
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: mocha
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
requirements:
|
130
|
-
- - "~>"
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: '1.2'
|
90
|
+
version: '3.12'
|
133
91
|
type: :development
|
134
92
|
prerelease: false
|
135
93
|
version_requirements: !ruby/object:Gem::Requirement
|
136
94
|
requirements:
|
137
95
|
- - "~>"
|
138
96
|
- !ruby/object:Gem::Version
|
139
|
-
version: '
|
97
|
+
version: '3.12'
|
140
98
|
- !ruby/object:Gem::Dependency
|
141
99
|
name: rake
|
142
100
|
requirement: !ruby/object:Gem::Requirement
|
143
101
|
requirements:
|
144
102
|
- - "~>"
|
145
103
|
- !ruby/object:Gem::Version
|
146
|
-
version: '
|
104
|
+
version: '13.0'
|
147
105
|
type: :development
|
148
106
|
prerelease: false
|
149
107
|
version_requirements: !ruby/object:Gem::Requirement
|
150
108
|
requirements:
|
151
109
|
- - "~>"
|
152
110
|
- !ruby/object:Gem::Version
|
153
|
-
version: '
|
111
|
+
version: '13.0'
|
154
112
|
- !ruby/object:Gem::Dependency
|
155
113
|
name: rubocop
|
156
114
|
requirement: !ruby/object:Gem::Requirement
|
157
115
|
requirements:
|
158
116
|
- - '='
|
159
117
|
- !ruby/object:Gem::Version
|
160
|
-
version:
|
118
|
+
version: 1.38.0
|
161
119
|
type: :development
|
162
120
|
prerelease: false
|
163
121
|
version_requirements: !ruby/object:Gem::Requirement
|
164
122
|
requirements:
|
165
123
|
- - '='
|
166
124
|
- !ruby/object:Gem::Version
|
167
|
-
version:
|
125
|
+
version: 1.38.0
|
168
126
|
- !ruby/object:Gem::Dependency
|
169
127
|
name: simplecov
|
170
128
|
requirement: !ruby/object:Gem::Requirement
|
171
129
|
requirements:
|
172
|
-
- - "
|
130
|
+
- - ">="
|
173
131
|
- !ruby/object:Gem::Version
|
174
|
-
version: '0
|
132
|
+
version: '0'
|
175
133
|
type: :development
|
176
134
|
prerelease: false
|
177
135
|
version_requirements: !ruby/object:Gem::Requirement
|
178
136
|
requirements:
|
179
|
-
- - "
|
137
|
+
- - ">="
|
180
138
|
- !ruby/object:Gem::Version
|
181
|
-
version: '0
|
139
|
+
version: '0'
|
182
140
|
- !ruby/object:Gem::Dependency
|
183
141
|
name: yard
|
184
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,13 +160,11 @@ extensions: []
|
|
202
160
|
extra_rdoc_files: []
|
203
161
|
files:
|
204
162
|
- ".githooks/pre-push"
|
163
|
+
- ".github/workflows/release.yml"
|
164
|
+
- ".github/workflows/test.yml"
|
205
165
|
- ".gitignore"
|
206
|
-
- ".hound.yml"
|
207
166
|
- ".rspec"
|
208
167
|
- ".rubocop.yml"
|
209
|
-
- ".rubocop_todo.yml"
|
210
|
-
- ".travis.yml"
|
211
|
-
- CHANGELOG.md
|
212
168
|
- Dockerfile
|
213
169
|
- Gemfile
|
214
170
|
- LICENSE.txt
|
@@ -226,14 +182,14 @@ files:
|
|
226
182
|
- lib/ext/string_ext.rb
|
227
183
|
- lib/slayer.rb
|
228
184
|
- lib/slayer/command.rb
|
185
|
+
- lib/slayer/compat/compat_040.rb
|
186
|
+
- lib/slayer/cops/return_matcher.rb
|
229
187
|
- lib/slayer/errors.rb
|
230
188
|
- lib/slayer/form.rb
|
231
|
-
- lib/slayer/hook.rb
|
232
189
|
- lib/slayer/minitest.rb
|
233
190
|
- lib/slayer/result.rb
|
234
191
|
- lib/slayer/result_matcher.rb
|
235
192
|
- lib/slayer/rspec.rb
|
236
|
-
- lib/slayer/service.rb
|
237
193
|
- lib/slayer/version.rb
|
238
194
|
- slayer.gemspec
|
239
195
|
- slayer_logo.png
|
@@ -256,8 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
256
212
|
- !ruby/object:Gem::Version
|
257
213
|
version: 1.3.1
|
258
214
|
requirements: []
|
259
|
-
|
260
|
-
rubygems_version: 2.6.13
|
215
|
+
rubygems_version: 3.2.3
|
261
216
|
signing_key:
|
262
217
|
specification_version: 4
|
263
218
|
summary: A killer service layer
|
data/.hound.yml
DELETED
data/.rubocop_todo.yml
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
# `rubocop --auto-gen-config`
|
3
|
-
# on 2017-02-13 09:02:04 -0800 using RuboCop version 0.47.1.
|
4
|
-
# The point is for the user to remove these configuration records
|
5
|
-
# one by one as the offenses are removed from the code base.
|
6
|
-
# Note that changes in the inspected code, or installation of new
|
7
|
-
# versions of RuboCop, may require this file to be generated again.
|
8
|
-
|
9
|
-
# Offense count: 2
|
10
|
-
Lint/HandleExceptions:
|
11
|
-
Exclude:
|
12
|
-
- 'lib/slayer/command.rb'
|
13
|
-
- 'test/lib/result_matcher_test.rb'
|
14
|
-
|
15
|
-
# Offense count: 2
|
16
|
-
# Cop supports --auto-correct.
|
17
|
-
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
18
|
-
Lint/UnusedMethodArgument:
|
19
|
-
Exclude:
|
20
|
-
- 'lib/slayer/form.rb'
|
21
|
-
|
22
|
-
# Offense count: 1
|
23
|
-
Metrics/AbcSize:
|
24
|
-
Max: 19
|
25
|
-
|
26
|
-
# Offense count: 1
|
27
|
-
Metrics/CyclomaticComplexity:
|
28
|
-
Max: 9
|
29
|
-
|
30
|
-
# Offense count: 5
|
31
|
-
# Configuration parameters: CountComments.
|
32
|
-
Metrics/MethodLength:
|
33
|
-
Max: 18
|
34
|
-
|
35
|
-
# Offense count: 1
|
36
|
-
Metrics/PerceivedComplexity:
|
37
|
-
Max: 10
|
38
|
-
|
39
|
-
# Offense count: 6
|
40
|
-
Style/Documentation:
|
41
|
-
Exclude:
|
42
|
-
- 'spec/**/*'
|
43
|
-
- 'test/**/*'
|
44
|
-
- 'lib/ext/**/*'
|
45
|
-
- 'lib/slayer/command.rb'
|
46
|
-
- 'lib/slayer/errors.rb'
|
47
|
-
- 'lib/slayer/form.rb'
|
48
|
-
- 'lib/slayer/result.rb'
|
data/.travis.yml
DELETED
data/CHANGELOG.md
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
# Changelog
|
2
|
-
All notable changes to this project will be documented in this file.
|
3
|
-
|
4
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
-
|
7
|
-
## [Unreleased]
|
8
|
-
### Added
|
9
|
-
- Added documentation for CHANGELOG to README
|
data/lib/slayer/hook.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
module Slayer
|
2
|
-
# Hook adds the ability to wrap all calls to a class in a wrapper method. The
|
3
|
-
# wrapper method is provided with a block that can be used to invoke the called
|
4
|
-
# method.
|
5
|
-
#
|
6
|
-
# The methods #skip_hook and #only_hook can be used to control which methods are
|
7
|
-
# and are not wrapped with the hook call.
|
8
|
-
#
|
9
|
-
# @example Including Hook on a class.
|
10
|
-
# class MyHookedClass
|
11
|
-
# include Hook
|
12
|
-
#
|
13
|
-
# hook :say_hello_and_goodbye
|
14
|
-
#
|
15
|
-
# def self.say_hello_and_goodbye
|
16
|
-
# puts "hello!"
|
17
|
-
#
|
18
|
-
# yield # calls hooked method
|
19
|
-
#
|
20
|
-
# puts "goodbye!"
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# def self.say_something
|
24
|
-
# puts "something"
|
25
|
-
# end
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# MyHookedClass.say_something
|
29
|
-
# # => "hello!"
|
30
|
-
# # "something"
|
31
|
-
# # "goodbye!"
|
32
|
-
#
|
33
|
-
# @example Skipping Hooks
|
34
|
-
#
|
35
|
-
# skip_hook :say_something, :do_something # the hook method will not be invoked for
|
36
|
-
# # these methods. They will be called directly.
|
37
|
-
#
|
38
|
-
# @example Only hooking
|
39
|
-
#
|
40
|
-
# only_hook :see_something, :hear_something # These are the only methods that will be
|
41
|
-
# # be hooked. All other methods will be
|
42
|
-
# # called directly.
|
43
|
-
module Hook
|
44
|
-
def self.included(klass)
|
45
|
-
klass.extend ClassMethods
|
46
|
-
end
|
47
|
-
|
48
|
-
# Everything in Hook::ClassMethods automatically get extended onto the
|
49
|
-
# class that includes Hook.
|
50
|
-
module ClassMethods
|
51
|
-
# Define the method that will be invoked whenever another method is invoked.
|
52
|
-
# This should be a class method.
|
53
|
-
def hook(hook_method)
|
54
|
-
@__hook = hook_method
|
55
|
-
end
|
56
|
-
|
57
|
-
# Define the set of methods that should always be called directly, and should
|
58
|
-
# never be hooked
|
59
|
-
def skip_hook(*hook_skips)
|
60
|
-
@__hook_skips = hook_skips
|
61
|
-
end
|
62
|
-
|
63
|
-
def singleton_skip_hook(*hook_skips)
|
64
|
-
@__singleton_hook_skips = hook_skips
|
65
|
-
end
|
66
|
-
|
67
|
-
# If only_hook is called then only the methods provided will be hooked. All
|
68
|
-
# other methods will be called directly.
|
69
|
-
def only_hook(*hook_only)
|
70
|
-
@__hook_only = hook_only
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def __hook
|
76
|
-
@__hook ||= nil
|
77
|
-
end
|
78
|
-
|
79
|
-
def __hook_skips
|
80
|
-
@__hook_skips ||= []
|
81
|
-
end
|
82
|
-
|
83
|
-
def __singleton_hook_skips
|
84
|
-
@__singleton_hook_skips ||= []
|
85
|
-
end
|
86
|
-
|
87
|
-
def __hook_only
|
88
|
-
@__hook_only ||= nil
|
89
|
-
end
|
90
|
-
|
91
|
-
def __current_methods
|
92
|
-
@__current_methods ||= nil
|
93
|
-
end
|
94
|
-
|
95
|
-
def run_hook(name, instance, passed_block, &block)
|
96
|
-
if __hook
|
97
|
-
send(__hook, name, instance, passed_block, &block)
|
98
|
-
else
|
99
|
-
# rubocop:disable Performance/RedundantBlockCall
|
100
|
-
block.call
|
101
|
-
# rubocop:enable Performance/RedundantBlockCall
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def singleton_method_added(name)
|
106
|
-
insert_hook_for(name,
|
107
|
-
define_method_fn: :define_singleton_method,
|
108
|
-
hook_target: self,
|
109
|
-
alias_target: singleton_class,
|
110
|
-
skip_methods: blacklist(__singleton_hook_skips))
|
111
|
-
end
|
112
|
-
|
113
|
-
def method_added(name)
|
114
|
-
insert_hook_for(name,
|
115
|
-
define_method_fn: :define_method,
|
116
|
-
hook_target: self,
|
117
|
-
alias_target: self,
|
118
|
-
skip_methods: blacklist(__hook_skips))
|
119
|
-
end
|
120
|
-
|
121
|
-
def insert_hook_for(name, define_method_fn:, hook_target:, alias_target:, skip_methods: [])
|
122
|
-
return if __current_methods && __current_methods.include?(name)
|
123
|
-
|
124
|
-
with_hooks = :"__#{name}_with_hooks"
|
125
|
-
without_hooks = :"__#{name}_without_hooks"
|
126
|
-
|
127
|
-
return if __hook_only && !__hook_only.include?(name.to_sym)
|
128
|
-
return if skip_methods.include? name.to_sym
|
129
|
-
|
130
|
-
@__current_methods = [name, with_hooks, without_hooks]
|
131
|
-
send(define_method_fn, with_hooks) do |*args, &block|
|
132
|
-
hook_target.send(:run_hook, name, self, block) do
|
133
|
-
send(without_hooks, *args)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
alias_target.send(:alias_method, without_hooks, name)
|
138
|
-
alias_target.send(:alias_method, name, with_hooks)
|
139
|
-
|
140
|
-
@__current_methods = nil
|
141
|
-
end
|
142
|
-
|
143
|
-
def blacklist(additional = [])
|
144
|
-
list = Object.methods(false) + Object.private_methods(false)
|
145
|
-
list += Slayer::Hook::ClassMethods.private_instance_methods(false)
|
146
|
-
list += Slayer::Hook::ClassMethods.instance_methods(false)
|
147
|
-
list += additional
|
148
|
-
list << __hook if __hook
|
149
|
-
|
150
|
-
list
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|