class Canister
A container that registers keys to values that are resolved at runtime. This allows for out-of-order declaration, automatic dependency resolution, and–upon redeclaration–automatic dependency cache invalidation.
Constants
- VERSION
Attributes
Public Class Methods
# File lib/canister.rb, line 11 def initialize @stack = [] @registry = {} @resolved = {} @dependents = Hash.new do |hash, key| hash[key] = [] end yield self if block_given? end
Public Instance Methods
# File lib/canister.rb, line 63 def keys registry.keys end
We override method_missing
to enable dot notation for accessing registered values.
# File lib/canister.rb, line 23 def method_missing(method, *args, &block) if handles?(method) resolve(method) else super(method, *args, block) end end
Register a value to a key by passing a block. Note that the value will be that returned by the block. If the key has been registered before, the old registration is overwritten. Dependents of the original registration are automatically invalidated. @param key [Symbol] @yield self [Container] Yields this container. @return the value defined in the block
# File lib/canister.rb, line 45 def register(key, &block) invalidate(key) if registered?(key) registry[key.to_sym] = block self end
Recursively resolves the object that was registered to the key. This value is memoized. @param key [Symbol]
# File lib/canister.rb, line 54 def resolve(key) add_dependent(key) stack << key value = resolved[key.to_sym] ||= registry[key.to_sym].call(self) stack.pop value end
We override respond_to? to enable dot notation for accessing registered values.
# File lib/canister.rb, line 33 def respond_to_missing?(method, include_all = false) handles?(method) || super(method, include_all) end
Private Instance Methods
# File lib/canister.rb, line 75 def add_dependent(key) unless stack.empty? dependents[key.to_sym] << stack.last end end
# File lib/canister.rb, line 71 def handles?(method) registered?(method) end
# File lib/canister.rb, line 89 def invalidate(key, first = true) unresolve(key) dependents[key.to_sym] .each {|child| invalidate(child, false) } dependents.delete(key.to_sym) if first end
# File lib/canister.rb, line 81 def registered?(key) registry.key?(key.to_sym) end
# File lib/canister.rb, line 85 def unresolve(key) resolved.delete(key.to_sym) end