finalist 0.1.3 → 0.1.4
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 +11 -1
- data/lib/finalist.rb +106 -54
- data/lib/finalist/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: 95b4f9fc3ce3038564d8cd5c1bcc745b3b55d2e960e9eb4411ede7da1bdd2e80
|
4
|
+
data.tar.gz: d1812c39cea0d783f131c5c954bc09245a63c3fdfd85589d8d432d09e16d9c76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 402f63f49c8785369a4d3756e84c7f8583959081c6757064c0bbb9ba14336a75b321ee4c8ab0e969eb2bd3773fe130335e5ee00daa836eb8d146a950328790af
|
7
|
+
data.tar.gz: 9646b7ba0b27596b54a2e9e1ba4062f0a8aad7c73be6fc6707f63b9dc102c66456c7c80c9de3deb9a5d9951378c77a82139753d7f94039c16d9b7064209322bf
|
data/README.md
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
# Finalist
|
2
2
|
[](https://travis-ci.org/joker1007/finalist)
|
3
|
+
[](https://badge.fury.io/rb/finalist)
|
3
4
|
|
4
5
|
Finalist adds `final` method modifier.
|
5
6
|
`final` forbids method override.
|
6
7
|
|
8
|
+
This gem is pseudo static code analyzer by `method_added` and `singleton_method_added` and `included` and `extended`.
|
9
|
+
|
10
|
+
it detect final violation when class(module) is defined, not runtime.
|
11
|
+
|
7
12
|
Simple case is following.
|
8
13
|
|
9
14
|
```ruby
|
@@ -15,7 +20,7 @@ class A1
|
|
15
20
|
end
|
16
21
|
|
17
22
|
class A2 < A1
|
18
|
-
def foo
|
23
|
+
def foo # => raise
|
19
24
|
end
|
20
25
|
end
|
21
26
|
```
|
@@ -25,6 +30,11 @@ This case raises `Finalist::OverrideFinalMethodError` at `def foo in A2 class`.
|
|
25
30
|
This gem supports other cases.
|
26
31
|
(see [finalist_spec.rb](https://github.com/joker1007/finalist/blob/master/spec/finalist_spec.rb))
|
27
32
|
|
33
|
+
### My similar gems
|
34
|
+
|
35
|
+
- [overrider](https://github.com/joker1007/overrider) (`override` implementation)
|
36
|
+
- [abstriker](https://github.com/joker1007/abstriker) (`abstract` implementation)
|
37
|
+
|
28
38
|
## Installation
|
29
39
|
|
30
40
|
Add this line to your application's Gemfile:
|
data/lib/finalist.rb
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
require "finalist/version"
|
2
2
|
require "set"
|
3
3
|
|
4
|
+
using Module.new {
|
5
|
+
refine Object do
|
6
|
+
def verify_final_method(meth, detect_type)
|
7
|
+
super_method = meth.super_method
|
8
|
+
while super_method
|
9
|
+
if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
|
10
|
+
backtrace = caller(1)
|
11
|
+
backtrace_start_pos = backtrace.rindex { |b| b.index(__FILE__) }
|
12
|
+
backtrace = backtrace.drop(backtrace_start_pos + 1)
|
13
|
+
raise Finalist::OverrideFinalMethodError.new(
|
14
|
+
"#{super_method.owner}##{super_method.name} at #{super_method.source_location.join(":")} is overrided\n by #{meth.owner}##{meth.name} at #{meth.source_location.join(":")}",
|
15
|
+
meth.owner, super_method.owner, meth, detect_type
|
16
|
+
).tap { |ex| ex.set_backtrace(backtrace) }
|
17
|
+
end
|
18
|
+
super_method = super_method.super_method
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
4
24
|
module Finalist
|
5
25
|
class OverrideFinalMethodError < StandardError
|
6
26
|
attr_reader :override_class, :origin_class, :unbound_method, :detect_type
|
@@ -41,7 +61,61 @@ module Finalist
|
|
41
61
|
@finalized_methods ||= {}
|
42
62
|
end
|
43
63
|
|
64
|
+
private
|
65
|
+
|
66
|
+
def method_added(symbol)
|
67
|
+
super
|
68
|
+
|
69
|
+
return if Finalist.disabled?
|
70
|
+
|
71
|
+
verify_final_method(instance_method(symbol), :method_added)
|
72
|
+
end
|
73
|
+
|
74
|
+
def singleton_method_added(symbol)
|
75
|
+
super
|
76
|
+
|
77
|
+
return if Finalist.disabled?
|
78
|
+
|
79
|
+
verify_final_method(singleton_class.instance_method(symbol), :singleton_method_added)
|
80
|
+
end
|
81
|
+
|
44
82
|
module ModuleMethods
|
83
|
+
def include(mod)
|
84
|
+
super
|
85
|
+
|
86
|
+
ancestors.drop(1).each do |mod|
|
87
|
+
Finalist.finalized_methods[mod]&.each do |final_method_name|
|
88
|
+
meth =
|
89
|
+
begin
|
90
|
+
instance_method(final_method_name)
|
91
|
+
rescue NoMethodError
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
verify_final_method(meth, :include) if meth
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def extend(mod)
|
101
|
+
super
|
102
|
+
|
103
|
+
singleton_class.ancestors.drop(1).each do |mod|
|
104
|
+
Finalist.finalized_methods[mod]&.each do |final_method_name|
|
105
|
+
meth =
|
106
|
+
begin
|
107
|
+
singleton_class.instance_method(final_method_name)
|
108
|
+
rescue NoMethodError
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
verify_final_method(meth, :extend) if meth
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
45
119
|
def included(base)
|
46
120
|
super
|
47
121
|
|
@@ -50,17 +124,15 @@ module Finalist
|
|
50
124
|
base.extend(Finalist)
|
51
125
|
|
52
126
|
base.ancestors.drop(1).each do |mod|
|
53
|
-
Finalist.finalized_methods[mod]&.each do |
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
super_method = super_method.super_method
|
127
|
+
Finalist.finalized_methods[mod]&.each do |final_method_name|
|
128
|
+
meth =
|
129
|
+
begin
|
130
|
+
meth = base.instance_method(final_method_name)
|
131
|
+
rescue NoMethodError
|
132
|
+
nil
|
62
133
|
end
|
63
|
-
|
134
|
+
|
135
|
+
verify_final_method(meth, :included) if meth
|
64
136
|
end
|
65
137
|
end
|
66
138
|
end
|
@@ -71,66 +143,46 @@ module Finalist
|
|
71
143
|
|
72
144
|
return if Finalist.disabled?
|
73
145
|
|
74
|
-
meth =
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
146
|
+
meth =
|
147
|
+
begin
|
148
|
+
singleton_class.instance_method(symbol)
|
149
|
+
rescue NoMethodError
|
150
|
+
nil
|
79
151
|
end
|
80
|
-
|
81
|
-
|
152
|
+
|
153
|
+
verify_final_method(meth, :extended_singleton_method_added) if meth
|
82
154
|
end
|
83
155
|
|
84
156
|
base.singleton_class.ancestors.drop(1).each do |mod|
|
85
|
-
Finalist.finalized_methods[mod]&.each do |
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
super_method = super_method.super_method
|
157
|
+
Finalist.finalized_methods[mod]&.each do |final_method_name|
|
158
|
+
meth =
|
159
|
+
begin
|
160
|
+
base.singleton_class.instance_method(final_method_name)
|
161
|
+
rescue NoMethodError
|
162
|
+
nil
|
93
163
|
end
|
94
|
-
|
164
|
+
|
165
|
+
verify_final_method(meth, :extended) if meth
|
95
166
|
end
|
96
167
|
end
|
97
168
|
end
|
98
169
|
end
|
99
170
|
|
100
171
|
module SyntaxMethods
|
172
|
+
private
|
173
|
+
|
101
174
|
def final(symbol)
|
102
175
|
method_set = Finalist.finalized_methods[self] ||= Set.new
|
176
|
+
instance_method(symbol)
|
103
177
|
method_set.add(symbol)
|
178
|
+
symbol
|
104
179
|
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def method_added(symbol)
|
108
|
-
super
|
109
|
-
|
110
|
-
return if Finalist.disabled?
|
111
|
-
|
112
|
-
meth = instance_method(symbol)
|
113
|
-
super_method = meth.super_method
|
114
|
-
while super_method
|
115
|
-
if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
|
116
|
-
raise OverrideFinalMethodError.new("#{super_method} at #{super_method.source_location.join(":")} is overrided\n by #{meth} at #{meth.source_location.join(":")}", self, super_method.owner, meth, :method_added)
|
117
|
-
end
|
118
|
-
super_method = super_method.super_method
|
119
|
-
end
|
120
|
-
end
|
121
180
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
meth = singleton_class.instance_method(symbol)
|
128
|
-
super_method = meth.super_method
|
129
|
-
while super_method
|
130
|
-
if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
|
131
|
-
raise OverrideFinalMethodError.new("#{super_method} at #{super_method.source_location.join(":")} is overrided\n by #{meth} at #{meth.source_location.join(":")}", self, super_method.owner, meth, :singleton_method_added)
|
132
|
-
end
|
133
|
-
super_method = super_method.super_method
|
181
|
+
def final_singleton_method(symbol)
|
182
|
+
method_set = Finalist.finalized_methods[self.singleton_class] ||= Set.new
|
183
|
+
singleton_class.instance_method(symbol)
|
184
|
+
method_set.add(symbol)
|
185
|
+
symbol
|
134
186
|
end
|
135
187
|
end
|
136
188
|
end
|
data/lib/finalist/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: finalist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joker1007
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|