calificador 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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