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
Public Instance Methods
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
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
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
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
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
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
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