Last active
May 11, 2016 02:11
-
-
Save IronSavior/8406cc52ae8a6eb69c68e84455171d34 to your computer and use it in GitHub Desktop.
Fun with Hash-like objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HashlikeFetchCache | |
include HashlikeOverlay | |
def initialize( context ) | |
@overlay = Hash[] | |
@context = context | |
freeze | |
end | |
def []( key ) | |
super.tap{ |value| update_cache key, value } | |
end | |
def fetch( key, * ) | |
super.tap{ |value| update_cache key, value } | |
end | |
def clear_cache | |
overlay.clear | |
end | |
private | |
attr_reader :overlay, :context | |
def update_cache( key, value ) | |
overlay[key] = value | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Hash-like interface composed of two Hash-like objects where one is an overlay for the other. Common Hash | |
# accessor methods like #fetch and #[] will search the overlay and then fall back to the context. Classes | |
# including this module must implement #overlay and #context. | |
module HashlikeOverlay | |
# Retrieve value associated with the given key. Defaulting behavior is delegated to context. | |
# Note: If context is a genuine Hash, #[] will likely return nil when the key is not found. | |
# @param key [Object] | |
# @return [Object] Value associated with the given key, or a default | |
def []( key ) | |
overlay.key?(key) ? overlay[key] : context[key] | |
end | |
# Retrieve value associated with the given key. Defaulting behavior is delegated to context. | |
# Note: If context is a genuine Hash, #fetch may raise KeyError when the key is not found. | |
# @param key [Object] | |
# @param default [Object] Value returned when key not found | |
# @param [Block] Invoked when key not found (overrides non-block default param) | |
# @return [Object] Value associated with the given key, or a default | |
def fetch( key, *default, &blk ) | |
overlay.fetch(key){ context.fetch key, *default, &blk } | |
end | |
# @param key [Object] Key to search for | |
# @return [Boolean] True when the given key is found in the overlay or context | |
def key?( key ) | |
overlay.key?(key) || context.key?(key) | |
end | |
alias_method :has_key?, :key? | |
# @param value [Object] Value to search for | |
# @return [Boolean] True when the given value is found in the overlay or context | |
def value?( value ) | |
overlay.value?(value) || context.value?(value) | |
end | |
alias_method :has_value?, :value? | |
# @return [Array] Unique all keys from overlay and context | |
def keys | |
overlay.keys | context.keys | |
end | |
# @return [Boolean] True when context and overlay are both empty | |
def empty? | |
overlay.empty? && context.empty? | |
end | |
# @return [Integer] Count of unique keys between context and overlay | |
def size | |
keys.size | |
end | |
# Explicit conversion to Hash | |
# @return [Hash] Union of context with overlay | |
def to_h | |
keys.reduce Hash[] do |h, k| | |
h.tap{ h[k] = self[k] } | |
end | |
end | |
# Implicit conversion to Hash. This works only when implicit conversion is supported by both overlay and context. | |
# @return [Hash] Union of context with overlay | |
def to_hash | |
context.to_hash.merge overlay.to_hash | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'forwardable' | |
class LexicalScope | |
include HashlikeOverlay | |
extend Forwardable | |
delegate [:store, :[]=] => :overlay | |
def initialize( context = {} ) | |
@overlay = Hash[] | |
@context = context | |
end | |
def inner_scope | |
self.class.new self | |
end | |
private | |
attr_reader :overlay, :context | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment