grift 1.0.2 → 2.0.1

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: 98c5113978ecfca383496652f50e2fee8b820bdf0f9dfd94e01649b567c44ee8
4
- data.tar.gz: 16d205bacdddd4018ef18654b09c7f9b7d283956a382875f6f4dbae58f1244dd
3
+ metadata.gz: '06800e91cb7e76be9232c7cf700d99ede4ba25212ed323abd1d5a4e944de455d'
4
+ data.tar.gz: 2d844fc80a5edcb9eb809c4946d7ee464465e8423b7a42e2f3a4ff4657e791d7
5
5
  SHA512:
6
- metadata.gz: 75ca213c47eabb2e1cf4ee8790949e041ff383193a844f34f1ab794486cd3afdf633e0206f367e7b74d358276bb43f48b7b0dcf8ae8fbb124977d42c34df1bb7
7
- data.tar.gz: 91e88879f44d036403d94808ab853007a66f10e60dad5569e38ace29f1969abc2abc24fdb87b6f9f5db61c98a8efdd34c6d4cfcb4f063fc147e9a1bc80ece52c
6
+ metadata.gz: c3a2e6a02bab0921a5c91c48c5fbbf67d1a9dd0b0d50bd3c4d9dfb49d6f686623ca0c017d1d51f1df3220b4c1c83c1fd9a26070daa05c36c38d657a2476a4602
7
+ data.tar.gz: a7197e5fb4f7bbaf506426c9f4ed2a04733201f8a27a4f015df9af7466c9bd8563e700c2adaaef34211690c5ecf795ded15308701877bd5a0fbb6ed5278b366a
@@ -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
 
@@ -26,13 +27,13 @@ jobs:
26
27
  run: bundle exec rubocop --format progress
27
28
 
28
29
  build:
29
- needs: [ linting ]
30
+ needs: [linting]
30
31
  runs-on: ubuntu-latest
31
32
  name: build (ruby v${{ matrix.ruby }})
32
33
  strategy:
33
34
  fail-fast: false
34
35
  matrix:
