workitcop 0.3.0 → 0.4.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: 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