Skip to content

Commit dd00e1b

Browse files
authored
Added constant validation (#1)
* Added constant validation * Update CHANGELOG.md
1 parent 82fe0fa commit dd00e1b

File tree

6 files changed

+57
-20
lines changed

6 files changed

+57
-20
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
## main (unreleased)
44

5-
---
5+
### New Features
6+
7+
- [#1](https://github.com/programyan/strong_interface/pull/1) Added constants validation
68

79
## 0.2.0
810

Gemfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
strong_interface (0.1.0)
4+
strong_interface (0.2.0)
55

66
GEM
77
remote: https://rubygems.org/

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Or install it yourself as:
3232

3333
```ruby
3434
module IDog
35+
WORD = String
3536
def self.create(*); end
3637
def eat(food); end
3738
def voice; end
@@ -45,6 +46,8 @@ class Lessy
4546
extend StrongInterface
4647
implements IDog
4748

49+
WORD = 'gav'
50+
4851
def self.create(name)
4952
# Creating...
5053
end
@@ -54,7 +57,7 @@ class Lessy
5457
end
5558

5659
def voice
57-
'Gav'
60+
WORD
5861
end
5962
end
6063
```
@@ -79,7 +82,8 @@ end
7982
#### Exception will be raised
8083
8184
```shell
82-
StrongInterface::MethodNotImplemented (Class method `create` is not implemented at `Lessy`)
85+
StrongInterface::ImplementationError (Constant `WORD` is absent at `Lessy`)
86+
Class method `create` is not implemented at `Lessy`
8387
Invalid parameters at method `eat`, expected: `def eat(food)`, got: `def eat(food, water)`
8488
```
8589
@@ -92,7 +96,7 @@ If the variable is not set, the `raise` strategy will be applied.
9296
9397
#### raise (default)
9498
95-
This is a default strategy. When validator finds incorrect implementation, it raises the `StrongInterface::MethodNotImplemented` exception,
99+
This is a default strategy. When validator finds incorrect implementation, it raises the `StrongInterface::ImplementationError` exception,
96100
and provides a list of methods which aren't implemented
97101
98102
#### log
@@ -105,6 +109,8 @@ even if it has this kind of a problem in code.
105109
106110
- [x] Check if methods of interfaces all exists in a class or module
107111
- [x] Check the arguments of methods
112+
- [x] Check constants
113+
- [ ] Checking the privacy of methods
108114
- [ ] Allow optional arguments at interface methods???
109115
110116
## Development

lib/strong_interface.rb

+14-7
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
require 'strong_interface/parameters_validator'
55

66
module StrongInterface
7-
MethodNotImplemented = Class.new(StandardError)
7+
ImplementationError = Class.new(StandardError)
88
UnknownStrategy = Class.new(StandardError)
99

1010
RAISING_STRATEGIES = {
11-
'raise' => ->(error) { raise MethodNotImplemented, error },
11+
'raise' => ->(error) { raise ImplementationError, error },
1212
'log' => ->(error) { Logger.new($stdout).warn { error } }
1313
}.freeze
1414

1515
# @param interfaces [Module|Class|Array<Module|Class>] the list of interfaces that class or module should implements
16-
# @raise [UnknownStrategy] if SI_NOTIFICATION environment variable has wrong value
17-
# @raise [ImplementationError] if describing some methods of an interface has been forgotten and SI_NOTIFICATION environment variable is set to `raise`
16+
# @raise [UnknownStrategy] if SI_VALIDATION_STRATEGY environment variable has wrong value
17+
# @raise [ImplementationError] if describing some methods of an interface has been forgotten and
18+
# SI_VALIDATION_STRATEGY environment variable is set to `raise`
1819
def implements(interfaces)
1920
TracePoint.trace(:end) do |t|
2021
next if self != t.self
@@ -34,13 +35,19 @@ def implements(interfaces)
3435

3536
def validate(interfaces)
3637
Array(interfaces).flat_map do |interface|
37-
validate_class_methods(interface) + validate_instance_methods(interface)
38+
validate_constants(interface) + validate_class_methods(interface) + validate_instance_methods(interface)
39+
end
40+
end
41+
42+
def validate_constants(interface)
43+
(interface.constants - constants).map do |missing_constant|
44+
"Constant `#{missing_constant}` is absent at `#{self}`"
3845
end
3946
end
4047

4148
def validate_class_methods(interface)
4249
interface.methods(false).filter_map do |klass_method|
43-
unless methods(false).include?(klass_method)
50+
if !methods(false).include?(klass_method)
4451
"Class method `#{klass_method}` is not implemented at `#{self}`"
4552
else
4653
ParametersValidator.new(interface.method(klass_method), method(klass_method)).validate
@@ -50,7 +57,7 @@ def validate_class_methods(interface)
5057

5158
def validate_instance_methods(interface)
5259
interface.instance_methods.filter_map do |instance_method|
53-
unless instance_methods.include?(instance_method)
60+
if !instance_methods.include?(instance_method)
5461
"Instance method `#{instance_method}` is not implemented at `#{self}`"
5562
else
5663
ParametersValidator.new(interface.instance_method(instance_method), instance_method(instance_method)).validate

lib/strong_interface/parameters_validator.rb

+8-7
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,17 @@ def valid?
2424
return false if @interface_method_parameters.size != @klass_method_parameters.size
2525

2626
@interface_method_parameters.each.with_index.all? do |key, index|
27-
if key == :req
28-
%i(req opt).include? @klass_method_parameters[index]
29-
elsif key == :keyreq
30-
%i(keyreq key).include? @klass_method_parameters[index]
27+
case key
28+
when :req
29+
%i[req opt].include? @klass_method_parameters[index]
30+
when :keyreq
31+
%i[keyreq key].include? @klass_method_parameters[index]
3132
end
3233
end
3334
end
3435

35-
def description(m)
36-
m.inspect.scan(/[\.|#](\S+?\(.*?\))/).last.first
36+
def description(metod)
37+
metod.inspect.scan(/[.|#](\S+?\(.*?\))/).last.first
3738
end
3839
end
39-
end
40+
end

spec/strong_interface_spec.rb

+22-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,28 @@ def say(text)
2020
# Say text somehow
2121
end
2222
end
23-
}.to raise_error(StrongInterface::MethodNotImplemented)
23+
}.to raise_error(StrongInterface::ImplementationError)
24+
end
25+
26+
context 'with missing constant' do
27+
it 'raises error' do
28+
expect {
29+
module IScream
30+
LOUD = Integer
31+
32+
def scream; end
33+
end
34+
35+
class TestClass
36+
extend StrongInterface
37+
implements IScream
38+
39+
def scream
40+
# Scream something somehow
41+
end
42+
end
43+
}.to raise_error(StrongInterface::ImplementationError)
44+
end
2445
end
2546

2647
it 'do not raise error when everything is ok' do

0 commit comments

Comments
 (0)