Last active
August 29, 2015 14:04
-
-
Save jszmajda/08603f08f554c87268d5 to your computer and use it in GitHub Desktop.
Dot Notation
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
# Simple-ish enumberable-simplifier. Useful for APIs like Twitter, etc | |
# | |
# If you have a hash or an array or something that quacks like one, you can do stuff | |
# example: | |
# h = {a: {b: {c: [{d: 'hi'}]}}} | |
# h.extend(DotNotation) | |
# h.dot('a.b.c.0.d') | |
# #=> 'hi' | |
# h.dot('a.b.c.foo.bar.bz.whatever.124.whocares') | |
# #=> nil | |
# | |
module DotNotation | |
def self.included(base) | |
raise "Unsupported Class" unless base.respond_to?('[]') | |
end | |
def dot(path) | |
return nil if self.nil? # optimization for NilClass | |
data = self | |
path.split(/\./).each do |selector| | |
selector = selector.to_i if selector =~ /^\d+$/ | |
if value = access(data, selector) | |
data = value | |
else | |
return nil | |
end | |
end | |
if @dot_options && @dot_options[:autodot] | |
extend_result!(data) | |
data.each{|e| extend_result!(e) } if data.kind_of? Array | |
end | |
data | |
end | |
def dot_options(options) | |
@dot_options = (@dot_options || {}).merge(options) | |
end | |
private | |
def extend_result!(result) | |
begin | |
result.extend(DotNotation) | |
result.dot_options(@dot_options) | |
rescue TypeError | |
# ignore, we get this when trying to extend an int or something | |
end | |
end | |
def access(data, selector) | |
if defined?(ActiveRecord::Base) && data.kind_of?(ActiveRecord::Base) | |
access_active_record(data, selector) | |
else | |
access_generic(data, selector) | |
end | |
end | |
def access_active_record(data, selector) | |
selsym = selector.respond_to?(:to_sym) ? selector.to_sym : nil | |
if selsym && data.respond_to?(selsym) | |
data.send(selsym) | |
else | |
access_generic(data, selector) | |
end | |
end | |
def access_generic(data, selector) | |
if data[selector] | |
data[selector] | |
else | |
selsym = selector.respond_to?(:to_sym) ? selector.to_sym : nil | |
if selsym && data[selsym] | |
data[selsym] | |
else | |
nil | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This will trash your method cache. Don't use unless you don't care