rspectre 0.0.4 → 0.1.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: b0c337fb9cef9cb104d3ca686aa194cbb81062c0407e52ffdecec1e0c393d0fa
4
- data.tar.gz: 144eee36cdd52ba9f99d38b3bc7bb57bcbd5d283accc4ba0eef11e474fe99ed6
3
+ metadata.gz: 87d88a2681d80d0f13e8cad1a0b5147c92d0ced19dede1657a74261cd4f9a8ae
4
+ data.tar.gz: 865b52f9b37fd3fa54b154dedb4196a4ce5bfcf20a0e8b8493e6bcd3611e8690
5
5
  SHA512:
6
- metadata.gz: 1a5cd59d5dff5c9becdfc36c28e1605f7a3e222fe7ffa7543974ad6e80bb80238adb654140d3b976c910d5fda36e946456539720801dfdc72844c3c59040c8cf
7
- data.tar.gz: ea374c050f039f1c027d12586f091c2fd15731b3a62648a95c15153bca1c03f145357ad3162eed228e3cedec293af7ba2009fc4178bf23d506bae33aa485f3c4
6
+ metadata.gz: cebc09f233bd5f6f2fd76c6f0741866472badae3a6a8f9c6012cfac379af4f2c4585827e0f73b0cd0e3b39848c0376dead07fad7bbd209666f10d8cc3242ed55
7
+ data.tar.gz: '09049b6500de8e538fa07a7e110e4671392e209b4345d1da8253c15901ce9af450cc54cfc330f19bcff1c5d05dd129df62ebcdc34c850d4daa92fa94e15056db'
data/bin/rspectre CHANGED
@@ -20,8 +20,8 @@ OptionParser.new do |opts|
20
20
  opts.on(
21
21
  '--auto-correct',
22
22
  'Enables auto-correct.',
23
- 'When auto-correct is enabled, rspectre will modify your source files in place and delete any'\
24
- ' unused test setup.'
23
+ 'When auto-correct is enabled, rspectre will modify your source files in place and delete ' \
24
+ 'any unused test setup.'
25
25
  ) do |value|
26
26
  options[:'auto-correct'] = value
27
27
  end
@@ -29,4 +29,4 @@ end.parse(ARGV)
29
29
 
30
30
  rspec, auto_correct = options.fetch_values(:rspec, :'auto-correct')
31
31
 
32
- RSpectre::Runner.new(rspec, auto_correct).lint
32
+ RSpectre::Runner.new(rspec_arguments: rspec, auto_correct: auto_correct).lint
@@ -2,13 +2,13 @@
2
2
 
3
3
  module RSpectre
4
4
  class AutoCorrector < Parser::TreeRewriter
5
- include Concord.new(:filename, :nodes, :buffer)
5
+ include KeywordStruct.new(:filename, :nodes, :buffer)
6
6
 
7
7
  def initialize(filename, nodes)
8
8
  buffer = Parser::Source::Buffer.new("(#{filename})")
9
9
  buffer.source = File.read(filename)
10
10
 
11
- super(filename, nodes, buffer)
11
+ super(filename: filename, nodes: nodes, buffer: buffer)
12
12
  end
13
13
 
