strict 0.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +14 -2
  3. data/Gemfile.lock +19 -2
  4. data/README.md +165 -6
  5. data/lib/strict/accessor/attributes.rb +15 -0
  6. data/lib/strict/accessor/module.rb +45 -0
  7. data/lib/strict/assignment_error.rb +25 -0
  8. data/lib/strict/attribute.rb +71 -0
  9. data/lib/strict/attributes/class.rb +17 -0
  10. data/lib/strict/attributes/coercer.rb +32 -0
  11. data/lib/strict/attributes/configuration.rb +46 -0
  12. data/lib/strict/attributes/dsl.rb +43 -0
  13. data/lib/strict/attributes/instance.rb +68 -0
  14. data/lib/strict/coercers/array.rb +22 -0
  15. data/lib/strict/coercers/hash.rb +34 -0
  16. data/lib/strict/dsl/coercible.rb +14 -0
  17. data/lib/strict/dsl/validatable.rb +28 -0
  18. data/lib/strict/implementation_does_not_conform_error.rb +88 -0
  19. data/lib/strict/initialization_error.rb +57 -0
  20. data/lib/strict/interface.rb +21 -0
  21. data/lib/strict/interfaces/instance.rb +54 -0
  22. data/lib/strict/method.rb +72 -0
  23. data/lib/strict/method_call_error.rb +72 -0
  24. data/lib/strict/method_definition_error.rb +46 -0
  25. data/lib/strict/method_return_error.rb +25 -0
  26. data/lib/strict/methods/configuration.rb +14 -0
  27. data/lib/strict/methods/dsl.rb +56 -0
  28. data/lib/strict/methods/module.rb +26 -0
  29. data/lib/strict/methods/verifiable_method.rb +158 -0
  30. data/lib/strict/object.rb +9 -0
  31. data/lib/strict/parameter.rb +63 -0
  32. data/lib/strict/reader/attributes.rb +15 -0
  33. data/lib/strict/reader/module.rb +27 -0
  34. data/lib/strict/return.rb +28 -0
  35. data/lib/strict/validators/all_of.rb +24 -0
  36. data/lib/strict/validators/any_of.rb +24 -0
  37. data/lib/strict/validators/anything.rb +20 -0
  38. data/lib/strict/validators/array_of.rb +24 -0
  39. data/lib/strict/validators/boolean.rb +20 -0
  40. data/lib/strict/validators/hash_of.rb +25 -0
  41. data/lib/strict/validators/range_of.rb +24 -0
  42. data/lib/strict/value.rb +22 -0
  43. data/lib/strict/version.rb +1 -1
  44. data/lib/strict.rb +1 -0
  45. data/strict.gemspec +41 -0
  46. metadata +97 -2
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module Strict
6
+ module Methods
7
+ class VerifiableMethod # rubocop:disable Metrics/ClassLength
8
+ extend Forwardable
9
+
10
+ class UnknownParameterError < Error
11
+ attr_reader :parameter_name
12
+
13
+ def initialize(parameter_name:)
14
+ super(message_from(parameter_name:))
15
+
16
+ @parameter_name = parameter_name
17
+ end
18
+
19
+ private
20
+
21
+ def message_from(parameter_name:)
22
+ "Strict tried to find a parameter named #{parameter_name} but was unable. " \
23
+ "It's likely this in an internal bug, feel free to open an issue at #{Strict::ISSUE_TRACKER} for help."
24
+ end
25
+ end
26
+
27
+ def_delegator :method, :name
28
+
29
+ attr_reader :parameters, :returns
30
+
31
+ def initialize(method:, parameters:, returns:, instance:)
32
+ @method = method
33
+ @parameters = parameters
34
+ @parameters_index = parameters.to_h { |p| [p.name, p] }
35
+ @returns = returns
36
+ @instance = instance
37
+ end
38
+
39
+ def to_s
40
+ "#{method.owner}#{separator}#{name}"
41
+ end
42
+
43
+ def verify_definition!
44
+ expected_parameters = Set.new(parameters.map(&:name))
45
+ defined_parameters = Set.new(method.parameters.filter_map { |kind, name| name unless kind == :block })
46
+ return if expected_parameters == defined_parameters
47
+
48
+ missing_parameters = expected_parameters - defined_parameters
49
+ additional_parameters = defined_parameters - expected_parameters
50
+ raise Strict::MethodDefinitionError.new(verifiable_method: self, missing_parameters:, additional_parameters:)
51
+ end
52
+
53
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/BlockLength
54
+ # TODO(kkt): clean this up- it's late, though, and the tests are passing
55
+ def verify_parameters!(*args, **kwargs)
56
+ invalid_parameters = nil
57
+ missing_parameters = nil
58
+
59
+ positional_arguments = []
60
+ keyword_arguments = {}
61
+
62
+ # TODO(kkt): doesn't handle oddly sorted optional positional parameters like def foo(opt = nil, req)
63
+ method.parameters.each do |kind, name|
64
+ case kind
65
+ when POSITIONAL
66
+ parameter_kind = :positional
67
+ value = args.any? ? args.shift : NOT_PROVIDED
68
+ when REST
69
+ parameter_kind = :rest
70
+ value = [*args]
71
+ args.clear
72
+ when KEYWORD
73
+ parameter_kind = :keyword
74
+ value = kwargs.key?(name) ? kwargs.delete(name) : NOT_PROVIDED
75
+ when KEYREST
76
+ parameter_kind = :keyrest
77
+ value = { **kwargs }
78
+ kwargs.clear
79
+ end
80
+ next unless parameter_kind
81
+
82
+ parameter = parameter_named!(name)
83
+ if value.equal?(NOT_PROVIDED) && parameter.optional?
84
+ value = parameter.default_generator.call
85
+ elsif value.equal?(NOT_PROVIDED)
86
+ missing_parameters ||= []
87
+ missing_parameters << parameter.name
88
+ next
89
+ end
90
+
91
+ value = parameter.coerce(value)
92
+ if parameter.valid?(value)
93
+ case parameter_kind
94
+ when :positional
95
+ positional_arguments << value
96
+ when :rest
97
+ positional_arguments.concat(value)
98
+ when :keyword
99
+ keyword_arguments[name] = value
100
+ when :keyrest
101
+ keyword_arguments.merge!(value)
102
+ end
103
+ else
104
+ invalid_parameters ||= {}
105
+ invalid_parameters[parameter] = value
106
+ end
107
+ end
108
+
109
+ if args.empty? && kwargs.empty? && invalid_parameters.nil? && missing_parameters.nil?
110
+ [positional_arguments, keyword_arguments]
111
+ else
112
+ raise Strict::MethodCallError.new(
113
+ verifiable_method: self,
114
+ remaining_args: args,
115
+ remaining_kwargs: kwargs,
116
+ invalid_parameters:,
117
+ missing_parameters:
118
+ )
119
+ end
120
+ end
121
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/BlockLength
122
+
123
+ def verify_returns!(value)
124
+ value = returns.coerce(value)
125
+ return if returns.valid?(value)
126
+
127
+ raise Strict::MethodReturnError.new(verifiable_method: self, value:)
128
+ end
129
+
130
+ private
131
+
132
+ POSITIONAL = Set.new(%i[req opt])
133
+ private_constant :POSITIONAL
134
+ REST = :rest
135
+ private_constant :REST
136
+ KEYWORD = Set.new(%i[keyreq key])
137
+ private_constant :KEYWORD
138
+ KEYREST = :keyrest
139
+ private_constant :KEYREST
140
+ NOT_PROVIDED = ::Object.new.freeze
141
+ private_constant :NOT_PROVIDED
142
+
143
+ attr_reader :method, :parameters_index
144
+
145
+ def instance?
146
+ @instance
147
+ end
148
+
149
+ def separator
150
+ instance? ? "#" : "."
151
+ end
152
+
153
+ def parameter_named!(name)
154
+ parameters_index.fetch(name) { raise UnknownParameterError.new(parameter_name: name) }
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Object
5
+ def self.included(mod)
6
+ mod.extend(Accessor::Attributes)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ class Parameter
5
+ NOT_PROVIDED = ::Object.new.freeze
6
+
7
+ class << self
8
+ def make(name, validator = Validators::Anything.instance, coerce: false, **defaults)
9
+ unless valid_defaults?(**defaults)
10
+ raise ArgumentError, "Only one of 'default', 'default_value', or 'default_generator' can be provided"
11
+ end
12
+
13
+ new(name: name.to_sym, validator:, default_generator: make_default_generator(**defaults), coercer: coerce)
14
+ end
15
+
16
+ private
17
+
18
+ def valid_defaults?(default: NOT_PROVIDED, default_value: NOT_PROVIDED, default_generator: NOT_PROVIDED)
19
+ defaults_provided = [default, default_value, default_generator].count do |default_option|
20
+ !default_option.equal?(NOT_PROVIDED)
21
+ end
22
+
23
+ defaults_provided <= 1
24
+ end
25
+
26
+ def make_default_generator(default: NOT_PROVIDED, default_value: NOT_PROVIDED, default_generator: NOT_PROVIDED)
27
+ if !default.equal?(NOT_PROVIDED)
28
+ default.respond_to?(:call) ? default : -> { default }
29
+ elsif !default_value.equal?(NOT_PROVIDED)
30
+ -> { default_value }
31
+ elsif !default_generator.equal?(NOT_PROVIDED)
32
+ default_generator
33
+ else
34
+ NOT_PROVIDED
35
+ end
36
+ end
37
+ end
38
+
39
+ attr_reader :name, :validator, :default_generator, :coercer
40
+
41
+ def initialize(name:, validator:, default_generator:, coercer:)
42
+ @name = name.to_sym
43
+ @validator = validator
44
+ @default_generator = default_generator
45
+ @coercer = coercer
46
+ @optional = !default_generator.equal?(NOT_PROVIDED)
47
+ end
48
+
49
+ def optional?
50
+ @optional
51
+ end
52
+
53
+ def valid?(value)
54
+ validator === value
55
+ end
56
+
57
+ def coerce(value)
58
+ return value unless coercer
59
+
60
+ coercer.call(value)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Reader
5
+ module Attributes
6
+ def attributes(&block)
7
+ block ||= -> {}
8
+ configuration = Strict::Attributes::Dsl.run(&block)
9
+ include Module.new(configuration)
10
+ include Strict::Attributes::Instance
11
+ extend Strict::Attributes::Class
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Reader
5
+ class Module < ::Module
6
+ attr_reader :configuration
7
+
8
+ def initialize(configuration)
9
+ super()
10
+
11
+ @configuration = configuration
12
+ const_set(Strict::Attributes::Class::CONSTANT, configuration)
13
+ configuration.attributes.each do |attribute|
14
+ module_eval(
15
+ "def #{attribute.name} = #{attribute.instance_variable}", # def name = @instance_variable
16
+ __FILE__,
17
+ __LINE__ - 2
18
+ )
19
+ end
20
+ end
21
+
22
+ def inspect
23
+ "#<#{self.class} (#{configuration.attributes.map(&:name).join(', ')})>"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ class Return
5
+ class << self
6
+ def make(validator = Validators::Anything.instance, coerce: false)
7
+ new(validator:, coercer: coerce)
8
+ end
9
+ end
10
+
11
+ attr_reader :validator, :coercer
12
+
13
+ def initialize(validator:, coercer:)
14
+ @validator = validator
15
+ @coercer = coercer
16
+ end
17
+
18
+ def valid?(value)
19
+ validator === value
20
+ end
21
+
22
+ def coerce(value)
23
+ return value unless coercer
24
+
25
+ coercer.call(value)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Validators
5
+ class AllOf
6
+ attr_reader :subvalidators
7
+
8
+ def initialize(*subvalidators)
9
+ @subvalidators = subvalidators
10
+ end
11
+
12
+ def ===(value)
13
+ subvalidators.all? do |subvalidator|
14
+ subvalidator === value
15
+ end
16
+ end
17
+
18
+ def inspect
19
+ "AllOf(#{subvalidators.map(&:inspect).join(', ')})"
20
+ end
21
+ alias to_s inspect
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Validators
5
+ class AnyOf
6
+ attr_reader :subvalidators
7
+
8
+ def initialize(*subvalidators)
9
+ @subvalidators = subvalidators
10
+ end
11
+
12
+ def ===(value)
13
+ subvalidators.any? do |subvalidator|
14
+ subvalidator === value
15
+ end
16
+ end
17
+
18
+ def inspect
19
+ "AnyOf(#{subvalidators.map(&:inspect).join(', ')})"
20
+ end
21
+ alias to_s inspect
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Strict
6
+ module Validators
7
+ class Anything
8
+ include Singleton
9
+
10
+ def ===(_value)
11
+ true
12
+ end
13
+
14
+ def inspect
15
+ "Anything()"
16
+ end
17
+ alias to_s inspect
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Validators
5
+ class ArrayOf
6
+ attr_reader :element_validator
7
+
8
+ def initialize(element_validator)
9
+ @element_validator = element_validator
10
+ end
11
+
12
+ def ===(value)
13
+ Array === value && value.all? do |v|
14
+ element_validator === v
15
+ end
16
+ end
17
+
18
+ def inspect
19
+ "ArrayOf(#{element_validator.inspect})"
20
+ end
21
+ alias to_s inspect
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Strict
6
+ module Validators
7
+ class Boolean
8
+ include Singleton
9
+
10
+ def ===(value)
11
+ value.equal?(true) || value.equal?(false)
12
+ end
13
+
14
+ def inspect
15
+ "Boolean()"
16
+ end
17
+ alias to_s inspect
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Validators
5
+ class HashOf
6
+ attr_reader :key_validator, :value_validator
7
+
8
+ def initialize(key_validator, value_validator)
9
+ @key_validator = key_validator
10
+ @value_validator = value_validator
11
+ end
12
+
13
+ def ===(value)
14
+ Hash === value && value.all? do |k, v|
15
+ key_validator === k && value_validator === v
16
+ end
17
+ end
18
+
19
+ def inspect
20
+ "HashOf(#{key_validator.inspect} => #{value_validator.inspect})"
21
+ end
22
+ alias to_s inspect
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Validators
5
+ class RangeOf
6
+ attr_reader :element_validator
7
+
8
+ def initialize(element_validator)
9
+ @element_validator = element_validator
10
+ end
11
+
12
+ def ===(value)
13
+ Range === value && [value.begin, value.end].compact.all? do |v|
14
+ element_validator === v
15
+ end
16
+ end
17
+
18
+ def inspect
19
+ "RangeOf(#{element_validator.inspect})"
20
+ end
21
+ alias to_s inspect
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strict
4
+ module Value
5
+ def self.included(mod)
6
+ mod.extend(Reader::Attributes)
7
+ end
8
+
9
+ def with(**attributes)
10
+ self.class.new(**to_h.merge(attributes))
11
+ end
12
+
13
+ def eql?(other)
14
+ self.class.equal?(other.class) && to_h.eql?(other.to_h)
15
+ end
16
+ alias == eql?
17
+
18
+ def hash
19
+ [self.class, to_h].hash
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Strict
4
- VERSION = "0.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/strict.rb CHANGED
@@ -5,4 +5,5 @@ loader = Zeitwerk::Loader.for_gem
5
5
  loader.setup
