workitcop 0.3.0 → 0.4.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
  SHA256:
3
- metadata.gz: d9a1c429544b92ec47ac6a467cef8d26a1bea4c43371299d323441636b0ecbfc
4
- data.tar.gz: 255c41e5e4995120ebea4370b3ef9e3a95773614d580b719c17041eec1883df9
3
+ metadata.gz: 5e5ee2757afa303b953874d6cdb8c968c6943d551e16f55380cfef5566978882
4
+ data.tar.gz: 4e08d0261c613fd3475f5dd10fe35aae463518d658b554460aa811e4e0d5b269
5
5
  SHA512:
6
- metadata.gz: 6513c422e88c53f8287f61fbfeedf160232340bebeea000ebfd2389b6d92b6ffa4b4a657d1a6fff5072281b09ebbc413ace375de128eb686605956dd56b4a869
7
- data.tar.gz: 5ea74291617530ff065df00d6ecbd3c9a5f339feb446417fae198667249e746f137424028158df6fe4ad91d364dcf6af10fc71725df7e33513e82688afdd5e50
6
+ metadata.gz: f85c072382c616c5979a1108239eca0b5db038b61a4270a79f9dd6fedf042d2e271eb931cf6bd7d5cf2016d20a4f5e97dfb4acc90c039cf3bc3dff49f36c2147
7
+ data.tar.gz: 88a58eafe677dbfc33bcd7138ecf78809f3ba8b731f72ecc70884c53e08905273de355a3e002ccbb4dd662a51790de8e5d4512ac72784e0b4b0c3e47551efb3c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.4.0 - 2022-12-12
6
+
7
+ - Add new `Workit/RSpecCapybaraPredicateMatcher` cop. ([@ydah])
8
+ - Add new `Workit/RSpecMinitestAssertions` cop. ([@ydah])
9
+ - Add new `Workit/RSpecCapybaraMatchStyle` cop. ([@ydah])
10
+
5
11
  ## 0.3.0 - 2022-12-08
6
12
 
7
13
  - Fix an error for `Workit/RestrictOnSend` when not in class. ([@ydah])
data/config/default.yml CHANGED
@@ -30,3 +30,21 @@ Workit/RestrictOnSend:
30
30
  Description: |
31
31
  Check for `RESTRICT_ON_SEND` is defined if `on_send` or `after_send` are defined.
32
32
  Enabled: false
