rubocop_spinel 0.1.0 → 0.2.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/.justfile +2 -1
- data/AGENTS.md +1 -0
- data/README.md +10 -4
- data/lib/rubocop/cop/spinel/unsupported.rb +86 -4
- data/lib/rubocop/spinel/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cb90d1e8bfc12fb703fdade6e8b05a163c5740166faaf0ebfee8ead533d5657d
|
|
4
|
+
data.tar.gz: 9fd52ef2c11aefb539f86884930d77953f153d071513d54e231a47ab6d791724
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 32ff355cd84068325e7ae7aad49c4512c95539cab59d9d7bf6f346797d5ab1040681d432742a67c1436de4d600adde44f9f6edbe98c7927d52d4bef0bae7e022
|
|
7
|
+
data.tar.gz: b730ed44bd08d28dc7e1ceedd10498aaef9c633f5a676d29c13c7e72e4c57ecb1d50c8c79df300600cd389e5f0ecb3172c9b0d39d3b8b0f010e0b76300b83a71
|
data/.justfile
CHANGED
|
@@ -22,7 +22,8 @@ test:
|
|
|
22
22
|
rake test
|
|
23
23
|
|
|
24
24
|
test-spinel:
|
|
25
|
-
bundle exec rubocop -r ./lib/rubocop_spinel --only Spinel/Unsupported
|
|
25
|
+
bundle exec rubocop -c test/test_spinel.yml -r ./lib/rubocop_spinel --only Spinel/Unsupported \
|
|
26
|
+
../spinel/test ../spinel/benchmark/bm_send_bmethod.rb ../spinel/spinel_codegen.rb
|
|
26
27
|
|
|
27
28
|
test-watch *ARGS:
|
|
28
29
|
watchexec --stop-timeout=0 --clear clear just test "{{ARGS}}"
|
data/AGENTS.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
- After changes, run `just check`
|
|
8
8
|
- Use `just fmt` / `just lint`, not rubocop or prettier directly
|
|
9
9
|
- Keep commit messages under 80 chars
|
|
10
|
+
- PR titles/bodies: super succinct, 1-2 short sentences or 1-2 bullets max
|
|
10
11
|
- Fail fast; don't be overly defensive
|
|
11
12
|
|
|
12
13
|
## Layout
|
data/README.md
CHANGED
|
@@ -36,12 +36,18 @@ class << self ...
|
|
|
36
36
|
sample.rb:9:1: C: Spinel/Unsupported: Spinel does not support threads or mutexes.
|
|
37
37
|
Thread.new { puts Example.bad }
|
|
38
38
|
^^^^^^
|
|
39
|
-
|
|
39
|
+
```
|
|
40
40
|
|
|
41
41
|
## Changelog
|
|
42
42
|
|
|
43
|
-
#### 0.0
|
|
43
|
+
#### 0.2.0 (May '26)
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
- allow `recv.instance_eval { ... }` ([Spinel #15](https://github.com/matz/spinel/pull/15))
|
|
46
|
+
- allow `def m(&block); instance_eval(&block); end` ([Spinel #124](https://github.com/matz/spinel/pull/124))
|
|
47
|
+
- allow static `define_method(:name) { ... }` ([Spinel 26e6aae](https://github.com/matz/spinel/commit/26e6aae))
|
|
48
|
+
- allow no-argument `module_function` in module bodies ([Spinel #295](https://github.com/matz/spinel/pull/295))
|
|
49
|
+
- allow module singleton accessors ([Spinel #126](https://github.com/matz/spinel/issues/126))
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
#### 0.1.0 (Apr '26)
|
|
52
|
+
|
|
53
|
+
- first release
|
|
@@ -7,23 +7,23 @@ module RuboCop
|
|
|
7
7
|
BANNED_METHODS = %i[
|
|
8
8
|
class_eval
|
|
9
9
|
const_get
|
|
10
|
-
define_method
|
|
11
10
|
define_singleton_method
|
|
12
11
|
eval
|
|
13
12
|
extend
|
|
14
|
-
instance_eval
|
|
15
13
|
method_missing
|
|
16
14
|
module_eval
|
|
17
|
-
module_function
|
|
18
15
|
public_send
|
|
19
16
|
remove_method
|
|
20
17
|
singleton_method
|
|
21
18
|
undef_method
|
|
22
19
|
].freeze
|
|
23
|
-
RESTRICT_ON_SEND = (BANNED_METHODS + %i[prepend send]).freeze
|
|
20
|
+
RESTRICT_ON_SEND = (BANNED_METHODS + %i[define_method instance_eval module_function prepend send]).freeze
|
|
24
21
|
TOP_LEVEL_CONSTS = %i[Mutex Thread].freeze
|
|
25
22
|
|
|
26
23
|
def on_send(node)
|
|
24
|
+
return handle_define_method(node) if node.method_name == :define_method
|
|
25
|
+
return handle_instance_eval(node) if node.method_name == :instance_eval
|
|
26
|
+
return handle_module_function(node) if node.method_name == :module_function
|
|
27
27
|
# `prepend` is only unsupported as a module/class feature.
|
|
28
28
|
return handle_prepend(node) if node.method_name == :prepend
|
|
29
29
|
return if allowed_send?(node)
|
|
@@ -40,11 +40,31 @@ module RuboCop
|
|
|
40
40
|
|
|
41
41
|
# `class << self` compiles in Spinel but does not work correctly.
|
|
42
42
|
def on_sclass(node)
|
|
43
|
+
return if supported_singleton_accessor?(node)
|
|
44
|
+
|
|
43
45
|
add_offense(node, message: "Spinel does not support singleton classes.")
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
private
|
|
47
49
|
|
|
50
|
+
def handle_define_method(node)
|
|
51
|
+
return if supported_define_method?(node)
|
|
52
|
+
|
|
53
|
+
add_offense(node.loc.selector, message: message_for(:define_method))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def handle_instance_eval(node)
|
|
57
|
+
return if supported_instance_eval?(node)
|
|
58
|
+
|
|
59
|
+
add_offense(node.loc.selector, message: message_for(:instance_eval))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def handle_module_function(node)
|
|
63
|
+
return if supported_module_function?(node)
|
|
64
|
+
|
|
65
|
+
add_offense(node.loc.selector, message: message_for(:module_function))
|
|
66
|
+
end
|
|
67
|
+
|
|
48
68
|
# Spinel rewrites receiver-style `obj.send(:name)` during parsing.
|
|
49
69
|
def allowed_send?(node)
|
|
50
70
|
node.method_name == :send && node.receiver && node.first_argument&.sym_type?
|
|
@@ -61,6 +81,68 @@ module RuboCop
|
|
|
61
81
|
node.method_name == :prepend && node.receiver.nil?
|
|
62
82
|
end
|
|
63
83
|
|
|
84
|
+
def supported_define_method?(node)
|
|
85
|
+
node.receiver.nil? && node.block_node && node.arguments.one? && node.first_argument&.sym_type?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def supported_module_function?(node)
|
|
89
|
+
node.receiver.nil? && !node.arguments? && module_body?(node)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def module_body?(node)
|
|
93
|
+
singleton_owner(node)&.module_type?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Spinel supports `recv.instance_eval { ... }` and the exact
|
|
97
|
+
# `def m(&block); instance_eval(&block); end` trampoline shape.
|
|
98
|
+
def supported_instance_eval?(node)
|
|
99
|
+
supported_instance_eval_block?(node) || supported_instance_eval_trampoline?(node)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def supported_instance_eval_block?(node)
|
|
103
|
+
node.receiver && node.block_node && !node.arguments?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def supported_instance_eval_trampoline?(node)
|
|
107
|
+
return false unless node.receiver.nil? && node.arguments.one?
|
|
108
|
+
|
|
109
|
+
block_pass = node.first_argument
|
|
110
|
+
return false unless block_pass&.block_pass_type?
|
|
111
|
+
|
|
112
|
+
forwarded = block_pass.children.first
|
|
113
|
+
return false unless forwarded&.lvar_type?
|
|
114
|
+
|
|
115
|
+
method_def = node.each_ancestor(:def, :defs).first
|
|
116
|
+
return false unless method_def&.body == node
|
|
117
|
+
|
|
118
|
+
block_arg = method_def.arguments.children.first
|
|
119
|
+
return false unless method_def.arguments.children.one? && block_arg&.blockarg_type?
|
|
120
|
+
|
|
121
|
+
forwarded.children.first == block_arg.children.first
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def supported_singleton_accessor?(node)
|
|
125
|
+
return false unless node.children.first&.self_type?
|
|
126
|
+
return false unless singleton_owner(node)&.module_type?
|
|
127
|
+
|
|
128
|
+
singleton_body(node).all? { supported_singleton_accessor_call?(_1) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def singleton_owner(node)
|
|
132
|
+
node.each_ancestor.find { _1.class_type? || _1.module_type? }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def singleton_body(node)
|
|
136
|
+
return [] unless node.body
|
|
137
|
+
|
|
138
|
+
node.body.begin_type? ? node.body.children : [node.body]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def supported_singleton_accessor_call?(node)
|
|
142
|
+
node.send_type? && node.receiver.nil? && node.method?(:attr_accessor) &&
|
|
143
|
+
node.arguments.all?(&:sym_type?)
|
|
144
|
+
end
|
|
145
|
+
|
|
64
146
|
def top_level_const?(node)
|
|
65
147
|
node.namespace.nil? || node.namespace.cbase_type?
|
|
66
148
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop_spinel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- gurgeous
|
|
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: '0'
|
|
90
90
|
requirements: []
|
|
91
|
-
rubygems_version:
|
|
91
|
+
rubygems_version: 4.0.6
|
|
92
92
|
specification_version: 4
|
|
93
93
|
summary: Custom RuboCop cops for Spinel compatibility.
|
|
94
94
|
test_files: []
|