class SleepingKingStudios::Tools::ObjectTools

Low-level tools for working with objects.

Constants

TEMPORARY_METHOD_NAME

Public Instance Methods

apply(receiver, proc, *args, &block) click to toggle source

Takes a proc or lambda and invokes it with the given object as receiver, with any additional arguments or block provided.

@param [Object] receiver The receiver. The proc will be called in the

context of this object.

@param [Proc] proc The proc or lambda to call. @param [Array] args Optional. Additional arguments to pass in to the

proc or lambda.

@param [block] block Optional. If present, will be passed in to proc or

lambda.

@return The result of calling the proc or lambda with the given

receiver and any additional arguments or block.
# File lib/sleeping_king_studios/tools/object_tools.rb, line 39
def apply(receiver, proc, *args, &block)
  return receiver.instance_exec(*args, &proc) unless block_given?

  method_name =
    Kernel.format(TEMPORARY_METHOD_NAME, Thread.current.object_id)

  with_temporary_method(receiver, method_name, proc) do
    receiver.send(method_name, *args, &block)
  end
end
deep_dup(obj) click to toggle source

Creates a deep copy of the object. If the object is an Array, returns a new Array with deep copies of each array item. If the object is a Hash, returns a new Hash with deep copies of each hash key and value. Otherwise, returns Object#dup.

@param [Object] obj The object to copy.

@return The copy of the object.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 58
def deep_dup(obj)
  case obj
  when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
    obj
  when ->(_) { ArrayTools.array?(obj) }
    ArrayTools.deep_dup obj
  when ->(_) { HashTools.hash?(obj) }
    HashTools.deep_dup obj
  else
    obj.respond_to?(:deep_dup) ? obj.deep_dup : obj.dup
  end
end
deep_freeze(obj) click to toggle source

Performs a deep freeze of the object. If the object is an Array, freezes the array and performs a deep freeze on each array item. If the object is a hash, freezes the hash and performs a deep freeze on each hash key and value. Otherwise, calls Object#freeze.

@param [Object] obj The object to freeze.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 77
def deep_freeze(obj)
  case obj
  when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
    # Object is inherently immutable; do nothing here.
  when ->(_) { ArrayTools.array?(obj) }
    ArrayTools.deep_freeze(obj)
  when ->(_) { HashTools.hash?(obj) }
    HashTools.deep_freeze obj
  else
    obj.respond_to?(:deep_freeze) ? obj.deep_freeze : obj.freeze
  end
end
dig(object, *method_names) click to toggle source

Accesses deeply nested attributes by calling the first named method on the given object, and each subsequent method on the result of the previous method call. If the object does not respond to the method name, nil is returned instead of calling the method.

@param [Object] object The object to dig. @param [Array] method_names The names of the methods to call.

@return [Object] The result of the last method call, or nil if the last

object does not respond to the last method.
# File lib/sleeping_king_studios/tools/object_tools.rb, line 100
def dig(object, *method_names)
  method_names.reduce(object) do |memo, method_name|
    memo.respond_to?(method_name) ? memo.send(method_name) : nil
  end
end
eigenclass(object) click to toggle source

Returns the object's eigenclass.

@param [Object] object The object for which an eigenclass is required.

@return [Class] The object's singleton class.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 118
def eigenclass(object)
  object.singleton_class
end
Also aliased as: metaclass
immutable?(obj) click to toggle source

Returns true if the object is immutable. Values of nil, false, and true are always immutable, as are instances of Numeric and Symbol. Arrays are immutable if the array is frozen and each array item is immutable. Hashes are immutable if the hash is frozen and each hash key and hash value are immutable. Otherwise, objects are immutable if they are frozen.

@param obj [Object] The object to test.

@return [Boolean] True if the object is immutable, otherwise false.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 132
def immutable?(obj)
  case obj
  when NilClass, FalseClass, TrueClass, Numeric, Symbol
    true
  when ->(_) { ArrayTools.array?(obj) }
    ArrayTools.immutable? obj
  when ->(_) { HashTools.hash?(obj) }
    HashTools.immutable? obj
  else
    obj.frozen?
  end
end
metaclass(object)
Alias for: eigenclass
mutable?(obj) click to toggle source

Returns true if the object is mutable.

@param obj [Object] The object to test.

@return [Boolean] True if the object is mutable, otherwise false.

@see immutable?

# File lib/sleeping_king_studios/tools/object_tools.rb, line 152
def mutable?(obj)
  !immutable?(obj)
end
object?(obj) click to toggle source

Returns true if the object is an Object. This should return true only for objects that have an alternate inheritance chain from BasicObject, such as a Proxy.

@param obj [Object] The object to test.

@return [Boolean] True if the object is an Object, otherwise false.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 163
def object?(obj)
  Object.instance_method(:is_a?).bind(obj).call(Object)
end
try(object, method_name, *args) click to toggle source

As send, but returns nil if the object does not respond to the method.

@param [Object] object The receiver of the message. @param [String, Symbol] method_name The name of the method to call. @param [Array] args The arguments to the message.

@see ActiveSupport::CoreExt::Object#try.

# File lib/sleeping_king_studios/tools/object_tools.rb, line 174
def try(object, method_name, *args)
  return object.try(method_name, *args) if object.respond_to?(:try)

  return nil unless object.respond_to?(method_name)

  object.send method_name, *args
end

Private Instance Methods

with_temporary_method(receiver, method_name, proc) { || ... } click to toggle source
# File lib/sleeping_king_studios/tools/object_tools.rb, line 184
def with_temporary_method(receiver, method_name, proc)
  metaclass = class << receiver; self; end
  metaclass.send :define_method, method_name, &proc

  yield
ensure
  metaclass.send :remove_method, method_name
end