optify-from_hash 0.2.1 → 0.3.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: 0e24ce9b23b87819fc6688195ca5a90cb43dfbe23b25264e269cf37daa97f531
4
- data.tar.gz: 18e142eb6c75bf80cfab5fb8d64079ec1f7fd2d212e97043def5555d595fcdd0
3
+ metadata.gz: 323fea346213dffe7e7b35edf19d78d2fa2f8ad7febff0dcb43d6982c48e6732
4
+ data.tar.gz: c85f2f191f33306858d91855ae8a32ad0de373d565dca8227250f9c20d59e2fe
5
5
  SHA512:
6
- metadata.gz: ecfa102d64db21405131a02545bfa524eebde5150c9030555faa89e8e802ec6bdf8006fbd90d30a713450a1beb28167302996bbee2507c01f6d67cea3196ad56
7
- data.tar.gz: 1943ab3ab4ec77e5441de4006b1699683a5bf0d9e8151d3b51ef4fcedd00e6eedf5b8baa5e9d42e7edff367f22d29109495e63ee2e6cff197facd2f5edd8ed79
6
+ metadata.gz: 274a651a061c8ac9840de8c75a46391e78ac599ba71135dbd9b748045567f7c957fe8e9ce87b3c43ddf969868d149aa6526327ed26f16204e3a0404413ff7a35
7
+ data.tar.gz: 7b8793ab933e2478b798a06557d812bca70fd9c031394076b06790672162187261cb2f0801bf6f27320ec55b434bf1c827414de65f6804085acc529d3900ca3c
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'json'
5
+ require 'set'
5
6
  require 'sorbet-runtime'
6
7
  require 'tapioca'
7
8
 
@@ -39,6 +40,14 @@ module Optify
39
40
  instance.freeze
40
41
  end
41
42
 
43
+ #: (Array[untyped], untyped) -> (Array[untyped] | Set[untyped])
44
+ def self._convert_array(value, unwrapped_type)
45
+ inner_type = unwrapped_type.type
46
+ return value.map { |v| _convert_value(v, inner_type) }.freeze if unwrapped_type.is_a?(T::Types::TypedArray)
47
+
48
+ Set.new(value.map { |v| _convert_value(v, inner_type) }).freeze
49
+ end
50
+
42
51
  #: (untyped, T::Types::Base) -> untyped
43
52
  def self._convert_value(value, type)
44
53
  if type.is_a?(T::Types::Untyped)
@@ -46,17 +55,12 @@ module Optify
46
55
  return value
47
56
  end
48
57
 
49
- return value.to_sym if type.is_a?(T::Types::Simple) && type.raw_type == Symbol
58
+ unwrapped_type = _unwrap_nilable(type)
59
+ return value&.to_sym if unwrapped_type.is_a?(T::Types::Simple) && unwrapped_type.raw_type == Symbol
50
60
 
51
61
  case value
52
62
  when Array
53
- # Handle `T.nilable(T::Array[...])`
54
- if type.respond_to?(:unwrap_nilable)
55
- type = type #: as untyped
56
- .unwrap_nilable
57
- end
58
- inner_type = type.type
59
- return value.map { |v| _convert_value(v, inner_type) }.freeze
63
+ return _convert_array(value, unwrapped_type)
60
64
  when Hash
61
65
  # Handle `T.nilable(T::Hash[...])` and `T.any(...)`.
62
66
  # We used to use `type = type.unwrap_nilable if type.respond_to?(:unwrap_nilable)`, but it's not needed now that we handle
@@ -104,7 +108,18 @@ module Optify
104
108
  raise TypeError, "Could not convert hash #{hash} to `#{type}`."
105
109
  end
106
110
 
107
- private_class_method :_convert_hash, :_convert_value
111
+ # Unwrap `T.nilable(...)` to get the inner type, or return the type as-is.
112
+ #: (T::Types::Base) -> T::Types::Base
113
+ def self._unwrap_nilable(type)
114
+ if type.respond_to?(:unwrap_nilable)
115
+ type #: as untyped
116
+ .unwrap_nilable
117
+ else
118
+ type
119
+ end
120
+ end
121
+
122
+ private_class_method :_convert_array, :_convert_hash, :_convert_value, :_unwrap_nilable
108
123
 
