lib/hamster/nested.rb
require "set" require "hamster/hash" require "hamster/set" require "hamster/vector" require "hamster/sorted_set" require "hamster/list" require "hamster/deque" require "hamster/core_ext/struct" module Hamster class << self # Create a Hamster immutable data structure with nested Hamster data # structure from a nested Ruby object `obj`. This method recursively # "walks" the Ruby object, converting Ruby `Hash` to {Hamster::Hash}, Ruby # `Array` to {Hamster::Vector}, Ruby `Set` to {Hamster::Set}, and Ruby # `SortedSet` to {Hamster::SortedSet}. Other objects are left as-is. # # @example # h = Hamster.from({ "a" => [1, 2], "b" => "c" }) # # => Hamster::Hash["a" => Hamster::Vector[1, 2], "b" => "c"] # # @return [Hash, Vector, Set, SortedSet, Object] def from(obj) case obj when ::Hash res = obj.map { |key, value| [from(key), from(value)] } Hamster::Hash.new(res) when Hamster::Hash obj.map { |key, value| [from(key), from(value)] } when ::Struct from(obj.to_h) when ::Array res = obj.map { |element| from(element) } Hamster::Vector.new(res) when ::SortedSet # This clause must go before ::Set clause, since ::SortedSet is a ::Set. res = obj.map { |element| from(element) } Hamster::SortedSet.new(res) when ::Set res = obj.map { |element| from(element) } Hamster::Set.new(res) when Hamster::Vector, Hamster::Set, Hamster::SortedSet obj.map { |element| from(element) } else obj end end # Create a Ruby object from Hamster data. This method recursively "walks" # the Hamster object, converting {Hamster::Hash} to Ruby `Hash`, # {Hamster::Vector} and {Hamster::Deque} to Ruby `Array`, {Hamster::Set} # to Ruby `Set`, and {Hamster::SortedSet} to Ruby `SortedSet`. Other # objects are left as-is. # # @example # h = Hamster.to_ruby(Hamster.from({ "a" => [1, 2], "b" => "c" })) # # => { "a" => [1, 2], "b" => "c" } # # @return [::Hash, ::Array, ::Set, ::SortedSet, Object] def to_ruby(obj) case obj when Hamster::Hash, ::Hash obj.each_with_object({}) { |keyval, hash| hash[to_ruby(keyval[0])] = to_ruby(keyval[1]) } when Hamster::Vector, ::Array obj.each_with_object([]) { |element, arr| arr << to_ruby(element) } when Hamster::Set, ::Set obj.each_with_object(::Set.new) { |element, set| set << to_ruby(element) } when Hamster::SortedSet, ::SortedSet obj.each_with_object(::SortedSet.new) { |element, set| set << to_ruby(element) } when Hamster::Deque obj.to_a.tap { |arr| arr.map! { |element| to_ruby(element) }} else obj end end end end