Skip to content

Commit

Permalink
Under ruby 2.x, the stdlib OpenStruct provides #[] and #[]=; fixes #816
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeer committed Mar 10, 2014
1 parent 84e23e1 commit 0b8ab23
Showing 1 changed file with 38 additions and 6 deletions.
44 changes: 38 additions & 6 deletions lib/blacklight/utils.rb
@@ -1,29 +1,48 @@
require 'ostruct'
module Blacklight
##
# An OpenStruct that responds to common Hash methods
class OpenStructWithHashAccess < OpenStruct
delegate :keys, :each, :map, :has_key?, :empty?, :delete, :length, :reject!, :select!, :include, :fetch, :to_json, :as_json, :to => :to_h

def []=(key, value)
send "#{key}=", value
end
if ::RUBY_VERSION < '2.0'
def []=(key, value)
send "#{key}=", value
end

def [](key)
send key
def [](key)
send key
end
end

##
# Expose the internal hash
# @return [Hash]
def to_h
@table
end

##
# Merge the values of this OpenStruct with another OpenStruct or Hash
# @param [Hash,#to_h]
# @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess
def merge other_hash
self.class.new to_h.merge((other_hash if other_hash.is_a? Hash) || other_hash.to_h)
end

##
# Merge the values of another OpenStruct or Hash into this object
# @param [Hash,#to_h]
# @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess
def merge! other_hash
@table.merge!((other_hash if other_hash.is_a? Hash) || other_hash.to_h)
end
end


##
# An OpenStruct refinement that converts any hash-keys into
# additional instances of NestedOpenStructWithHashAccess
class NestedOpenStructWithHashAccess < OpenStructWithHashAccess
attr_reader :nested_class
delegate :default_proc=, :to => :to_h
Expand Down Expand Up @@ -54,25 +73,38 @@ def initialize klass, *args
set_default_proc!
end

##
# Add an new key to the object, with a default default
def << key
@table[key]
end

##
# Add a new key/value to the object; if it's a Hash, turn it
# into another NestedOpenStructWithHashAccess
def []=(key, value)
if value.is_a? Hash
send "#{key}=", nested_class.new(value)
else
elsif ::RUBY_VERSION < '2.0'
send "#{key}=", value
else
super
end
end

##
# Before serializing, we need to reset the default proc
# so it can be serialized appropriately
def marshal_dump
h = to_h.dup
h.default = nil

[nested_class, h]
end

##
# After deserializing, we need to re-add the default proc
# to the internal hash
def marshal_load x
@nested_class = x.first
super x.last
Expand Down

0 comments on commit 0b8ab23

Please sign in to comment.