rubocop-rspec 1.7.0 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +955 -79
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +1 -2
- data/README.md +35 -35
- data/config/default.yml +940 -52
- data/config/obsoletion.yml +30 -0
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
- data/lib/rubocop/cop/rspec/around_block.rb +97 -0
- data/lib/rubocop/cop/rspec/base.rb +26 -0
- data/lib/rubocop/cop/rspec/be.rb +39 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
- data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +57 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
- data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
- data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
- data/lib/rubocop/cop/rspec/described_class.rb +181 -34
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
- data/lib/rubocop/cop/rspec/dialect.rb +84 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
- data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +38 -20
- data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
- data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
- data/lib/rubocop/cop/rspec/focus.rb +79 -25
- data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
- data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
- data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
- data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
- data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
- data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
- data/lib/rubocop/cop/rspec/pending.rb +80 -0
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
- data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
- data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
- data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
- data/lib/rubocop/cop/rspec/yield.rb +82 -0
- data/lib/rubocop/cop/rspec_cops.rb +112 -0
- data/lib/rubocop/rspec/align_let_brace.rb +63 -0
- data/lib/rubocop/rspec/concept.rb +33 -0
- data/lib/rubocop/rspec/config_formatter.rb +27 -4
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
- data/lib/rubocop/rspec/description_extractor.rb +60 -18
- data/lib/rubocop/rspec/example.rb +37 -0
- data/lib/rubocop/rspec/example_group.rb +67 -0
- data/lib/rubocop/rspec/hook.rb +79 -0
- data/lib/rubocop/rspec/inject.rb +3 -1
- data/lib/rubocop/rspec/language.rb +184 -41
- data/lib/rubocop/rspec/node.rb +19 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +61 -19
- data/lib/rubocop/rspec.rb +6 -2
- data/lib/rubocop-rspec.rb +45 -34
- metadata +130 -195
- data/Gemfile +0 -13
- data/Rakefile +0 -48
- data/lib/rubocop/cop/rspec/file_path.rb +0 -83
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/lib/rubocop/rspec/top_level_describe.rb +0 -61
- data/lib/rubocop/rspec/util.rb +0 -19
- data/rubocop-rspec.gemspec +0 -42
- data/spec/expect_violation/expectation_spec.rb +0 -85
- data/spec/project/changelog_spec.rb +0 -81
- data/spec/project/default_config_spec.rb +0 -52
- data/spec/project/project_requires_spec.rb +0 -8
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
- data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
- data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
- data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
- data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
- data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
- data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
- data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
- data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
- data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
- data/spec/rubocop/rspec/util/one_spec.rb +0 -21
- data/spec/rubocop/rspec/wording_spec.rb +0 -44
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
- data/spec/spec_helper.rb +0 -41
- data/spec/support/expect_violation.rb +0 -166
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'rspec/align_left_let_brace'
|
4
|
+
require_relative 'rspec/align_right_let_brace'
|
5
|
+
require_relative 'rspec/any_instance'
|
6
|
+
require_relative 'rspec/around_block'
|
7
|
+
require_relative 'rspec/be'
|
8
|
+
require_relative 'rspec/be_empty'
|
9
|
+
require_relative 'rspec/be_eq'
|
10
|
+
require_relative 'rspec/be_eql'
|
11
|
+
require_relative 'rspec/be_nil'
|
12
|
+
require_relative 'rspec/before_after_all'
|
13
|
+
require_relative 'rspec/change_by_zero'
|
14
|
+
require_relative 'rspec/class_check'
|
15
|
+
require_relative 'rspec/contain_exactly'
|
16
|
+
require_relative 'rspec/context_method'
|
17
|
+
require_relative 'rspec/context_wording'
|
18
|
+
require_relative 'rspec/describe_class'
|
19
|
+
require_relative 'rspec/describe_method'
|
20
|
+
require_relative 'rspec/describe_symbol'
|
21
|
+
require_relative 'rspec/described_class'
|
22
|
+
require_relative 'rspec/described_class_module_wrapping'
|
23
|
+
require_relative 'rspec/dialect'
|
24
|
+
require_relative 'rspec/duplicated_metadata'
|
25
|
+
require_relative 'rspec/empty_example_group'
|
26
|
+
require_relative 'rspec/empty_hook'
|
27
|
+
require_relative 'rspec/empty_line_after_example'
|
28
|
+
require_relative 'rspec/empty_line_after_example_group'
|
29
|
+
require_relative 'rspec/empty_line_after_final_let'
|
30
|
+
require_relative 'rspec/empty_line_after_hook'
|
31
|
+
require_relative 'rspec/empty_line_after_subject'
|
32
|
+
require_relative 'rspec/empty_metadata'
|
33
|
+
require_relative 'rspec/empty_output'
|
34
|
+
require_relative 'rspec/eq'
|
35
|
+
require_relative 'rspec/example_length'
|
36
|
+
require_relative 'rspec/example_without_description'
|
37
|
+
require_relative 'rspec/example_wording'
|
38
|
+
require_relative 'rspec/excessive_docstring_spacing'
|
39
|
+
require_relative 'rspec/expect_actual'
|
40
|
+
require_relative 'rspec/expect_change'
|
41
|
+
require_relative 'rspec/expect_in_hook'
|
42
|
+
require_relative 'rspec/expect_in_let'
|
43
|
+
require_relative 'rspec/expect_output'
|
44
|
+
require_relative 'rspec/focus'
|
45
|
+
require_relative 'rspec/hook_argument'
|
46
|
+
require_relative 'rspec/hooks_before_examples'
|
47
|
+
require_relative 'rspec/identical_equality_assertion'
|
48
|
+
require_relative 'rspec/implicit_block_expectation'
|
49
|
+
require_relative 'rspec/implicit_expect'
|
50
|
+
require_relative 'rspec/implicit_subject'
|
51
|
+
require_relative 'rspec/indexed_let'
|
52
|
+
require_relative 'rspec/instance_spy'
|
53
|
+
require_relative 'rspec/instance_variable'
|
54
|
+
require_relative 'rspec/is_expected_specify'
|
55
|
+
require_relative 'rspec/it_behaves_like'
|
56
|
+
require_relative 'rspec/iterated_expectation'
|
57
|
+
require_relative 'rspec/leading_subject'
|
58
|
+
require_relative 'rspec/leaky_constant_declaration'
|
59
|
+
require_relative 'rspec/let_before_examples'
|
60
|
+
require_relative 'rspec/let_setup'
|
61
|
+
require_relative 'rspec/match_array'
|
62
|
+
require_relative 'rspec/message_chain'
|
63
|
+
require_relative 'rspec/message_expectation'
|
64
|
+
require_relative 'rspec/message_spies'
|
65
|
+
require_relative 'rspec/metadata_style'
|
66
|
+
require_relative 'rspec/missing_example_group_argument'
|
67
|
+
require_relative 'rspec/missing_expectation_target_method'
|
68
|
+
require_relative 'rspec/multiple_describes'
|
69
|
+
require_relative 'rspec/multiple_expectations'
|
70
|
+
require_relative 'rspec/multiple_memoized_helpers'
|
71
|
+
require_relative 'rspec/multiple_subjects'
|
72
|
+
require_relative 'rspec/named_subject'
|
73
|
+
require_relative 'rspec/nested_groups'
|
74
|
+
require_relative 'rspec/no_expectation_example'
|
75
|
+
require_relative 'rspec/not_to_not'
|
76
|
+
require_relative 'rspec/overwriting_setup'
|
77
|
+
require_relative 'rspec/pending'
|
78
|
+
require_relative 'rspec/pending_without_reason'
|
79
|
+
require_relative 'rspec/predicate_matcher'
|
80
|
+
require_relative 'rspec/receive_counts'
|
81
|
+
require_relative 'rspec/receive_messages'
|
82
|
+
require_relative 'rspec/receive_never'
|
83
|
+
require_relative 'rspec/redundant_around'
|
84
|
+
require_relative 'rspec/redundant_predicate_matcher'
|
85
|
+
require_relative 'rspec/remove_const'
|
86
|
+
require_relative 'rspec/repeated_description'
|
87
|
+
require_relative 'rspec/repeated_example'
|
88
|
+
require_relative 'rspec/repeated_example_group_body'
|
89
|
+
require_relative 'rspec/repeated_example_group_description'
|
90
|
+
require_relative 'rspec/repeated_include_example'
|
91
|
+
require_relative 'rspec/repeated_subject_call'
|
92
|
+
require_relative 'rspec/return_from_stub'
|
93
|
+
require_relative 'rspec/scattered_let'
|
94
|
+
require_relative 'rspec/scattered_setup'
|
95
|
+
require_relative 'rspec/shared_context'
|
96
|
+
require_relative 'rspec/shared_examples'
|
97
|
+
require_relative 'rspec/single_argument_message_chain'
|
98
|
+
require_relative 'rspec/skip_block_inside_example'
|
99
|
+
require_relative 'rspec/sort_metadata'
|
100
|
+
require_relative 'rspec/spec_file_path_format'
|
101
|
+
require_relative 'rspec/spec_file_path_suffix'
|
102
|
+
require_relative 'rspec/stubbed_mock'
|
103
|
+
require_relative 'rspec/subject_declaration'
|
104
|
+
require_relative 'rspec/subject_stub'
|
105
|
+
require_relative 'rspec/undescriptive_literals_description'
|
106
|
+
require_relative 'rspec/unspecified_exception'
|
107
|
+
require_relative 'rspec/variable_definition'
|
108
|
+
require_relative 'rspec/variable_name'
|
109
|
+
require_relative 'rspec/verified_double_reference'
|
110
|
+
require_relative 'rspec/verified_doubles'
|
111
|
+
require_relative 'rspec/void_expect'
|
112
|
+
require_relative 'rspec/yield'
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Shared behavior for aligning braces for single line lets
|
6
|
+
class AlignLetBrace
|
7
|
+
include RuboCop::RSpec::Language
|
8
|
+
include RuboCop::Cop::Util
|
9
|
+
|
10
|
+
def initialize(root, token)
|
11
|
+
@root = root
|
12
|
+
@token = token
|
13
|
+
end
|
14
|
+
|
15
|
+
def offending_tokens
|
16
|
+
single_line_lets.reject do |let|
|
17
|
+
target_column_for(let) == let_token(let).column
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def indent_for(node)
|
22
|
+
' ' * (target_column_for(node) - let_token(node).column)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def let_token(node)
|
28
|
+
node.loc.public_send(token)
|
29
|
+
end
|
30
|
+
|
31
|
+
def target_column_for(let)
|
32
|
+
let_group_for(let).map { |member| let_token(member).column }.max
|
33
|
+
end
|
34
|
+
|
35
|
+
def let_group_for(let)
|
36
|
+
adjacent_let_chunks.detect do |chunk|
|
37
|
+
chunk.any? do |member|
|
38
|
+
member == let && same_line?(member, let)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def adjacent_let_chunks
|
44
|
+
last_line = nil
|
45
|
+
|
46
|
+
single_line_lets.chunk do |node|
|
47
|
+
line = node.loc.line
|
48
|
+
last_line = (line if last_line.nil? || last_line + 1 == line)
|
49
|
+
last_line.nil?
|
50
|
+
end.map(&:last)
|
51
|
+
end
|
52
|
+
|
53
|
+
def single_line_lets
|
54
|
+
@single_line_lets ||=
|
55
|
+
root.each_node(:block).select do |node|
|
56
|
+
let?(node) && node.single_line?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :root, :token
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Wrapper for RSpec DSL methods
|
6
|
+
class Concept
|
7
|
+
extend RuboCop::NodePattern::Macros
|
8
|
+
include Language
|
9
|
+
|
10
|
+
def initialize(node)
|
11
|
+
@node = node
|
12
|
+
end
|
13
|
+
|
14
|
+
def eql?(other)
|
15
|
+
node == other.node
|
16
|
+
end
|
17
|
+
|
18
|
+
alias == eql?
|
19
|
+
|
20
|
+
def hash
|
21
|
+
[self.class, node].hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_node
|
25
|
+
node
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
attr_reader :node
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,10 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
|
3
5
|
module RuboCop
|
4
6
|
module RSpec
|
5
7
|
# Builds a YAML config file from two config hashes
|
6
8
|
class ConfigFormatter
|
7
|
-
|
9
|
+
EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
|
10
|
+
SUBDEPARTMENTS = [].freeze
|
11
|
+
AMENDMENTS = %(Metrics/BlockLength)
|
12
|
+
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
|
8
13
|
|
9
14
|
def initialize(config, descriptions)
|
10
15
|
@config = config
|
@@ -12,19 +17,37 @@ module RuboCop
|
|
12
17
|
end
|
13
18
|
|
14
19
|
def dump
|
15
|
-
YAML.dump(unified_config)
|
20
|
+
YAML.dump(unified_config)
|
21
|
+
.gsub(EXTENSION_ROOT_DEPARTMENT, "\n\\1")
|
22
|
+
.gsub(*AMENDMENTS, "\n\\0")
|
23
|
+
.gsub(/^(\s+)- /, '\1 - ')
|
24
|
+
.gsub('"~"', '~')
|
16
25
|
end
|
17
26
|
|
18
27
|
private
|
19
28
|
|
20
29
|
def unified_config
|
21
30
|
cops.each_with_object(config.dup) do |cop, unified|
|
22
|
-
|
31
|
+
next if SUBDEPARTMENTS.include?(cop) || AMENDMENTS.include?(cop)
|
32
|
+
|
33
|
+
replace_nil(unified[cop])
|
34
|
+
unified[cop].merge!(descriptions.fetch(cop))
|
35
|
+
unified[cop]['Reference'] = reference(cop)
|
23
36
|
end
|
24
37
|
end
|
25
38
|
|
26
39
|
def cops
|
27
|
-
(descriptions.keys
|
40
|
+
(descriptions.keys | config.keys).grep(EXTENSION_ROOT_DEPARTMENT)
|
41
|
+
end
|
42
|
+
|
43
|
+
def replace_nil(config)
|
44
|
+
config.each do |key, value|
|
45
|
+
config[key] = '~' if value.nil?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def reference(cop)
|
50
|
+
COP_DOC_BASE_URL + cop
|
28
51
|
end
|
29
52
|
|
30
53
|
attr_reader :config, :descriptions
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
module Cop
|
6
|
+
# Source and spec generator for new cops
|
7
|
+
#
|
8
|
+
# This generator will take a cop name and generate a source file
|
9
|
+
# and spec file when given a valid qualified cop name.
|
10
|
+
# @api private
|
11
|
+
class Generator < RuboCop::Cop::Generator
|
12
|
+
def todo
|
13
|
+
<<~TODO
|
14
|
+
Do 4 steps:
|
15
|
+
1. Modify the description of #{badge} in config/default.yml
|
16
|
+
2. Implement your new cop in the generated file!
|
17
|
+
3. Add an entry about new cop to CHANGELOG.md
|
18
|
+
4. Commit your new cop with a message such as
|
19
|
+
e.g. "Add new `#{badge}` cop"
|
20
|
+
TODO
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
module Corrector
|
6
|
+
# Helper methods to move a node
|
7
|
+
class MoveNode
|
8
|
+
include RuboCop::Cop::RangeHelp
|
9
|
+
include RuboCop::Cop::RSpec::CommentsHelp
|
10
|
+
include RuboCop::Cop::RSpec::FinalEndLocation
|
11
|
+
|
12
|
+
attr_reader :original, :corrector, :processed_source
|
13
|
+
|
14
|
+
def initialize(node, corrector, processed_source)
|
15
|
+
@original = node
|
16
|
+
@corrector = corrector
|
17
|
+
@processed_source = processed_source # used by RangeHelp
|
18
|
+
end
|
19
|
+
|
20
|
+
def move_before(other)
|
21
|
+
position = start_line_position(other)
|
22
|
+
|
23
|
+
corrector.insert_before(position, "#{source(original)}\n")
|
24
|
+
corrector.remove(node_range_with_surrounding_space(original))
|
25
|
+
end
|
26
|
+
|
27
|
+
def move_after(other)
|
28
|
+
position = end_line_position(other)
|
29
|
+
|
30
|
+
corrector.insert_after(position, "\n#{source(original)}")
|
31
|
+
corrector.remove(node_range_with_surrounding_space(original))
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def source(node)
|
37
|
+
node_range(node).source
|
38
|
+
end
|
39
|
+
|
40
|
+
def node_range(node)
|
41
|
+
source_range_with_comment(node)
|
42
|
+
end
|
43
|
+
|
44
|
+
def node_range_with_surrounding_space(node)
|
45
|
+
range = node_range(node)
|
46
|
+
range_by_whole_lines(range, include_final_newline: true)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,35 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RuboCop
|
2
4
|
module RSpec
|
3
5
|
# Extracts cop descriptions from YARD docstrings
|
4
6
|
class DescriptionExtractor
|
5
|
-
COP_NAMESPACE = 'RuboCop::Cop::RSpec'.freeze
|
6
|
-
COP_FORMAT = 'RSpec/%s'.freeze
|
7
|
-
|
8
7
|
def initialize(yardocs)
|
9
|
-
@
|
8
|
+
@code_objects = yardocs.map(&CodeObject.public_method(:new))
|
10
9
|
end
|
11
10
|
|
12
11
|
def to_h
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
12
|
+
code_objects
|
13
|
+
.select(&:rspec_cop?)
|
14
|
+
.map(&:configuration)
|
15
|
+
.reduce(:merge)
|
18
16
|
end
|
19
17
|
|
20
18
|
private
|
21
19
|
|
22
|
-
|
23
|
-
yardocs
|
24
|
-
.select(&method(:cop?))
|
25
|
-
.map { |doc| [doc.name, doc.docstring] }
|
26
|
-
end
|
20
|
+
attr_reader :code_objects
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
# Decorator of a YARD code object for working with documented rspec cops
|
23
|
+
class CodeObject
|
24
|
+
RSPEC_COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Base'
|
25
|
+
RUBOCOP_COP_CLASS_NAME = 'RuboCop::Cop::Base'
|
26
|
+
RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'
|
27
|
+
|
28
|
+
def initialize(yardoc)
|
29
|
+
@yardoc = yardoc
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
# Test if the YARD code object documents a concrete rspec cop class
|
33
|
+
#
|
34
|
+
# @return [Boolean]
|
35
|
+
def rspec_cop?
|
36
|
+
cop_subclass? && !abstract? && rspec_cop_namespace?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Configuration for the documented cop that would live in default.yml
|
40
|
+
#
|
41
|
+
# @return [Hash]
|
42
|
+
def configuration
|
43
|
+
{ cop_name => { 'Description' => description } }
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def cop_name
|
49
|
+
Object.const_get(documented_constant).cop_name
|
50
|
+
end
|
51
|
+
|
52
|
+
def description
|
53
|
+
yardoc.docstring.split("\n\n").first.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def rspec_cop_namespace?
|
57
|
+
documented_constant.start_with?(RSPEC_NAMESPACE)
|
58
|
+
end
|
59
|
+
|
60
|
+
def documented_constant
|
61
|
+
yardoc.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def cop_subclass?
|
65
|
+
yardoc.superclass.path == RSPEC_COP_CLASS_NAME ||
|
66
|
+
yardoc.superclass.path == RUBOCOP_COP_CLASS_NAME
|
67
|
+
end
|
68
|
+
|
69
|
+
def abstract?
|
70
|
+
yardoc.tags.any? { |tag| tag.tag_name.eql?('abstract') }
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :yardoc
|
74
|
+
end
|
33
75
|
end
|
34
76
|
end
|
35
77
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Wrapper for RSpec examples
|
6
|
+
class Example < Concept
|
7
|
+
# @!method extract_doc_string(node)
|
8
|
+
def_node_matcher :extract_doc_string, '(send _ _ $_ ...)'
|
9
|
+
|
10
|
+
# @!method extract_metadata(node)
|
11
|
+
def_node_matcher :extract_metadata, '(send _ _ _ $...)'
|
12
|
+
|
13
|
+
# @!method extract_implementation(node)
|
14
|
+
def_node_matcher :extract_implementation, '(block send args $_)'
|
15
|
+
|
16
|
+
def doc_string
|
17
|
+
extract_doc_string(definition)
|
18
|
+
end
|
19
|
+
|
20
|
+
def metadata
|
21
|
+
extract_metadata(definition)
|
22
|
+
end
|
23
|
+
|
24
|
+
def implementation
|
25
|
+
extract_implementation(node)
|
26
|
+
end
|
27
|
+
|
28
|
+
def definition
|
29
|
+
if node.send_type?
|
30
|
+
node
|
31
|
+
else
|
32
|
+
node.send_node
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Wrapper for RSpec example groups
|
6
|
+
class ExampleGroup < Concept
|
7
|
+
# @!method scope_change?(node)
|
8
|
+
#
|
9
|
+
# Detect if the node is an example group or shared example
|
10
|
+
#
|
11
|
+
# Selectors which indicate that we should stop searching
|
12
|
+
#
|
13
|
+
def_node_matcher :scope_change?, <<~PATTERN
|
14
|
+
(block {
|
15
|
+
(send #rspec? {#SharedGroups.all #ExampleGroups.all} ...)
|
16
|
+
(send nil? #Includes.all ...)
|
17
|
+
} ...)
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
def lets
|
21
|
+
find_all_in_scope(node, :let?)
|
22
|
+
end
|
23
|
+
|
24
|
+
def subjects
|
25
|
+
find_all_in_scope(node, :subject?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def examples
|
29
|
+
find_all_in_scope(node, :example?).map do |node|
|
30
|
+
Example.new(node)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def hooks
|
35
|
+
find_all_in_scope(node, :hook?).map do |node|
|
36
|
+
Hook.new(node)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Recursively search for predicate within the current scope
|
43
|
+
#
|
44
|
+
# Searches node and halts when a scope change is detected
|
45
|
+
#
|
46
|
+
# @param node [RuboCop::AST::Node] node to recursively search
|
47
|
+
# @param predicate [Symbol] method to call with node as argument
|
48
|
+
#
|
49
|
+
# @return [Array<RuboCop::AST::Node>] discovered nodes
|
50
|
+
def find_all_in_scope(node, predicate)
|
51
|
+
node.each_child_node.flat_map do |child|
|
52
|
+
find_all(child, predicate)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_all(node, predicate)
|
57
|
+
if public_send(predicate, node)
|
58
|
+
[node]
|
59
|
+
elsif scope_change?(node) || example?(node)
|
60
|
+
[]
|
61
|
+
else
|
62
|
+
find_all_in_scope(node, predicate)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Wrapper for RSpec hook
|
6
|
+
class Hook < Concept
|
7
|
+
# @!method extract_metadata(node)
|
8
|
+
def_node_matcher :extract_metadata, <<~PATTERN
|
9
|
+
(block
|
10
|
+
(send _ _ #valid_scope? ? $...) ...
|
11
|
+
)
|
12
|
+
PATTERN
|
13
|
+
|
14
|
+
def name
|
15
|
+
node.method_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def knowable_scope?
|
19
|
+
scope_argument.nil? ||
|
20
|
+
scope_argument.sym_type? ||
|
21
|
+
scope_argument.hash_type?
|
22
|
+
end
|
23
|
+
|
24
|
+
def example?
|
25
|
+
scope.equal?(:each)
|
26
|
+
end
|
27
|
+
|
28
|
+
def scope
|
29
|
+
return :each if scope_argument&.hash_type?
|
30
|
+
|
31
|
+
case scope_name
|
32
|
+
when nil, :each, :example then :each
|
33
|
+
when :context, :all then :context
|
34
|
+
when :suite then :suite
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def metadata
|
39
|
+
(extract_metadata(node) || [])
|
40
|
+
.map { |meta| transform_metadata(meta) }
|
41
|
+
.flatten
|
42
|
+
.inject(&:merge)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def valid_scope?(node)
|
48
|
+
node&.sym_type? && Language::HookScopes.all(node.value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def transform_metadata(meta)
|
52
|
+
if meta.sym_type?
|
53
|
+
{ meta => true }
|
54
|
+
else
|
55
|
+
# This check is to be able to compare those two hooks:
|
56
|
+
#
|
57
|
+
# before(:example, :special) { ... }
|
58
|
+
# before(:example, special: true) { ... }
|
59
|
+
#
|
60
|
+
# In the second case it's a node with a pair that has a value
|
61
|
+
# of a `true_type?`.
|
62
|
+
meta.pairs.map { |pair| { pair.key => transform_true(pair.value) } }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def transform_true(node)
|
67
|
+
node.true_type? ? true : node
|
68
|
+
end
|
69
|
+
|
70
|
+
def scope_name
|
71
|
+
scope_argument.to_a.first
|
72
|
+
end
|
73
|
+
|
74
|
+
def scope_argument
|
75
|
+
node.send_node.first_argument
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/rubocop/rspec/inject.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RuboCop
|
2
4
|
module RSpec
|
3
5
|
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
@@ -6,7 +8,7 @@ module RuboCop
|
|
6
8
|
def self.defaults!
|
7
9
|
path = CONFIG_DEFAULT.to_s
|
8
10
|
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
9
|
-
config = Config.new(hash, path)
|
11
|
+
config = RuboCop::Config.new(hash, path)
|
10
12
|
puts "configuration from #{path}" if ConfigLoader.debug?
|
11
13
|
config = ConfigLoader.merge_with_default(config, path)
|
12
14
|
ConfigLoader.instance_variable_set(:@default_configuration, config)
|