strong_interface 0.1.0 → 0.3.1

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: 623aa81d3e30d46a852d757e6911005dca1b09c0cdb1589be7696a216847b2b2
4
- data.tar.gz: c39798e031a50dea42bed5c47e335b7072dc62024ecbc2f87c6cc248ee2e291b
3
+ metadata.gz: 8cf1e550ee688057b954e398cd8b74fa8c6622c46ff79e3d5783dab70d977ca2
4
+ data.tar.gz: b6430938ec444d0a5686560b850143626fca0ecadbe06a6961f960fde0f98030
5
5
  SHA512:
6
- metadata.gz: 2867ff46ed12b7fa6357d697a49cca3c8e7931298b9cbbeaf64fc1f6ea9bb91231609e0c6dd3bbc6ec98071715a0383867b73ff08aab4f00e899b2c8fec1c5d4
7
- data.tar.gz: b20a94a556ed3c8c0c41516628889d4b28628947cdec0a331226d5fb168b87bdf9aca25650956a213354b699a2f7eacd2ee7132a5e973f32ca2eaa76f2617572
6
+ metadata.gz: 2734acdbd5793a2746beaafd088b7fc9263b9326034a3e7db3004b159024673c7a02bdd94a1fea3a979b56c84c3cf37ce950f486b4fdd54f8b80355a3f03c131
7
+ data.tar.gz: 5211b5df2b6f50be7ba05dbe698fa36f5f7bd6f99239ceb4afd14e562d9b4282ec9d09ee0e4bdb03d2bef6bc7fcfd0bcb513bfbef9fea4f4c51dfe52791ad192
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ ## main (unreleased)
4
+
5
+ ---
6
+
7
+ ## 0.3.1
8
+
9
+ ## Bugfixes
10
+
11
+ - Fixed CHANGELOG.md
12
+
13
+ ## 0.3.0
14
+
15
+ ### New Features
16
+
17
+ - [#1](https://github.com/programyan/strong_interface/pull/1) Added constants validation
18
+
19
+ ## 0.2.0
20
+
21
+ ### New features
22
+
23
+ - [9506eb3](https://github.com/programyan/strong_interface/commit/9506eb31666628cd6d06a4a4608ca81081a1315b) Add validation parameters
24
+
25
+ ## 0.1.0
26
+
27
+ - DSL
28
+ - Basic implementation of methods presence
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- strong_interface (0.1.0)
4
+ strong_interface (0.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -32,8 +32,9 @@ Or install it yourself as:
32
32
 
33
33
  ```ruby
34
34
  module IDog
35
+ WORD = String
35
36
  def self.create(*); end
36
- def eat(*); end
37
+ def eat(food); end
37
38
  def voice; end
38
39
  end
39
40
  ```
@@ -45,16 +46,18 @@ class Lessy
45
46
  extend StrongInterface
46
47
  implements IDog
47
48
 
49
+ WORD = 'gav'
50
+
48
51
  def self.create(name)
49
- ...
52
+ # Creating...
50
53
  end
51
54
 
52
55
  def eat(food)
53
- ...
56
+ # Eating...
54
57
  end
55
58
 
56
59
  def voice
57
- 'Gav'
60
+ WORD
58
61
  end
59
62
  end
60
63
  ```
@@ -66,6 +69,10 @@ class Lessy
66
69
  extend StrongInterface
67
70
  implements IDog
68
71
 
72
+ def eat(food, water)
73
+ # Eating...
74
+ end
75
+
69
76
  def voice
70
77
  'Gav'
71
78
  end
@@ -75,8 +82,9 @@ end
75
82
  #### Exception will be raised
76
83
 
77
84
  ```shell
78
- StrongInterface::MethodNotImplemented (Class method `create` is not implemented at `Lessy`)
79
- Instance method `eat` is not implemented at `Lessy`
85
+ StrongInterface::ImplementationError (Constant `WORD` is absent at `Lessy`)
86
+ Class method `create` is not implemented at `Lessy`
87
+ Invalid parameters at method `eat`, expected: `def eat(food)`, got: `def eat(food, water)`
80
88
  ```
81
89
 
82
90
  ## Validation Strategies
@@ -88,7 +96,7 @@ If the variable is not set, the `raise` strategy will be applied.
88
96
 
89
97
  #### raise (default)
90
98
 
91
- 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,
92
100
  and provides a list of methods which aren't implemented
93
101
 
94
102
  #### log
@@ -100,7 +108,10 @@ even if it has this kind of a problem in code.
100
108
  ## TODO
101
109
 
102
110
  - [x] Check if methods of interfaces all exists in a class or module
103
- - [ ] Check the arguments of methods
111
+ - [x] Check the arguments of methods
112
+ - [x] Check constants
113
+ - [ ] Checking the privacy of methods???
114
+ - [ ] Allow optional arguments at interface methods???
104
115
 
105
116
  ## Development
106
117
 
@@ -110,7 +121,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
110
121
 
111
122
  ## Contributing
112
123
 
113
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/strong_interface. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/strong_interface/blob/master/CODE_OF_CONDUCT.md).
124
+ Bug reports and pull requests are welcome on GitHub at https://github.com/programyan/strong_interface. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/programyan/strong_interface/blob/main/CODE_OF_CONDUCT.md).
114
125
 
115
126
 
116
127
  ## License
@@ -119,4 +130,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
119
130
 
120
131
  ## Code of Conduct
121
132
 
122
- Everyone interacting in the StrongInterface project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/strong_interface/blob/master/CODE_OF_CONDUCT.md).
133
+ Everyone interacting in the StrongInterface project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/programyan/strong_interface/blob/main/CODE_OF_CONDUCT.md).
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StrongInterface
4
+ class ParametersValidator
5
+ def initialize(interface_method, klass_method)
6
+ @interface_method = interface_method
7
+ @interface_method_parameters = interface_method.parameters.map { |param| param[0] }
8
+ @klass_method = klass_method
9
+ @klass_method_parameters = klass_method.parameters.map { |param| param[0] }
10
+ end
11
+
12
+ def validate
13
+ return if valid?
14
+
15
+ "Invalid parameters at method `#{@klass_method.name}`, expected: `def #{description(@interface_method)}`," \
16
+ " got: `def #{description(@klass_method)}`"
17
+ end
18
+
19
+ def valid?
20
+ return true if @interface_method_parameters == [:rest]
21
+ return true if @klass_method_parameters == [:rest]
22
+
23
+ return true if @interface_method_parameters == @klass_method_parameters
24
+ return false if @interface_method_parameters.size != @klass_method_parameters.size
25
+
26
+ @interface_method_parameters.each.with_index.all? do |key, 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]
32
+ end
33
+ end
34
+ end
35
+
36
+ def description(metod)
37
+ metod.inspect.scan(/[.|#](\S+?\(.*?\))/).last.first
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StrongInterface
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'strong_interface/version'
4
+ require 'strong_interface/parameters_validator'
4
5
 
5
6
  module StrongInterface
6
- MethodNotImplemented = Class.new(StandardError)
7
+ ImplementationError = Class.new(StandardError)
7
8
  UnknownStrategy = Class.new(StandardError)
8
9
 
9
10
  RAISING_STRATEGIES = {
10
- 'raise' => ->(error) { raise MethodNotImplemented, error },
11
+ 'raise' => ->(error) { raise ImplementationError, error },
11
12
  'log' => ->(error) { Logger.new($stdout).warn { error } }
12
13
  }.freeze
13
14
 
14
15
  # @param interfaces [Module|Class|Array<Module|Class>] the list of interfaces that class or module should implements
15
- # @raise [UnknownStrategy] if SI_NOTIFICATION environment variable has wrong value
16
- # @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`
17
19
  def implements(interfaces)
18
20
  TracePoint.trace(:end) do |t|
19
21
  next if self != t.self
@@ -33,20 +35,32 @@ module StrongInterface
33
35
 
34
36
  def validate(interfaces)
35
37
  Array(interfaces).flat_map do |interface|
36
- 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}`"
37
45
  end
38
46
  end
39
47
 
40
48
  def validate_class_methods(interface)
41
49
  interface.methods(false).filter_map do |klass_method|
42
- "Class method `#{klass_method}` is not implemented at `#{self}`" unless methods(false).include?(klass_method)
50
+ if !methods(false).include?(klass_method)
51
+ "Class method `#{klass_method}` is not implemented at `#{self}`"
52
+ else
53
+ ParametersValidator.new(interface.method(klass_method), method(klass_method)).validate
54
+ end
43
55
  end
44
56
  end
45
57
 
46
58
  def validate_instance_methods(interface)
47
59
  interface.instance_methods.filter_map do |instance_method|
48
- unless instance_methods.include?(instance_method)
60
+ if !instance_methods.include?(instance_method)
49
61
  "Instance method `#{instance_method}` is not implemented at `#{self}`"
62
+ else
63
+ ParametersValidator.new(interface.instance_method(instance_method), instance_method(instance_method)).validate
50
64
  end
51
65
  end
52
66
  end
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = 'https://github.com/programyan/strong_interface'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/programyan/strong_interface/blob/main/CHANGELOG.md'
19
20
 
20
21
  # Specify which files should be added to the gem when it is released.
21
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_interface
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Ageev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-09 00:00:00.000000000 Z
11
+ date: 2022-06-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Simple implementation of an interface pattern for Ruby
14
14
  email:
@@ -19,6 +19,7 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - ".gitignore"
21
21
  - ".rspec"
22
+ - CHANGELOG.md
22
23
  - CODE_OF_CONDUCT.md
23
24
  - Gemfile
24
25
  - Gemfile.lock
@@ -28,6 +29,7 @@ files:
28
29
  - bin/console
29
30
  - bin/setup
30
31
  - lib/strong_interface.rb
32
+ - lib/strong_interface/parameters_validator.rb
31
33
  - lib/strong_interface/version.rb
32
34
  - strong_interface.gemspec
33
35
  homepage: https://github.com/programyan/strong_interface
@@ -36,6 +38,7 @@ licenses:
36
38
  metadata:
37
39
  homepage_uri: https://github.com/programyan/strong_interface
38
40
  source_code_uri: https://github.com/programyan/strong_interface
41
+ changelog_uri: https://github.com/programyan/strong_interface/blob/main/CHANGELOG.md
39
42
  post_install_message:
40
43
  rdoc_options: []
41
44
  require_paths: