Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ruby/from_hash/.rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Layout/LineLength:
Metrics/AbcSize:
Max: 22

Metrics/ClassLength:
Max: 106

Metrics/CyclomaticComplexity:
Max: 12

Expand All @@ -26,4 +29,4 @@ Metrics/PerceivedComplexity:
Naming/FileName:
Exclude:
# Filename deliberately matches gem name
- 'lib/optify-from_hash.rb'
- 'lib/optify-from_hash.rb'
2 changes: 1 addition & 1 deletion ruby/from_hash/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
optify-from_hash (0.2.1)
optify-from_hash (0.2.2)
sorbet-runtime (>= 0.5, < 1)

GEM
Expand Down
24 changes: 16 additions & 8 deletions ruby/from_hash/lib/optify_from_hash/from_hashable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,13 @@ def self._convert_value(value, type)
return value
end

return value.to_sym if type.is_a?(T::Types::Simple) && type.raw_type == Symbol
unwrapped_type = _unwrap_nilable(type)
return value&.to_sym if unwrapped_type.is_a?(T::Types::Simple) && unwrapped_type.raw_type == Symbol

case value
when Array
# Handle `T.nilable(T::Array[...])`
if type.respond_to?(:unwrap_nilable)
type = type #: as untyped
.unwrap_nilable
end
inner_type = type.type
inner_type = unwrapped_type #: as untyped
.type
return value.map { |v| _convert_value(v, inner_type) }.freeze
when Hash
# Handle `T.nilable(T::Hash[...])` and `T.any(...)`.
Expand Down Expand Up @@ -104,7 +101,18 @@ def self._convert_hash(hash, type)
raise TypeError, "Could not convert hash #{hash} to `#{type}`."
end

private_class_method :_convert_hash, :_convert_value
# Unwrap `T.nilable(...)` to get the inner type, or return the type as-is.
#: (T::Types::Base) -> T::Types::Base
def self._unwrap_nilable(type)
if type.respond_to?(:unwrap_nilable)
type #: as untyped
.unwrap_nilable
else
type
end
end

private_class_method :_convert_hash, :_convert_value, :_unwrap_nilable

# Compare this object with another object for equality.
# @param other The object to compare.
Expand Down
2 changes: 1 addition & 1 deletion ruby/from_hash/optify-from_hash.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

LIB_VERSION = '0.2.1'
LIB_VERSION = '0.2.2'

Gem::Specification.new do |spec|
spec.name = 'optify-from_hash'
Expand Down
2 changes: 1 addition & 1 deletion ruby/from_hash/test/.rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Metrics/AbcSize:
Max: 45

Metrics/ClassLength:
Max: 260
Max: 280

Metrics/MethodLength:
Max: 40
27 changes: 27 additions & 0 deletions ruby/from_hash/test/from_hash_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class TestConfig < Optify::FromHashable
sig { returns(T::Array[T::Hash[Symbol, TestObject]]) }
attr_reader :hashes

sig { returns(Symbol) }
attr_reader :symbol

sig { returns(T.nilable(Symbol)) }
attr_reader :nilable_symbol

sig { returns(T::Hash[Symbol, Symbol]) }
attr_reader :symbol_to_symbol

Expand Down Expand Up @@ -365,6 +371,27 @@ def skip_test_nilable_hash_with_string_or_object_or_object2_invalid_value
exception.message)
end

def test_symbol
hash = { 'symbol' => 'hello' }
c = TestConfig.from_hash(hash)
assert_instance_of(Symbol, c.symbol)
assert_equal(:hello, c.symbol)
assert_equal({ symbol: :hello }, c.to_h)
end

def test_nilable_symbol
hash = { 'nilable_symbol' => 'world' }
c = TestConfig.from_hash(hash)
assert_instance_of(Symbol, c.nilable_symbol)
assert_equal(:world, c.nilable_symbol)
assert_equal({ nilable_symbol: :world }, c.to_h)

hash = { 'nilable_symbol' => nil }
c = TestConfig.from_hash(hash)
assert_nil(c.nilable_symbol)
assert_equal({ nilable_symbol: nil }, c.to_h)
end

def test_symbol_to_symbol
hash = { 'symbol_to_symbol' => { 'key' => 'value' } }
c = TestConfig.from_hash(hash)
Expand Down
Loading