Skip to content

Instantly share code, notes, and snippets.

@jonaphin
Created June 28, 2011 03:53
Show Gist options
  • Save jonaphin/1050452 to your computer and use it in GitHub Desktop.
Save jonaphin/1050452 to your computer and use it in GitHub Desktop.
Fun with Hashes and to_proc implementation
### Jonathan Lancar - https://github.com/jonaphin ###
#########################
## Simple Hash Example ##
#########################
class Hash
# if argument passed to the hash is a key of it,
# call the hash's value (at key) as a method that acts on said key
def to_proc
proc { |arg| self.has_key?(arg) ? self[arg].to_proc.call(arg) : arg }
end
end
## USE-CASE ##
a_hash = {"name" => :upcase, :id => :to_s}
params = ["name", :id, 3, 4]
params.map &a_hash
# => ["NAME", "id", 3, 4]
################################
## A More Interesting Example ##
################################
=begin *** REASONING ***
Hashes are great at data representation. The versatility of the key-value pair scheme is just enough organization
for defining any kind of data structure.
As a proc, it may feel natural, in a theoritical environment, to boost the Hash's status to dare become the structure it normally represents.
Along this line of thinking, I went ahead and made Hash#to_proc transform key-value to Class#method / Class#method(arg)
This implementation does not cover all cases, but may serve as a basis for future work in the direction it takes
=end
class Hash
# Processes arg through a method or a series of methods according to arg's type
# This implementation matches arg's type to its ancestors as well
# Hash can be formed as follows
# {
# class_type => :method,
# class_type => [:first_method, second_method],
# class_type => {:method, :argument}
# }
def to_proc
proc { |arg|
_type = arg.class
if self.has_key_of_type?(_type)
_type = key_for_type(_type)
if self[_type].is_a?(Hash)
arg.send(self[_type].first[0].to_sym, self[_type].first[1])
else
self[_type].to_proc.call(arg)
end
else
arg
end
}
end
def has_key_of_type?(a_key)
self.each_key{|key| return true if a_key < key }
false
end
def key_for_type(a_key)
return nil unless has_key_of_type?(a_key)
self.each_key{|key| return key if a_key < key }
end
end
## Our example requires the following implementation Array#to_proc ##
class Array
# Calls each element on arg iteratively
# Returns the last iteration (the 'arg' for which all methods have been applied)
def to_proc
proc { |arg| self.map { |idx| arg = idx.to_proc.call(arg) }.last }
end
def to_leet
tmp = LeetArray.new
self.each{|x| tmp.push(x) }
tmp
end
end
# Let's also create LeetArray for the sake of testing
# if inherited classes also benefit from our proc-ed Hash
class LeetArray < Array
end
## USE-CASE ##
a_hash = {String => :downcase, Fixnum => :to_s, Symbol => [:to_s, :upcase], Array => {:join => " "} }
params = ["Hello", 3, :world, ["how", "are", "you?"].to_leet]
p params.map &a_hash
# => ["hello", "3", "WORLD", "how are you?"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment