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 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