leto 2.1.0 → 2.3.0
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +29 -13
- data/lib/leto/call.rb +16 -5
- data/lib/leto/features.rb +12 -0
- data/lib/leto/utils.rb +13 -6
- data/lib/leto/version.rb +1 -1
- data/lib/leto.rb +1 -0
- metadata +4 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a4c2fdd688142eb3f9db1a5d0d10cad624225413f6892a65eeef1a0aec3df00
|
|
4
|
+
data.tar.gz: 7ee194719f3912044b675f874f60d42bf4c6e7c60be5e83318cf3f2aaeca6225
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4edd7d0d8677b548585517b499a57ae630b5326053192f7b10b6de101c8899aab46d956de787df0a480cf66f73fd34c5da3518db2f1c61abc82b7758cdef7cbe
|
|
7
|
+
data.tar.gz: c3678597e116adf629f4229193c921a003e1f270030c2d076464af427806b76ce1560f6726a231eca7507af334be457e91f2c286d1bc2d0349d66696f73c25d8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.3.0] - 2026-09-29
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- support for Ruby 4's native `Set` class
|
|
8
|
+
|
|
9
|
+
## [2.2.0] - 2026-09-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- support for varargs in `::shared_mutable_state?`
|
|
14
|
+
|
|
3
15
|
## [2.1.0] - 2023-05-20
|
|
4
16
|
|
|
5
17
|
### Added
|
data/README.md
CHANGED
|
@@ -12,9 +12,10 @@ Takes an object and recursively yields:
|
|
|
12
12
|
- instance variables, class variables, constants
|
|
13
13
|
- Hash keys and values
|
|
14
14
|
- Enumerable members
|
|
15
|
+
- Range begins and ends
|
|
15
16
|
- Struct members
|
|
16
17
|
- [Data](https://docs.ruby-lang.org/en/3.2/Data.html) members
|
|
17
|
-
-
|
|
18
|
+
- Set members (for [native Sets on Ruby >= 4.0](https://bugs.ruby-lang.org/issues/21216))
|
|
18
19
|
|
|
19
20
|
This makes stuff like deep-freezing fairly easy to implement:
|
|
20
21
|
|
|
@@ -37,22 +38,29 @@ Basic example:
|
|
|
37
38
|
```ruby
|
|
38
39
|
object = [{ a: ['b', 'c'..'d'] }]
|
|
39
40
|
|
|
40
|
-
Leto.call(object) { |el|
|
|
41
|
+
Leto.call(object) { |el| puts "#{el.class}: #{el}" }
|
|
41
42
|
# prints:
|
|
42
43
|
#
|
|
43
|
-
# [{:
|
|
44
|
-
# {:
|
|
45
|
-
# :a
|
|
46
|
-
# ["b",
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
44
|
+
# Array: [{a: ["b", "c".."d"]}]
|
|
45
|
+
# Hash: {a: ["b", "c".."d"]}
|
|
46
|
+
# Symbol: a
|
|
47
|
+
# Array: ["b", "c".."d"]
|
|
48
|
+
# String: b
|
|
49
|
+
# Range: c..d
|
|
50
|
+
# String: c
|
|
51
|
+
# String: d
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Calls without a block return an `Enumerator`:
|
|
51
55
|
|
|
56
|
+
```ruby
|
|
52
57
|
Leto.call(object).to_a
|
|
53
58
|
# => [[{:a=>["b", ["c".."d"]]}], {:a=>["b", ["c".."d"]]}, :a, ...]
|
|
59
|
+
```
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
`Leto.trace` behaves like `.call`, but also yields each (sub-)object's `Path`:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
56
64
|
Leto.trace(object) { |el, path| puts "#{el.inspect.ljust(23)} @#{path}" }
|
|
57
65
|
# prints:
|
|
58
66
|
#
|
|
@@ -64,11 +72,19 @@ Leto.trace(object) { |el, path| puts "#{el.inspect.ljust(23)} @#{path}" }
|
|
|
64
72
|
# "c".."d" @#<Leto::Path [{:a=>["b", "c".."d"]}][0][:a][1]>
|
|
65
73
|
# "c" @#<Leto::Path [{:a=>["b", "c".."d"]}][0][:a][1].begin>
|
|
66
74
|
# "d" @#<Leto::Path [{:a=>["b", "c".."d"]}][0][:a][1].end>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Paths can be looked up with `Leto::Path#resolve` or `Leto.dig`:
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
```ruby
|
|
69
80
|
path = Leto.trace(object).map { |_el, path| path }.last # => #<Leto::Path...>
|
|
70
81
|
path.resolve # => "d"
|
|
71
82
|
Leto.dig(object, path) # => "d"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Arrays of Arrays, where the latter ones contain method names and arguments, are valid paths:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
72
88
|
Leto.dig(object, [[:[], 0], [:[], :a], [:[], 1], [:end]]) # => "d"
|
|
73
89
|
```
|
|
74
90
|
|
|
@@ -82,7 +98,7 @@ Leto.dig(object, [[:[], 0], [:[], :a], [:[], 1], [:end]]) # => "d"
|
|
|
82
98
|
- stricter version of `#eql?` that takes all ivars into consideration
|
|
83
99
|
- [`Leto.deep_dup(obj)`](https://github.com/search?q=deep_dup+repo%3Ajaynetics%2Fleto+path%3Alib%2Fleto%2Futils.rb&type=code)
|
|
84
100
|
- more thorough than [`active_support`](https://www.rubydoc.info/search/gems/activesupport?q=deep_dup) or [`deep_dup`](https://github.com/ollie/deep_dup) gems, e.g. dups ivars
|
|
85
|
-
- [`Leto.shared_mutable_state?(obj1, obj2)`](https://github.com/search?q=shared_mutable_state+repo%3Ajaynetics%2Fleto+path%3Alib%2Fleto%2Futils.rb&type=code)
|
|
101
|
+
- [`Leto.shared_mutable_state?(obj1, obj2, ...)`](https://github.com/search?q=shared_mutable_state+repo%3Ajaynetics%2Fleto+path%3Alib%2Fleto%2Futils.rb&type=code)
|
|
86
102
|
- useful for debugging or verifying that a `#dup` implementation is sane
|
|
87
103
|
- [`Leto.shared_mutables(obj1, obj2)`](https://github.com/search?q=shared_mutables+repo%3Ajaynetics%2Fleto+path%3Alib%2Fleto%2Futils.rb&type=code)
|
|
88
104
|
- useful for debugging or verifying that a `#dup` implementation is sane
|
data/lib/leto/call.rb
CHANGED
|
@@ -60,12 +60,19 @@ module Leto
|
|
|
60
60
|
obj.members.each do |member|
|
|
61
61
|
traverse(obj[member], path&.+([[:[], member]]), depth, max_depth, seen, block)
|
|
62
62
|
end
|
|
63
|
-
when Enumerable
|
|
64
|
-
obj.each_with_index do |el, idx|
|
|
65
|
-
traverse(el, path&.+([[:[], idx]]), depth, max_depth, seen, block)
|
|
66
|
-
end
|
|
67
63
|
#{
|
|
68
|
-
|
|
64
|
+
set_feature? && <<-SET_FEATURE_RUBY
|
|
65
|
+
when Set
|
|
66
|
+
obj.each_with_index do |el, idx|
|
|
67
|
+
traverse(
|
|
68
|
+
el, path&.+([[:to_a], [:[], idx]]),
|
|
69
|
+
depth, max_depth, seen, block
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
SET_FEATURE_RUBY
|
|
73
|
+
}
|
|
74
|
+
#{
|
|
75
|
+
data_feature? && <<-DATA_FEATURE_RUBY
|
|
69
76
|
when Data
|
|
70
77
|
obj.members.each do |member|
|
|
71
78
|
traverse(
|
|
@@ -76,6 +83,10 @@ module Leto
|
|
|
76
83
|
end
|
|
77
84
|
DATA_FEATURE_RUBY
|
|
78
85
|
}
|
|
86
|
+
when Enumerable
|
|
87
|
+
obj.each_with_index do |el, idx|
|
|
88
|
+
traverse(el, path&.+([[:[], idx]]), depth, max_depth, seen, block)
|
|
89
|
+
end
|
|
79
90
|
end
|
|
80
91
|
end
|
|
81
92
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# feature detection code for ruby
|
|
2
|
+
module Leto
|
|
3
|
+
def self.data_feature?
|
|
4
|
+
defined?(Data) && Data.respond_to?(:define)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Pre-Ruby-4.0, Hash-backed Sets are traversed through their
|
|
8
|
+
# @hash instance variable and don't need custom handling.
|
|
9
|
+
def self.set_feature?
|
|
10
|
+
defined?(Set) && Set.respond_to?(:[]) && !Set[].instance_variable_defined?(:@hash)
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/leto/utils.rb
CHANGED
|
@@ -10,8 +10,7 @@ module Leto
|
|
|
10
10
|
def self.deep_print(obj, print_method: :inspect, indent: 4, show_path: true)
|
|
11
11
|
trace(obj) do |el, path|
|
|
12
12
|
puts "#{' ' * path.count * indent}#{el.send(print_method)}" \
|
|
13
|
-
"#{" @ #{path.inspect}" if show_path}"
|
|
14
|
-
[0..78]
|
|
13
|
+
"#{" @ #{path.inspect}" if show_path}"[0..78]
|
|
15
14
|
end
|
|
16
15
|
nil
|
|
17
16
|
end
|
|
@@ -35,16 +34,24 @@ module Leto
|
|
|
35
34
|
copy[*args] = deep_dup(el, include_modules: include_modules)
|
|
36
35
|
when :send # Data
|
|
37
36
|
copy = copy.with(args[0] => deep_dup(el, include_modules: include_modules))
|
|
37
|
+
when :to_a # Set
|
|
38
|
+
copy = (copy - [el]) + [deep_dup(el, include_modules: include_modules)]
|
|
38
39
|
when :begin
|
|
39
|
-
return Range.new(
|
|
40
|
+
return Range.new(
|
|
41
|
+
deep_dup(obj.begin, include_modules: include_modules),
|
|
42
|
+
deep_dup(obj.end, include_modules: include_modules),
|
|
43
|
+
obj.exclude_end?,
|
|
44
|
+
)
|
|
40
45
|
end
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
copy
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
def self.shared_mutable_state?(
|
|
47
|
-
|
|
51
|
+
def self.shared_mutable_state?(*objects)
|
|
52
|
+
objects.combination(2).any? do |obj1, obj2|
|
|
53
|
+
each_shared_object(obj1, obj2, filter: method(:mutable?)).any?
|
|
54
|
+
end
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
# returns [[shared_object, path1, path2], ...], e.g.:
|
|
@@ -87,7 +94,7 @@ module Leto
|
|
|
87
94
|
if defined?(Integer)
|
|
88
95
|
Integer
|
|
89
96
|
else
|
|
90
|
-
Fixnum # rubocop:disable Lint/UnifiedInteger for Ruby < 2.4
|
|
97
|
+
Fixnum # rubocop:disable Lint/UnifiedInteger -- for Ruby < 2.4
|
|
91
98
|
end,
|
|
92
99
|
NilClass,
|
|
93
100
|
Symbol,
|
data/lib/leto/version.rb
CHANGED
data/lib/leto.rb
CHANGED
metadata
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janosch Müller
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
|
-
description:
|
|
14
12
|
email:
|
|
15
13
|
- janosch84@gmail.com
|
|
16
14
|
executables: []
|
|
@@ -29,6 +27,7 @@ files:
|
|
|
29
27
|
- lib/leto.rb
|
|
30
28
|
- lib/leto/call.rb
|
|
31
29
|
- lib/leto/dig.rb
|
|
30
|
+
- lib/leto/features.rb
|
|
32
31
|
- lib/leto/path.rb
|
|
33
32
|
- lib/leto/utils.rb
|
|
34
33
|
- lib/leto/version.rb
|
|
@@ -38,7 +37,6 @@ licenses:
|
|
|
38
37
|
metadata:
|
|
39
38
|
changelog_uri: https://github.com/jaynetics/leto/blob/main/CHANGELOG.md
|
|
40
39
|
homepage_uri: https://github.com/jaynetics/leto
|
|
41
|
-
post_install_message:
|
|
42
40
|
rdoc_options: []
|
|
43
41
|
require_paths:
|
|
44
42
|
- lib
|
|
@@ -53,8 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
53
51
|
- !ruby/object:Gem::Version
|
|
54
52
|
version: '0'
|
|
55
53
|
requirements: []
|
|
56
|
-
rubygems_version:
|
|
57
|
-
signing_key:
|
|
54
|
+
rubygems_version: 4.0.20
|
|
58
55
|
specification_version: 4
|
|
59
56
|
summary: Generic object traverser
|
|
60
57
|
test_files: []
|