class Xf::Scope

A play on Lenses in Ruby, though not quite as powerful they can be useful for getting and setting deep values on collections.

@author baweaver @since 0.0.2

Public Class Methods

new(paths) click to toggle source

Creates a Scope @param paths [Array] Paths to follow to reach the desired value

@return [Xf::Scope]

# File lib/xf/scope.rb, line 13
def initialize(paths)
  @paths = paths
end

Public Instance Methods

get(&fn) click to toggle source

Gets a value from a Hash

@return [type] [description]

# File lib/xf/scope.rb, line 20
def get(&fn)
  Proc.new { |hash| get_value(hash, &fn) }
end
get_value(hash, &fn) click to toggle source

Direct value getter, though it may be wiser to use Hash#dig here instead if you're concerned about speed.

If the object does not respond to dig, Xf will attempt to use an array bracket accessor dive instead for compatability reasons.

@param hash [Hash] Hash to get value from

@return [Any]

# File lib/xf/scope.rb, line 60
def get_value(hash, &fn)
  value = if hash.respond_to?(:dig)
    hash.dig(*@paths)
  else
    new_hash = hash
    @paths.each { |s| new_hash = new_hash[s] }
    new_hash
  end

  block_given? ? fn[value] : value
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/scope.rb, line 35
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/scope.rb, line 47
def set!(value = nil, &fn)
  Proc.new { |hash| set_value!(hash, value, &fn) }
end
set_value(hash, value = nil, &fn) click to toggle source

Sets a value at the bottom of a path without mutating the original.

@param hash [Hash]

Hash to set value on

@param value = nil [Any]

Value to set

@param &fn [Proc]

If present, current value is yielded to it and the return
value is the new set value

@return [Hash]

Clone of the original with the value set
# File lib/xf/scope.rb, line 86
def set_value(hash, value = nil, &fn)
  set_value!(deep_clone(hash), value, &fn)
end
set_value!(hash, value = nil) { |new_hash| ... } click to toggle source

Mutating form of `#set_value`

@see set_value

# File lib/xf/scope.rb, line 93
def set_value!(hash, value = nil, &fn)
  lead_in    = @paths[0..-2]
  target_key = @paths[-1]

  new_hash = hash
  lead_in.each { |s| new_hash = new_hash[s] }

  new_value = block_given? ?
    yield(new_hash[target_key]) :
    value

  new_hash[target_key] = new_value

  hash
end

Private Instance Methods

deep_clone(hash) click to toggle source

Private API - Methods below here are subject to change, please don't use them directly.

# File lib/xf/scope.rb, line 112
        def deep_clone(hash)
  Marshal.load(Marshal.dump(hash))
end