109
124
  # Compare this object with another object for equality.
110
125
  # @param other The object to compare.
@@ -119,6 +134,23 @@ module Optify
119
134
  end
120
135
  end
121
136
 
137
+ # Support equality by value so that instances can be used in Sets and as Hash keys.
138
+ #: (untyped) -> bool
139
+ def eql?(other)
140
+ return true if other.equal?(self)
141
+ return false if self.class != other.class
142
+
143
+ instance_variables.all? do |name|
144
+ instance_variable_get(name).eql?(other.instance_variable_get(name))
145
+ end
146
+ end
147
+
148
+ # @return [Integer] a hash value based on the object's class and instance variables.
149
+ #: () -> Integer
150
+ def hash
151
+ [self.class, *instance_variables.sort.map { |name| instance_variable_get(name) }].hash
152
+ end
153
+
122
154
  # Convert this object to a JSON string.
123
155
  #: (?JSON::State?) -> String
124
156
  def to_json(state = nil)
@@ -147,7 +179,8 @@ module Optify
147
179
  #: (untyped) -> untyped
148
180
  def self._convert_value_for_to_h(value)
149
181
  case value
150
- when Array
182
+ # Treat sets like arrays for JSON serialization.
183
+ when Array, Set
151
184
  value.map { |v| _convert_value_for_to_h(v) }
152
185
  when Hash
153
186
  value.transform_values { |v| _convert_value_for_to_h(v) }
@@ -5,6 +5,8 @@
5
5
  module Optify
6
6
  # A base class for classes that can be created from a hash.
7
7
  class FromHashable
8
+ extend T::Sig
9
+ extend T::Helpers
8
10
  abstract!
9
11
 
10
12
  # Create a new instance of the class from a hash.
@@ -31,5 +33,13 @@ module Optify
31
33
  # @return [Boolean] true if the objects are equal; otherwise, false.
32
34
  sig { params(other: T.untyped).returns(T::Boolean) }
33
35
  def ==(other); end
36
+
37
+ # Support equality by value so that instances can be used in Sets and as Hash keys.
38
+ sig { params(other: T.untyped).returns(T::Boolean) }
39
+ def eql?(other); end
40
+
41
+ # @return a hash value based on the object's class and instance variables.
42
+ sig { returns(Integer) }
43
+ def hash; end
34
44
  end
35
45
  end
@@ -4,6 +4,8 @@ end
4
4
 
5
5
  # A base class for classes that can be created from a hash.
6
6
  class Optify::FromHashable
7
+ extend T::Helpers
8
+
7
9
  # Create a new instance of the class from a hash.
8
10
  #
9
11
  # @param hash The hash to create the instance from.
@@ -24,4 +26,10 @@ class Optify::FromHashable
24
26
  # @param other The object to compare.
25
27
  # @return [Boolean] true if the objects are equal; otherwise, false.
26
28
  def ==: (untyped other) -> bool
29
+
30
+ # Support equality by value so that instances can be used in Sets and as Hash keys.
31
+ def eql?: (untyped other) -> bool
32
+
33
+ # @return a hash value based on the object's class and instance variables.
34
+ def hash: () -> Integer
27
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optify-from_hash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin D. Harris
@@ -49,14 +49,14 @@ dependencies:
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: 4.0.0.dev.4
52
+ version: 4.0.3
53
53
  type: :development
54
54
  prerelease: false
55
55
  version_requirements: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: 4.0.0.dev.4
59
+ version: 4.0.3
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: sorbet
62
62
  requirement: !ruby/object:Gem::Requirement
@@ -83,14 +83,14 @@ dependencies:
83
83
  requirements:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
- version: 0.17.7
86
+ version: 0.19.1
87
87
  type: :development
88
88
  prerelease: false
89
89
  version_requirements: !ruby/object:Gem::Requirement
90
90
  requirements:
91
91
  - - "~>"
92
92
  - !ruby/object:Gem::Version
93
- version: 0.17.7
93
+ version: 0.19.1
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: test-unit
96
96
  requirement: !ruby/object:Gem::Requirement