33
+
34
+ Workit/RSpecCapybaraMatchStyle:
35
+ Description: Checks for usage of deprecated style methods.
36
+ Enabled: false
37
+
38
+ Workit/RSpecCapybaraPredicateMatcher:
39
+ Description: Prefer using predicate matcher over using predicate method directly.
40
+ Enabled: false
41
+ Strict: true
42
+ EnforcedStyle: inflected
43
+ AllowedExplicitMatchers: []
44
+ SupportedStyles:
45
+ - inflected
46
+ - explicit
47
+
48
+ Workit/RSpecMinitestAssertions:
49
+ Description: Check if using Minitest matchers.
50
+ Enabled: false
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # A helper for `explicit` style
7
+ module RSpecExplicitHelp
8
+ include RuboCop::RSpec::Language
9
+ extend NodePattern::Macros
10
+
11
+ MSG_EXPLICIT = "Prefer using `%<predicate_name>s` over " \
12
+ "`%<matcher_name>s` matcher."
13
+ BUILT_IN_MATCHERS = %w[
14
+ be_truthy be_falsey be_falsy
15
+ have_attributes have_received
16
+ be_between be_within
17
+ ].freeze
18
+
19
+ private
20
+
21
+ def allowed_explicit_matchers
22
+ cop_config.fetch("AllowedExplicitMatchers", []) + BUILT_IN_MATCHERS
23
+ end
24
+
25
+ def check_explicit(node)
26
+ predicate_matcher_block?(node) do |actual, matcher|
27
+ add_offense(node, message: message_explicit(matcher)) do |corrector|
28
+ to_node = node.send_node
29
+ corrector_explicit(corrector, to_node, actual, matcher, to_node)
30
+ end
31
+ ignore_node(node.children.first)
32
+ return
33
+ end
34
+
35
+ return if part_of_ignored_node?(node)
36
+
37
+ predicate_matcher?(node) do |actual, matcher|
38
+ add_offense(node, message: message_explicit(matcher)) do |corrector|
39
+ corrector_explicit(corrector, node, actual, matcher, matcher)
40
+ end
41
+ end
42
+ end
43
+
44
+ # @!method predicate_matcher?(node)
45
+ def_node_matcher :predicate_matcher?, <<-PATTERN
46
+ (send
47
+ (send nil? :expect $!nil?)
48
+ #Runners.all
49
+ {$(send nil? #predicate_matcher_name? ...)
50
+ (block $(send nil? #predicate_matcher_name? ...) ...)})
51
+ PATTERN
52
+
53
+ # @!method predicate_matcher_block?(node)
54
+ def_node_matcher :predicate_matcher_block?, <<-PATTERN
55
+ (block
56
+ (send
57
+ (send nil? :expect $!nil?)
58
+ #Runners.all
59
+ $(send nil? #predicate_matcher_name?))
60
+ ...)
61
+ PATTERN
62
+
63
+ def predicate_matcher_name?(name)
64
+ raise ::NotImplementedError
65
+ end
66
+
67
+ def message_explicit(matcher)
68
+ format(MSG_EXPLICIT,
69
+ predicate_name: to_predicate_method(matcher.method_name),
70
+ matcher_name: matcher.method_name)
71
+ end
72
+
73
+ def corrector_explicit(corrector, to_node, actual, matcher, block_child)
74
+ replacement_matcher = replacement_matcher(to_node)
75
+ corrector.replace(matcher.loc.expression, replacement_matcher)
76
+ move_predicate(corrector, actual, matcher, block_child)
77
+ corrector.replace(to_node.loc.selector, "to")
78
+ end
79
+
80
+ def move_predicate(corrector, actual, matcher, block_child)
81
+ predicate = to_predicate_method(matcher.method_name)
82
+ args = args_loc(matcher).source
83
+ block_loc = block_loc(block_child)
84
+ block = block_loc ? block_loc.source : ""
85
+
86
+ corrector.remove(block_loc) if block_loc
87
+ corrector.insert_after(actual.loc.expression,
88
+ ".#{predicate}" + args + block)
89
+ end
90
+
91
+ def to_predicate_method(matcher)
92
+ raise ::NotImplementedError
93
+ end
94
+
95
+ def replacement_matcher(node)
96
+ case [cop_config["Strict"], node.method?(:to)]
97
+ when [true, true]
98
+ "be(true)"
99
+ when [true, false]
100
+ "be(false)"
101
+ when [false, true]
102
+ "be_truthy"
103
+ when [false, false]
104
+ "be_falsey"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # A helper for `inflected` style
7
+ module RSpecInflectedHelp
8
+ include RuboCop::RSpec::Language
9
+ extend NodePattern::Macros
10
+
11
+ MSG_INFLECTED = "Prefer using `%<matcher_name>s` matcher over " \
12
+ "`%<predicate_name>s`."
13
+
14
+ private
15
+
16
+ def check_inflected(node)
17
+ predicate_in_actual?(node) do |predicate, to, matcher|
18
+ msg = message_inflected(predicate)
19
+ add_offense(node, message: msg) do |corrector|
20
+ remove_predicate(corrector, predicate)
21
+ corrector.replace(node.loc.selector,
22
+ true?(to, matcher) ? "to" : "not_to")
23
+ rewrite_matcher(corrector, predicate, matcher)
24
+ end
25
+ end
26
+ end
27
+
28
+ # @!method predicate_in_actual?(node)
29
+ def_node_matcher :predicate_in_actual?, <<-PATTERN
30
+ (send
31
+ (send nil? :expect {
32
+ (block $(send !nil? #predicate? ...) ...)
33
+ $(send !nil? #predicate? ...)})
34
+ $#Runners.all
35
+ $#boolean_matcher?)
36
+ PATTERN
37
+
38
+ # @!method be_bool?(node)
39
+ def_node_matcher :be_bool?, <<-PATTERN
40
+ (send nil? {:be :eq :eql :equal} {true false})
41
+ PATTERN
42
+
43
+ # @!method be_boolthy?(node)
44
+ def_node_matcher :be_boolthy?, <<-PATTERN
45
+ (send nil? {:be_truthy :be_falsey :be_falsy :a_truthy_value :a_falsey_value :a_falsy_value})
46
+ PATTERN
47
+
48
+ def boolean_matcher?(node)
49
+ if cop_config["Strict"]
50
+ be_boolthy?(node)
51
+ else
52
+ be_bool?(node) || be_boolthy?(node)
53
+ end
54
+ end
55
+
56
+ def predicate?(sym)
57
+ raise ::NotImplementedError
58
+ end
59
+
60
+ def message_inflected(predicate)
61
+ format(MSG_INFLECTED,
62
+ predicate_name: predicate.method_name,
63
+ matcher_name: to_predicate_matcher(predicate.method_name))
64
+ end
65
+
66
+ def to_predicate_matcher(name)
67
+ raise ::NotImplementedError
68
+ end
69
+
70
+ def remove_predicate(corrector, predicate)
71
+ range = predicate.loc.dot.with(
72
+ end_pos: predicate.loc.expression.end_pos
73
+ )
74
+
75
+ corrector.remove(range)
76
+
77
+ block_range = block_loc(predicate)
78
+ corrector.remove(block_range) if block_range
79
+ end
80
+
81
+ def rewrite_matcher(corrector, predicate, matcher)
82
+ args = args_loc(predicate).source
83
+ block_loc = block_loc(predicate)
84
+ block = block_loc ? block_loc.source : ""
85
+
86
+ corrector.replace(
87
+ matcher.loc.expression,
88
+ to_predicate_matcher(predicate.method_name) + args + block
89
+ )
90
+ end
91
+
92
+ def true?(to_symbol, matcher)
93
+ result = case matcher.method_name
94
+ when :be, :eq
95
+ matcher.first_argument.true_type?
96
+ when :be_truthy, :a_truthy_value
97
+ true
98
+ when :be_falsey, :be_falsy, :a_falsey_value, :a_falsy_value
99
+ false
100
+ end
101
+ to_symbol == :to ? result : !result
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # Helper methods for Predicate matcher.
7
+ module RSpecPredicateMatcherBase
8
+ include ConfigurableEnforcedStyle
9
+ include RSpecInflectedHelp
10
+ include RSpecExplicitHelp
11
+
12
+ RESTRICT_ON_SEND = %i[to to_not not_to].freeze
13
+
14
+ def on_send(node)
15
+ case style
16
+ when :inflected
17
+ check_inflected(node)
18
+ when :explicit
19
+ check_explicit(node)
20
+ end
21
+ end
22
+
23
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
24
+ check_explicit(node) if style == :explicit
25
+ end
26
+
27
+ private
28
+
29
+ # returns args location with whitespace
30
+ # @example
31
+ # foo 1, 2
32
+ # ^^^^^
33
+ def args_loc(send_node)
34
+ send_node.loc.selector.end.with(
35
+ end_pos: send_node.loc.expression.end_pos
36
+ )
37
+ end
38
+
39
+ # returns block location with whitespace
40
+ # @example
41
+ # foo { bar }
42
+ # ^^^^^^^^
43
+ def block_loc(send_node)
44
+ parent = send_node.parent
45
+ return unless parent.block_type?
46
+
47
+ send_node.loc.expression.end.with(
48
+ end_pos: parent.loc.expression.end_pos
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # Checks for usage of deprecated style methods.
7
+ #
8
+ # @example when using `assert_style`
9
+ # # bad
10
+ # page.find(:css, '#first').assert_style(display: 'block')
11
+ #
12
+ # # good
13
+ # page.find(:css, '#first').assert_matches_style(display: 'block')
14
+ #
15
+ # @example when using `has_style?`
16
+ # # bad
17
+ # expect(page.find(:css, 'first')
18
+ # .has_style?(display: 'block')).to be true
19
+ #
20
+ # # good
21
+ # expect(page.find(:css, 'first')
22
+ # .matches_style?(display: 'block')).to be true
23
+ #
24
+ # @example when using `have_style`
25
+ # # bad
26
+ # expect(page).to have_style(display: 'block')
27
+ #
28
+ # # good
29
+ # expect(page).to match_style(display: 'block')
30
+ #
31
+ class RSpecCapybaraMatchStyle < Base
32
+ extend AutoCorrector
33
+
34
+ MSG = "Use `%<good>s` instead of `%<bad>s`."
35
+ RESTRICT_ON_SEND = %i[assert_style has_style? have_style].freeze
36
+ PREFERRED_METHOD = {
37
+ "assert_style" => "assert_matches_style",
38
+ "has_style?" => "matches_style?",
39
+ "have_style" => "match_style"
40
+ }.freeze
41
+
42
+ def on_send(node)
43
+ method_node = node.loc.selector
44
+ add_offense(method_node) do |corrector|
45
+ corrector.replace(method_node,
46
+ PREFERRED_METHOD[method_node.source])
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def message(node)
53
+ format(MSG, good: PREFERRED_METHOD[node.source], bad: node.source)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # Prefer using predicate matcher over using predicate method directly.
7
+ #
8
+ # Capybara defines magic matchers for predicate methods.
9
+ # This cop recommends to use the predicate matcher instead of using
10
+ # predicate method directly.
11
+ #
12
+ # @example Strict: true, EnforcedStyle: inflected (default)
13
+ # # bad
14
+ # expect(foo.matches_css?(bar: 'baz')).to be_truthy
15
+ # expect(foo.matches_selector?(bar: 'baz')).to be_truthy
16
+ # expect(foo.matches_style?(bar: 'baz')).to be_truthy
17
+ # expect(foo.matches_xpath?(bar: 'baz')).to be_truthy
18
+ #
19
+ # # good
20
+ # expect(foo).to match_css(bar: 'baz')
21
+ # expect(foo).to match_selector(bar: 'baz')
22
+ # expect(foo).to match_style(bar: 'baz')
23
+ # expect(foo).to match_xpath(bar: 'baz')
24
+ #
25
+ # # also good - It checks "true" strictly.
26
+ # expect(foo.matches_style?(bar: 'baz')).to be(true)
27
+ #
28
+ # @example Strict: false, EnforcedStyle: inflected
29
+ # # bad
30
+ # expect(foo.matches_style?(bar: 'baz')).to be_truthy
31
+ # expect(foo.matches_style?(bar: 'baz')).to be(true)
32
+ #
33
+ # # good
34
+ # expect(foo).to match_style(bar: 'baz')
35
+ #
36
+ # @example Strict: true, EnforcedStyle: explicit
37
+ # # bad
38
+ # expect(foo).to match_style(bar: 'baz')
39
+ #
40
+ # # good - the above code is rewritten to it by this cop
41
+ # expect(foo.matches_style?(bar: 'baz')).to be(true)
42
+ #
43
+ # @example Strict: false, EnforcedStyle: explicit
44
+ # # bad
45
+ # expect(foo).to match_style(bar: 'baz')
46
+ #
47
+ # # good - the above code is rewritten to it by this cop
48
+ # expect(foo.matches_style?(bar: 'baz')).to be_truthy
49
+ #
50
+ class RSpecCapybaraPredicateMatcher < Base
51
+ extend AutoCorrector
52
+ include RuboCop::Cop::Workit::RSpecPredicateMatcherBase
53
+
54
+ MATCHER_SUFFIX = %w[css selector style xpath].freeze
55
+ INFLECTED_MATCHER = MATCHER_SUFFIX.each.map do |suffix|
56
+ "match_#{suffix}"
57
+ end.freeze
58
+ EXPLICIT_MATCHER = MATCHER_SUFFIX.each.map do |suffix|
59
+ "matches_#{suffix}?"
60
+ end.freeze
61
+
62
+ def predicate_matcher_name?(name)
63
+ name = name.to_s
64
+ return false if allowed_explicit_matchers.include?(name)
65
+
66
+ INFLECTED_MATCHER.include?(name)
67
+ end
68
+
69
+ def to_predicate_matcher(name)
70
+ name.to_s.sub("matches_", "match_")[0..-2]
71
+ end
72
+
73
+ def predicate?(sym)
74
+ EXPLICIT_MATCHER.include?(sym.to_s)
75
+ end
76
+
77
+ def to_predicate_method(matcher)
78
+ "#{matcher.to_s.sub("match_", "matches_")}?"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Workit
6
+ # Check if using Minitest matchers.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # assert_equal(a, b)
11
+ # assert_equal a, b, "must be equal"
12
+ # refute_equal(a, b)
13
+ #
14
+ # # good
15
+ # expect(a).to eq(b)
16
+ # expect(a).to(eq(b), "must be equal")
17
+ # expect(a).not_to eq(b)
18
+ #
19
+ class RSpecMinitestAssertions < Base
20
+ extend AutoCorrector
21
+
22
+ MSG = "Use `%<prefer>s`."
23
+ RESTRICT_ON_SEND = %i[assert_equal refute_equal].freeze
24
+
25
+ # @!method minitest_assertion(node)
26
+ def_node_matcher :minitest_assertion, <<-PATTERN
27
+ (send nil? {:assert_equal :refute_equal} $_ $_ $_?)
28
+ PATTERN
29
+
30
+ def on_send(node)
31
+ minitest_assertion(node) do |expected, actual, failure_message|
32
+ prefer = replacement(node, expected, actual, failure_message.first)
33
+ add_offense(node, message: message(prefer)) do |corrector|
34
+ corrector.replace(node, prefer)
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def replacement(node, expected, actual, failure_message)
42
+ runner = node.method?(:assert_equal) ? "to" : "not_to"
43
+ if failure_message.nil?
44
+ "expect(#{expected.source}).#{runner} eq(#{actual.source})"
45
+ else
46
+ "expect(#{expected.source}).#{runner}(eq(#{actual.source}), " \
47
+ "#{failure_message.source})"
48
+ end
49
+ end
50
+
51
+ def message(prefer)
52
+ format(MSG, prefer: prefer)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rubocop"
4
+ require "rubocop-rspec"
4
5
 
5
6
  module Workitcop
6
7
  module Inject
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Workitcop
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/workitcop.rb CHANGED
@@ -3,10 +3,17 @@
3
3
  require_relative "workitcop/inject"
4
4
  require_relative "workitcop/version"
5
5
 
6
+ require_relative "rubocop/cop/workit/mixin/rspec_explicit_help"
7
+ require_relative "rubocop/cop/workit/mixin/rspec_inflected_help"
8
+ require_relative "rubocop/cop/workit/mixin/rspec_predicate_matcher_base"
9
+
6
10
  require_relative "rubocop/cop/workit/action_args"
7
11
  require_relative "rubocop/cop/workit/comittee_assert_schema_confirm"
8
12
  require_relative "rubocop/cop/workit/noop_rescue"
9
13
  require_relative "rubocop/cop/workit/restrict_on_send"
14
+ require_relative "rubocop/cop/workit/rspec_capybara_match_style"
15
+ require_relative "rubocop/cop/workit/rspec_capybara_predicate_matcher"
16
+ require_relative "rubocop/cop/workit/rspec_minitest_assertions"
10
17
 
11
18
  module Workitcop
12
19
  PROJECT_ROOT = ::Pathname.new(__dir__).parent.expand_path.freeze
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workitcop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ydah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-08 00:00:00.000000000 Z
11
+ date: 2022-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -40,8 +40,14 @@ files:
40
40
  - config/default.yml
41
41
  - lib/rubocop/cop/workit/action_args.rb
42
42
  - lib/rubocop/cop/workit/comittee_assert_schema_confirm.rb
43
+ - lib/rubocop/cop/workit/mixin/rspec_explicit_help.rb
44
+ - lib/rubocop/cop/workit/mixin/rspec_inflected_help.rb
45
+ - lib/rubocop/cop/workit/mixin/rspec_predicate_matcher_base.rb
43
46
  - lib/rubocop/cop/workit/noop_rescue.rb
44
47
  - lib/rubocop/cop/workit/restrict_on_send.rb
48
+ - lib/rubocop/cop/workit/rspec_capybara_match_style.rb
49
+ - lib/rubocop/cop/workit/rspec_capybara_predicate_matcher.rb
50
+ - lib/rubocop/cop/workit/rspec_minitest_assertions.rb
45
51
  - lib/workitcop.rb
46
52
  - lib/workitcop/inject.rb
47
53
  - lib/workitcop/version.rb