Created
September 26, 2013 07:41
-
-
Save maraigue/6710983 to your computer and use it in GitHub Desktop.
[Ruby] Hashのキーをドット繋ぎでもアクセス可能にする(hoge[:piyo] → hoge.piyo)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# -*- coding: utf-8 -*- | |
class Hash | |
# hashobj[:hoge] を hashobj.hoge でもアクセス可能にする | |
# ・値の読み取りはどんなキーでも対象 | |
# ・値の書き込みはすでに存在するキーのみ対象 | |
# ・すでに存在するメソッドと名前が重複した場合は、 | |
# すでに存在するメソッドへのアクセスが優先される | |
# ・当該名称のキーがStringとSymbolの両方で存在する場合は例外 | |
# (例えば、{:a => 1, "a" => 3}.method_type_access.a は例外) | |
def method_type_access | |
instance_eval do | |
def method_missing(method_name, *args) | |
n = method_name.to_s | |
if n[-1] == "=" | |
n = n[0..-2] | |
access = :write | |
raise ArgumentError, "wrong number of arguments(#{args.size} for 1)" if args.size != 1 | |
else | |
access = :read | |
raise ArgumentError, "wrong number of arguments(#{args.size} for 0)" if args.size != 0 | |
end | |
if self[n] | |
if self[n.intern] | |
raise KeyError, "duplicated keys: #{n.inspect} and #{n.intern.inspect}" | |
else | |
target = n | |
end | |
elsif self[n.intern] | |
target = n.intern | |
else | |
raise NameError, "undefined method `#{method_name}' for: #{self.inspect}:#{self.class}" | |
end | |
if access == :write | |
self[target] = args.first | |
else | |
self[target] | |
end | |
end | |
end | |
self | |
end | |
end | |
if $0 == __FILE__ | |
# 普通に使う例 | |
puts "[hash1]" | |
hash1 = {:a => 1, :b => 2, :object_id => "hoge"} | |
hash1.method_type_access | |
p hash1.a | |
p hash1.b | |
hash1.b = 5 | |
p hash1.b | |
begin | |
hash1.c # 例外発生 | |
rescue Exception => e | |
puts "ERROR(#{e.class}): #{e}" | |
end | |
p hash1.object_id # "hoge"ではなく、本来のobject_idメソッドが呼び出される | |
hash1.object_id = "piyo" # でもこれはハッシュの値へのアクセスになる | |
p hash1[:object_id] # なのでここでは"piyo"が表示される | |
# キーが重複している例 | |
puts "[hash2]" | |
hash2 = {:a => 1, "a" => 3} | |
hash2.method_type_access | |
begin | |
hash2.a # 例外発生 | |
rescue Exception => e | |
puts "ERROR(#{e.class}): #{e}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment