OpenObject

OpenObject is very similar to Ruby‘s own OpenStruct, but it offers some useful advantages. With OpenStruct slots with the same name‘s as predefined Object methods can not be used. With OpenObject any slot can be defined, OpendObject is also a bit faster becuase it is based on a Hash, not method signitures.

Because OpenObject is a subclass of Hash, it can do just about everything a Hash can do, except that most public methods have been made protected and thus available only internally or via send.

OpenObject will also clobber any method for which a slot is defined. Even generally very important methods can be clobbered, like instance_eval. So be aware of this. OpenObject should be used in well controlled scenarios.

If you wish to pass an OpenObject to a routine that normal takes a Hash, but are uncertain it can handle the distictions properly you can convert easily to a Hash using to_hash! and the result will automatically be converted back to an OpenObject on return.

  o = OpenObject.new(:a=>1,:b=>2)
  o.as_hash!{ |h| h.update(:a=>6) }
  o #=> #<OpenObject {:a=>6,:b=>2}>

Finally, unlike a regular Hash, all OpenObject‘s keys are symbols and all keys are converted to such using to_sym on the fly.

Methods
== [] [] []= as_hash! default! define_slot delete each fetch initialize_copy inspect merge method_missing new protect_slot store to_a to_h to_hash to_openobject to_proc update
Constants
PUBLIC_METHODS = /(^__|^instance_|^object_|^\W|^as$|^send$|^class$|\?$)/
Public Class methods
[](hash=nil)
# File lib/more/facets/openobject.rb, line 88
  def self.[](hash=nil)
    new(hash)
  end
new( hash=nil, &yld )

Inititalizer for OpenObject is slightly differnt than that of Hash. It does not take a default parameter, but an initial priming Hash as with OpenStruct. The initializer can still take a default block however. To set the degault value use ++default!(value)++.

  OpenObject(:a=>1).default!(0)
# File lib/more/facets/openobject.rb, line 102
  def initialize( hash=nil, &yld )
    super( &yld )
    hash.each { |k,v| define_slot(k,v) } if hash
  end
Public Instance methods
==( other )

Check equality. (Should equal be true for Hash too?)

# File lib/more/facets/openobject.rb, line 175
  def ==( other )
    return false unless OpenObject === other
    super(other) #(other.send(:table))
  end
[](k)
# File lib/more/facets/openobject.rb, line 185
  def [](k)
    super(k.to_sym)
  end
[]=(k,v)
# File lib/more/facets/openobject.rb, line 180
  def []=(k,v)
    protect_slot(k)
    super(k.to_sym,v)
  end
as_hash!(&yld)

Preform inplace action on OpenObject as if it were a regular Hash.

# File lib/more/facets/openobject.rb, line 169
  def as_hash!(&yld)
    replace(yld.call(to_hash))
  end
default!(default)

Set the default value.

# File lib/more/facets/openobject.rb, line 159
  def default!(default)
    self.default = default
  end
delete(key)
# File lib/more/facets/openobject.rb, line 153
  def delete(key)
    super(key.to_sym)
  end
each(&yld)

Iterate over each key-value pair. (Careful, this can be clobbered!)

# File lib/more/facets/openobject.rb, line 130
  def each(&yld) super(&yld) end
initialize_copy( orig )
# File lib/more/facets/openobject.rb, line 107
  def initialize_copy( orig )
    orig.each { |k,v| define_slot(k,v) }
  end
inspect()

Object inspection. (Careful, this can be clobbered!)

# File lib/more/facets/openobject.rb, line 113
  def inspect
    "#<#{object_class}:#{object_hexid} #{super}>"
  end
merge( other )

Merge one OpenObject with another creating a new OpenObject.

# File lib/more/facets/openobject.rb, line 134
  def merge( other )
    d = dup
    d.send(:update, other)
    d
  end
to_a()

Conversion methods. (Careful, these can be clobbered!)

# File lib/more/facets/openobject.rb, line 119
  def to_a() super end
to_h()
# File lib/more/facets/openobject.rb, line 121
  def to_h() {}.update(self) end
to_hash()
# File lib/more/facets/openobject.rb, line 122
  def to_hash() {}.update(self) end
to_openobject()
# File lib/more/facets/openobject.rb, line 126
  def to_openobject() self end
to_proc()
# File lib/more/facets/openobject.rb, line 124
  def to_proc() super  end
update( other )

Update this OpenObject with another.

# File lib/more/facets/openobject.rb, line 142
  def update( other )
    begin
      other.each { |k,v| define_slot(k,v) }
    rescue
      other = other.to_h
      retry
    end
  end
Protected Instance methods
define_slot( key, value=nil )
# File lib/more/facets/openobject.rb, line 200
    def define_slot( key, value=nil )
      protect_slot( key )
      self[key.to_sym] = value
    end
fetch(k,*d,&b)
# File lib/more/facets/openobject.rb, line 196
    def fetch(k,*d,&b)
      super(k.to_sym,*d,&b)
    end
method_missing( sym, arg=nil, &blk)
# File lib/more/facets/openobject.rb, line 211
    def method_missing( sym, arg=nil, &blk)
      type = sym.to_s[-1,1]
      key = sym.to_s.sub(/[=?!]$/,'').to_sym
      if type == '='
        define_slot(key,arg)
      elsif type == '!'
        define_slot(key,arg)
        self
      else
        self[key]
      end
    end
protect_slot( key )
# File lib/more/facets/openobject.rb, line 205
    def protect_slot( key )
      (class << self; self; end).class_eval {
        protected key rescue nil
      }
    end
store(k,v)
# File lib/more/facets/openobject.rb, line 191
    def store(k,v)
      super(k.to_sym,v)
      define_slot(k)
    end