class Xf::Trace

A more abstract version of a Scope in which the lead key is treated as if it could be anywhere in a hash tree. A Trace will dive until it finds all matching nodes.

Note that this can potentially be slow, but is also very difficult to emulate succinctly inline in vanilla Ruby.

@author baweaver @since 0.1.0

Public Class Methods

new(trace_path) click to toggle source

Creates a Scope

@param trace_path [Any]

What node to try and locate

@return [Xf::Trace]

# File lib/xf/trace.rb, line 19
def initialize(trace_path)
  @trace_path = trace_path
end

Public Instance Methods

get(&fn) click to toggle source

Gets a value from a Hash

@param &fn [Proc]

Block to yield the hash, key, and value from any matching element
into. Used to transform returned values upon retrieval

@return [Proc -> Array]

Array containing matching values, optionally transformed
# File lib/xf/trace.rb, line 31
def get(&fn)
  Proc.new { |target| get_value(target, &fn) }
end
get_value(hash, &fn) click to toggle source
# File lib/xf/trace.rb, line 35
def get_value(hash, &fn)
  retrieved_values = []

  recursing_dive(hash) { |h, k, v|
    retrieved_values.push(block_given? ? fn[h, k, v] : v)
  }

  retrieved_values
end
set(value = nil, &fn) click to toggle source

Sets a value in a Hash

@param value = nil [Any]

Value to set at the target

@param &fn [Proc]

Block to yield target value to. Returned value will be set as the new
value at the target.

@return [Proc -> Hash]

New Hash with transformation applied
# File lib/xf/trace.rb, line 56
def set(value = nil, &fn)
  Proc.new { |hash| set_value(hash, value, &fn) }
end
set!(value = nil, &fn) click to toggle source

Mutates a value in a Hash

@see set

@note

This method does the same thing as `#set`, except that it mutates the
target value instead of creating a clone first.
# File lib/xf/trace.rb, line 68
def set!(value = nil, &fn)
  Proc.new { |hash| set_value!(hash, value, &fn) }
end
set_value(hash, value = nil, &fn) click to toggle source
# File lib/xf/trace.rb, line 72
def set_value(hash, value = nil, &fn)
  set_value!(deep_clone(hash), value, &fn)
end
set_value!(hash, value = nil) { |v| ... } click to toggle source
# File lib/xf/trace.rb, line 76
def set_value!(hash, value = nil, &fn)
  recursing_dive(hash) { |h, k, v|
    h[k] = block_given? ? yield(v) : value
  }

  hash
end

Private Instance Methods

deep_clone(hash) click to toggle source
# File lib/xf/trace.rb, line 104
        def deep_clone(hash)
  Marshal.load(Marshal.dump(hash))
end
match?(hash, key, value, matcher) click to toggle source

Match is defined as having complete access to a hash, key, and value to make it easier to override for other future fun tasks.

In the base case of trace we only really care about the key matching for speed reasons. If you really want power though you could rig this up to work with Qo to query things.

@param hash [Hash] [description] @param key [Any] [description] @param value [Any] [description] @param matcher [#===] [description]

@return [type] [description]

# File lib/xf/trace.rb, line 100
        def match?(hash, key, value, matcher)
  matcher === key
end
recursing_dive(target_hash) { |target_hash, k, v| ... } click to toggle source
# File lib/xf/trace.rb, line 108
        def recursing_dive(target_hash, &fn)
  target_hash.each { |k, v|
    yield(target_hash, k, v) if match?(target_hash, k, v, @trace_path)

    next unless target_hash[k].is_a?(Hash)

    recursing_dive(target_hash[k], &fn)
  }
end