35
- ruby: [ '2.5', '2.6', '2.7', '3.0' ]
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,7 +6,46 @@ 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
+
11
+ ## [2.0.1](https://github.com/clarkedb/grift/releases/tag/v2.0.1) - 2022-03-27
12
+
13
+ ### Fixed
14
+
15
+ * When spying on a method that takes a block, the block now gets forwarded to the original method ([#78](https://github.com/clarkedb/grift/pull/78))
16
+ * When mocking the implementation, if a block is not provided a `Grift::Error` is raised instead of a `LocalJumpError` ([#77](https://github.com/clarkedb/grift/pull/77))
17
+
18
+ ## [2.0.0](https://github.com/clarkedb/grift/releases/tag/v2.0.0) - 2022-03-14
19
+
20
+ This version adds true keyword argument support for Ruby 3. See below for how to handle breaking changes.
21
+
22
+ ### Changed
23
+
24
+ * Dropped support for Ruby 2.5 ([#69](https://github.com/clarkedb/grift/pull/69))
25
+ * Dropped support for Ruby 2.6 ([#72](https://github.com/clarkedb/grift/pull/72))
26
+ * 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))
27
+ + This changes the way that your tests will interact with mock calls
28
+ + When before `calls` returned an array, it returns a `Grift::MockMethod::MockExecutions::MockArguments` object
29
+ + Migrating to maintain previous behavior just requires appending `.args` to `calls[i]`
30
+
31
+ ### Added
32
+
33
+ * Support for mocking private instance and class methods ([#68](https://github.com/clarkedb/grift/pull/68))
34
+ * Support for mocking methods that take positional and keyword arguments ([#72](https://github.com/clarkedb/grift/pull/72))
35
+
36
+ ### Fixed
37
+
38
+ * When mocking protected methods, the method now remains protected while mocked and after unmocking ([#68](https://github.com/clarkedb/grift/pull/68))
39
+ * When mocking inherited methods, the method goes back to the ancestor's definition after unmocking ([#69](https://github.com/clarkedb/grift/pull/69))
40
+ * When mocking methods with keyword arugments in Ruby 3.x, no error is thrown ([#72](https://github.com/clarkedb/grift/pull/72))
41
+
42
+ ## [1.1.0](https://github.com/clarkedb/grift/releases/tag/v1.1.0) - 2022-02-03
43
+
44
+ This version adds support for Ruby 3.1 and updates various dependencies.
45
+
46
+ ### Added
47
+
48
+ * Support Ruby 3.1 ([#52](https://github.com/clarkedb/grift/pull/52))
10
49
 
11
50
  ## [1.0.2](https://github.com/clarkedb/grift/releases/tag/v1.0.2) - 2021-11-11
12
51
 
@@ -14,7 +53,7 @@ This version fixes a bug that prevented the mocking of methods defined by a clas
14
53
 
15
54
  ### Fixed
16
55
 
17
- * Allow mocks of inherited methods
56
+ * Allow mocks of inherited methods ([#34](https://github.com/clarkedb/grift/pull/34))
18
57
 
19
58
  ## [1.0.1](https://github.com/clarkedb/grift/releases/tag/v1.0.1) - 2021-11-10
20
59
 
@@ -22,12 +61,7 @@ This version fixes a bug that prevented most mocking features in Grift from func
22
61
 
23
62
  ### Fixed
24
63
 
25
- * Uses relative path for yaml config files
26
-
27
- ### Updated
28
-
29
- * Updates `rubocop-performance`
30
- * Updates `rake`
64
+ * Uses relative path for yaml config files ([#28](https://github.com/clarkedb/grift/pull/28))
31
65
 
32
66
  ## [1.0.0](https://github.com/clarkedb/grift/releases/tag/v1.0.0) - 2021-11-06
33
67
 
@@ -35,12 +69,12 @@ The first major version of Grift! 100% documentation and 100% code coverage.
35
69
 
36
70
  ### Added
37
71
 
38
- * Spying on method
39
- * Mocking method return values
40
- * Mocking method implementation
41
- * Restricted methods that cannot be mocked
42
- * MiniTest Plugin to use hooks and clean up after tests
43
- * Documentation!
72
+ * Spying on method ([#9](https://github.com/clarkedb/grift/pull/9))
73
+ * Mocking method return values ([#9](https://github.com/clarkedb/grift/pull/9))
74
+ * Mocking method implementation ([#13](https://github.com/clarkedb/grift/pull/13))
75
+ * Restricted methods that cannot be mocked ([#20](https://github.com/clarkedb/grift/pull/20))
76
+ * MiniTest Plugin to use hooks and clean up after tests ([#17](https://github.com/clarkedb/grift/pull/17))
77
+ * Documentation! ([#23](https://github.com/clarkedb/grift/pull/23))
44
78
 
45
79
  ## [0.1.0](https://github.com/clarkedb/grift/releases/tag/v0.1.0) - 2021-10-12
46
80
 
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.0.2)
4
+ grift (2.0.1)
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)
13
- minitest (5.14.4)
14
- minitest-reporters (1.4.3)
16
+ iniparse (1.5.0)
17
+ minitest (5.15.0)
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.0.2.0)
28
+ parser (3.1.1.0)
21
29
  ast (~> 2.4.1)
22
- rainbow (3.0.0)
30
+ rainbow (3.1.1)
23
31
  rake (13.0.6)
24
- regexp_parser (2.1.1)
32
+ regexp_parser (2.2.1)
25
33
  rexml (3.2.5)
26
- rubocop (1.22.3)
34
+ rubocop (1.26.0)
27
35
  parallel (~> 1.10)
28
- parser (>= 3.0.0.0)
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.12.0, < 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.12.0)
36
- parser (>= 3.0.1.1)
37
- rubocop-minitest (0.15.2)
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.12.0)
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
@@ -65,4 +75,4 @@ DEPENDENCIES
65
75
  simplecov (>= 0.21.2)
66
76
 
67
77
  BUNDLED WITH
68
- 2.1.4
78
+ 2.2.32
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,23 @@ 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
+ ```
90
+
80
91
  ### Chaining
81
92
 
82
93
  You can chain `mock_return_value` and `mock_implementation` after initializing the mock.
83
94
 
84
95
  ```ruby
85
- my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args|
86
- do_something(*args)
96
+ my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args, **kwargs|
97
+ do_something(*args, **kwargs)
87
98
  end
88
99
  #=> Grift::MockMethod object is returned
89
100
  ```
@@ -98,19 +109,31 @@ my_mock.mock.count
98
109
  #=> 2
99
110
 
100
111
  # get args for each call to the method while mocked
101
- my_mock.mock.calls
102
- #=> [['first_arg1', 'second_arg1'], ['first_arg2', 'second_arg2']]
112
+ my_mock.mock.calls[0].args
113
+ #=> ['first_arg1', 'second_arg1']
114
+
115
+ # get kwargs for each call to the method while mocked
116
+ my_mock.mock.calls[0].kwargs
117
+ #=> { first_arg1: 'value' }
103
118
 
104
119
  # get results (return value) for each call to the method while mocked
105
120
  my_mock.mock.results
106
121
  #=> ['result1', 'result2']
107
122
  ```
108
123
 
124
+ ## Requirements
125
+
126
+ Grift supports all Ruby versions >= 2.7 (including 3.1).
127
+
109
128
  ## Development
110
129
 
111
130
  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.
112
131
 
113
- 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).
132
+ 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).
133
+
134
+ ### Docs
135
+
136
+ 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.
114
137
 
115
138
  ## Contributing
116
139
 
data/grift.gemspec CHANGED
@@ -12,20 +12,21 @@ 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",
19
19
  'changelog_uri' => "#{spec.homepage}/blob/main/CHANGELOG.md",
20
20
  'documentation_uri' => spec.homepage.to_s,
21
21
  'homepage_uri' => spec.homepage.to_s,
22
+ 'rubygems_mfa_required' => 'true',
22
23
  'source_code_uri' => spec.homepage.to_s
23
24
  }
24
25
 
25
26
  # Specify which files should be added to the gem when it is released.
26
27
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
28
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
- `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
29
30
  end
30
31
  spec.bindir = 'exe'
31
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,29 @@ 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
+ raise(Grift::Error, 'Must provide a block for the new implementation') unless block_given?
138
+
137
139
  premock_setup
138
140
  mock_executions = @mock_executions # required to access inside class instance block
139
141
 
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)
142
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
143
+ class_instance.define_method @method_name do |*args, **kwargs|
144
+ return_value = yield(*args, **kwargs)
143
145
 
144
146
  # record the args passed in the call to the method and the result
145
- mock_executions.store(args, return_value)
147
+ mock_executions.store(args: args, result: return_value)
146
148
  return return_value
147
149
  end
150
+ class_instance.send(@method_access, @method_name)
148
151
 
149
152
  self
150
153
  end
@@ -162,18 +165,19 @@ module Grift
162
165
  #
163
166
  # @param return_value the value to return from the method
164
167
  #
165
- # @return [Grift::MockMethod] the mock itself
168
+ # @return [self] the mock itself
166
169
  #
167
170
  def mock_return_value(return_value = nil)
168
171
  premock_setup
169
172
  mock_executions = @mock_executions # required to access inside class instance block
170
173
 
171
- class_instance.remove_method(@method_name) if method_defined?
172
- class_instance.define_method @method_name do |*args|
174
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
175
+ class_instance.define_method @method_name do |*args, **kwargs|
173
176
  # record the args passed in the call to the method and the result
174
- mock_executions.store(args, return_value)
177
+ mock_executions.store(args: args, kwargs: kwargs, result: return_value)
175
178
  return return_value
176
179
  end
180
+ class_instance.send(@method_access, @method_name)
177
181
 
178
182
  self
179
183
  end
@@ -210,21 +214,22 @@ module Grift
210
214
  ##
211
215
  # Watches the method without mocking its impelementation or return value.
212
216
  #
213
- # @return [Grift::MockMethod] the mock itself
217
+ # @return [self] the mock itself
214
218
  #
215
219
  def watch_method
216
220
  premock_setup
217
221
  mock_executions = @mock_executions # required to access inside class instance block
218
222
  cache_method_name = @cache_method_name
219
223
 
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)
224
+ class_instance.remove_method(@method_name) if !@inherited && method_defined?
225
+ class_instance.define_method @method_name do |*args, **kwargs, &block|
226
+ return_value = send(cache_method_name, *args, **kwargs, &block)
223
227
 
224
228
  # record the args passed in the call to the method and the result
225
- mock_executions.store(args, return_value)
229
+ mock_executions.store(args: args, kwargs: kwargs, result: return_value)
226
230
  return return_value
227
231
  end
232
+ class_instance.send(@method_access, @method_name)
228
233
 
229
234
  self
230
235
  end
@@ -238,7 +243,7 @@ module Grift
238
243
  raise(Grift::Error, 'Method is not cached') unless @true_method_cached
239
244
 
240
245
  class_instance.remove_method(@method_name) if method_defined?
241
- class_instance.alias_method(@method_name, @cache_method_name)
246
+ class_instance.alias_method(@method_name, @cache_method_name) unless @inherited
242
247
  class_instance.remove_method(@cache_method_name)
243
248
 
244
249
  @true_method_cached = false
@@ -289,7 +294,26 @@ module Grift
289
294
  # @return [Boolean]
290
295
  #
291
296
  def method_defined?
292
- class_instance.instance_methods(false).include?(@method_name)
297
+ class_instance.instance_methods(false).include?(@method_name) ||
298
+ class_instance.private_instance_methods(false).include?(@method_name)
299
+ end
300
+
301
+ ##
302
+ # Checks for the original access of the method (public, protected, private),
303
+ # and if that definition is inherited from an ancestor (super) class.
304
+ # Returns `nil` if no definition for the method is found.
305
+ #
306
+ # @return [Symbol] the method access
307
+ # @return [Boolean] true if the method is inherited
308
+ #
309
+ def method_access_definition
310
+ if class_instance.public_method_defined?(@method_name, true)
311
+ [:public, !class_instance.public_method_defined?(@method_name, false)]
312
+ elsif class_instance.protected_method_defined?(@method_name, true)
313
+ [:protected, !class_instance.protected_method_defined?(@method_name, false)]
314
+ elsif class_instance.private_method_defined?(@method_name, true)
315
+ [:private, !class_instance.private_method_defined?(@method_name, false)]
316
+ end
293
317
  end
294
318
  end
295
319
  end
data/lib/grift/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Grift
4
4
  # gem version
5
- VERSION = '1.0.2'
5
+ VERSION = '2.0.1'
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.0.2
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clark Brown
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-11 00:00:00.000000000 Z
11
+ date: 2022-03-27 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
@@ -50,6 +52,7 @@ metadata:
50
52
  changelog_uri: https://github.com/clarkedb/grift/blob/main/CHANGELOG.md
51
53
  documentation_uri: https://github.com/clarkedb/grift
52
54
  homepage_uri: https://github.com/clarkedb/grift
55
+ rubygems_mfa_required: 'true'
53
56
  source_code_uri: https://github.com/clarkedb/grift
54
57
  post_install_message:
55
58
  rdoc_options: []
@@ -59,14 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
62
  requirements:
60
63
  - - ">="
61
64
  - !ruby/object:Gem::Version
62
- version: 2.5.0
65
+ version: 2.7.0
63
66
  required_rubygems_version: !ruby/object:Gem::Requirement
64
67
  requirements:
65
68
  - - ">="
66
69
  - !ruby/object:Gem::Version
67
70
  version: '0'
68
71
  requirements: []
69
- rubygems_version: 3.1.2
72
+ rubygems_version: 3.2.32
70
73
  signing_key:
71
74
  specification_version: 4
72
75
  summary: Mocking and spying in MiniTest