rspectre 0.0.4 → 0.1.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: 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.