6
6
 
7
7
  module Strict
8
+ ISSUE_TRACKER = "https://github.com/kylekthompson/strict/issues"
8
9
  end
data/strict.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/strict/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "strict"
7
+ spec.version = Strict::VERSION
8
+ spec.authors = ["Kyle Thompson"]
9
+ spec.email = ["me@kkt.dev"]
10
+
11
+ spec.summary = "Strictly define a contract for your objects and methods"
12
+ spec.homepage = "https://github.com/kylekthompson/strict"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.1.2"
15
+
16
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_dependency "zeitwerk", "~> 2.6"
33
+ spec.add_development_dependency "debug", ">= 1.0.0"
34
+ spec.add_development_dependency "gem-release", "~> 2.2"
35
+ spec.add_development_dependency "minitest", "~> 5.0"
36
+ spec.add_development_dependency "minitest-spec-context", "~> 0.0.4"
37
+ spec.add_development_dependency "rake", "~> 13.0"
38
+ spec.add_development_dependency "rubocop", "~> 1.21"
39
+ spec.add_development_dependency "rubocop-minitest", "~> 0.22"
40
+ spec.add_development_dependency "rubocop-rake", "~> 0.6"
41
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strict
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Thompson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-01 00:00:00.000000000 Z
11
+ date: 2022-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: debug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: gem-release
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-spec-context
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.4
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.4
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rake
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +108,34 @@ dependencies:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
110
  version: '1.21'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.22'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.22'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.6'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.6'
