calificador 0.1.0 → 0.2.0

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -16
  3. data/TODO.md +16 -0
  4. data/calificador.gemspec +54 -0
  5. data/lib/calificador.rb +8 -4
  6. data/lib/calificador/assert.rb +15 -0
  7. data/lib/calificador/assertor.rb +79 -35
  8. data/lib/calificador/build/attribute_evaluator.rb +34 -30
  9. data/lib/calificador/build/basic_factory.rb +195 -0
  10. data/lib/calificador/build/mock_factory.rb +151 -0
  11. data/lib/calificador/build/object_factory.rb +85 -0
  12. data/lib/calificador/build/trait.rb +0 -20
  13. data/lib/calificador/context/basic_context.rb +406 -0
  14. data/lib/calificador/context/class_method_context.rb +0 -0
  15. data/lib/calificador/{spec → context}/condition_context.rb +1 -3
  16. data/lib/calificador/{spec/type_context.rb → context/instance_context.rb} +5 -10
  17. data/lib/calificador/context/operation_context.rb +27 -0
  18. data/lib/calificador/context/override/argument_override.rb +73 -0
  19. data/lib/calificador/context/override/basic_override.rb +14 -0
  20. data/lib/calificador/context/override/factory_override.rb +31 -0
  21. data/lib/calificador/context/override/property_override.rb +61 -0
  22. data/lib/calificador/context/test_environment.rb +283 -0
  23. data/lib/calificador/{spec → context}/test_method.rb +2 -31
  24. data/lib/calificador/{spec → context}/test_root.rb +3 -15
  25. data/lib/calificador/{spec/examine_context.rb → context/type_context.rb} +7 -10
  26. data/lib/calificador/key.rb +27 -15
  27. data/lib/calificador/minitest/minitest_patches.rb +0 -2
  28. data/lib/calificador/test.rb +1 -3
  29. data/lib/calificador/test_mixin.rb +143 -139
  30. data/lib/calificador/util/call_formatter.rb +5 -5
  31. data/lib/calificador/util/core_extensions.rb +104 -79
  32. data/lib/calificador/util/proxy_object.rb +63 -0
  33. data/lib/calificador/version.rb +1 -1
  34. metadata +22 -42
  35. data/lib/calificador/build/attribute_container.rb +0 -103
  36. data/lib/calificador/build/factory.rb +0 -132
  37. data/lib/calificador/spec/basic_context.rb +0 -353
  38. data/lib/calificador/spec/class_method_context.rb +0 -42
  39. data/lib/calificador/spec/instance_method_context.rb +0 -38
  40. data/lib/calificador/spec/test_environment.rb +0 -141
  41. data/lib/calificador/spec/value_override.rb +0 -37
@@ -5,11 +5,11 @@ require "pp"
5
5
  module Calificador
6
6
  module Util
7
7
  class CallFormatter
8
- def method(method:, arguments: [], options: {})
8
+ def format_method(name:, arguments: [], keywords: {})
9
9
  info = ::StringIO.new
10
- info << method
10
+ info << name
11
11
 
12
- unless arguments.empty? && options.empty?
12
+ unless arguments.empty? && keywords.empty?
13
13
  info << "("
14
14
 
15
15
  arguments.each_with_index do |argument, i|
@@ -17,7 +17,7 @@ module Calificador
17
17
  append_value(value: argument, out: info)
18
18
  end
19
19
 
20
- options.each_with_index do |(name, value), i|
20
+ keywords.each_with_index do |(name, value), i|
21
21
  info << ", " unless i.zero? && arguments.empty?
22
22
  info << name << ": "
23
23
  append_value(value: value, out: info)
@@ -29,7 +29,7 @@ module Calificador
29
29
  info.string
30
30
  end
31
31
 
32
- def value(value:)
32
+ def format_value(value:)
33
33
  append_value(value: value, out: StringIO.new).string
34
34
  end
35
35
 
@@ -1,72 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "docile"
4
3
  require "ostruct"
5
4
 
