rubyzen-lint 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/rubyzen/collections/arguments_collection.rb +16 -0
- data/lib/rubyzen/collections/assignments_collection.rb +11 -0
- data/lib/rubyzen/collections/blocks_collection.rb +21 -0
- data/lib/rubyzen/collections/expressions_collection.rb +27 -0
- data/lib/rubyzen/collections/methods_collection.rb +29 -0
- data/lib/rubyzen/collections/returns_collection.rb +20 -0
- data/lib/rubyzen/declarations/assignment_declaration.rb +57 -0
- data/lib/rubyzen/declarations/block_declaration.rb +2 -0
- data/lib/rubyzen/declarations/call_site_declaration.rb +14 -0
- data/lib/rubyzen/declarations/expression_declaration.rb +99 -0
- data/lib/rubyzen/declarations/method_declaration.rb +2 -0
- data/lib/rubyzen/declarations/return_declaration.rb +51 -0
- data/lib/rubyzen/providers/arguments_provider.rb +15 -0
- data/lib/rubyzen/providers/assignments_provider.rb +15 -0
- data/lib/rubyzen/providers/enclosing_blocks_provider.rb +16 -0
- data/lib/rubyzen/providers/returns_provider.rb +49 -0
- data/lib/rubyzen/version.rb +1 -1
- metadata +18 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 500e791179afc539a3b93a9300c55661567131776188a7ae484e5a2cffa3e12d
|
|
4
|
+
data.tar.gz: 1793077a6d2cfaa933c8a607cab96a3f84afe97e58f1a1926eaf6d60d2febed6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc076838beaafc1461c8c650e7a50e92ad0f4d32adc1c7f2ee15e9b47aeb9ac33a4742b2a98d47c23c2a73085f58b9cbbaa16d6a0d03526866472462bcb8f71f
|
|
7
|
+
data.tar.gz: b26b14d82f55b207b61601dd629154765488bf6154256738e11b1e96dfe14669109406513a12d4814c128e2cfbfc97b697c88ae68910d9d6c6c03a96c0d62164
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`ExpressionDeclaration`** — a value-expression primitive wrapping any AST node, with
|
|
8
|
+
predicates (`constant?`, `local_variable?`, `method_call?`, `constructor?`, `hash_literal?`,
|
|
9
|
+
`symbol?`, `string?`) and accessors (`constant_name`, `method_name`, `name`).
|
|
10
|
+
- **`#returns`** on `MethodDeclaration` and `BlockDeclaration` — the points at which it yields a
|
|
11
|
+
value (the implicit final expression plus explicit `return`s) as `ReturnDeclaration`s
|
|
12
|
+
(`#explicit?`, `#implicit?`, `#expression`), collected in a `ReturnsCollection` (`#expressions`).
|
|
13
|
+
`#return_expressions` remains as a shortcut for `returns.expressions` — an `ExpressionsCollection`
|
|
14
|
+
(`#hash_literals`, `#constants`). Both are bridged on `MethodsCollection` and `BlocksCollection`.
|
|
15
|
+
- **`CallSiteDeclaration#arguments`** — the call's arguments as an `ArgumentsCollection`
|
|
16
|
+
(a subclass of `ExpressionsCollection`, so it keeps `#hash_literals`/`#constants`).
|
|
17
|
+
- **`CallSiteDeclaration#receiver_expression`** — the receiver modeled structurally (constant /
|
|
18
|
+
constructor / local variable). `#receiver` (String const-name) is unchanged.
|
|
19
|
+
- **`CallSiteDeclaration#enclosing_blocks`** — the chain of enclosing `do..end`/`{ }` blocks
|
|
20
|
+
(innermost first), as a `BlocksCollection`.
|
|
21
|
+
- **`#assignments`** on `MethodDeclaration` and `BlockDeclaration` — local-variable assignments
|
|
22
|
+
(`AssignmentDeclaration`, with `#name` and `#value`) as an `AssignmentsCollection`. Bridged on
|
|
23
|
+
`MethodsCollection` and `BlocksCollection`.
|
|
24
|
+
|
|
25
|
+
All additions are backward-compatible; no existing API changed.
|
|
26
|
+
|
|
3
27
|
## [0.2.0]
|
|
4
28
|
|
|
5
29
|
### Added
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Collections
|
|
3
|
+
# Collection of {Rubyzen::Declarations::ExpressionDeclaration} representing the arguments
|
|
4
|
+
# passed at a call site.
|
|
5
|
+
#
|
|
6
|
+
# A specialization of {ExpressionsCollection}: arguments are value-expressions, so this
|
|
7
|
+
# inherits the value-expression filters (`#hash_literals`, `#constants`) and remains a
|
|
8
|
+
# drop-in `ExpressionsCollection`. It exists as a distinct type so argument-specific
|
|
9
|
+
# filters (e.g. positional vs keyword) can be added later without a breaking change.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# call_site.arguments.first.constant_name
|
|
13
|
+
class ArgumentsCollection < ExpressionsCollection
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Collections
|
|
3
|
+
# Collection of {Rubyzen::Declarations::AssignmentDeclaration} (local-variable assignments).
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# method.assignments.with_name('user')
|
|
7
|
+
class AssignmentsCollection < BaseCollection
|
|
8
|
+
include Rubyzen::Providers::CollectionFilterProvider
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -22,6 +22,27 @@ module Rubyzen
|
|
|
22
22
|
all_call_sites = flat_map(&:call_sites)
|
|
23
23
|
CallSiteCollection.new(all_call_sites)
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
# Returns all return points across every block.
|
|
27
|
+
#
|
|
28
|
+
# @return [ReturnsCollection]
|
|
29
|
+
def returns
|
|
30
|
+
ReturnsCollection.new(flat_map(&:returns))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns all return expressions across every block.
|
|
34
|
+
#
|
|
35
|
+
# @return [ExpressionsCollection]
|
|
36
|
+
def return_expressions
|
|
37
|
+
returns.expressions
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns all local-variable assignments across every block.
|
|
41
|
+
#
|
|
42
|
+
# @return [AssignmentsCollection]
|
|
43
|
+
def assignments
|
|
44
|
+
AssignmentsCollection.new(flat_map(&:assignments))
|
|
45
|
+
end
|
|
25
46
|
end
|
|
26
47
|
end
|
|
27
48
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Collections
|
|
3
|
+
# Collection of {Rubyzen::Declarations::ExpressionDeclaration} — return values,
|
|
4
|
+
# call arguments, and other value-expressions.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# method.return_expressions.hash_literals
|
|
8
|
+
class ExpressionsCollection < BaseCollection
|
|
9
|
+
include Rubyzen::Providers::CollectionFilterProvider
|
|
10
|
+
|
|
11
|
+
# Filters to only braced Hash-literal expressions.
|
|
12
|
+
#
|
|
13
|
+
# @return [ExpressionsCollection]
|
|
14
|
+
def hash_literals
|
|
15
|
+
filter(&:hash_literal?)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Filters to only constant expressions, including constructors of a constant
|
|
19
|
+
# (e.g. both +Repos::Foo+ and +Repos::Foo.new+).
|
|
20
|
+
#
|
|
21
|
+
# @return [ExpressionsCollection]
|
|
22
|
+
def constants
|
|
23
|
+
filter(&:constant_name)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -62,6 +62,35 @@ module Rubyzen
|
|
|
62
62
|
end
|
|
63
63
|
)
|
|
64
64
|
end
|
|
65
|
+
|
|
66
|
+
# Returns all return points across every method.
|
|
67
|
+
#
|
|
68
|
+
# @return [ReturnsCollection]
|
|
69
|
+
def returns
|
|
70
|
+
ReturnsCollection.new(
|
|
71
|
+
flat_map do |method|
|
|
72
|
+
method.returns
|
|
73
|
+
end
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns all return expressions across every method.
|
|
78
|
+
#
|
|
79
|
+
# @return [ExpressionsCollection]
|
|
80
|
+
def return_expressions
|
|
81
|
+
returns.expressions
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns all local-variable assignments across every method.
|
|
85
|
+
#
|
|
86
|
+
# @return [AssignmentsCollection]
|
|
87
|
+
def assignments
|
|
88
|
+
AssignmentsCollection.new(
|
|
89
|
+
flat_map do |method|
|
|
90
|
+
method.assignments
|
|
91
|
+
end
|
|
92
|
+
)
|
|
93
|
+
end
|
|
65
94
|
end
|
|
66
95
|
end
|
|
67
96
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Collections
|
|
3
|
+
# Collection of {Rubyzen::Declarations::ReturnDeclaration} — the points at which a
|
|
4
|
+
# method or block yields a value.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# method.returns.expressions.hash_literals
|
|
8
|
+
class ReturnsCollection < BaseCollection
|
|
9
|
+
include Rubyzen::Providers::CollectionFilterProvider
|
|
10
|
+
|
|
11
|
+
# The value expressions of every return. Bare +return+s (which have no value)
|
|
12
|
+
# are omitted.
|
|
13
|
+
#
|
|
14
|
+
# @return [ExpressionsCollection]
|
|
15
|
+
def expressions
|
|
16
|
+
ExpressionsCollection.new(filter_map(&:expression))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Declarations
|
|
3
|
+
# Represents a local-variable assignment (an +lvasgn+ node), e.g. +x = Repos::Foo.new+.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# assignment = method.assignments.first
|
|
7
|
+
# assignment.name #=> "x"
|
|
8
|
+
# assignment.value.constructor? #=> true
|
|
9
|
+
# assignment.value.constant_name #=> "Repos::Foo"
|
|
10
|
+
#
|
|
11
|
+
# NOTE: Multiple assignment (+a, b = ...+) is only partially modelled. Each target is
|
|
12
|
+
# surfaced as its own AssignmentDeclaration with a correct {#name}, but {#value} is +nil+:
|
|
13
|
+
# in the AST the right-hand side lives on the enclosing +masgn+ node, not on the per-target
|
|
14
|
+
# +lvasgn+, and which value each variable receives generally cannot be known statically
|
|
15
|
+
# (e.g. +a, b = build_pair+). If a rule ever needs to trace destructured assignments, model
|
|
16
|
+
# the shared source explicitly (a +multiple_assignment?+ predicate + +shared_source+) rather
|
|
17
|
+
# than attributing the shared right-hand side to each variable's {#value}.
|
|
18
|
+
#
|
|
19
|
+
class AssignmentDeclaration
|
|
20
|
+
include Rubyzen::Providers::FilePathProvider
|
|
21
|
+
include Rubyzen::Providers::LineNumberProvider
|
|
22
|
+
include Rubyzen::Providers::ClassNameProvider
|
|
23
|
+
include Rubyzen::Providers::SourceCodeProvider
|
|
24
|
+
|
|
25
|
+
# @return [RuboCop::AST::Node]
|
|
26
|
+
attr_reader :node
|
|
27
|
+
|
|
28
|
+
# @return [MethodDeclaration, BlockDeclaration]
|
|
29
|
+
attr_reader :parent
|
|
30
|
+
|
|
31
|
+
# @param node [RuboCop::AST::Node] the +lvasgn+ node
|
|
32
|
+
# @param parent [MethodDeclaration, BlockDeclaration] the enclosing declaration
|
|
33
|
+
def initialize(node, parent)
|
|
34
|
+
@node = node
|
|
35
|
+
@parent = parent
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns the name of the assigned local variable.
|
|
39
|
+
#
|
|
40
|
+
# @return [String] e.g. +"x"+
|
|
41
|
+
def name
|
|
42
|
+
node.children.first.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns the assigned value as an expression, or +nil+ when there is no value
|
|
46
|
+
# node (e.g. the per-variable targets of a multiple assignment, +a, b = foo+).
|
|
47
|
+
#
|
|
48
|
+
# @return [ExpressionDeclaration, nil]
|
|
49
|
+
def value
|
|
50
|
+
value_node = node.children[1]
|
|
51
|
+
return nil if value_node.nil?
|
|
52
|
+
|
|
53
|
+
ExpressionDeclaration.new(value_node, self)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -17,6 +17,8 @@ module Rubyzen
|
|
|
17
17
|
include Rubyzen::Providers::RaisesProvider
|
|
18
18
|
include Rubyzen::Providers::SourceCodeProvider
|
|
19
19
|
include Rubyzen::Providers::CallSiteProvider
|
|
20
|
+
include Rubyzen::Providers::ReturnsProvider
|
|
21
|
+
include Rubyzen::Providers::AssignmentsProvider
|
|
20
22
|
|
|
21
23
|
# @return [RuboCop::AST::Node]
|
|
22
24
|
attr_reader :node
|
|
@@ -13,6 +13,8 @@ module Rubyzen
|
|
|
13
13
|
include Rubyzen::Providers::LineNumberProvider
|
|
14
14
|
include Rubyzen::Providers::ClassNameProvider
|
|
15
15
|
include Rubyzen::Providers::SourceCodeProvider
|
|
16
|
+
include Rubyzen::Providers::ArgumentsProvider
|
|
17
|
+
include Rubyzen::Providers::EnclosingBlocksProvider
|
|
16
18
|
|
|
17
19
|
# @return [RuboCop::AST::Node]
|
|
18
20
|
attr_reader :node
|
|
@@ -41,6 +43,18 @@ module Rubyzen
|
|
|
41
43
|
node.receiver&.type == :const ? node.receiver.const_name : nil
|
|
42
44
|
end
|
|
43
45
|
|
|
46
|
+
# Returns the receiver as an expression, or +nil+ for a receiverless call (e.g. +save+).
|
|
47
|
+
#
|
|
48
|
+
# Unlike {#receiver} (which returns a constant-name String), this models the receiver
|
|
49
|
+
# structurally — constant, constructor, or local variable.
|
|
50
|
+
#
|
|
51
|
+
# @return [Rubyzen::Declarations::ExpressionDeclaration, nil]
|
|
52
|
+
def receiver_expression
|
|
53
|
+
return nil if node.receiver.nil?
|
|
54
|
+
|
|
55
|
+
ExpressionDeclaration.new(node.receiver, self)
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
# Returns the called method name.
|
|
45
59
|
#
|
|
46
60
|
# @return [String]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Declarations
|
|
3
|
+
# Represents an arbitrary Ruby value-expression node — the value a method returns,
|
|
4
|
+
# the receiver of a call, a positional argument, the value of an assignment, and so on.
|
|
5
|
+
# Wraps any AST node and exposes its "kind" through predicates, so rules can ask
|
|
6
|
+
# structural questions without touching the raw AST.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# expr = call_site.receiver_expression
|
|
10
|
+
# expr.constructor? #=> true (for Repos::Foo.new.bar)
|
|
11
|
+
# expr.constant_name #=> "Repos::Foo"
|
|
12
|
+
#
|
|
13
|
+
class ExpressionDeclaration
|
|
14
|
+
include Rubyzen::Providers::FilePathProvider
|
|
15
|
+
include Rubyzen::Providers::LineNumberProvider
|
|
16
|
+
include Rubyzen::Providers::ClassNameProvider
|
|
17
|
+
include Rubyzen::Providers::SourceCodeProvider
|
|
18
|
+
|
|
19
|
+
# @return [RuboCop::AST::Node]
|
|
20
|
+
attr_reader :node
|
|
21
|
+
|
|
22
|
+
# @return [Object] the declaration that produced this expression
|
|
23
|
+
attr_reader :parent
|
|
24
|
+
|
|
25
|
+
# @param node [RuboCop::AST::Node] the value-expression node
|
|
26
|
+
# @param parent [Object] the declaration that produced this expression
|
|
27
|
+
def initialize(node, parent)
|
|
28
|
+
@node = node
|
|
29
|
+
@parent = parent
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns a short identifier: the constant, variable, or method name, falling
|
|
33
|
+
# back to the node type.
|
|
34
|
+
#
|
|
35
|
+
# @return [String]
|
|
36
|
+
def name
|
|
37
|
+
constant_name || local_variable_name || (method_call? ? method_name : node.type.to_s)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [Boolean] true if the expression is a bare constant, e.g. +Repos::Foo+
|
|
41
|
+
def constant?
|
|
42
|
+
node.const_type?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Boolean] true if the expression references a local variable
|
|
46
|
+
def local_variable?
|
|
47
|
+
node.lvar_type?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return [Boolean] true if the expression is a method call (a +send+ node)
|
|
51
|
+
def method_call?
|
|
52
|
+
node.send_type?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return [Boolean] true if the expression is a constructor call, e.g. +Repos::Foo.new+
|
|
56
|
+
def constructor?
|
|
57
|
+
method_call? && node.method_name == :new
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Boolean] true if the expression is a braced Hash literal with at least one pair
|
|
61
|
+
def hash_literal?
|
|
62
|
+
node.hash_type? && node.braces? && node.pairs.any?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Boolean] true if the expression is a symbol literal
|
|
66
|
+
def symbol?
|
|
67
|
+
node.sym_type?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [Boolean] true if the expression is a string literal
|
|
71
|
+
def string?
|
|
72
|
+
node.str_type?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Returns the constant name when the expression is a constant or constructs from one.
|
|
76
|
+
#
|
|
77
|
+
# @return [String, nil] e.g. +"Repos::Foo"+ for both +Repos::Foo+ and +Repos::Foo.new+
|
|
78
|
+
def constant_name
|
|
79
|
+
return node.const_name if constant?
|
|
80
|
+
return node.receiver.const_name if constructor? && node.receiver&.const_type?
|
|
81
|
+
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns the called method name when the expression is a method call.
|
|
86
|
+
#
|
|
87
|
+
# @return [String, nil]
|
|
88
|
+
def method_name
|
|
89
|
+
node.method_name.to_s if method_call?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def local_variable_name
|
|
95
|
+
node.children.first.to_s if local_variable?
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -21,6 +21,8 @@ module Rubyzen
|
|
|
21
21
|
include Rubyzen::Providers::VisibilityProvider
|
|
22
22
|
include Rubyzen::Providers::RescuesProvider
|
|
23
23
|
include Rubyzen::Providers::RaisesProvider
|
|
24
|
+
include Rubyzen::Providers::ReturnsProvider
|
|
25
|
+
include Rubyzen::Providers::AssignmentsProvider
|
|
24
26
|
|
|
25
27
|
# @return [RuboCop::AST::Node]
|
|
26
28
|
attr_reader :node
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Declarations
|
|
3
|
+
# Represents a single point at which a method or block yields a value: the
|
|
4
|
+
# implicit final expression of its body, or an explicit +return+ statement.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# ret = method.returns.first
|
|
8
|
+
# ret.explicit? #=> false
|
|
9
|
+
# ret.expression.hash_literal? #=> true
|
|
10
|
+
#
|
|
11
|
+
class ReturnDeclaration
|
|
12
|
+
include Rubyzen::Providers::FilePathProvider
|
|
13
|
+
include Rubyzen::Providers::LineNumberProvider
|
|
14
|
+
include Rubyzen::Providers::ClassNameProvider
|
|
15
|
+
include Rubyzen::Providers::SourceCodeProvider
|
|
16
|
+
|
|
17
|
+
# @return [RuboCop::AST::Node] the +return+ node, or the implicit final-expression node
|
|
18
|
+
attr_reader :node
|
|
19
|
+
|
|
20
|
+
# @return [MethodDeclaration, BlockDeclaration] the declaration that returns this value
|
|
21
|
+
attr_reader :parent
|
|
22
|
+
|
|
23
|
+
# @param node [RuboCop::AST::Node] the +return+ node, or the implicit final-expression node
|
|
24
|
+
# @param parent [MethodDeclaration, BlockDeclaration] the enclosing declaration
|
|
25
|
+
def initialize(node, parent)
|
|
26
|
+
@node = node
|
|
27
|
+
@parent = parent
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Boolean] true if this is an explicit +return+ statement
|
|
31
|
+
def explicit?
|
|
32
|
+
node.return_type?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Boolean] true if this is the implicit final expression of the body
|
|
36
|
+
def implicit?
|
|
37
|
+
!explicit?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The value expression being returned.
|
|
41
|
+
#
|
|
42
|
+
# @return [ExpressionDeclaration, nil] +nil+ for a bare +return+ with no value
|
|
43
|
+
def expression
|
|
44
|
+
value_node = explicit? ? node.children.first : node
|
|
45
|
+
return nil if value_node.nil?
|
|
46
|
+
|
|
47
|
+
ExpressionDeclaration.new(value_node, self)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Providers
|
|
3
|
+
# Provides the arguments passed at a call site (or macro), as expressions.
|
|
4
|
+
module ArgumentsProvider
|
|
5
|
+
# @return [Rubyzen::Collections::ArgumentsCollection]
|
|
6
|
+
def arguments
|
|
7
|
+
Collections::ArgumentsCollection.new(
|
|
8
|
+
node.arguments.map do |argument_node|
|
|
9
|
+
Declarations::ExpressionDeclaration.new(argument_node, self)
|
|
10
|
+
end
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Providers
|
|
3
|
+
# Provides local-variable assignments within a method or block.
|
|
4
|
+
module AssignmentsProvider
|
|
5
|
+
# @return [Rubyzen::Collections::AssignmentsCollection]
|
|
6
|
+
def assignments
|
|
7
|
+
Collections::AssignmentsCollection.new(
|
|
8
|
+
node.each_descendant(:lvasgn).map do |assignment_node|
|
|
9
|
+
Declarations::AssignmentDeclaration.new(assignment_node, self)
|
|
10
|
+
end
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Providers
|
|
3
|
+
# Provides the chain of blocks (do..end / { }) that lexically enclose a declaration,
|
|
4
|
+
# innermost first.
|
|
5
|
+
module EnclosingBlocksProvider
|
|
6
|
+
# @return [Rubyzen::Collections::BlocksCollection]
|
|
7
|
+
def enclosing_blocks
|
|
8
|
+
Collections::BlocksCollection.new(
|
|
9
|
+
node.each_ancestor(:block).map do |block_node|
|
|
10
|
+
Declarations::BlockDeclaration.new(block_node, parent)
|
|
11
|
+
end
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Rubyzen
|
|
2
|
+
module Providers
|
|
3
|
+
# Provides the points at which a method or block yields a value: the implicit final
|
|
4
|
+
# expression of its body, plus every explicit +return+. Each is wrapped in a
|
|
5
|
+
# {Rubyzen::Declarations::ReturnDeclaration}, which knows how to extract its own value.
|
|
6
|
+
module ReturnsProvider
|
|
7
|
+
# @return [Rubyzen::Collections::ReturnsCollection]
|
|
8
|
+
def returns
|
|
9
|
+
Collections::ReturnsCollection.new(
|
|
10
|
+
return_nodes.map do |return_node|
|
|
11
|
+
Declarations::ReturnDeclaration.new(return_node, self)
|
|
12
|
+
end
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The value-expression(s) this method or block evaluates to, as a flat collection.
|
|
17
|
+
# A shortcut for +returns.expressions+.
|
|
18
|
+
#
|
|
19
|
+
# @return [Rubyzen::Collections::ExpressionsCollection]
|
|
20
|
+
def return_expressions
|
|
21
|
+
returns.expressions
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# The return points to wrap: the implicit final expression of the body (unless it is
|
|
27
|
+
# itself an explicit +return+, which is collected separately to avoid double-counting),
|
|
28
|
+
# followed by every explicit +return+.
|
|
29
|
+
def return_nodes
|
|
30
|
+
nodes = []
|
|
31
|
+
final = implicit_final_node
|
|
32
|
+
nodes << final unless final.nil?
|
|
33
|
+
node.each_descendant(:return) { |return_node| nodes << return_node }
|
|
34
|
+
nodes
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The node a body implicitly evaluates to: the last statement of a multi-statement
|
|
38
|
+
# body (+begin+) or an explicit +begin..end+ (+kwbegin+), otherwise the body itself.
|
|
39
|
+
# Returns +nil+ when that node is an explicit +return+ (collected separately).
|
|
40
|
+
def implicit_final_node
|
|
41
|
+
body = node.body
|
|
42
|
+
return nil if body.nil?
|
|
43
|
+
|
|
44
|
+
final = body.begin_type? || body.kwbegin_type? ? body.children.last : body
|
|
45
|
+
final unless final.return_type?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/rubyzen/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyzen-lint
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Perry Street Software
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubocop-ast
|
|
@@ -90,7 +90,7 @@ description: Rubyzen is a modern linter for Ruby that allows you to write archit
|
|
|
90
90
|
lint rules as unit tests. In the era of AI-generated code, it provides your team
|
|
91
91
|
with deterministic guardrails to keep your codebase clean, maintainable, and consistent
|
|
92
92
|
as it grows.
|
|
93
|
-
email:
|
|
93
|
+
email:
|
|
94
94
|
executables: []
|
|
95
95
|
extensions: []
|
|
96
96
|
extra_rdoc_files: []
|
|
@@ -105,6 +105,8 @@ files:
|
|
|
105
105
|
- lib/rubyzen/assertions/assert_zen_true.rb
|
|
106
106
|
- lib/rubyzen/assertions/zen_assertions.rb
|
|
107
107
|
- lib/rubyzen/cache/parse_cache.rb
|
|
108
|
+
- lib/rubyzen/collections/arguments_collection.rb
|
|
109
|
+
- lib/rubyzen/collections/assignments_collection.rb
|
|
108
110
|
- lib/rubyzen/collections/attributes_collection.rb
|
|
109
111
|
- lib/rubyzen/collections/base_collection.rb
|
|
110
112
|
- lib/rubyzen/collections/blocks_collection.rb
|
|
@@ -112,6 +114,7 @@ files:
|
|
|
112
114
|
- lib/rubyzen/collections/classes_collection.rb
|
|
113
115
|
- lib/rubyzen/collections/constants_collection.rb
|
|
114
116
|
- lib/rubyzen/collections/declaration_collection.rb
|
|
117
|
+
- lib/rubyzen/collections/expressions_collection.rb
|
|
115
118
|
- lib/rubyzen/collections/file_collection.rb
|
|
116
119
|
- lib/rubyzen/collections/macros_collection.rb
|
|
117
120
|
- lib/rubyzen/collections/methods_collection.rb
|
|
@@ -120,12 +123,15 @@ files:
|
|
|
120
123
|
- lib/rubyzen/collections/raises_collection.rb
|
|
121
124
|
- lib/rubyzen/collections/requires_collection.rb
|
|
122
125
|
- lib/rubyzen/collections/rescues_collection.rb
|
|
126
|
+
- lib/rubyzen/collections/returns_collection.rb
|
|
123
127
|
- lib/rubyzen/core.rb
|
|
128
|
+
- lib/rubyzen/declarations/assignment_declaration.rb
|
|
124
129
|
- lib/rubyzen/declarations/attribute_declaration.rb
|
|
125
130
|
- lib/rubyzen/declarations/block_declaration.rb
|
|
126
131
|
- lib/rubyzen/declarations/call_site_declaration.rb
|
|
127
132
|
- lib/rubyzen/declarations/class_declaration.rb
|
|
128
133
|
- lib/rubyzen/declarations/constant_declaration.rb
|
|
134
|
+
- lib/rubyzen/declarations/expression_declaration.rb
|
|
129
135
|
- lib/rubyzen/declarations/file_declaration.rb
|
|
130
136
|
- lib/rubyzen/declarations/if_statement_declaration.rb
|
|
131
137
|
- lib/rubyzen/declarations/macro_declaration.rb
|
|
@@ -135,6 +141,7 @@ files:
|
|
|
135
141
|
- lib/rubyzen/declarations/raise_declaration.rb
|
|
136
142
|
- lib/rubyzen/declarations/require_declaration.rb
|
|
137
143
|
- lib/rubyzen/declarations/rescue_declaration.rb
|
|
144
|
+
- lib/rubyzen/declarations/return_declaration.rb
|
|
138
145
|
- lib/rubyzen/expectation_helpers.rb
|
|
139
146
|
- lib/rubyzen/lint.rb
|
|
140
147
|
- lib/rubyzen/matchers/zen_empty_matcher.rb
|
|
@@ -143,12 +150,15 @@ files:
|
|
|
143
150
|
- lib/rubyzen/minitest.rb
|
|
144
151
|
- lib/rubyzen/parsers/a_s_t_parser.rb
|
|
145
152
|
- lib/rubyzen/project.rb
|
|
153
|
+
- lib/rubyzen/providers/arguments_provider.rb
|
|
154
|
+
- lib/rubyzen/providers/assignments_provider.rb
|
|
146
155
|
- lib/rubyzen/providers/attributes_provider.rb
|
|
147
156
|
- lib/rubyzen/providers/blocks_provider.rb
|
|
148
157
|
- lib/rubyzen/providers/call_site_provider.rb
|
|
149
158
|
- lib/rubyzen/providers/class_name_provider.rb
|
|
150
159
|
- lib/rubyzen/providers/collection_filter_provider.rb
|
|
151
160
|
- lib/rubyzen/providers/constants_provider.rb
|
|
161
|
+
- lib/rubyzen/providers/enclosing_blocks_provider.rb
|
|
152
162
|
- lib/rubyzen/providers/file_path_provider.rb
|
|
153
163
|
- lib/rubyzen/providers/if_statements_provider.rb
|
|
154
164
|
- lib/rubyzen/providers/line_number_provider.rb
|
|
@@ -157,6 +167,7 @@ files:
|
|
|
157
167
|
- lib/rubyzen/providers/raises_provider.rb
|
|
158
168
|
- lib/rubyzen/providers/requires_provider.rb
|
|
159
169
|
- lib/rubyzen/providers/rescues_provider.rb
|
|
170
|
+
- lib/rubyzen/providers/returns_provider.rb
|
|
160
171
|
- lib/rubyzen/providers/source_code_provider.rb
|
|
161
172
|
- lib/rubyzen/providers/visibility_provider.rb
|
|
162
173
|
- lib/rubyzen/rspec.rb
|
|
@@ -170,7 +181,7 @@ metadata:
|
|
|
170
181
|
bug_tracker_uri: https://github.com/perrystreetsoftware/Rubyzen/issues
|
|
171
182
|
documentation_uri: https://perrystreetsoftware.github.io/Rubyzen
|
|
172
183
|
changelog_uri: https://github.com/perrystreetsoftware/Rubyzen/blob/main/CHANGELOG.md
|
|
173
|
-
post_install_message:
|
|
184
|
+
post_install_message:
|
|
174
185
|
rdoc_options: []
|
|
175
186
|
require_paths:
|
|
176
187
|
- lib
|
|
@@ -185,8 +196,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
185
196
|
- !ruby/object:Gem::Version
|
|
186
197
|
version: '0'
|
|
187
198
|
requirements: []
|
|
188
|
-
rubygems_version: 3.
|
|
189
|
-
signing_key:
|
|
199
|
+
rubygems_version: 3.5.22
|
|
200
|
+
signing_key:
|
|
190
201
|
specification_version: 4
|
|
191
202
|
summary: Architectural linter for Ruby — write lint rules as unit tests
|
|
192
203
|
test_files: []
|