finalist 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c16358bc0a05975770702b6234cbb3c03f457fb4a1fd5ec707e0c87106247b50
4
- data.tar.gz: 8da986b8a9c507c4dfb5bf200d3b92e59ac2cc7a1925f8202e49d8968cab87b3
3
+ metadata.gz: 95b4f9fc3ce3038564d8cd5c1bcc745b3b55d2e960e9eb4411ede7da1bdd2e80
4
+ data.tar.gz: d1812c39cea0d783f131c5c954bc09245a63c3fdfd85589d8d432d09e16d9c76
5
5
  SHA512:
6
- metadata.gz: 2884650dd911c2667fa754e6fe6a35834b6704ea7081803ba5a34d7e0585899572fe351da5854cf57fac1d7fecbbc87227ff8b80586d74a51c5fc3214c31ed02
7
- data.tar.gz: 01bd8655ba387ef3a885adfa44e9b345f49d8b5af7fed03a7369652114284fc295d18dcdadc01d11f04423f6c234c2fddbd3ebfcce4ceaeb71a794b3be6dfd8c
6
+ metadata.gz: 402f63f49c8785369a4d3756e84c7f8583959081c6757064c0bbb9ba14336a75b321ee4c8ab0e969eb2bd3773fe130335e5ee00daa836eb8d146a950328790af
7
+ data.tar.gz: 9646b7ba0b27596b54a2e9e1ba4062f0a8aad7c73be6fc6707f63b9dc102c66456c7c80c9de3deb9a5d9951378c77a82139753d7f94039c16d9b7064209322bf
data/README.md CHANGED
@@ -1,9 +1,14 @@
1
1
  # Finalist
2
2
  [![Build Status](https://travis-ci.org/joker1007/finalist.svg?branch=master)](https://travis-ci.org/joker1007/finalist)
3
+ [![Gem Version](https://badge.fury.io/rb/finalist.svg)](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:
@@ -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 |fmeth_name|
54
- if meth = base.instance_method(fmeth_name)
55
- super_method = meth.super_method
56
- while super_method
57
- if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
58
- raise OverrideFinalMethodError.new("#{super_method} at #{super_method.source_location.join(":")} is overrided\n by #{meth} at #{meth.source_location.join(":")}", base, super_method.owner, meth, :included)
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
- end
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 = singleton_class.instance_method(symbol)
75
- super_method = meth.super_method
76
- while super_method
77
- if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
78
- raise OverrideFinalMethodError.new("#{super_method} at #{super_method.source_location.join(":")} is overrided\n by #{meth} at #{meth.source_location.join(":")}", singleton_class, super_method.owner, meth, :extended_singleton_method_added)
146
+ meth =
147
+ begin
148
+ singleton_class.instance_method(symbol)
149
+ rescue NoMethodError
150
+ nil
79
151
  end
80
- super_method = super_method.super_method
81
- end
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 |fmeth_name|
86
- if meth = base.singleton_class.instance_method(fmeth_name)
87
- super_method = meth.super_method
88
- while super_method
89
- if Finalist.finalized_methods[super_method.owner]&.member?(super_method.name)
90
- raise OverrideFinalMethodError.new("#{super_method} at #{super_method.source_location.join(":")} is overrided\n by #{meth} at #{meth.source_location.join(":")}", base.singleton_class, super_method.owner, meth, :extended)
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
- end
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
- def singleton_method_added(symbol)
123
- super
124
-
125
- return if Finalist.disabled?
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
@@ -1,3 +1,3 @@
1
1
  module Finalist
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
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.3
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-01-25 00:00:00.000000000 Z
11
+ date: 2018-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler