aye_var 0.1.0 → 0.1.1
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/README.md +13 -5
- data/lib/aye_var/version.rb +1 -1
- data/lib/aye_var.rb +116 -28
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e1eb735e2846d27610ccd41568c9022de487d62ccbf2c9d212af0019c72e1c9
|
4
|
+
data.tar.gz: 0ceb88f7fe73970d8c7c47d15671ecc2fc8350a8c05e29eed55d4ce6935828bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac42f044cd02865cd63d7194b76bbe5111da98bbdf9286ebc1975ff460bad95c22a6070c29238a2c2fa6ffdca2597f8f28aad1e0dfd7a3235c6051e635d16fc1
|
7
|
+
data.tar.gz: 52673c9d24958003fc168ddf02075332aac4d3275c70e73d0d3d86aca54aa6bc17ae2226cbb0c75df8d5537f0f3f208b0ce980c49b3f23160cdab75440f56ee9
|
data/README.md
CHANGED
@@ -1,14 +1,22 @@
|
|
1
|
-
|
1
|
+
# AyeVar 🏴☠️
|
2
2
|
|
3
|
-
|
3
|
+
Arrr, this gem be mighty fresh an’ experimental, me hearties! Th’ API be likely to shift with th’ tides.
|
4
4
|
|
5
|
-
|
5
|
+
## What does it do?
|
6
|
+
|
7
|
+
It prevents ye from usin’ undefined instance variables by transformin’ yer code as it be loaded, savvy?
|
8
|
+
|
9
|
+
Instance variables must be declared in yer object’s initializer (even if they be initially set to `nil`). Only then can ye access ’em in th’ rest o’ yer code, ye scurvy dog!
|
10
|
+
|
11
|
+
## Setup
|
12
|
+
|
13
|
+
Add this treasure to yer gemfile, arr!
|
6
14
|
|
7
15
|
```ruby
|
8
16
|
gem "aye_var", require: false
|
9
17
|
```
|
10
18
|
|
11
|
-
Then require
|
19
|
+
Then require an’ initialize it in yer vessel as early as possible, ye hear? If ye be usin’ Bootsnap, it should be right after Bootsnap, or I’ll make ye walk th’ plank!
|
12
20
|
|
13
21
|
```ruby
|
14
22
|
require "aye_var"
|
@@ -16,4 +24,4 @@ require "aye_var"
|
|
16
24
|
AyeVar.init(include: ["#{Dir.pwd}/**/*"])
|
17
25
|
```
|
18
26
|
|
19
|
-
|
27
|
+
Ye can pass in an array o’ globs to `include:` an’ `exclude:`, ye bilge rat!
|
data/lib/aye_var/version.rb
CHANGED
data/lib/aye_var.rb
CHANGED
@@ -1,77 +1,165 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "require-hooks/setup"
|
4
|
+
require "prism"
|
4
5
|
|
5
6
|
module AyeVar
|
7
|
+
METHODS_PERMITTED_FOR_DEFINITION = Set[:initialize, :setup].freeze
|
8
|
+
|
9
|
+
NameError = Class.new(::NameError)
|
10
|
+
|
11
|
+
def self.init(include: [], exclude: [])
|
12
|
+
RequireHooks.source_transform(patterns: include, exclude_patterns: exclude) do |path, source|
|
13
|
+
source ||= File.read(path)
|
14
|
+
Processor.call(source)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
class Processor < Prism::Visitor
|
7
19
|
def self.call(source)
|
8
|
-
|
9
|
-
|
20
|
+
visitor = new
|
21
|
+
visitor.visit(Prism.parse(source).value)
|
10
22
|
|
11
23
|
buffer = source.dup
|
12
24
|
|
13
|
-
|
25
|
+
visitor.annotations.sort_by(&:first).reverse_each do |offset, action, name|
|
14
26
|
case action
|
15
27
|
when :start
|
16
28
|
buffer.insert(offset, "((raise ::AyeVar::NameError.new('Undefined instance variable #{name}') unless defined?(#{name}));")
|
17
29
|
when :end
|
18
30
|
buffer.insert(offset, ")")
|
31
|
+
else
|
32
|
+
raise "Invalid annotation"
|
19
33
|
end
|
20
34
|
end
|
21
35
|
|
22
36
|
buffer
|
23
37
|
end
|
24
38
|
|
25
|
-
def initialize
|
26
|
-
@
|
27
|
-
@
|
39
|
+
def initialize
|
40
|
+
@definition_context = true
|
41
|
+
@this = nil
|
42
|
+
@context = nil
|
43
|
+
@annotations = []
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :annotations
|
47
|
+
|
48
|
+
def visit_class_node(node)
|
49
|
+
new_context(node) { super }
|
50
|
+
end
|
51
|
+
|
52
|
+
def visit_module_node(node)
|
53
|
+
new_context(node) { super }
|
28
54
|
end
|
29
55
|
|
30
|
-
|
56
|
+
def visit_block_node(node)
|
57
|
+
new_context(node) { super }
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_singleton_class_node(node)
|
61
|
+
new_context(node) { super }
|
62
|
+
end
|
31
63
|
|
32
64
|
def visit_def_node(node)
|
33
|
-
|
34
|
-
|
35
|
-
|
65
|
+
parent = @this
|
66
|
+
|
67
|
+
new_context(node) do
|
68
|
+
if METHODS_PERMITTED_FOR_DEFINITION.include?(node.name) || Prism::SelfNode === node.receiver || !(Prism::ClassNode === parent)
|
36
69
|
super
|
37
|
-
|
38
|
-
|
70
|
+
else
|
71
|
+
prevent_definitions { super }
|
39
72
|
end
|
40
|
-
else
|
41
|
-
super
|
42
73
|
end
|
43
74
|
end
|
44
75
|
|
76
|
+
def visit_if_node(node)
|
77
|
+
visit(node.predicate)
|
78
|
+
|
79
|
+
branch { visit(node.statements) }
|
80
|
+
branch { visit(node.subsequent) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def visit_case_node(node)
|
84
|
+
visit(node.predicate)
|
85
|
+
|
86
|
+
node.conditions.each do |condition|
|
87
|
+
branch { visit(condition) }
|
88
|
+
end
|
89
|
+
|
90
|
+
branch { visit(node.else_clause) }
|
91
|
+
end
|
92
|
+
|
45
93
|
def visit_instance_variable_read_node(node)
|
46
|
-
location = node.location
|
47
94
|
name = node.name
|
48
95
|
|
49
|
-
|
50
|
-
|
96
|
+
unless context.include?(name)
|
97
|
+
location = node.location
|
98
|
+
|
99
|
+
context << name
|
100
|
+
|
101
|
+
@annotations << [location.start_character_offset, :start, name]
|
102
|
+
@annotations << [location.end_character_offset, :end, name]
|
103
|
+
end
|
104
|
+
|
51
105
|
super
|
52
106
|
end
|
53
107
|
|
54
108
|
def visit_instance_variable_write_node(node)
|
55
|
-
|
109
|
+
name = node.name
|
110
|
+
|
111
|
+
unless @definition_context || context.include?(name)
|
56
112
|
location = node.location
|
57
|
-
name = node.name
|
58
113
|
|
59
|
-
|
60
|
-
|
114
|
+
context << name
|
115
|
+
|
116
|
+
@annotations << [location.start_character_offset, :start, name]
|
117
|
+
@annotations << [location.end_character_offset, :end, name]
|
61
118
|
end
|
62
119
|
|
63
120
|
super
|
64
121
|
end
|
65
|
-
end
|
66
122
|
|
67
|
-
|
123
|
+
private def new_context(this)
|
124
|
+
original_this = @this
|
125
|
+
original_context = @context
|
68
126
|
|
69
|
-
|
127
|
+
@this = this
|
128
|
+
@context = Set[]
|
70
129
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
130
|
+
begin
|
131
|
+
yield
|
132
|
+
ensure
|
133
|
+
@this = original_this
|
134
|
+
@context = original_context
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private def branch
|
139
|
+
original_context = @context
|
140
|
+
@context = original_context.dup
|
141
|
+
|
142
|
+
begin
|
143
|
+
yield
|
144
|
+
ensure
|
145
|
+
@context = original_context
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# The current context on the stack
|
150
|
+
private def context
|
151
|
+
@context
|
152
|
+
end
|
153
|
+
|
154
|
+
private def prevent_definitions
|
155
|
+
original_definition_context = @definition_context
|
156
|
+
|
157
|
+
begin
|
158
|
+
@definition_context = false
|
159
|
+
yield
|
160
|
+
ensure
|
161
|
+
@definition_context = original_definition_context
|
162
|
+
end
|
75
163
|
end
|
76
164
|
end
|
77
165
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aye_var
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
@@ -23,6 +23,20 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: prism
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
26
40
|
description: Raise an exception when using undefined instance variables.
|
27
41
|
email:
|
28
42
|
- joel@drapper.me
|