grift 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a37d5a48e24392779fb59d698491aab83b2ebd26118cd3b25e8af70f2762731e
4
- data.tar.gz: cde1463f8b56b94dcc94d94cef6fc42629bff64a323c24253c966d733eb910b1
3
+ metadata.gz: 62cac26275a4af88278a38985c4edc2e3d001954fe68e491e242add325e49576
4
+ data.tar.gz: 03ddad7645f758c5708e353e8780001cfd4ce7b478cee2a4c5d60ae7a180cb80
5
5
  SHA512:
6
- metadata.gz: 87c96bd3c0ba9f35a6aae57b99b4b1efb1e065c3c63a610971d202b0964787661eaec6cdf7a26840e8e246fba012628979f6ffb1999efaa47298302290be4ba1
7
- data.tar.gz: f5b66d0f079d8850c770fef90768da8a10a62f657f4645901758f0137235eb403cf2cd1f426a7b13ddc16546ba278f0d38776e102a180181a15ce81135b07be9
6
+ metadata.gz: 8df483db6759b17e6c8d7d6f05a81ed3b507b4be7d9a3d5b0f0adaa70bc8fec798d8d3e750d6f512a586e128ca0f492288d5b32a6e772a8ca6e2a67903116f41
7
+ data.tar.gz: c6460882f099ec2622fe92b99882e52b54df86c5aaf86311f86104326a94455235890ca5cc161448f8b7d5ab60d6853c1d65287764b8516eeebb5fd53ba3c8e3
@@ -4,8 +4,10 @@ updates:
4
4
  - directory: /
5
5
  open-pull-requests-limit: 10
6
6
  package-ecosystem: bundler
7
- target-branch: develop
7
+ target-branch: main
8
8
  schedule:
9
9
  interval: weekly
10
10
  labels:
11
11
  - dependencies
12
+ assignees:
13
+ - clarkedb
@@ -3,6 +3,7 @@ name: CI
3
3
  on: push
4
4
 
5
5
  env:
6
+ CI: true
6
7
  GIT_COMMIT_SHA: ${{ github.sha }}
7
8
  GIT_BRANCH: ${{ github.ref }}
8
9
 
@@ -32,7 +33,7 @@ jobs:
32
33
  strategy:
33
34
  fail-fast: false
34
35
  matrix:
35
- ruby: ["2.5", "2.6", "2.7", "3.0", "3.1"]
36
+ ruby: ["2.7", "3.0", "3.1"]
36
37
 
37
38
  steps:
38
39
  - uses: actions/checkout@v2
@@ -44,3 +45,12 @@ jobs:
44
45
  - name: Test
45
46
  continue-on-error: ${{ matrix.experimental }}
46
47
  run: bundle exec rake test
48
+
49
+ - name: Upload coverage to Codecov
50
+ uses: codecov/codecov-action@v2
51
+ with:
52
+ token: ${{ secrets.CODECOV_TOKEN }}
53
+ files: ./coverage/.resultset.json
54
+ name: codecov-umbrella
55
+ verbose: true
56
+ fail_ci_if_error: true
data/.overcommit.yml ADDED
@@ -0,0 +1,8 @@
1
+ PreCommit:
2
+ RuboCop:
3
+ enabled: true
4
+ on_warn: fail # Treat all warnings as failures
5
+
6
+ CommitMsg:
7
+ ALL:
8
+ enabled: false
data/.rubocop.yml CHANGED
@@ -9,6 +9,11 @@
9
9
  #
10
10
  # See https://docs.rubocop.org/rubocop/configuration
11
11
 
12
+ require:
13
+ - rubocop-minitest
14
+ - rubocop-packaging
15
+ - rubocop-performance
16
+
12
17
  # General
13
18
  AllCops:
14
19
  NewCops: enable
@@ -119,6 +124,16 @@ Metrics/MethodLength:
119
124
  Exclude:
120
125
  - "test/**/*"
121
126
 
127
+ # Minitest
128
+ Minitest/AssertPredicate:
129
+ Enabled: false
130
+
131
+ Minitest/MultipleAssertions:
132
+ Max: 10
133
+
134
+ Minitest/RefutePredicate:
135
+ Enabled: false
136
+
122
137
  # Naming
