sleeping_king_studios-tools 1.3.0.rc.1 → 1.3.0.rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b3b28222878c3e3bf364e7467ca85e76b4ba8c40e86b1062169d2943ab9a181
|
|
4
|
+
data.tar.gz: 31cbc80f6c696aebbb9f5ed955852424bda57b03ec65a4f37bdcd969fa6825d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e14d9a823ebbd1a3eb8cf4e00ae298bfbedfa1fd797b19b493b0187a6b5f128c6f2d08e05101a39619ea51755fb321798b27af6d8741b1cdea2695a2a8d4f204
|
|
7
|
+
data.tar.gz: b26b0693f575e15c0c1a91b97eae350d677f73fa6c7426b4b77b92537a6e988fa52c52f68e0a88a210fad78d617cdb298b663c0cae3fd20992aed7017e3c1145
|
data/CHANGELOG.md
CHANGED
|
@@ -62,6 +62,8 @@ Added `#[]` support to `ObjectTools#dig`, allowing access through indexed data s
|
|
|
62
62
|
|
|
63
63
|
Added `ObjectTools#fetch`, which tries to find the requested value via the named method call or by calling `#[]`.
|
|
64
64
|
|
|
65
|
+
Added `ObjectTools#format_inspect`, which generates a `String` representation of the object (similar to the built-in `Object#inspect`) with support for `BasicObject`s and for customizing the displayed properties.
|
|
66
|
+
|
|
65
67
|
Deprecated methods with native equivalents:
|
|
66
68
|
|
|
67
69
|
- Deprecated `#eigenclass` - use `Object#singleton_class` instead.
|
|
@@ -5,6 +5,9 @@ require 'sleeping_king_studios/tools'
|
|
|
5
5
|
module SleepingKingStudios::Tools
|
|
6
6
|
# Low-level tools for working with objects.
|
|
7
7
|
class ObjectTools < SleepingKingStudios::Tools::Base # rubocop:disable Metrics/ClassLength
|
|
8
|
+
MEMORY_ADDRESS_PATTERN = /#<[:\w]+:(?'address'0x\h+)/
|
|
9
|
+
private_constant :MEMORY_ADDRESS_PATTERN
|
|
10
|
+
|
|
8
11
|
TEMPORARY_METHOD_NAME =
|
|
9
12
|
'__sleeping_king_studios_tools_apply_%i__'
|
|
10
13
|
private_constant :TEMPORARY_METHOD_NAME
|
|
@@ -283,6 +286,39 @@ module SleepingKingStudios::Tools
|
|
|
283
286
|
end
|
|
284
287
|
end
|
|
285
288
|
|
|
289
|
+
# Creates a string representation of the object and specified properties.
|
|
290
|
+
#
|
|
291
|
+
# The string representation resembles the output of Object#inspect, but with
|
|
292
|
+
# support for BasicObjects and greater customization of the displayed
|
|
293
|
+
# properties.
|
|
294
|
+
#
|
|
295
|
+
# @param obj [BasicObject] the object to inspect.
|
|
296
|
+
# @param address [true, false] if true, includes the formatted memory
|
|
297
|
+
# address from Object#inspect. Defaults to true.
|
|
298
|
+
# @param properties [Array, Hash] the properties to display. If the given
|
|
299
|
+
# properties are an Array, maps the values to instance variables or public
|
|
300
|
+
# methods based on the property name.
|
|
301
|
+
#
|
|
302
|
+
# @return [String] the string representation of the object.
|
|
303
|
+
def format_inspect(obj, address: true, properties: {}) # rubocop:disable Metrics/MethodLength
|
|
304
|
+
str = "#<#{class_name(obj)}"
|
|
305
|
+
|
|
306
|
+
if address
|
|
307
|
+
native = Object.instance_method(:inspect).bind(obj).call
|
|
308
|
+
address = MEMORY_ADDRESS_PATTERN.match(native)&.[](:address)
|
|
309
|
+
|
|
310
|
+
str << ':' << address
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
if properties.is_a?(Hash)
|
|
314
|
+
format_properties_hash(str, **properties)
|
|
315
|
+
elsif properties.is_a?(Enumerable)
|
|
316
|
+
format_properties_array(str, obj, *properties)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
str << '>'
|
|
320
|
+
end
|
|
321
|
+
|
|
286
322
|
# Checks if the object is immutable.
|
|
287
323
|
#
|
|
288
324
|
# - nil, false, and true are always immutable, as are instances of Numeric
|
|
@@ -417,6 +453,17 @@ module SleepingKingStudios::Tools
|
|
|
417
453
|
|
|
418
454
|
private
|
|
419
455
|
|
|
456
|
+
def class_name(obj)
|
|
457
|
+
klass =
|
|
458
|
+
if object?(obj)
|
|
459
|
+
obj.class
|
|
460
|
+
else
|
|
461
|
+
Object.instance_method(:class).bind(obj).call
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
klass.name || klass.inspect
|
|
465
|
+
end
|
|
466
|
+
|
|
420
467
|
def fetch_array(ary, index, default = UNDEFINED, &)
|
|
421
468
|
return toolbelt.array_tools.fetch(ary, index, &) if default == UNDEFINED
|
|
422
469
|
|
|
@@ -431,6 +478,45 @@ module SleepingKingStudios::Tools
|
|
|
431
478
|
toolbelt.hash_tools.fetch(hsh, key, default, indifferent_key:, &)
|
|
432
479
|
end
|
|
433
480
|
|
|
481
|
+
def format_properties_array(buf, obj, *properties)
|
|
482
|
+
properties.each do |property|
|
|
483
|
+
property_name = property.to_s
|
|
484
|
+
|
|
485
|
+
value = get_object_property(obj, property_name)
|
|
486
|
+
|
|
487
|
+
buf << ' ' << property_name << '=' << value
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def format_properties_hash(buf, **properties)
|
|
492
|
+
properties.each do |property, value|
|
|
493
|
+
property_name = property.to_s
|
|
494
|
+
|
|
495
|
+
buf << ' ' << property_name << '=' << value.inspect
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def get_instance_variable(obj, property_name)
|
|
500
|
+
return obj.instance_variable_get(property_name) if object?(obj)
|
|
501
|
+
|
|
502
|
+
Object
|
|
503
|
+
.instance_method(:instance_variable_get)
|
|
504
|
+
.bind(obj)
|
|
505
|
+
.call(property_name)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def get_object_property(obj, property_name)
|
|
509
|
+
if property_name.start_with?('@')
|
|
510
|
+
return 'undefined' unless has_instance_variable?(obj, property_name)
|
|
511
|
+
|
|
512
|
+
get_instance_variable(obj, property_name).inspect
|
|
513
|
+
else
|
|
514
|
+
return 'undefined' unless respond_to_method?(obj, property_name)
|
|
515
|
+
|
|
516
|
+
obj.__send__(property_name).inspect
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
434
520
|
def handle_invalid_fetch(obj, key, default, &block)
|
|
435
521
|
return block.call(key) if block_given?
|
|
436
522
|
|
|
@@ -443,6 +529,15 @@ module SleepingKingStudios::Tools
|
|
|
443
529
|
raise NoMethodError, message
|
|
444
530
|
end
|
|
445
531
|
|
|
532
|
+
def has_instance_variable?(obj, property_name) # rubocop:disable Naming/PredicatePrefix
|
|
533
|
+
return obj.instance_variable_defined?(property_name) if object?(obj)
|
|
534
|
+
|
|
535
|
+
Object
|
|
536
|
+
.instance_method(:instance_variable_defined?)
|
|
537
|
+
.bind(obj)
|
|
538
|
+
.call(property_name)
|
|
539
|
+
end
|
|
540
|
+
|
|
446
541
|
def indifferent_get(object, key)
|
|
447
542
|
case key
|
|
448
543
|
when String
|
|
@@ -462,6 +557,15 @@ module SleepingKingStudios::Tools
|
|
|
462
557
|
object.respond_to?(maybe_method_name)
|
|
463
558
|
end
|
|
464
559
|
|
|
560
|
+
def respond_to_method?(obj, method_name)
|
|
561
|
+
return obj.respond_to?(method_name) if object?(obj)
|
|
562
|
+
|
|
563
|
+
Object
|
|
564
|
+
.instance_method(:respond_to?)
|
|
565
|
+
.bind(obj)
|
|
566
|
+
.call(method_name)
|
|
567
|
+
end
|
|
568
|
+
|
|
465
569
|
def with_temporary_method(receiver, method_name, proc)
|
|
466
570
|
metaclass = class << receiver; self; end
|
|
467
571
|
metaclass.send :define_method, method_name, &proc
|
|
@@ -129,25 +129,18 @@ module SleepingKingStudios::Tools::Toolbox
|
|
|
129
129
|
# @return [Class, nil] the parent data class.
|
|
130
130
|
attr_reader :parent_class
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return enum_for(:each_ancestor) unless block_given?
|
|
132
|
+
# Iterates over the ::HeritableMethods modules for parent classes.
|
|
133
|
+
def each_heritable_module
|
|
134
|
+
return enum_for(:each_heritable_module) unless block_given?
|
|
136
135
|
|
|
137
|
-
ancestor =
|
|
136
|
+
ancestor = self
|
|
138
137
|
|
|
139
138
|
while ancestor
|
|
140
|
-
yield ancestor
|
|
139
|
+
yield ancestor
|
|
141
140
|
|
|
142
|
-
ancestor = ancestor::HeritableMethods
|
|
141
|
+
ancestor = ancestor.parent_class&.then { |mod| mod::HeritableMethods }
|
|
143
142
|
end
|
|
144
143
|
end
|
|
145
|
-
|
|
146
|
-
def included(other)
|
|
147
|
-
super
|
|
148
|
-
|
|
149
|
-
each_ancestor { |ancestor| other.include(ancestor) }
|
|
150
|
-
end
|
|
151
144
|
end
|
|
152
145
|
|
|
153
146
|
class << self
|
|
@@ -174,7 +167,7 @@ module SleepingKingStudios::Tools::Toolbox
|
|
|
174
167
|
HeritableData::HeritableMethods.new(parent_class:, &)
|
|
175
168
|
)
|
|
176
169
|
|
|
177
|
-
data_class.include(data_class::HeritableMethods)
|
|
170
|
+
data_class.include(*data_class::HeritableMethods.each_heritable_module)
|
|
178
171
|
end
|
|
179
172
|
|
|
180
173
|
def included(other)
|