low_type 1.1.12 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2fcf04f2854f50e253d36245bf0d9fa90d94248a991e4717641a24c05450ec0
4
- data.tar.gz: 9b928d0bc25abe8e6ea5587e20df05b81e34df27f5df77ae42e8b67e97bdb01e
3
+ metadata.gz: 218e91b66e1cd32b9760929f79046c215475f4b07416589443e92cd61ff35af5
4
+ data.tar.gz: bd69d269f5d4cab60a1e9b1277c93d62ab9540ae483a9c176921062150ef4430
5
5
  SHA512:
6
- metadata.gz: a8286bae517dc33436bef96d00beac3880c030c408f50380d2ce69e94918155d139da500bd907f5d32e1423f2f0c1195b411f78e9cd7cfcaa87bcad01a4a4a2c
7
- data.tar.gz: af7112a058d902e419e05cd6a698a79624b6441e5568a9b5194dde65f6bbafd645f0a5f8fd24c6b6bf8d88ec40a24bd969ae91a6300c00b1f68d6ec95685ab87
6
+ metadata.gz: e03cedbb09f99af96a08cd6a3d755e775cefea140f9fa25b4a920079298b0e65fefcc27a5600890404c6988b977d6dc3540d3db5abdab37e4347aad6f322bd1e
7
+ data.tar.gz: d31c9c3bd5e645043b4ad710c415858300013000862ab2ef0a6664e3e59751251c448c6a6cbaedf63147446aaa0aca1d5bac433b60952b7a7bd05a05b1342440
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'expressions'
4
4
 
5
+ require_relative 'value_expression'
5
6
  require_relative '../proxies/param_proxy'
6
7
  require_relative '../queries/type_query'
7
8
 
@@ -123,6 +124,10 @@ module Low
123
124
  end
124
125
 
125
126
  def hash_types_match_values?(types:, values:)
127
+ return true if values.empty? && empty_hash_default_value?
128
+ return values.empty? if types.empty?
129
+ return false if values.empty?
130
+
126
131
  # TODO: Shallow validation of hash could be made deeper with user config.
127
132
  types.keys[0] == values.keys[0].class && types.values[0] == values.values[0].class
128
133
  end
@@ -130,9 +135,10 @@ module Low
130
135
  def type_matches_value?(type:, value:, proxy:)
131
136
  if type.instance_of?(Class)
132
137
  return type.match?(value:) if Low::TypeQuery.complex_type?(expression: type)
138
+ return value.value <= type if value.instance_of?(ValueExpression)
133
139
 
134
- return type == value.class
135
- elsif type.instance_of?(::Low::TypeExpression)
140
+ return value.is_a?(type)
141
+ elsif type.instance_of?(Low::TypeExpression)
136
142
  type.validate!(value:, proxy:)
137
143
  return true
138
144
  end
@@ -145,5 +151,9 @@ module Low
145
151
 
146
152
  LowType.config.deep_type_check
147
153
  end
154
+
155
+ def empty_hash_default_value?
156
+ @default_value.is_a?(Hash) && @default_value.empty?
157
+ end
148
158
  end
149
159
  end
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # A value expression presents a type as a value:
4
- # 1. It is an instance
5
- # 2. It has a class method
6
- class ValueExpression
7
- attr_reader :value
3
+ module Low
4
+ # A value expression presents a type as a value:
5
+ # 1. It is an instance
6
+ # 2. It mimics the class method
7
+ class ValueExpression
8
+ attr_reader :value
8
9
 
9
- def initialize(value:)
10
- @value = value
11
- end
10
+ def initialize(value:)
11
+ @value = value
12
+ end
12
13
 
13
- def class
14
- @value
14
+ def class
15
+ @value
16
+ end
15
17
  end
16
18
  end
data/lib/low_type.rb CHANGED
@@ -31,23 +31,36 @@ require_relative 'types/complex_types'
31
31
  # │ │ │◄┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
32
32
  # │ │ │ │ │
33
33
  module LowType
34
- # We do as much as possible on class load rather than on object instantiation to be thread-safe and efficient.
34
+ # Defers evaluation and redefinition until after the class body finishes loading via TracePoint :end.
35
35
  def self.included(klass)
36
36
  file_path = Low::FileQuery.file_path(klass:)
37
37
  file_proxy = Lowkey.load(file_path)
38
38
  class_proxy = file_proxy[klass.name]
39
39
 
40
- Low::Evaluator.evaluate(method_proxies: class_proxy.keyed_methods)
41
-
42
40
  klass.include Low::ExpressionHelpers
43
41
  klass.extend Low::ExpressionHelpers
44
42
  klass.extend Low::TypeAccessors
45
43
  klass.extend Low::Types
46
44
 
47
- klass.prepend Low::Redefiner.redefine(method_proxies: class_proxy.instance_methods, class_proxy:)
48
- klass.singleton_class.prepend Low::Redefiner.redefine(method_proxies: class_proxy.class_methods, class_proxy:)
45
+ # Use TracePoint :end to capture the class binding after the class body finishes loading.
46
+ # At :end time, trace.self is the including class and trace.binding is the class body's binding,
47
+ # stored on class_proxy.class_binding for use by LowType and other consumers.
48
+ tp = TracePoint.new(:end) do |trace|
49
+ next unless trace.self == klass
50
+
51
+ class_proxy.class_binding = trace.binding
52
+
53
+ Low::Evaluator.evaluate(method_proxies: class_proxy.keyed_methods)
54
+
55
+ klass.prepend Low::Redefiner.redefine(method_proxies: class_proxy.instance_methods, class_proxy:)
56
+ klass.singleton_class.prepend Low::Redefiner.redefine(method_proxies: class_proxy.class_methods, class_proxy:)
57
+
58
+ Low::Adapter::Loader.load(klass:, class_proxy:)
59
+
60
+ tp.disable
61
+ end
49
62
 
50
- Low::Adapter::Loader.load(klass:, class_proxy:)
63
+ tp.enable
51
64
  end
52
65
 
53
66
  class << self
@@ -6,24 +6,12 @@ module Low
6
6
  class FileQuery
7
7
  class << self
8
8
  def file_path(klass:)
9
- includer_line = line_from_class(klass:) || line_from_include || ''
10
- file_path = includer_line.split(':').first || ''
9
+ file_path = Object.const_source_location(klass.name).first
11
10
 
12
11
  return file_path if File.exist?(file_path)
13
12
 
14
13
  raise MissingFileError, "No file found at path '#{file_path}'"
15
14
  end
16
-
17
- private
18
-
19
- def line_from_class(klass:)
20
- class_name = klass.to_s.split(':').last # Also remove the module namespaces from the class.
21
- caller.find { |callee| callee.end_with?("<class:#{class_name}>'") }
22
- end
23
-
24
- def line_from_include
25
- caller.find { |callee| callee.end_with?("include'") }
26
- end
27
15
  end
28
16
  end
29
17
  end
data/lib/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Low
4
4
  module Type
5
- VERSION = '1.1.12'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: low_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.12
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
- rubygems_version: 3.7.2
91
+ rubygems_version: 4.0.6
92
92
  specification_version: 4
93
93
  summary: Elegant types in Ruby
94
94
  test_files: []