14
14
  def correct
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpectre
4
+ # Heavily influenced by dkubb/equalizer, mbj/concord, and mbj/anima
5
+ class KeywordStruct < Module
6
+ def initialize(*names) # rubocop:disable Lint/MissingSuper
7
+ raise 'Specify at least one keyword name!' if names.empty?
8
+
9
+ names.each do |name|
10
+ next if /\A\w+\z/.match?(name)
11
+
12
+ raise "Invalid keyword name #{name.inspect}!"
13
+ end
14
+
15
+ @module =
16
+ Module.new do
17
+ attr_reader(*names)
18
+
19
+ define_method(:eql?) do |other|
20
+ other.instance_of?(self.class) && names.all? do |name|
21
+ __send__(name).eql?(other.__send__(name))
22
+ end
23
+ end
24
+ alias_method :==, :eql?
25
+
26
+ define_method(:hash) do
27
+ [self.class, *names.map { |name| __send__(name) }].hash
28
+ end
29
+
30
+ define_method(:inspect) do
31
+ class_name = self.class.name || self.class.inspect
32
+ attributes = names.map { |name| "#{name}=#{__send__(name).inspect}" }.join(' ')
33
+ "#<#{class_name} #{attributes}>"
34
+ end
35
+ end.tap do |generated_module|
36
+ generated_module.class_eval(<<~RUBY, __FILE__, __LINE__ + 1) # rubocop:disable Style/DocumentDynamicEvalDefinition
37
+ def initialize(#{names.map { |name| "#{name}:" }.join(', ')})
38
+ #{names.map { |name| "@#{name} = #{name}" }.join("\n ")}
39
+ end
40
+ RUBY
41
+ end
42
+ end
43
+
44
+ def included(descendant)
45
+ descendant.include(@module)
46
+ end
47
+ end
48
+ end
@@ -10,21 +10,21 @@ module RSpectre
10
10
  original_method = receiver.method(method)
11
11
 
12
12
  # Overwrite the class method using define_singleton_method
13
- receiver.__send__(:define_singleton_method, method) do |name, *args, &block|
13
+ receiver.__send__(:define_singleton_method, method) do |name, *args, **kwargs, &block|
14
14
  # When we can locate the source of the node, tag it
15
15
  if (node = UnusedSharedSetup.register(method, caller_locations))
16
- # And call the orignal
17
- original_method.(name, *args) do |*shared_args|
16
+ # And call the original
17
+ original_method.(name, *args, **kwargs) do |*shared_args, **shared_kwargs|
18
18
  # But record that it was used in a `before`
19
19
  before { UnusedSharedSetup.record(node) }
20
20
 
21
21
  # And then perform the original block in a `class_exec` like the original block was
22
22
  # supposed to be
23
- class_exec(*shared_args, &block)
23
+ class_exec(*shared_args, **shared_kwargs, &block)
24
24
  end
25
25
  else
26
26
  # If we couldn't locate the source, just delegate to the original method.
27
- original_method.(name, *args, &block)
27
+ original_method.(name, *args, **kwargs, &block)
28
28
  end
29
29
  end
30
30
  end
@@ -46,39 +46,39 @@ module RSpectre
46
46
  # terms of the old method. I think we can probably do some kind of module inclusion to reduce
47
47
  # this duplication (which is effectively what happens here anyway, i think), but this works
48
48
  # for now.
49
- def example_group.shared_examples(name, *args, &block)
49
+ def example_group.shared_examples(name, *args, **kwargs, &block)
50
50
  if (node = UnusedSharedSetup.register(:shared_examples, caller_locations))
51
- super(name, *args) do |*shared_args|
51
+ super(name, *args, **kwargs) do |*shared_args, **shared_kwargs|
52
52
  before { UnusedSharedSetup.record(node) }
53
53
 
54
- class_exec(*shared_args, &block)
54
+ class_exec(*shared_args, **shared_kwargs, &block)
55
55
  end
56
56
  else
57
- super(name, *args, &block)
57
+ super(name, *args, **kwargs, &block)
58
58
  end
59
59
  end
60
60
 
61
- def example_group.shared_examples_for(name, *args, &block)
61
+ def example_group.shared_examples_for(name, *args, **kwargs, &block)
62
62
  if (node = UnusedSharedSetup.register(:shared_examples_for, caller_locations))
63
- super(name, *args) do |*shared_args|
63
+ super(name, *args, **kwargs) do |*shared_args, **shared_kwargs|
64
64
  before { UnusedSharedSetup.record(node) }
65
65
 
66
- class_exec(*shared_args, &block)
66
+ class_exec(*shared_args, **shared_kwargs, &block)
67
67
  end
68
68
  else
69
- super(name, *args, &block)
69
+ super(name, *args, **kwargs, &block)
70
70
  end
71
71
  end
72
72
 
73
- def example_group.shared_context(name, *args, &block)
73
+ def example_group.shared_context(name, *args, **kwargs, &block)
74
74
  if (node = UnusedSharedSetup.register(:shared_context, caller_locations))
75
- super(name, *args) do |*shared_args|
75
+ super(name, *args, **kwargs) do |*shared_args, **shared_kwargs|
76
76
  before { UnusedSharedSetup.record(node) }
77
77
 
78
- class_exec(*shared_args, &block)
78
+ class_exec(*shared_args, **shared_kwargs, &block)
79
79
  end
80
80
  else
81
- super(name, *args, &block)
81
+ super(name, *args, **kwargs, &block)
82
82
  end
83
83
  end
84
84
  end
@@ -19,7 +19,7 @@ module RSpectre
19
19
  raw_node = node_map(file).find_method(selector, line)
20
20
 
21
21
  if raw_node
22
- node = RSpectre::Node.new(file, line, raw_node)
22
+ node = RSpectre::Node.new(file: file, line: line, node: raw_node)
23
23
  TRACKER.register(self::TAG, node)
24
24
  if block_given?
25
25
  yield node
@@ -40,10 +40,10 @@ module RSpectre
40
40
  def self.prepend_behavior(scope, method_name)
41
41
  original_method = scope.instance_method(method_name)
42
42
 
43
- scope.__send__(:define_method, method_name) do |*args, &block|
43
+ scope.__send__(:define_method, method_name) do |*args, **kwargs, &block|
44
44
  yield
45
45
 
46
- original_method.bind(self).(*args, &block)
46
+ original_method.bind_call(self, *args, **kwargs, &block)
47
47
  end
48
48
  end
49
49
 
data/lib/rspectre/node.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RSpectre
4
4
  class Node
5
- include Concord::Public.new(:file, :line, :node)
5
+ include KeywordStruct.new(:file, :line, :node)
6
6
 
7
7
  def start_column
8
8
  location.column + 1
@@ -27,7 +27,11 @@ module RSpectre
27
27
  end
28
28
 
29
29
  def location
30
- node.children.first.location
30
+ if node.type.equal?(:block)
31
+ node.children.first.location
32
+ else
33
+ node.location
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -2,13 +2,13 @@
2
2
 
3
3
  module RSpectre
4
4
  class Offense
5
- include Anima.new(:file, :line, :source_line, :start_column, :end_column, :type)
5
+ include KeywordStruct.new(:file, :line, :source_line, :start_column, :end_column, :type)
6
6
 
7
7
  DESCRIPTIONS = {
8
8
  'UnusedLet' => 'Unused `let` definition.',
9
9
  'UnusedSubject' => 'Unused `subject` definition.',
10
- 'UnusedSharedSetup' => 'Unused `shared_examples`, `shared_examples_for`, or'\
11
- ' `shared_context` definition.'
10
+ 'UnusedSharedSetup' => 'Unused `shared_examples`, `shared_examples_for`, or ' \
11
+ '`shared_context` definition.'
12
12
  }.freeze
13
13
 
14
14
  def self.parse(type, node)
@@ -23,7 +23,7 @@ module RSpectre
23
23
  end
24
24
 
25
25
  def warn
26
- puts to_s
26
+ puts self
27
27
  end
28
28
 
29
29
  def to_s
@@ -2,11 +2,11 @@
2
2
 
3
3
  module RSpectre
4
4
  class Runner
5
- include Concord.new(:rspec_arguments, :auto_correct)
5
+ include KeywordStruct.new(:rspec_arguments, :auto_correct)
6
6
 
7
7
  EXIT_SUCCESS = 0
8
8
 
9
- def initialize(*)
9
+ def initialize(**)
10
10
  super
11
11
  @rspec_output = StringIO.new
12
12
  end
@@ -39,7 +39,7 @@ module RSpectre
39
39
 
40
40
  abort(
41
41
  Color.red(
42
- 'Running the specs failed. Either your tests do not pass '\
42
+ 'Running the specs failed. Either your tests do not pass ' \
43
43
  'normally or this is a bug in RSpectre.'
44
44
  ) + <<~TEXT
45
45
 
@@ -3,7 +3,7 @@
3
3
  module RSpectre
4
4
  class SourceMap
5
5
  class Parser
6
- include Concord.new(:file)
6
+ include KeywordStruct.new(:file)
7
7
 
8
8
  def populate(map)
9
9
  walk(parsed_source) { |node| map.add(node) }
@@ -2,15 +2,15 @@
2
2
 
3
3
  module RSpectre
4
4
  class SourceMap
5
- include Concord.new(:map)
5
+ include KeywordStruct.new(:map)
6
6
 
7
7
  def initialize
8
- super(Hash.new { [] })
8
+ super(map: Hash.new { [] })
9
9
  end
10
10
  private_class_method :new
11
11
 
12
12
  def self.parse(file)
13
- self::Parser.new(file).populate(new)
13
+ self::Parser.new(file: file).populate(new)
14
14
  end
15
15
 
16
16
  def add(node)
@@ -32,18 +32,35 @@ module RSpectre
32
32
  private
33
33
 
34
34
  def find_methods(target_selector, line)
35
- block_nodes(line).select do |node|
36
- send, = *node
37
- _receiver, selector = *send
35
+ block_candidates =
36
+ block_nodes(line).select do |node|
37
+ send, = *node
38
+ matching_send?(send, target_selector)
39
+ end
38
40
 
39
- selector.equal?(target_selector)
41
+ if block_candidates.any?
42
+ block_candidates
43
+ else
44
+ send_nodes(line).select do |node|
45
+ matching_send?(node, target_selector)
46
+ end
40
47
  end
41
48
  end
42
49
 
50
+ def matching_send?(node, method_name)
51
+ _receiver, selector = *node
52
+
53
+ selector.equal?(method_name)
54
+ end
55
+
43
56
  def block_nodes(line)
44
57
  map.fetch(line, []).select { |node| node.type.equal?(:block) }
45
58
  end
46
59
 
60
+ def send_nodes(line)
61
+ map.fetch(line, []).select { |node| node.type.equal?(:send) }
62
+ end
63
+
47
64
  class Null < self
48
65
  public_class_method :new
49
66
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  module RSpectre
4
4
  class Tracker
5
- include Concord.new(:registry, :tracker)
5
+ include KeywordStruct.new(:registry, :tracker)
6
6
 
7
7
  def initialize
8
- super(Hash.new { Set.new }, Hash.new { Set.new })
8
+ super(registry: Hash.new { Set.new }, tracker: Hash.new { Set.new })
9
9
  end
10
10
 
11
11
  def register(type, node)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpectre
4
- VERSION = '0.0.4'
4
+ VERSION = '0.1.0'
5
5
  end
data/lib/rspectre.rb CHANGED
@@ -6,11 +6,11 @@ require 'pathname'
6
6
  require 'set'
7
7
  require 'stringio'
8
8
 
9
- require 'anima'
10
- require 'concord'
11
9
  require 'parser/current'
12
10
  require 'rspec'
13
11
 
12
+ require 'rspectre/keyword_struct'
13
+
14
14
  require 'rspectre/auto_corrector'
15
15
  require 'rspectre/color'
16
16
  require 'rspectre/node'
metadata CHANGED
@@ -1,71 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspectre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Gollahon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-10 00:00:00.000000000 Z
11
+ date: 2023-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: anima
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.3'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '0.3'
27
- - !ruby/object:Gem::Dependency
28
- name: concord
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.1'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.1'
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: parser
43
15
  requirement: !ruby/object:Gem::Requirement
44
16
  requirements:
45
17
  - - ">="
46
18
  - !ruby/object:Gem::Version
47
- version: '2.6'
19
+ version: 3.2.2.1
48
20
  type: :runtime
49
21
  prerelease: false
50
22
  version_requirements: !ruby/object:Gem::Requirement
51
23
  requirements:
52
24
  - - ">="
53
25
  - !ruby/object:Gem::Version
54
- version: '2.6'
26
+ version: 3.2.2.1
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: rspec
57
29
  requirement: !ruby/object:Gem::Requirement
58
30
  requirements:
59
31
  - - "~>"
60
32
  - !ruby/object:Gem::Version
61
- version: '3.0'
33
+ version: '3.9'
62
34
  type: :runtime
63
35
  prerelease: false
64
36
  version_requirements: !ruby/object:Gem::Requirement
65
37
  requirements:
66
38
  - - "~>"
67
39
  - !ruby/object:Gem::Version
68
- version: '3.0'
40
+ version: '3.9'
69
41
  - !ruby/object:Gem::Dependency
70
42
  name: pry
71
43
  requirement: !ruby/object:Gem::Requirement
@@ -86,28 +58,28 @@ dependencies:
86
58
  requirements:
87
59
  - - "~>"
88
60
  - !ruby/object:Gem::Version
89
- version: 1.24.1
61
+ version: 1.51.0
90
62
  type: :development
91
63
  prerelease: false
92
64
  version_requirements: !ruby/object:Gem::Requirement
93
65
  requirements:
94
66
  - - "~>"
95
67
  - !ruby/object:Gem::Version
96
- version: 1.24.1
68
+ version: 1.51.0
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: rubocop-rspec
99
71
  requirement: !ruby/object:Gem::Requirement
100
72
  requirements:
101
73
  - - "~>"
102
74
  - !ruby/object:Gem::Version
103
- version: 2.7.0
75
+ version: 2.22.0
104
76
  type: :development
105
77
  prerelease: false
106
78
  version_requirements: !ruby/object:Gem::Requirement
107
79
  requirements:
108
80
  - - "~>"
109
81
  - !ruby/object:Gem::Version
110
- version: 2.7.0
82
+ version: 2.22.0
111
83
  description:
112
84
  email:
113
85
  executables:
@@ -119,6 +91,7 @@ files:
119
91
  - lib/rspectre.rb
120
92
  - lib/rspectre/auto_corrector.rb
121
93
  - lib/rspectre/color.rb
94
+ - lib/rspectre/keyword_struct.rb
122
95
  - lib/rspectre/linter.rb
123
96
  - lib/rspectre/linter/unused_let.rb
124
97
  - lib/rspectre/linter/unused_shared_setup.rb
@@ -144,14 +117,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
117
  requirements:
145
118
  - - ">="
146
119
  - !ruby/object:Gem::Version
147
- version: '2.6'
120
+ version: '3.0'
148
121
  required_rubygems_version: !ruby/object:Gem::Requirement
149
122
  requirements:
150
123
  - - ">="
151
124
  - !ruby/object:Gem::Version
152
125
  version: '0'
153
126
  requirements: []
154
- rubygems_version: 3.1.6
127
+ rubygems_version: 3.4.10
155
128
  signing_key:
156
129
  specification_version: 4
157
130
  summary: A tool for linting RSpec test suites.