class Octothorpe
A very simple hash-like class that borrows a little from OpenStruct, etc.
-
Treats string and symbol keys as equal
-
Access member objects with ot.>>.keyname
-
Guard conditions allow you to control what returns if key is not present
-
Pretty much read-only, for better or worse
Meant to facilitate message-passing between classes.
Simple example:
ot = Octothorpe.new(one: 1, "two" => 2, "weird key" => 3) ot.>>.one # -> 1 ot.>>.two # -> 2 ot.get("weird key") # -> 3
With guard conditions:
ot = Octotghorpe.new(one: 1, "two" => 2) ot.guard(Array, :three) ot.freeze # optional step - makes OT truly read-only ot.>>.three # -> [] ot.>>.three[9] # valid (of course; returns nil)
Octothorpe
additionally responds to the following methods exactly as a Hash would:
empty?, has_key?, has_value?, include? each, each_key, each_value, keys, values select, map, reject, inject merge, <, >< ==, >+, <=
Constants
- VERSION
Gem version number
Public Class Methods
Initialise an Octothorpe
object by passing it a hash.
You can create an empty OT by calling Octothorpe.new
, but there's probably little utility in that, given that it is read-only.
If you pass anything other than nil or something OT can treat as a Hash, you will cause an Octothorpe::BadHash
exception.
# File lib/octothorpe.rb, line 89 def initialize(hash=nil) @store = Storage.new( symbol_hash(hash || {}) ) @inner_hash = @store.octothorpe_store end
Public Instance Methods
# File lib/octothorpe.rb, line 208 def <(other); compare_as_hash(other, :<); end
# File lib/octothorpe.rb, line 211 def <=(other); compare_as_hash(other, :<=); end
Resolve some of the standard comparisons (with an OT or a hash)
# File lib/octothorpe.rb, line 207 def ==(other); compare_as_hash(other, :==); end
# File lib/octothorpe.rb, line 209 def >(other); compare_as_hash(other, :>); end
# File lib/octothorpe.rb, line 210 def >=(other); compare_as_hash(other, :>=); end
You can use >> to access member objects in somewhat the same way as an OpenStruct.
ot = Octothorpe.new(one: 1, "two" => 2) ot.>>.one # -> 1
This will not work for members that have keys with spaces in, keys which have the same name as methods on Object, or keys that aren't String or Symbol. Use get for those.
# File lib/octothorpe.rb, line 107 def >>; @store; end
You can use get to access member object values instead of the >> syntax.
Unlike >>, this works for keys with spaces, or keys that have the same name as methods on Object.
# File lib/octothorpe.rb, line 121 def get(key); @store.octothorpe_store[octokey key]; end
Guarantees the initial state of a memnber. Each key that is not already present will be set to <class>.new. Has no effect if key is already present. Class must be some class Thing that can respond to a vanilla Thing.new.
Alternatively, for the block form, the key is passed to the block, and the value of the key becomes the return value of the block … but again, ONLY if the key is not already set.
Note that this is the only time that you can modify an Octothorpe
object once it is created. If you call freeze on an it, it will become genuinely read-only, and any call to guard from then on will raise Octothorpe::Frozen
.
# File lib/octothorpe.rb, line 149 def guard(*args) raise Frozen if self.frozen? klass = args.shift unless block_given? keys = args.map{|k| octokey k} if block_given? keys.each{|k| @store.octothorpe_store[k] ||= yield k } else keys.each{|k| @store.octothorpe_store[k] ||= klass.new } end self end
Inspect exposes a view of the inner hash
# File lib/octothorpe.rb, line 217 def inspect "#<Octothorpe#{@store.octothorpe_store.inspect}>" end
Exactly as Hash.merge, but returns a new Octothorpe
object.
You may pass a hash or an octothorpe. Raises Octothorpe::BadHash
if it is anything else.
# File lib/octothorpe.rb, line 174 def merge(other) thisHash = @store.octothorpe_store otherHash = symbol_hash(other) merged = if block_given? thisHash.merge(otherHash) {|key,old,new| yield key, old, new } else thisHash.merge(otherHash) end Octothorpe.new(merged) end
Returns a hash of the object.
# File lib/octothorpe.rb, line 130 def to_h; @store.octothorpe_store; end
Return an Octothorpe
containing only these keys.
If you name a key that is missing, that key will also be missing in the output; use Guard if that's not what you want.
# File lib/octothorpe.rb, line 198 def whitelist(*keys) Octothorpe.new @inner_hash.select{|k,_| symbol_hash(keys).include? k} end
Private Instance Methods
Given an 'other' - Hash or OT - render both self and other down to a hash then run the given comparason on them and return the result
# File lib/octothorpe.rb, line 243 def compare_as_hash(other, method) thisHash = @store.octothorpe_store.to_h otherHash = symbol_hash(other) thisHash.send(method, otherHash) end
Munge a potential key so we can use it
# File lib/octothorpe.rb, line 253 def octokey(thing) thing.is_a?(String) ? thing.to_sym : thing end
Try to return thing as a hash with symbols for keys
# File lib/octothorpe.rb, line 228 def symbol_hash(thing) if thing.kind_of?(Octothorpe) thing.to_h else thing.each_with_object({}) {|(k,v),m| m[octokey k] = v } end rescue raise BadHash, $! end