strict_ivars 0.4.1 → 0.5.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/README.md +46 -2
- data/lib/strict_ivars/configuration.rb +31 -0
- data/lib/strict_ivars/patch_eval.rb +84 -0
- data/lib/strict_ivars/version.rb +1 -1
- data/lib/strict_ivars.rb +9 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65516e69e17c893c02c57e0cc0be683c57c9dc3fd91b80f56942453d5df43649
|
4
|
+
data.tar.gz: 16d3c581474be1f5a7500eb24e442ac8bcd54f55ee5d7afef6cdea3ef986381f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b92fa82ca1acbcef116a5ab531bb1a4ec08301db0b17eb9d5f5a99af47c29face2c82a51d0f63b905eec0a7506e2453b040731848a69afff951f6f44b18e789e
|
7
|
+
data.tar.gz: b650231f2312548af22bd11ecc031dbdcbf178a5ce4f501b29f48687a59209a6533c12a4ef8fe78a351cc03e591bbd3e01c1edf67f03568620279b3990ab0e63
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Strict Ivars
|
2
2
|
|
3
|
-
Strict Ivars is a tiny pre-processor for Ruby that guards your instance variable reads, ensuring the instance variable is actually defined. This helps catch typos nice and early.
|
3
|
+
Strict Ivars is a tiny pre-processor for Ruby that guards your instance variable reads, ensuring the instance variable is actually defined. This helps catch typos nice and early. It‘s especially good when used with [Literal](https://literal.fun).
|
4
4
|
|
5
5
|
## How does it work?
|
6
6
|
|
@@ -26,6 +26,50 @@ The replacement happens on load, so you never see this in your source code. It
|
|
26
26
|
|
27
27
|
The real guard is a little uglier than this. It uses `::Kernel.raise` so it’s compatible with `BasicObject`. It also raises a `StrictIvars::NameError` with a helpful message mentioning the name of the instance variable, and that inherits from `NameError`, allowing you to rescue either `NameError` or `StrictIvars::NameError`.
|
28
28
|
|
29
|
+
**When you check defined already**
|
30
|
+
|
31
|
+
Within the same context (e.g. class definition, module definition, block, method), if you check `defined?`, Strict Ivars will not add a guard to reads of the checked instance variable.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
if defined?(@foo)
|
35
|
+
@foo
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
This applies even if the read is not in one of the conditional’s branches since you’ve indicated local awareness of the potential for this instance variable not being defined.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
if defined?(@foo)
|
43
|
+
# anything
|
44
|
+
end
|
45
|
+
|
46
|
+
@foo
|
47
|
+
```
|
48
|
+
|
49
|
+
**Writes:**
|
50
|
+
|
51
|
+
Strict Ivars doesn’t apply to writes, since these are considered the authoritative source of the instance variable definitions.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
@foo = 1
|
55
|
+
```
|
56
|
+
|
57
|
+
**Or-writes:**
|
58
|
+
|
59
|
+
This is considered a definition and not guarded.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
@foo ||= 1
|
63
|
+
```
|
64
|
+
|
65
|
+
**And-writes:**
|
66
|
+
|
67
|
+
This is considered a definition and not guarded.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
@foo &&= 1
|
71
|
+
```
|
72
|
+
|
29
73
|
## Setup
|
30
74
|
|
31
75
|
Install the gem by adding it to your `Gemfile` and running `bundle install`.
|
@@ -41,7 +85,7 @@ Now the gem is installed, you should require and initialize the gem as early as
|
|
41
85
|
```ruby
|
42
86
|
require "strict_ivars"
|
43
87
|
|
44
|
-
StrictIvars.init(include: ["#{Dir.pwd}/**/*"])
|
88
|
+
StrictIvars.init(include: ["#{Dir.pwd}/**/*"], exclude: ["#{Dir.pwd}/vendor/**/*"])
|
45
89
|
```
|
46
90
|
|
47
91
|
You can pass an array of globs to `include:` and `exclude:`.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class StrictIvars::Configuration
|
4
|
+
def initialize
|
5
|
+
@mutex = Mutex.new
|
6
|
+
@include = []
|
7
|
+
@exclude = []
|
8
|
+
end
|
9
|
+
|
10
|
+
#: (*String) -> void
|
11
|
+
def include(*patterns)
|
12
|
+
@mutex.synchronize do
|
13
|
+
@include.concat(patterns)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#: (*String) -> void
|
18
|
+
def exclude(*patterns)
|
19
|
+
@mutex.synchronize do
|
20
|
+
@exclude.concat(patterns)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#: (String) -> bool
|
25
|
+
def match(path)
|
26
|
+
path = File.absolute_path(path)
|
27
|
+
return false if @exclude.any? { |pattern| File.fnmatch?(pattern, path) }
|
28
|
+
return true if @include.any? { |pattern| File.fnmatch?(pattern, path) }
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StrictIvars
|
4
|
+
module ModuleEvalPatch
|
5
|
+
#: (String, ?String, ?Integer) -> void
|
6
|
+
#: () { () -> void } -> void
|
7
|
+
def class_eval(*args)
|
8
|
+
source, file, lineno = args
|
9
|
+
|
10
|
+
file ||= caller_locations(1, 1).first.path
|
11
|
+
|
12
|
+
if source && file && CONFIG.match(file)
|
13
|
+
args[0] = Processor.call(source)
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
#: (String, ?String, ?Integer) -> void
|
20
|
+
#: () { () -> void } -> void
|
21
|
+
def module_eval(*args)
|
22
|
+
source, file, lineno = args
|
23
|
+
|
24
|
+
file ||= caller_locations(1, 1).first.path
|
25
|
+
|
26
|
+
if source && file && CONFIG.match(file)
|
27
|
+
args[0] = Processor.call(source)
|
28
|
+
end
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module InstanceEvalPatch
|
35
|
+
#: (String, ?String, ?Integer) -> void
|
36
|
+
#: () { () -> void } -> void
|
37
|
+
def instance_eval(*args)
|
38
|
+
source, file, lineno = args
|
39
|
+
|
40
|
+
file ||= caller_locations(1, 1).first.path
|
41
|
+
|
42
|
+
if source && file && CONFIG.match(file)
|
43
|
+
args[0] = Processor.call(source)
|
44
|
+
end
|
45
|
+
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module KernelEvalPatch
|
51
|
+
#: (String, Binding, ?String, ?Integer) -> void
|
52
|
+
def eval(*args)
|
53
|
+
source, binding, file, lineno = args
|
54
|
+
|
55
|
+
file ||= caller_locations(1, 1).first.path
|
56
|
+
|
57
|
+
if source && file && CONFIG.match(file)
|
58
|
+
args[0] = Processor.call(source.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module BindingEvalPatch
|
66
|
+
#: (String, ?String, ?Integer) -> void
|
67
|
+
def eval(*args)
|
68
|
+
source, file, lineno = args
|
69
|
+
|
70
|
+
file ||= caller_locations(1, 1).first.path
|
71
|
+
|
72
|
+
if source && file && CONFIG.match(file)
|
73
|
+
args[0] = Processor.call(source.to_s)
|
74
|
+
end
|
75
|
+
|
76
|
+
super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Kernel.prepend(KernelEvalPatch)
|
81
|
+
Module.prepend(ModuleEvalPatch)
|
82
|
+
Binding.prepend(BindingEvalPatch)
|
83
|
+
BasicObject.prepend(InstanceEvalPatch)
|
84
|
+
end
|
data/lib/strict_ivars/version.rb
CHANGED
data/lib/strict_ivars.rb
CHANGED
@@ -2,12 +2,21 @@
|
|
2
2
|
|
3
3
|
require "prism"
|
4
4
|
require "require-hooks/setup"
|
5
|
+
require "strict_ivars/version"
|
6
|
+
require "strict_ivars/configuration"
|
5
7
|
|
6
8
|
module StrictIvars
|
7
9
|
NameError = Class.new(::NameError)
|
8
10
|
|
11
|
+
CONFIG = Configuration.new
|
12
|
+
|
9
13
|
#: (include: Array[String], exclude: Array[String]) -> void
|
10
14
|
def self.init(include: [], exclude: [])
|
15
|
+
require "strict_ivars/patch_eval"
|
16
|
+
|
17
|
+
CONFIG.include(*include)
|
18
|
+
CONFIG.exclude(*exclude)
|
19
|
+
|
11
20
|
RequireHooks.source_transform(
|
12
21
|
patterns: include,
|
13
22
|
exclude_patterns: exclude
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strict_ivars
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
@@ -47,6 +47,8 @@ files:
|
|
47
47
|
- LICENSE.txt
|
48
48
|
- README.md
|
49
49
|
- lib/strict_ivars.rb
|
50
|
+
- lib/strict_ivars/configuration.rb
|
51
|
+
- lib/strict_ivars/patch_eval.rb
|
50
52
|
- lib/strict_ivars/processor.rb
|
51
53
|
- lib/strict_ivars/version.rb
|
52
54
|
homepage: https://github.com/joeldrapper/strict_ivars
|