6
5
  module Calificador
7
6
  module Util
8
7
  # Extensions to core classes
9
8
  module CoreExtensions
10
- module_function
11
-
12
- def map_call_arguments(signature:, arguments:, options:)
13
- min_argument_count = 0
14
- max_argument_count = 0
15
- option_names = Set.new
16
-
17
- signature.each do |type, name|
18
- case type
19
- when :req
20
- min_argument_count += 1
21
- max_argument_count += 1
22
- when :opt
23
- max_argument_count += 1
24
- when :rest
25
- max_argument_count = nil
26
- when :keyreq
27
- raise ArgumentError, "Required option #{name} missing for #{self} #{signature}" unless options.key?(name)
28
-
29
- option_names << name
30
- when :key
31
- option_names << name
32
- when :keyrest
33
- option_names += options.keys
34
- when :block
35
- # ignore
36
- else
37
- raise ArgumentError, "Illegal parameter type #{type} for #{self} #{signature}"
38
- end
39
- end
40
-
41
- argument_count = arguments.size
42
- argument_count = max_argument_count if max_argument_count && argument_count > max_argument_count
43
-
44
- raise ArgumentError, "Not enough parameters to call proc with #{signature}" if argument_count < min_argument_count
45
-
46
- arguments = arguments[0...argument_count]
47
- options = options.slice(*option_names)
48
-
49
- [arguments, options]
50
- end
51
-
52
- refine Object do
9
+ module ObjectMixins
53
10
  def to_bool
54
11
  self ? true : false
55
12
  end
56
-
57
- def dsl_config(&block)
58
- target = self
59
-
60
- if block
61
- dsl = self.class.const_get(:Dsl).new(delegate: target)
62
- Docile.dsl_eval(dsl, &block)
63
- end
64
-
65
- target
66
- end
67
13
  end
68
14
 
69
- refine String do
15
+ Object.include(ObjectMixins)
16
+
17
+ module StringMixins
70
18
  def snake_case
71
19
  gsub(%r{(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])}, "_").downcase
72
20
  end
@@ -78,9 +26,14 @@ module Calificador
78
26
  end
79
27
  end
80
28
 
81
- refine Module do
29
+ String.include(StringMixins)
30
+
31
+ module ModuleMixins
82
32
  def parent_module
83
- @__calificador_parent_module ||= Nil[parent_name&.then { |m| const_get(m) }]
33
+ if !instance_variable_defined?(:@__calificador_parent_module) || @__calificador_parent_module.nil?
34
+ @__calificador_parent_module = Nil[parent_name&.then { |m| const_get(m) }]
35
+ end
36
+
84
37
  @__calificador_parent_module.unmask_nil
85
38
  end
86
39
 
@@ -89,47 +42,119 @@ module Calificador
89
42
  end
90
43
 
91
44
  def base_name
