Class: SleepingKingStudios::Tools::ObjectTools
- Defined in:
- lib/sleeping_king_studios/tools/object_tools.rb
Overview
Low-level tools for working with objects.
Instance Method Summary collapse
-
#apply(receiver, proc, *args, **kwargs, &block) ⇒ Object
Calls a Proc or lambda on the given receiver with the given parameters.
-
#deep_dup(obj) ⇒ Object
Creates a deep copy of the object.
-
#deep_freeze(obj) ⇒ Object
Performs a deep freeze of the object.
-
#dig(obj, *method_names, indifferent_keys: false) ⇒ Object?
Accesses deeply nested properties on an object.
-
#eigenclass(obj) ⇒ Class
(also: #metaclass)
deprecated
Deprecated.
v1.3.0 Use Object#singleton_class instead.
- #fetch(obj, key_or_index, default = UNDEFINED, indifferent_key: false) ⇒ Object
-
#format_inspect(obj, address: true, properties: {}) ⇒ String
Creates a string representation of the object and specified properties.
-
#immutable?(obj) ⇒ Boolean
Checks if the object is immutable.
-
#mutable?(obj) ⇒ Boolean
Checks if the object is mutable.
-
#object?(obj) ⇒ Boolean
Returns true if the object is an Object.
-
#try(obj, method_name, *args) ⇒ Object?
As #send, but returns nil if the object does not respond to the method.
Methods inherited from Base
#initialize, instance, #toolbelt
Constructor Details
This class inherits a constructor from SleepingKingStudios::Tools::Base
Instance Method Details
#apply(receiver, proc, *args, **kwargs, &block) ⇒ Object
Calls a Proc or lambda on the given receiver with the given parameters.
Unlike calling #instance_exec with the block, ObjectTools#apply allows you to specify a block parameter.
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 54 def apply(receiver, proc, *args, **kwargs, &block) return receiver.instance_exec(*args, **kwargs, &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, **kwargs, &block) end end |
#deep_dup(obj) ⇒ Object
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.
109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 109 def deep_dup(obj) # rubocop:disable Metrics/AbcSize case obj when FalseClass, Integer, Float, NilClass, Symbol, TrueClass obj when ->(_) { toolbelt.array_tools.array?(obj) } toolbelt.array_tools.deep_dup obj when ->(_) { toolbelt.hash_tools.hash?(obj) } toolbelt.hash_tools.deep_dup obj else obj.respond_to?(:deep_dup) ? obj.deep_dup : obj.dup end end |
#deep_freeze(obj) ⇒ Object
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.
162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 162 def deep_freeze(obj) # rubocop:disable Metrics/AbcSize case obj when FalseClass, Integer, Float, NilClass, Symbol, TrueClass # Object is inherently immutable; do nothing here. when ->(_) { toolbelt.array_tools.array?(obj) } toolbelt.array_tools.deep_freeze(obj) when ->(_) { toolbelt.hash_tools.hash?(obj) } toolbelt.hash_tools.deep_freeze obj else obj.respond_to?(:deep_freeze) ? obj.deep_freeze : obj.freeze end end |
#dig(obj, *method_names, indifferent_keys: false) ⇒ Object?
Accesses deeply nested properties on an object.
This method finds the first named property on the given object, and then each subsequent property on the result of the previous call.
-
If the object responds to the property name as a public method, it calls the method directly.
-
If the object does not respond to the property name, or if the property name is not itself a valid method name, checks if the object responds to #[]; if so, calls #[] with the property name.
-
Otherwise, immediately returns nil.
Using #[] access allows digging through Array (using integer indices) and Hash data structures as well as object methods.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 201 def dig(obj, *method_names, indifferent_keys: false) method_names.reduce(obj) do |memo, method_name| if object_responds_to_method?(memo, method_name) next memo.public_send(method_name) end next nil unless memo.respond_to?(:[]) next memo[method_name] unless indifferent_keys indifferent_get(memo, method_name) end rescue NameError nil end |
#eigenclass(obj) ⇒ Class Also known as: metaclass
v1.3.0 Use Object#singleton_class instead.
Returns the object’s eigenclass.
224 225 226 227 228 229 230 231 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 224 def eigenclass(obj) toolbelt.core_tools.deprecate( "#{self.class.name}#eigenclass", message: 'Use Object#singleton_class instead.' ) obj.singleton_class end |
#fetch(obj, key, default = nil, indifferent_key: false) ⇒ Object #fetch(obj, key, indifferent_key: false) {|key| ... } ⇒ Object
276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 276 def fetch(obj, key_or_index, default = UNDEFINED, indifferent_key: false, &) case obj when ->(_) { object_responds_to_method?(obj, key_or_index) } obj.public_send(key_or_index) when ->(_) { toolbelt.array_tools.array?(obj) } fetch_array(obj, key_or_index, default, &) when ->(_) { toolbelt.hash_tools.hash?(obj) } fetch_hash(obj, key_or_index, default, indifferent_key:, &) else handle_invalid_fetch(obj, key_or_index, default, &) end end |
#format_inspect(obj, address: true, properties: {}) ⇒ String
Creates a string representation of the object and specified properties.
The string representation resembles the output of Object#inspect, but with support for BasicObjects and greater customization of the displayed properties.
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 303 def format_inspect(obj, address: true, properties: {}) # rubocop:disable Metrics/MethodLength str = "#<#{class_name(obj)}" if address native = Object.instance_method(:inspect).bind(obj).call address = MEMORY_ADDRESS_PATTERN.match(native)&.[](:address) str << ':' << address end if properties.is_a?(Hash) format_properties_hash(str, **properties) elsif properties.is_a?(Enumerable) format_properties_array(str, obj, *properties) end str << '>' end |
#immutable?(obj) ⇒ Boolean
Checks if the object is immutable.
-
nil, false, and true are always immutable, as are instances of Numeric and Symbol.
-
Strings are immutable if frozen, such as strings defined in a file with a frozen_string_literal pragma.
-
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.
368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 368 def immutable?(obj) case obj when NilClass, FalseClass, TrueClass, Numeric, Symbol true when ->(_) { toolbelt.array_tools.array?(obj) } toolbelt.array_tools.immutable?(obj) when ->(_) { toolbelt.hash_tools.hash?(obj) } toolbelt.hash_tools.immutable?(obj) else obj.frozen? end end |
#mutable?(obj) ⇒ Boolean
Checks if the object is mutable.
388 389 390 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 388 def mutable?(obj) !immutable?(obj) end |
#object?(obj) ⇒ Boolean
Returns true if the object is an Object.
This should return false only for objects that have an alternate inheritance chain from BasicObject, such as a Proxy.
416 417 418 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 416 def object?(obj) Object.instance_method(:is_a?).bind(obj).call(Object) end |
#try(obj, method_name, *args) ⇒ Object?
441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/sleeping_king_studios/tools/object_tools.rb', line 441 def try(obj, method_name, *) toolbelt.core_tools.deprecate( "#{self.class.name}#try", message: 'Use the safe access operator &. instead.' ) return obj.try(method_name, *) if obj.respond_to?(:try) return nil unless obj.respond_to?(method_name) obj.send(method_name, *) end |