Class: Hashery::OpenHash

Inherits:
CRUDHash show all
Defined in:
lib/hashery/open_hash.rb

Overview

OpenHash is a Hash, but also supports open properties much like OpenStruct.

Only names that are name methods of Hash can be used as open slots. To open a slot for a name that would otherwise be a method, the method needs to be made private. The `#open!` method can be used to handle this.

Examples

o = OpenHash.new
o.open!(:send)
o.send = 4

Direct Known Subclasses

OpenCascade

Constant Summary

Constant Summary

Constants inherited from CRUDHash

CRUDHash::NA

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from CRUDHash

#<<, [], #[], #[]=, auto, #cast, #cast_key, #default_proc, #delete, #each, #fetch, #key?, #key_proc, #key_proc=, #merge, #read, #replace, #retrieve, #to_hash, #update, #values_at

Methods inherited from Hash

create, #rekey, #rekey!, #retrieve, #to_hash, #to_stash

Constructor Details

#initialize(default = nil, safe = false, &block) ⇒ OpenHash

Initialize new OpenHash instance.

TODO: Maybe `safe` should be the first argument?



33
34
35
36
# File 'lib/hashery/open_hash.rb', line 33

def initialize(default=nil, safe=false, &block)
  @safe = safe
  super(*[default].compact, &block)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(s, *a, &b) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/hashery/open_hash.rb', line 120

def method_missing(s,*a, &b)
  type = s.to_s[-1,1]
  name = s.to_s.sub(/[!?=]$/, '')
  key  = name.to_sym

  case type
  when '='
    store(key, a.first)
  when '?'
    key?(key)
  when '!'
    # call an underlying private method
    # TODO: limit this to omitted methods (from included) ?
    __send__(name, *a, &b)
  else
    #if key?(key)
      retrieve(key)
    #else
    #  super(s,*a,&b)
    #end
  end
end

Instance Attribute Details

#safeObject

If safe is set to true, then public methods cannot be overriden by hash keys.



42
43
44
# File 'lib/hashery/open_hash.rb', line 42

def safe
  @safe
end

Instance Method Details

#close!(*methods) ⇒ Object

Make specific Hash methods available for use that have previously opened.

methods - [Array<String,Symbol>] method names

Returns methods.



112
113
114
115
# File 'lib/hashery/open_hash.rb', line 112

def close!(*methods)
  (class << self; self; end).class_eval{ public *methods }
  methods
end

#open!(*methods) ⇒ Object Also known as: omit!

Open up a slot that that would normally be a Hash method.

The only methods that can't be opened are ones starting with `__`.

methods - [Array<String,Symbol>] method names

Returns Array of slot names that were opened.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/hashery/open_hash.rb', line 72

def open!(*methods)
  # Only select string and symbols, any other type of key is allowed,
  # it just won't be accessible via dynamic methods.
  methods = methods.select{ |x| String === x || Symbol === x }
  if methods.any?{ |m| m.to_s.start_with?('__') }
    raise ArgumentError, "cannot open shadow methods"
  end
  # only public methods need be made protected
  methods = methods.map{ |x| x.to_sym }
  methods = methods & public_methods(true).map{ |x| x.to_sym }
  if @safe
    raise ArgumentError, "cannot set public method" unless methods.empty?
  else
    (class << self; self; end).class_eval{ protected *methods }
  end
  methods
end

#open?(method) ⇒ Boolean

Is a slot open?

method - [String,Symbol] method name

Returns `true` or `false`.



100
101
102
103
# File 'lib/hashery/open_hash.rb', line 100

def open?(method)
  methods = public_methods(true).map{ |m| m.to_sym }
  ! methods.include?(method.to_sym)
end

#store(key, value) ⇒ Object

Index `value` to `key`. Unless safe mode, will also open up the key if it is not already open.

key - Index key to associate with value. value - Value to be associate with key.

Returns value.



58
59
60
61
# File 'lib/hashery/open_hash.rb', line 58

def store(key, value)
  #open!(key)
  super(key, value)
end