92
- @__calificador_base_name ||= if %r{(?:^|::)(?<base_name>(?:[^:]|:[^:])+)\z} =~ name
93
- %r{\A#<.+>\z} =~ base_name ? Nil.instance : base_name
94
- else
95
- Nil.instance
45
+ if !instance_variable_defined?(:@__calificador_base_name) || @__calificador_base_name.nil?
46
+ @__calificador_base_name = if %r{(?:^|::)(?<base_name>(?:[^:]|:[^:])+)\z} =~ name
47
+ Nil[base_name]
48
+ else
49
+ Nil.instance
50
+ end
96
51
  end
97
52
 
98
53
  @__calificador_base_name.unmask_nil
99
54
  end
100
55
 
101
56
  def parent_name
102
- @__calificador_parent_name ||= if %r{(?<parent_name>\A.*)::} =~ name
103
- %r{#<} =~ parent_name ? Nil.instance : parent_name
104
- else
105
- Nil.instance
57
+ if !instance_variable_defined?(:@__calificador_parent_name) || @__calificador_parent_name.nil?
58
+ @__calificador_parent_name = if %r{(?<parent_name>\A.*)::} =~ name
59
+ parent_name
60
+ else
61
+ Nil.instance
62
+ end
106
63
  end
107
64
 
108
65
  @__calificador_parent_name.unmask_nil
109
66
  end
110
- end
111
67
 
112
- [Method, Proc].each do |callable|
113
- refine callable do
114
- def map_call_arguments(*arguments, **options)
115
- CoreExtensions.map_call_arguments(signature: parameters, arguments: arguments, options: options)
68
+ def name_without_common_parents(base:)
69
+ path = name&.split("::")
70
+
71
+ result = if path
72
+ base_path = base&.name&.split("::")
73
+ path.remove_common_prefix(base_path).join("::") if base_path
116
74
  end
117
75
 
118
- def invoke(*arguments, **options, &block)
119
- arguments, options = map_call_arguments(*arguments, **options)
120
- call(*arguments, **options, &block)
76
+ result || name
77
+ end
78
+ end
79
+
80
+ Module.include(ModuleMixins)
81
+
82
+ module ArrayMixins
83
+ def remove_common_prefix(other)
84
+ drop_while.with_index do |element, index|
85
+ index < size && element == other[index]
121
86
  end
87
+ end
88
+ end
122
89
 
123
- def invoke_with_target(target, *arguments, **options)
124
- arguments, options = map_call_arguments(*arguments, **options)
125
- target.instance_exec(*arguments, **options, &self)
90
+ Array.include(ArrayMixins)
91
+
92
+ module CallableMixins
93
+ REQUIRED_ARGUMENT_TYPES = %i[req keyreq].freeze
94
+
95
+ def map_call_arguments(arguments:, keywords:)
96
+ min_argument_count = 0
97
+ max_argument_count = 0
98
+ option_names = Set.new
99
+
100
+ parameters.each do |type, name|
101
+ case type
102
+ when :req
103
+ min_argument_count += 1
104
+ max_argument_count += 1
105
+ when :opt
106
+ max_argument_count += 1
107
+ when :rest
108
+ max_argument_count = nil
109
+ when :keyreq
110
+ raise ArgumentError, "Required option #{name} missing for #{self} #{parameters}" unless keywords.key?(name)
111
+
112
+ option_names << name
113
+ when :key
114
+ option_names << name
115
+ when :keyrest
116
+ option_names += keywords.keys
117
+ when :block
118
+ # ignore
119
+ else
120
+ raise ArgumentError, "Illegal parameter type #{type} for #{self} #{parameters}"
121
+ end
126
122
  end
127
123
 
128
- def source_location_info
129
- source_location ? source_location.join(":") : nil
124
+ argument_count = arguments.size
125
+ argument_count = max_argument_count if max_argument_count && argument_count > max_argument_count
126
+
127
+ if argument_count < min_argument_count
128
+ raise ArgumentError, "Not enough parameters to call proc with #{parameters}"
130
129
  end
130
+
131
+ arguments = arguments[0...argument_count]
132
+ keywords = keywords.slice(*option_names)
133
+
134
+ [arguments, keywords]
135
+ end
136
+
137
+ def invoke(*arguments, **keywords, &block)
138
+ arguments, keywords = map_call_arguments(arguments: arguments, keywords: keywords)
139
+ call(*arguments, **keywords, &block)
140
+ end
141
+
142
+ def invoke_with_target(target, *arguments, **keywords)
143
+ arguments, keywords = map_call_arguments(arguments: arguments, keywords: keywords)
144
+ target.instance_exec(*arguments, **keywords, &self)
145
+ end
146
+
147
+ def source_location_info
148
+ source_location ? source_location.join(":") : nil
149
+ end
150
+
151
+ def required_arguments?
152
+ parameters.any? { |type, _name| REQUIRED_ARGUMENT_TYPES.include?(type) }
131
153
  end
132
154
  end
155
+
156
+ Method.include(CallableMixins)
157
+ Proc.include(CallableMixins)
133
158
  end
134
159
  end
135
160
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Calificador
4
+ module Util
5
+ # Base class for proxy objects
6
+ class ProxyObject < BasicObject
7
+ FALLBACK_METHODS = %i[class to_s inspect eval].freeze
8
+
9
+ def respond_to?(name, include_all = false) # rubocop:disable Style/OptionalBooleanParameter
10
+ __class.public_instance_methods(true).include?(name) ||
11
+ include_all && (
12
+ __class.protected_instance_methods(true).include?(name) ||
13
+ __class.private_instance_methods(true).include?(name)
14
+ ) ||
15
+ respond_to_missing?(name, include_all)
16
+ end
17
+
18
+ def respond_to_missing?(name, include_all)
19
+ name.start_with?("__") ? false : __respond_to_missing?(name: name, include_all: include_all)
20
+ end
21
+
22
+ def method_missing(name, *arguments, **keywords, &block)
23
+ if name.start_with?("__")
24
+ super(name, *arguments, **keywords, &block)
25
+ else
26
+ __method_missing(name: name, arguments: arguments, keywords: keywords, block: block)
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def __class
33
+ (class << self; self end).superclass
34
+ end
35
+
36
+ def __to_s
37
+ "#<#{__class}>"
38
+ end
39
+
40
+ def __inspect
41
+ "#<#{__class}>"
42
+ end
43
+
44
+ def __eval(*arguments)
45
+ instance_eval(*arguments)
46
+ end
47
+
48
+ def __respond_to_missing?(name:, include_all:)
49
+ false
50
+ end
51
+
52
+ def __method_missing(name:, arguments:, keywords:, block:)
53
+ if ::Kernel.respond_to?(name)
54
+ ::Kernel.send(name, *arguments, **keywords, &block)
55
+ elsif FALLBACK_METHODS.include?(name)
56
+ __send__(:"__#{name}", *arguments, **keywords, &block)
57
+ else
58
+ ::Kernel.raise ::NoMethodError, "undefined name `#{name}' for #{__class}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Calificador
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calificador
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jochen Seeber
8
8
  autorequire:
9
9
  bindir: cmd
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: docile
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 1.3.5
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 1.3.5
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: minitest
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +52,6 @@ dependencies:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
54
  version: '2.1'
69
- - !ruby/object:Gem::Dependency
70
- name: coveralls
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - '='
74
- - !ruby/object:Gem::Version
75
- version: 0.8.23.js
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - '='
81
- - !ruby/object:Gem::Version
82
- version: 0.8.23.js
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: debase
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -201,25 +173,32 @@ extra_rdoc_files: []
201
173
  files:
202
174
  - LICENSE.txt
203
175
  - README.md
176
+ - TODO.md
177
+ - calificador.gemspec
204
178
  - lib/calificador.rb
179
+ - lib/calificador/assert.rb
205
180
  - lib/calificador/assertor.rb
206
181
  - lib/calificador/build/attribute.rb
207
- - lib/calificador/build/attribute_container.rb
208
182
  - lib/calificador/build/attribute_evaluator.rb
209
- - lib/calificador/build/factory.rb
183
+ - lib/calificador/build/basic_factory.rb
184
+ - lib/calificador/build/mock_factory.rb
185
+ - lib/calificador/build/object_factory.rb
210
186
  - lib/calificador/build/trait.rb
187
+ - lib/calificador/context/basic_context.rb
188
+ - lib/calificador/context/class_method_context.rb
189
+ - lib/calificador/context/condition_context.rb
190
+ - lib/calificador/context/instance_context.rb
191
+ - lib/calificador/context/operation_context.rb
192
+ - lib/calificador/context/override/argument_override.rb
193
+ - lib/calificador/context/override/basic_override.rb
194
+ - lib/calificador/context/override/factory_override.rb
195
+ - lib/calificador/context/override/property_override.rb
196
+ - lib/calificador/context/test_environment.rb
197
+ - lib/calificador/context/test_method.rb
198
+ - lib/calificador/context/test_root.rb
199
+ - lib/calificador/context/type_context.rb
211
200
  - lib/calificador/key.rb
212
201
  - lib/calificador/minitest/minitest_patches.rb
213
- - lib/calificador/spec/basic_context.rb
214
- - lib/calificador/spec/class_method_context.rb
215
- - lib/calificador/spec/condition_context.rb
216
- - lib/calificador/spec/examine_context.rb
217
- - lib/calificador/spec/instance_method_context.rb
218
- - lib/calificador/spec/test_environment.rb
219
- - lib/calificador/spec/test_method.rb
220
- - lib/calificador/spec/test_root.rb
221
- - lib/calificador/spec/type_context.rb
222
- - lib/calificador/spec/value_override.rb
223
202
  - lib/calificador/test.rb
224
203
  - lib/calificador/test_mixin.rb
225
204
  - lib/calificador/util/call_formatter.rb
@@ -227,6 +206,7 @@ files:
227
206
  - lib/calificador/util/core_extensions.rb
228
207
  - lib/calificador/util/missing.rb
229
208
  - lib/calificador/util/nil.rb
209
+ - lib/calificador/util/proxy_object.rb
230
210
  - lib/calificador/version.rb
231
211
  homepage: https://github.com/jochenseeber/calificador
232
212
  licenses: []
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Calificador::Util::CoreExtensions
4
-
5
- module Calificador
6
- module Build
7
- # Factory calss
8
- class AttributeContainer
9
- class Dsl
10
- def initialize(delegate:)
11
- @delegate = delegate
12
- @property_type = nil
13
- end
14
-
15
- def add_attribute(name, type: nil, &config)
16
- type ||= @delegate.parent&.attribute(name: name)&.type || @property_type || :property
17
- @delegate.add_attribute(Attribute.new(name: name, type: type, config: config))
18
- end
19
-
20
- def transient(&block)
21
- raise ArgumentError, "Transient requires a block" if block.nil?
22
-
23
- old_property_type = @property_type
24
- @property_type = :transient
25
-
26
- begin
27
- instance_exec(self, &block)
28
- ensure
29
- @property_type = old_property_type
30
- end
31
- end
32
-
33
- def init_with(&block)
34
- raise "Initializer requires a block to create the object" if block.nil?
35
-
36
- @delegate.init_with = block
37
- end
38
-
39
- def before_create(&block)
40
- raise "Before requires a block to call" if block.nil?
41
-
42
- @delegate.before_create = block
43
- end
44
-
45
- def after_create(&block)
46
- raise "After requires a block to call" if block.nil?
47
-
48
- @delegate.after_create = block
49
- end
50
-
51
- def respond_to_missing?(method, include_all = false)
52
- if method.start_with?("__")
53
- super
54
- else
55
- true
56
- end
57
- end
58
-
59
- def method_missing(method, *arguments, &block)
60
- if method.start_with?("__")
61
- super
62
- else
63
- unless arguments.empty?
64
- raise ::ArgumentError, <<~ERROR
65
- Attribute #{method} cannot have arguments. Please use a block to configure the value
66
- ERROR
67
- end
68
-
69
- raise ::ArgumentError, "Attribute #{method} must have a block to provide the value" if block.nil?
70
-
71
- add_attribute(method, &block)
72
- end
73
- end
74
- end
75
-
76
- attr_reader :parent, :description
77
- attr_accessor :init_with, :before_create, :after_create
78
-
79
- def initialize(parent:, description:)
80
- @parent = parent
81
- @description = description.dup.freeze
82
- @attributes = {}
83
- @init_with = nil
84
- @before_create = nil
85
- @after_create = nil
86
- end
87
-
88
- def attributes
89
- @attributes.dup.freeze
90
- end
91
-
92
- def attribute(name:)
93
- @attributes[name]
94
- end
95
-
96
- def add_attribute(attribute)
97
- raise KeyError, "Duplicate attribute name #{name}" if @attributes.key?(attribute.name)
98
-
99
- @attributes[attribute.name] = attribute
100
- end
101
- end
102
- end
103
- end