123
138
  Naming/InclusiveLanguage:
124
139
  Enabled: true
data/CHANGELOG.md CHANGED
@@ -6,23 +6,37 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
6
6
 
7
7
  ## Unreleased
8
8
 
9
- N/A
9
+ None
10
10
 
11
- ## [1.1.0](https://github.com/clarkedb/grift/releases/tag/v1.1.0) - 2022-02-03
11
+ ## [2.0.0](https://github.com/clarkedb/grift/releases/tag/v2.0.0) - 2022-03-14
12
12
 
13
- This version adds support for Ruby 3.1 and updates various dependencies.
13
+ ### Changed
14
+
15
+ * Dropped support for Ruby 2.5 ([#69](https://github.com/clarkedb/grift/pull/69))
16
+ * Dropped support for Ruby 2.6 ([#72](https://github.com/clarkedb/grift/pull/72))
17
+ * To support keyword arguments, records of call arguments are no longer stored in simple arrays but in a custom Enumerable ([#72](https://github.com/clarkedb/grift/pull/72))
18
+ + This changes the way that your tests will interact with mock calls
19
+ + When before `calls` returned an array, it returns a `Grift::MockMethod::MockExecutions::MockArguments` object
20
+ + Migrating to maintain previous behavior just requires appending `.args` to `calls`
14
21
 
15
22
  ### Added
16
23
 
17
- * Support Ruby 3.1
24
+ * Support for mocking private instance and class methods ([#68](https://github.com/clarkedb/grift/pull/68))
25
+ * Support for mocking methods that take positional and keyword arguments ([#72](https://github.com/clarkedb/grift/pull/72))
18
26
 
19
- ### Updated
27
+ ### Fixed
20
28
 
21
- * Updates `minitest`
22
- * Updates `minitest-reporters`
23
- * Updates `rubocop`
24
- * Updates `rubocop-minitest`
25
- * Updates `rubocop-performance`
29
+ * When mocking protected methods, the method now remains protected while mocked and after unmocking ([#68](https://github.com/clarkedb/grift/pull/68))
30
+ * When mocking inherited methods, the method goes back to the ancestor's definition after unmocking ([#69](https://github.com/clarkedb/grift/pull/69))
31
+ * When mocking methods with keyword arugments in Ruby 3.x, no error is thrown ([#72](https://github.com/clarkedb/grift/pull/72))
32
+
33
+ ## [1.1.0](https://github.com/clarkedb/grift/releases/tag/v1.1.0) - 2022-02-03
34
+
35
+ This version adds support for Ruby 3.1 and updates various dependencies.
36
+
37
+ ### Added
38
+
39
+ * Support Ruby 3.1 ([#52](https://github.com/clarkedb/grift/pull/52))
26
40
 
27
41
  ## [1.0.2](https://github.com/clarkedb/grift/releases/tag/v1.0.2) - 2021-11-11
28
42
 
@@ -30,7 +44,7 @@ This version fixes a bug that prevented the mocking of methods defined by a clas
30
44
 
31
45
  ### Fixed
32
46
 
33
- * Allow mocks of inherited methods
47
+ * Allow mocks of inherited methods ([#34](https://github.com/clarkedb/grift/pull/34))
34
48
 
35
49
  ## [1.0.1](https://github.com/clarkedb/grift/releases/tag/v1.0.1) - 2021-11-10
36
50
 
@@ -38,12 +52,7 @@ This version fixes a bug that prevented most mocking features in Grift from func
38
52
 
39
53
  ### Fixed
40
54
 
41
- * Uses relative path for yaml config files
42
-
43
- ### Updated
44
-
45
- * Updates `rubocop-performance`
46
- * Updates `rake`
55
+ * Uses relative path for yaml config files ([#28](https://github.com/clarkedb/grift/pull/28))
47
56
 
48
57
  ## [1.0.0](https://github.com/clarkedb/grift/releases/tag/v1.0.0) - 2021-11-06
49
58
 
@@ -51,12 +60,12 @@ The first major version of Grift! 100% documentation and 100% code coverage.
51
60
 
52
61
  ### Added
53
62
 
54
- * Spying on method
55
- * Mocking method return values
56
- * Mocking method implementation
57
- * Restricted methods that cannot be mocked
58
- * MiniTest Plugin to use hooks and clean up after tests
59
- * Documentation!
63
+ * Spying on method ([#9](https://github.com/clarkedb/grift/pull/9))
64
+ * Mocking method return values ([#9](https://github.com/clarkedb/grift/pull/9))
65
+ * Mocking method implementation ([#13](https://github.com/clarkedb/grift/pull/13))
66
+ * Restricted methods that cannot be mocked ([#20](https://github.com/clarkedb/grift/pull/20))
67
+ * MiniTest Plugin to use hooks and clean up after tests ([#17](https://github.com/clarkedb/grift/pull/17))
68
+ * Documentation! ([#23](https://github.com/clarkedb/grift/pull/23))
60
69
 
61
70
  ## [0.1.0](https://github.com/clarkedb/grift/releases/tag/v0.1.0) - 2021-10-12
62
71
 
data/Gemfile CHANGED
@@ -8,12 +8,14 @@ gemspec
8
8
  gem 'rake', '>= 12.0'
9
9
 
10
10
  group :development, :test do
11
+ gem 'codecov'
11
12
  gem 'minitest', '>= 5.0'
12
13
  gem 'minitest-reporters', '>= 1.4.3'
13
14
  gem 'simplecov', '>= 0.21.2'
14
15
  end
15
16
 
16
17
  group :development, :lint do
18
+ gem 'overcommit'
17
19
  gem 'rubocop'
18
20
  gem 'rubocop-minitest'
19
21
  gem 'rubocop-packaging', '>= 0.5'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grift (1.1.0)
4
+ grift (2.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -9,36 +9,44 @@ GEM
9
9
  ansi (1.5.0)
10
10
  ast (2.4.2)
11
11
  builder (3.2.4)
12
+ childprocess (4.1.0)
13
+ codecov (0.6.0)
14
+ simplecov (>= 0.15, < 0.22)
12
15
  docile (1.4.0)
16
+ iniparse (1.5.0)
13
17
  minitest (5.15.0)
14
18
  minitest-reporters (1.5.0)
15
19
  ansi
16
20
  builder
17
21
  minitest (>= 5.0)
18
22
  ruby-progressbar
23
+ overcommit (0.58.0)
24
+ childprocess (>= 0.6.3, < 5)
25
+ iniparse (~> 1.4)
26
+ rexml (~> 3.2)
19
27
  parallel (1.21.0)
20
- parser (3.1.0.0)
28
+ parser (3.1.1.0)
21
29
  ast (~> 2.4.1)
22
30
  rainbow (3.1.1)
23
31
  rake (13.0.6)
24
- regexp_parser (2.2.0)
32
+ regexp_parser (2.2.1)
25
33
  rexml (3.2.5)
26
- rubocop (1.25.1)
34
+ rubocop (1.26.0)
27
35
  parallel (~> 1.10)
28
36
  parser (>= 3.1.0.0)
29
37
  rainbow (>= 2.2.2, < 4.0)
30
38
  regexp_parser (>= 1.8, < 3.0)
31
39
  rexml
32
- rubocop-ast (>= 1.15.1, < 2.0)
40
+ rubocop-ast (>= 1.16.0, < 2.0)
33
41
  ruby-progressbar (~> 1.7)
34
42
  unicode-display_width (>= 1.4.0, < 3.0)
35
- rubocop-ast (1.15.1)
36
- parser (>= 3.0.1.1)
37
- rubocop-minitest (0.17.1)
43
+ rubocop-ast (1.16.0)
44
+ parser (>= 3.1.1.0)
45
+ rubocop-minitest (0.18.0)
38
46
  rubocop (>= 0.90, < 2.0)
39
47
  rubocop-packaging (0.5.1)
40
48
  rubocop (>= 0.89, < 2.0)
41
- rubocop-performance (1.13.2)
49
+ rubocop-performance (1.13.3)
42
50
  rubocop (>= 1.7.0, < 2.0)
43
51
  rubocop-ast (>= 0.4.0)
44
52
  ruby-progressbar (1.11.0)
@@ -54,9 +62,11 @@ PLATFORMS
54
62
  ruby
55
63
 
56
64
  DEPENDENCIES
65
+ codecov
57
66
  grift!
58
67
  minitest (>= 5.0)
59
68
  minitest-reporters (>= 1.4.3)
69
+ overcommit
60
70
  rake (>= 12.0)
61
71
  rubocop
62
72
  rubocop-minitest
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![gem version](https://badge.fury.io/rb/grift.svg)](https://rubygems.org/gems/grift)
4
4
  [![downloads](https://ruby-gem-downloads-badge.herokuapp.com/grift)](https://rubygems.org/gems/grift)
5
5
  [![build](https://github.com/clarkedb/grift/actions/workflows/ci.yml/badge.svg)](https://github.com/clarkedb/grift/actions?query=workflow%3ACI)
6
+ [![codecov](https://codecov.io/gh/clarkedb/grift/branch/main/graph/badge.svg)](https://codecov.io/gh/clarkedb/grift)
6
7
 
7
8
  Mocking and spying in Ruby's MiniTest framework
8
9
 
@@ -77,13 +78,22 @@ my_spy.mock_implementation do |arg1, arg2|
77
78
  end
78
79
  ```
79
80
 
81
+ or for a method taking keyword arguments:
82
+
83
+ ```ruby
84
+ my_spy = Grift.spy_on(MyClass, :my_method)
85
+ my_spy.mock_implementation do |arg1, arg2, **kwargs|
86
+ x = do_something(arg1, arg2, kwargs[:arg3], kwargs[:arg4])
87
+ do_something_else(x) # the last line will be returned
88
+ end
89
+
80
90
  ### Chaining
81
91
 
82
92
  You can chain `mock_return_value` and `mock_implementation` after initializing the mock.
83
93
 
84
94
  ```ruby
85
- my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args|
86
- do_something(*args)
95
+ my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args, **kwargs|
96
+ do_something(*args, **kwargs)
87
97
  end
88
98
  #=> Grift::MockMethod object is returned
89
99
  ```
@@ -98,8 +108,12 @@ my_mock.mock.count
98
108
  #=> 2
99
109
 
100
110
  # get args for each call to the method while mocked
101
- my_mock.mock.calls
102
- #=> [['first_arg1', 'second_arg1'], ['first_arg2', 'second_arg2']]
111
+ my_mock.mock.calls[0].args
112
+ #=> ['first_arg1', 'second_arg1']
113
+
114
+ # get kwargs for each call to the method while mocked
115
+ my_mock.mock.calls[0].kwargs
116
+ #=> { first_arg1: 'value' }
103
117
 
104
118
  # get results (return value) for each call to the method while mocked
105
119
  my_mock.mock.results
@@ -108,17 +122,17 @@ my_mock.mock.results
108
122
 
109
123
  ## Requirements
110
124
 
111
- Grift supports all Ruby versions >= 2.5 (including 3.1).
125
+ Grift supports all Ruby versions >= 2.7 (including 3.1).
112
126
 
113
127
  ## Development
114
128
 
115
129
  After forking the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
116
130
 
117
- When developing, to install Grift whith your changes onto your local machine, run `bundle exec rake install` . To release a new version, update the version number in `version.rb` , and then run `bundle exec rake release` , which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
131
+ When developing, to install Grift whith your changes onto your local machine, run `bundle exec rake install` . For those with write access: to release a new version, update the version number in `version.rb` , and then run `bundle exec rake release` , which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
118
132
 
119
133
  ### Docs
120
134
 
121
- The docs are generated using YARD. To build the docs, first `gem install yard`. Then run `yardoc` to build the new docs. This is always done before a release to update the docs that get published and made available with the gem.
135
+ The docs are generated using YARD. To build the docs, first `gem install yard` . Then run `yardoc` to build the new docs. This is always done before a release to update the docs that get published and made available with the gem.
122
136
 
123
137
  ## Contributing
124
138
 
data/grift.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "A gem for simple mocking and spying in Ruby's MiniTest framework."
13
13
  spec.homepage = 'https://github.com/clarkedb/grift'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
16
16
 
17
17
  spec.metadata = {
18
18
  'bug_tracker_uri' => "#{spec.homepage}/issues",
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  # Specify which files should be added to the gem when it is released.
27
27
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
28
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|docs|spec|features)/}) }
29
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|docs|spec|features)/}) } # rubocop:disable Packaging/GemspecGit
30
30
  end
31
31
  spec.bindir = 'exe'
32
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grift
4
+ class MockMethod
5
+ class MockExecutions
6
+ ##
7
+ # An immutable Enumerable that stores the arguments used in a call for {Grift::MockMethod::MockExecutions}.
8
+ #
9
+ class MockArguments
10
+ include Enumerable
11
+
12
+ attr_reader :args, :kwargs
13
+
14
+ ##
15
+ # A new instance of MockArguments.
16
+ #
17
+ # @return [Grift::MockMethod::MockExecutions::MockArguments]
18
+ #
19
+ def initialize(args: [], kwargs: {})
20
+ @args = args.freeze
21
+ @kwargs = kwargs.freeze
22
+ end
23
+
24
+ ##
25
+ # Retrieves a stored argument by an accessor. For positional arguments this would be an integer
26
+ # corresponding to the arguments position in the method call signature. For keyword arguments
27
+ # this would be the key / parameter name as a symbol or string.
28
+ #
29
+ # @example
30
+ # my_mock = Grift.mock(Request, :new)
31
+ # request = Request.new('/users', method: 'GET')
32
+ # #=> <Request object>
33
+ # my_mock.mock.calls.last[0] # integer access for positional
34
+ # #=> '/users'
35
+ # my_mock.mock.calls.last[:method] # key access for keyword
36
+ # #=> 'GET'
37
+ #
38
+ # @param index [Integer, Symbol, String] the accessor for the desired argument
39
+ #
40
+ # @raise [Grift::Error] exception if accessor is not a supported type
41
+ #
42
+ # @return the specified value
43
+ #
44
+ def [](index)
45
+ if index.instance_of?(Integer)
46
+ @args[index]
47
+ elsif index.instance_of?(Symbol)
48
+ @kwargs[index]
49
+ elsif index.instance_of?(String)
50
+ @kwargs[index.to_sym]
51
+ else
52
+ raise(Grift::Error, "Cannot access by type '#{index.class}'. Expected an Integer, Symbol, or String")
53
+ end
54
+ end
55
+
56
+ ##
57
+ # Calls the given block once for each argument value, passing that value
58
+ # as a parameter.
59
+ #
60
+ # @return [void]
61
+ #
62
+ def each(&block)
63
+ @args.each(&block)
64
+ @kwargs.each_value(&block)
65
+ end
66
+
67
+ ##
68
+ # @see Enumerable#first
69
+ #
70
+ # Returns the last argument passed in the call.
71
+ #
72
+ # @example
73
+ # my_mock = Grift.mock(Request, :new)
74
+ # request = Request.new('/users', method: 'GET')
75
+ # #=> <Request object>
76
+ # my_mock.mock.calls.last.last
77
+ # #=> 'GET'
78
+ #
79
+ # @return [Any]
80
+ #
81
+ def last
82
+ @args.last || @kwargs.values.last
83
+ end
84
+
85
+ ##
86
+ # Returns the number of arguments passed in the call.
87
+ #
88
+ # @example
89
+ # arr = [1, 2, 3]
90
+ # my_mock = Grift.mock(Array, :count)
91
+ # arr.count
92
+ # #=> 3
93
+ # my_mock.mock.calls.last.length
94
+ # #=> 0
95
+ # arr.count(3)
96
+ # #=> 1
97
+ # my_mock.mock.calls.last.length
98
+ # #=> 1
99
+ #
100
+ # @return [Integer]
101
+ #
102
+ def length
103
+ @args.length + @kwargs.length
104
+ end
105
+
106
+ ##
107
+ # Returns true if the call included no arguments.
108
+ #
109
+ # @example
110
+ # arr = [1, 2, 3]
111
+ # my_mock = Grift.mock(Array, :count)
112
+ # arr.count
113
+ # #=> 3
114
+ # my_mock.mock.calls.last.empty?
115
+ # #=> true
116
+ # arr.count(2)
117
+ # #=> 1
118
+ # my_mock.mock.calls.last.empty?
119
+ # #=> false
120
+ #
121
+ # @return [Boolean] true if the no arguments were used
122
+ #
123
+ def empty?
124
+ @args.empty? && @kwargs.empty?
125
+ end
126
+
127
+ ##
128
+ # Returns the keyword parameter keys passed in the call.
129
+ #
130
+ # To get the values, use {Grift::MockMethod::MockExecutions::MockArguments#values}.
131
+ #
132
+ # @example
133
+ # my_mock = Grift.mock(Request, :new)
134
+ # request = Request.new('/users', method: 'GET')
135
+ # #=> <Request object>
136
+ # my_mock.mock.calls.last.keys
137
+ # #=> [:method]
138
+ #
139
+ # @return [Array<Symbol>] the parameter keys
140
+ #
141
+ def keys
142
+ @kwargs.keys
143
+ end
144
+
145
+ ##
146
+ # Returns the arguments passed in the call.
147
+ #
148
+ # If a keyword argument was used, then only the value will be returned.
149
+ # To get the keys, use {Grift::MockMethod::MockExecutions::MockArguments#keys}.
150
+ #
151
+ # @example
152
+ # my_mock = Grift.mock(Request, :new)
153
+ # request = Request.new('/users', method: 'GET')
154
+ # #=> <Request object>
155
+ # my_mock.mock.calls.last.keys
156
+ # #=> [:method]
157
+ #
158
+ # @return [Array] the argument values
159
+ #
160
+ def values
161
+ @args + @kwargs.values
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -9,7 +9,7 @@ module Grift
9
9
  ##
10
10
  # A new instance of MockExecutions.
11
11
  #
12
- # @return [Grift::MockMethod::MockExectuions]
12
+ # @return [Grift::MockMethod::MockExecutions]
13
13
  #
14
14
  def initialize
15
15
  @executions = []
@@ -21,14 +21,14 @@ module Grift
21
21
  # @example
22
22
  # my_mock = Grift.spy_on(Number, :+)
23
23
  # x = (3 + 4) + 5
24
- # my_mock.mock.calls
24
+ # my_mock.mock.calls.map(&:values)
25
25
  # #=> [[4], [5]]
26
26
  #
27
- # @return [Array<Array>] an array of arrays of args
27
+ # @return [Array<Grift::MockMethod::MockExecutions::MockArguments>] an array of MockArguments
28
28
  #
29
29
  def calls
30
30
  @executions.map do |exec|
31
- exec[:args]
31
+ exec[:arguments]
32
32
  end
33
33
  end
34
34
 
@@ -89,13 +89,17 @@ module Grift
89
89
  # Stores an args and result pair to the executions array.
90
90
  #
91
91
  # @example
92
- # mock_store = Grift::MockMethod::MockExecutions.new
93
- # mock_store.store([1, 1], [2])
92
+ # mock_executions = Grift::MockMethod::MockExecutions.new
93
+ # mock_executions.store(args: [1, 1], kwargs: { test: true }, result: 2)
94
94
  #
95
- # @return [Array] an array of results
95
+ # @param args [Array] the postitional args to store
96
+ # @param kwargs [Hash] the keyword args to store
97
+ # @param result the method result to store
98
+ #
99
+ # @return [Array] an updated array of executions
96
100
  #
97
- def store(args, result)
98
- @executions.push({ args: args, result: result })
101
+ def store(args: [], kwargs: {}, result: nil)
102
+ @executions.push({ arguments: MockArguments.new(args: args, kwargs: kwargs), result: result })
99
103
  end
100
104
  end
101
105
  end
@@ -6,7 +6,7 @@ module Grift
6
6
  # usually returns a {Grift::MockMethod}.
7
7
  #
8
8
  class MockMethod
9
- attr_reader :true_method_cached, :klass, :method_name
9
+ attr_reader :true_method_cached, :klass, :method_name, :method_access
10
10
 
11
11
  CACHE_METHOD_PREFIX = 'grift_cache'
12
12
  private_constant :CACHE_METHOD_PREFIX
@@ -39,13 +39,13 @@ module Grift
39
39
  @cache_method_name = "#{CACHE_METHOD_PREFIX}_#{method_name}".to_sym
40
40
 
41
41
  # class methods are really instance methods of the singleton class
42
- @class_method = klass.singleton_class.instance_methods(true).include?(method_name)
42
+ @class_method = klass.singleton_class.method_defined?(method_name, true) ||
43
+ klass.singleton_class.private_method_defined?(method_name, true)
43
44
 
44
- unless @class_method || class_instance.instance_methods(true).include?(method_name)
45
- raise(Grift::Error, "Cannot mock unknown method #{method_name} for class #{klass}")
46
- end
45
+ @method_access, @inherited = method_access_definition
46
+ raise(Grift::Error, "Cannot mock unknown method #{method_name} for class #{klass}") unless @method_access
47
47
 
48
- if class_instance.instance_methods.include?(@cache_method_name)
48
+ if class_instance.method_defined?(@cache_method_name)
49
49
  raise(Grift::Error, "Cannot mock already mocked method #{method_name} for class #{klass}")
50
50
  end
51
51
 
@@ -125,26 +125,27 @@ module Grift
125
125
  # #=> '7'
126
126
  #
127
127
  # @example
128
- # my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |first, second|
129
- # [second, first]
128
+ # my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |first, second, **kwargs|
129
+ # [second, kwargs[:third], first]
130
130
  # end
131
- # MyClass.my_method(1, 2)
132
- # #=> [2, 1]
131
+ # MyClass.my_method(1, 2, third: 3)
132
+ # #=> [2, 3, 1]
133
133
  #
134
- # @return [Grift::MockMethod] the mock itself
134
+ # @return [self] the mock itself
135
135
  #
136
- def mock_implementation(&block)
136
+ def mock_implementation(*)
137
137
  premock_setup
138
138
  mock_executions = @mock_executions # required to access inside class instance block
139
139
 
140
- class_instance.remove_method(@method_name) if class_instance.instance_methods(false).include?(@method_name)
141
- class_instance.define_method @method_name do |*args|
142
- return_value = block.call(*args)
140
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
141
+ class_instance.define_method @method_name do |*args, **kwargs|
142
+ return_value = yield(*args, **kwargs)
143
143
 
144
144
  # record the args passed in the call to the method and the result
145
- mock_executions.store(args, return_value)
145
+ mock_executions.store(args: args, result: return_value)
146
146
  return return_value
147
147
  end
148
+ class_instance.send(@method_access, @method_name)
148
149
 
149
150
  self
150
151
  end
@@ -162,18 +163,19 @@ module Grift
162
163
  #
163
164
  # @param return_value the value to return from the method
164
165
  #
165
- # @return [Grift::MockMethod] the mock itself
166
+ # @return [self] the mock itself
166
167
  #
167
168
  def mock_return_value(return_value = nil)
168
169
  premock_setup
169
170
  mock_executions = @mock_executions # required to access inside class instance block
170
171
 
171
- class_instance.remove_method(@method_name) if method_defined?
172
- class_instance.define_method @method_name do |*args|
172
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
173
+ class_instance.define_method @method_name do |*args, **kwargs|
173
174
  # record the args passed in the call to the method and the result
174
- mock_executions.store(args, return_value)
175
+ mock_executions.store(args: args, kwargs: kwargs, result: return_value)
175
176
  return return_value
176
177
  end
178
+ class_instance.send(@method_access, @method_name)
177
179
 
178
180
  self
179
181
  end
@@ -210,21 +212,22 @@ module Grift
210
212
  ##
211
213
  # Watches the method without mocking its impelementation or return value.
212
214
  #
213
- # @return [Grift::MockMethod] the mock itself
215
+ # @return [self] the mock itself
214
216
  #
215
217
  def watch_method
216
218
  premock_setup
217
219
  mock_executions = @mock_executions # required to access inside class instance block
218
220
  cache_method_name = @cache_method_name
219
221
 
220
- class_instance.remove_method(@method_name) if method_defined?
221
- class_instance.define_method @method_name do |*args|
222
- return_value = send(cache_method_name, *args)
222
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
223
+ class_instance.define_method @method_name do |*args, **kwargs|
224
+ return_value = send(cache_method_name, *args, **kwargs)
223
225
 
224
226
  # record the args passed in the call to the method and the result
225
- mock_executions.store(args, return_value)
227
+ mock_executions.store(args: args, kwargs: kwargs, result: return_value)
226
228
  return return_value
227
229
  end
230
+ class_instance.send(@method_access, @method_name)
228
231
 
229
232
  self
230
233
  end
@@ -238,7 +241,7 @@ module Grift
238
241
  raise(Grift::Error, 'Method is not cached') unless @true_method_cached
239
242
 
240
243
  class_instance.remove_method(@method_name) if method_defined?
241
- class_instance.alias_method(@method_name, @cache_method_name)
244
+ class_instance.alias_method(@method_name, @cache_method_name) unless @inherited
242
245
  class_instance.remove_method(@cache_method_name)
243
246
 
244
247
  @true_method_cached = false
@@ -289,7 +292,26 @@ module Grift
289
292
  # @return [Boolean]
290
293
  #
291
294
  def method_defined?
292
- class_instance.instance_methods(false).include?(@method_name)
295
+ class_instance.instance_methods(false).include?(@method_name) ||
296
+ class_instance.private_instance_methods(false).include?(@method_name)
297
+ end
298
+
299
+ ##
300
+ # Checks for the original access of the method (public, protected, private),
301
+ # and if that definition is inherited from an ancestor (super) class.
302
+ # Returns `nil` if no definition for the method is found.
303
+ #
304
+ # @return [Symbol] the method access
305
+ # @return [Boolean] true if the method is inherited
306
+ #
307
+ def method_access_definition
308
+ if class_instance.public_method_defined?(@method_name, true)
309
+ [:public, !class_instance.public_method_defined?(@method_name, false)]
310
+ elsif class_instance.protected_method_defined?(@method_name, true)
311
+ [:protected, !class_instance.protected_method_defined?(@method_name, false)]
312
+ elsif class_instance.private_method_defined?(@method_name, true)
313
+ [:private, !class_instance.private_method_defined?(@method_name, false)]
314
+ end
293
315
  end
294
316
  end
295
317
  end
data/lib/grift/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Grift
4
4
  # gem version
5
- VERSION = '1.1.0'
5
+ VERSION = '2.0.0'
6
6
  public_constant :VERSION
7
7
  end
data/lib/grift.rb CHANGED
@@ -5,6 +5,7 @@ require 'grift/error'
5
5
  require 'grift/minitest_plugin'
6
6
  require 'grift/mock_method'
7
7
  require 'grift/mock_method/mock_executions'
8
+ require 'grift/mock_method/mock_executions/mock_arguments'
8
9
  require 'grift/mock_store'
9
10
  require 'grift/version'
10
11
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grift
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clark Brown
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-04 00:00:00.000000000 Z
11
+ date: 2022-03-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A gem for simple mocking and spying in Ruby's MiniTest framework.
14
14
  email:
@@ -22,6 +22,7 @@ files:
22
22
  - ".github/dependabot.yml"
23
23
  - ".github/workflows/ci.yml"
24
24
  - ".gitignore"
25
+ - ".overcommit.yml"
25
26
  - ".rubocop.yml"
26
27
  - ".yardopts"
27
28
  - CHANGELOG.md
@@ -40,6 +41,7 @@ files:
40
41
  - lib/grift/minitest_plugin.rb
41
42
  - lib/grift/mock_method.rb
42
43
  - lib/grift/mock_method/mock_executions.rb
44
+ - lib/grift/mock_method/mock_executions/mock_arguments.rb
43
45
  - lib/grift/mock_store.rb
44
46
  - lib/grift/version.rb
45
47
  homepage: https://github.com/clarkedb/grift
@@ -60,14 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
62
  requirements:
61
63
  - - ">="
62
64
  - !ruby/object:Gem::Version
63
- version: 2.5.0
65
+ version: 2.7.0
64
66
  required_rubygems_version: !ruby/object:Gem::Requirement
65
67
  requirements:
66
68
  - - ">="
67
69
  - !ruby/object:Gem::Version
68
70
  version: '0'
69
71
  requirements: []
70
- rubygems_version: 3.3.3
72
+ rubygems_version: 3.1.6
71
73
  signing_key:
72
74
  specification_version: 4
73
75
  summary: Mocking and spying in MiniTest