Skip to content

Instantly share code, notes, and snippets.

@radiospiel
Created January 26, 2017 07:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save radiospiel/af6d55bbe2714bf1c44e58a1295576f3 to your computer and use it in GitHub Desktop.
Save radiospiel/af6d55bbe2714bf1c44e58a1295576f3 to your computer and use it in GitHub Desktop.
def Immutable(object)
Immutable.create(object)
end
class Immutable
# turns an object, which can be a hash or array of hashes, arrays, and scalars
# into an object which you can use to access with dot methods.
def self.create(object, max_depth = 5)
case object
when Array
raise ArgumentError, 'Object nested too deep (or inner loop?)' if max_depth < 0
object.map { |obj| create obj, max_depth - 1 }
when Hash
Immutable.new(object)
else
object
end
end
private
def initialize(hsh)
@hsh = hsh
end
def method_missing(sym, *args, &block)
if args.empty? && !block
begin
value = @hsh.fetch(sym.to_sym) { @hsh.fetch(sym.to_s) }
return Immutable.create(value)
rescue KeyError
STDERR.puts "Missing attribute #{sym} for Immutable w/#{@hsh.inspect}"
end
end
super
end
public
def respond_to?(sym)
super || @hsh.key?(sym.to_s) || @hsh.key?(sym.to_sym)
end
def ==(other)
@hsh == other
end
end
if __FILE__ == $0
require "test-unit"
class Immutable::TestCase < Test::Unit::TestCase
def hsh
{
a: "a-value",
"b": "b-value",
"child": {
name: "childname",
grandchild: {
name: "grandchildname"
}
},
"children": [
"anna",
"arthur",
{
action: {
keep_your_mouth_shut: true
}
}
]
}
end
def immutable
Immutable hsh
end
def test_hash_access
assert_equal "a-value", immutable.a
assert_equal "b-value", immutable.b
end
def test_comparison
immutable = Immutable hsh
assert_equal immutable, hsh
assert_not_equal({}, immutable)
end
def test_child_access
child = immutable.child
assert_kind_of(Immutable, child)
assert_equal "childname", immutable.child.name
assert_equal "grandchildname", immutable.child.grandchild.name
end
def test_array_access
assert_kind_of(Array, immutable.children)
assert_equal 3, immutable.children.length
assert_equal "anna", immutable.children[0]
assert_kind_of(Immutable, immutable.children[2])
assert_equal true, immutable.children[2].action.keep_your_mouth_shut
end
def test_base_class
assert_nothing_raised {
immutable.object_id
}
end
def test_missing_keys
assert_raise(NoMethodError) {
immutable.foo
}
end
def test_skip_when_args_or_block
assert_raise(NoMethodError) {
immutable.a(1,2,3)
}
assert_raise(NoMethodError) {
immutable.a { :dummy }
}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment