structure 3.5.0 → 3.6.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: 69015a521f4a1a35438cd69d0d195e8f0fa276156d64371c8a6437030b14caf0
4
- data.tar.gz: d4e5c263a7c92ae2bfbdbe5213b933c55ea1a8f0c9a8d6583302f8c032bb69a9
3
+ metadata.gz: 5f6aed363a91e514906a1c005fe2af6ec3583fa8742f997055def47e1f085c0c
4
+ data.tar.gz: 574b02c68a6a84f98384d9ba60c8b2d88b95c2cb3db49aa2eccb61e3e1dfc9ab
5
5
  SHA512:
6
- metadata.gz: 1e8ace0197fb9b9cd4811cc1eb7774fe98eff67df140400b567a0a636b9bdabcf2e7858586a7b13f96fbc95e101e2eef74518d9940b1f7c4dab168fec119fb3e
7
- data.tar.gz: 9d7fa653f6b4aeb60b10bfca4a940677bee89c6803a8e50d893e9dc0ce687306691bbb6f92f4af0a59c89245c3583e8b6d64f477d27b44b71f0f1b7fc359bb26
6
+ metadata.gz: 0a73835caa30f00145df491efd1bbcedbb2a7ada0cd0b2328cc8c0d9004bd51607328883630529165e9863a9852df40e17414854133a1d1d0144f690e49a50ef
7
+ data.tar.gz: ecb9bc59302300646d8dad3ea1345aecf236aec833e35cf1c83cedbfe5de5369c87965f3877d93e952cbf3536ff603fea2564032a07dba3db77c9872a4d46318
@@ -60,8 +60,8 @@ module Structure
60
60
  @mappings.keys
61
61
  end
62
62
 
63
- def coercions
64
- @types.transform_values { |type| Types.coerce(type) }
63
+ def coercions(context_class = nil)
64
+ @types.transform_values { |type| Types.coerce(type, context_class) }
65
65
  end
66
66
 
67
67
  def predicate_methods
@@ -11,7 +11,7 @@ module Structure
11
11
 
12
12
  # Main factory method for creating type coercers
13
13
  #
14
- # @param type [Class, Symbol, Array] Type specification
14
+ # @param type [Class, Symbol, Array, String] Type specification
15
15
  # @return [Proc, Object] Coercion proc or the type itself if no coercion available
16
16
  #
17
17
  # @example Boolean type
@@ -25,15 +25,20 @@ module Structure
25
25
  #
26
26
  # @example Array types
27
27
  # coerce([String]) # => proc that coerces array elements to String
28
- def coerce(type)
28
+ #
29
+ # @example String class name (lazy resolved)
30
+ # coerce("MyClass") # => proc that resolves and coerces to MyClass
31
+ def coerce(type, context_class = nil)
29
32
  case type
30
33
  when :boolean
31
34
  boolean
32
35
  when :self
33
36
  self_referential
37
+ when String
38
+ string_class(type, context_class)
34
39
  when Array
35
40
  if type.length == 1
36
- array(type.first)
41
+ array(type.first, context_class)
37
42
  else
38
43
  type
39
44
  end
@@ -48,6 +53,25 @@ module Structure
48
53
  end
49
54
  end
50
55
 
56
+ def resolve_class(class_name, context_class)
57
+ if context_class && defined?(context_class.name)
58
+ namespace = context_class.name.to_s.split("::")[0...-1]
59
+ if namespace.any?
60
+ begin
61
+ namespace.reduce(Object) { |mod, name| mod.const_get(name) }.const_get(class_name)
62
+ rescue NameError
63
+ Object.const_get(class_name)
64
+ end
65
+ else
66
+ Object.const_get(class_name)
67
+ end
68
+ else
69
+ Object.const_get(class_name)
70
+ end
71
+ rescue NameError => e
72
+ raise NameError, "Unable to resolve class '#{class_name}': #{e.message}"
73
+ end
74
+
51
75
  private