83
139
  description:
84
140
  email:
85
141
  - me@kkt.dev
@@ -96,9 +152,48 @@ files:
96
152
  - README.md
97
153
  - Rakefile
98
154
  - lib/strict.rb
155
+ - lib/strict/accessor/attributes.rb
156
+ - lib/strict/accessor/module.rb
157
+ - lib/strict/assignment_error.rb
158
+ - lib/strict/attribute.rb
159
+ - lib/strict/attributes/class.rb
160
+ - lib/strict/attributes/coercer.rb
161
+ - lib/strict/attributes/configuration.rb
162
+ - lib/strict/attributes/dsl.rb
163
+ - lib/strict/attributes/instance.rb
164
+ - lib/strict/coercers/array.rb
165
+ - lib/strict/coercers/hash.rb
166
+ - lib/strict/dsl/coercible.rb
167
+ - lib/strict/dsl/validatable.rb
99
168
  - lib/strict/error.rb
169
+ - lib/strict/implementation_does_not_conform_error.rb
170
+ - lib/strict/initialization_error.rb
171
+ - lib/strict/interface.rb
172
+ - lib/strict/interfaces/instance.rb
173
+ - lib/strict/method.rb
174
+ - lib/strict/method_call_error.rb
175
+ - lib/strict/method_definition_error.rb
176
+ - lib/strict/method_return_error.rb
177
+ - lib/strict/methods/configuration.rb
178
+ - lib/strict/methods/dsl.rb
179
+ - lib/strict/methods/module.rb
180
+ - lib/strict/methods/verifiable_method.rb
181
+ - lib/strict/object.rb
182
+ - lib/strict/parameter.rb
183
+ - lib/strict/reader/attributes.rb
184
+ - lib/strict/reader/module.rb
185
+ - lib/strict/return.rb
186
+ - lib/strict/validators/all_of.rb
187
+ - lib/strict/validators/any_of.rb
188
+ - lib/strict/validators/anything.rb
189
+ - lib/strict/validators/array_of.rb
190
+ - lib/strict/validators/boolean.rb
191
+ - lib/strict/validators/hash_of.rb
192
+ - lib/strict/validators/range_of.rb
193
+ - lib/strict/value.rb
100
194
  - lib/strict/version.rb
101
195
  - sig/strict.rbs
196
+ - strict.gemspec
102
197
  homepage: https://github.com/kylekthompson/strict
103
198
  licenses:
104
199
  - MIT