leto 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0362bb08490e1bd600bb8996a1be449584295433c047472864578b2d43a6cb5
4
- data.tar.gz: de8244c6e7d6bd2a58453effbadf1e93f9956a0aace1fc0fcef1c97660e486f4
3
+ metadata.gz: 7a4c2fdd688142eb3f9db1a5d0d10cad624225413f6892a65eeef1a0aec3df00
4
+ data.tar.gz: 7ee194719f3912044b675f874f60d42bf4c6e7c60be5e83318cf3f2aaeca6225
5
5
  SHA512:
6
- metadata.gz: a8a4a40c37e53158ce69775451a56a2b939cecb01df5c8441a0c7a18b9e4c88db68d350dd57abbc2d87fd03c770335f2e92344e2fba4370280796bb46fce1d6e
7
- data.tar.gz: b73106dde5c5f19b65c6b95ac6f0fdf4039ab84eaf6dfb53abe705e54e4b7c2f8951fd3ebe205cf53ca46faaccf3812cc1fc2e534979a8adfd99df07bc0a66fb
6
+ metadata.gz: 4edd7d0d8677b548585517b499a57ae630b5326053192f7b10b6de101c8899aab46d956de787df0a480cf66f73fd34c5da3518db2f1c61abc82b7758cdef7cbe
7
+ data.tar.gz: c3678597e116adf629f4229193c921a003e1f270030c2d076464af427806b76ce1560f6726a231eca7507af334be457e91f2c286d1bc2d0349d66696f73c25d8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
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
+
3
9
  ## [2.2.0] - 2026-09-03
4
10
 
5
11
  ### 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
- - Range begins and ends
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| p el }
41
+ Leto.call(object) { |el| puts "#{el.class}: #{el}" }
41
42
  # prints:
42
43
  #
43
- # [{:a=>["b", ["c".."d"]]}]
44
- # {:a=>["b", ["c".."d"]]}
45
- # :a
46
- # ["b", ["c".."d"]]
47
- # "b"
48
- # "c".."d"
49
- # "c"
50
- # "d"
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
- # Leto::trace behaves like ::call, but also yields each (sub-)object's path:
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
- # paths can be looked up with Leto::Path#resolve or Leto::dig
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
 
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
- defined?(Data) && Data.respond_to?(:define) && <<-DATA_FEATURE_RUBY
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
@@ -34,8 +34,14 @@ module Leto
34
34
  copy[*args] = deep_dup(el, include_modules: include_modules)
35
35
  when :send # Data
36
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)]
37
39
  when :begin
38
- return Range.new(deep_dup(obj.begin), deep_dup(obj.end), obj.exclude_end?)
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
+ )
39
45
  end
40
46
  end
41
47
 
data/lib/leto/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leto
4
- VERSION = "2.2.0"
4
+ VERSION = "2.3.0"
5
5
  end
data/lib/leto.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'leto/features'
3
4
  require_relative 'leto/call'
4
5
  require_relative 'leto/dig'
5
6
  require_relative 'leto/path'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leto
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janosch Müller
@@ -27,6 +27,7 @@ files:
27
27
  - lib/leto.rb
28
28
  - lib/leto/call.rb
29
29
  - lib/leto/dig.rb
30
+ - lib/leto/features.rb
30
31
  - lib/leto/path.rb
31
32
  - lib/leto/utils.rb
32
33
  - lib/leto/version.rb
@@ -50,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
51
  - !ruby/object:Gem::Version
51
52
  version: '0'
52
53
  requirements: []
53
- rubygems_version: 4.0.3
54
+ rubygems_version: 4.0.20
54
55
  specification_version: 4
55
56
  summary: Generic object traverser
56
57
  test_files: []