52
76
 
53
77
  def boolean
@@ -66,7 +90,19 @@ module Structure
66
90
  ->(val) { type.parse(val) }
67
91
  end
68
92
 
69
- def array(element_type)
93
+ def string_class(class_name, context_class)
94
+ resolved_class = nil
95
+ proc do |value|
96
+ resolved_class ||= Structure::Types.resolve_class(class_name, context_class)
97
+ if resolved_class.respond_to?(:parse)
98
+ resolved_class.parse(value) # steep:ignore
99
+ else
100
+ value
101
+ end
102
+ end
103
+ end
104
+
105
+ def array(element_type, context_class = nil)
70
106
  if element_type == :self
71
107
  proc do |value|
72
108
  unless value.respond_to?(:map)
@@ -75,8 +111,23 @@ module Structure
75
111
 
76
112
  value.map { |element| parse(element) }
77
113
  end
114
+ elsif element_type.is_a?(String)
115
+ proc do |value|
116
+ unless value.respond_to?(:map)
117
+ raise TypeError, "can't convert #{value.class} into Array"
118
+ end
119
+
120
+ resolved_class = Structure::Types.resolve_class(element_type, context_class)
121
+ value.map do |element|
122
+ if resolved_class.respond_to?(:parse)
123
+ resolved_class.parse(element)
124
+ else
125
+ element
126
+ end
127
+ end
128
+ end
78
129
  else
79
- element_coercer = coerce(element_type)
130
+ element_coercer = coerce(element_type, context_class)
80
131
  lambda do |value|
81
132
  unless value.respond_to?(:map)
82
133
  raise TypeError, "can't convert #{value.class} into Array"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Structure
4
- VERSION = "3.5.0"
4
+ VERSION = "3.6.0"
5
5
  end
data/lib/structure.rb CHANGED
@@ -37,13 +37,13 @@ module Structure
37
37
 
38
38
  # capture locals for method generation
39
39
  mappings = builder.mappings
40
- coercions = builder.coercions
40
+ coercions = builder.coercions(klass)
41
41
  predicates = builder.predicate_methods
42
42
  after = builder.after_parse_callback
43
43
 
44
44
  # Define predicate methods
45
45
  predicates.each do |pred, attr|
46
- klass.define_method(pred) { public_send(attr) }
46
+ klass.define_method(pred) { !!public_send(attr) }
47
47
  end
48
48
 
49
49
  # recursive to_h
@@ -14,7 +14,7 @@ module Structure
14
14
  def mappings: () -> Hash[Symbol, String]
15
15
  def types: () -> Hash[Symbol, untyped]
16
16
  def defaults: () -> Hash[Symbol, untyped]
17
- def coercions: () -> Hash[Symbol, Proc]
17
+ def coercions: (?untyped? context_class) -> Hash[Symbol, Proc]
18
18
  def predicate_methods: () -> Hash[Symbol, Symbol]
19
19
  def after_parse_callback: () -> (Proc | nil)
20
20
  end
@@ -4,11 +4,13 @@ module Structure
4
4
 
5
5
  self.@boolean: Proc
6
6
 
7
- def self.coerce: (untyped type) -> untyped
7
+ def self.coerce: (untyped type, ?untyped? context_class) -> untyped
8
+ def self.resolve_class: (String class_name, untyped? context_class) -> untyped
8
9
 
9
10
  private def self.boolean: () -> Proc
10
11
  private def self.self_referential: () -> Proc
11
- private def self.array: (untyped type) -> Proc
12
+ private def self.string_class: (String class_name, untyped? context_class) -> Proc
13
+ private def self.array: (untyped element_type, ?untyped? context_class) -> Proc
12
14
  private def self.parseable: (untyped type) -> Proc
13
15
  private def self.kernel: (Class type) -> Proc
14
16
  private def self.parse: (untyped val) -> untyped
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structure
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.0
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hakan Ensari