tins 1.52.0 → 1.53.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: 8fa2fd818ec06340248491b7ddd9710f6960351402305ed0e74967db12e067ef
4
- data.tar.gz: e5626b112f428aeed1596384aa03642faeb6aea685b7f08e962bde6cb37f4ed1
3
+ metadata.gz: 7878ad969917b7fe9cb5ecdd474c612c5a440434331b3036729000b42ba26f7a
4
+ data.tar.gz: c0a7b9b5d3f69b19ed6ef11de637e70a286324089bf12f28c555502af1d7b775
5
5
  SHA512:
6
- metadata.gz: 935cffcff615ef5e3b73580a1222f8b6210c1b1b007cedcd9c5332bd707f2dd99c7b74775ea52ec6fa2f55b3936869f670392a7c497e0bce1dd87f546d9dd5a6
7
- data.tar.gz: df651121d32df44d80d974209bce4087dddc5277f7568e6b9e7ec4591719ca7b931ec2bcda6cf9bf2c084de519750f4b3fa5c47d38e3f533f7dbafecedf1571d
6
+ metadata.gz: 240db7924b97b15d7e8df113407fd3878f08911caf4c4b362569a6fb563ca49d6a7ffa2227ea9ff8180fb5b321e174def7799b9c147b6b29a8d5fde6e2d14f7a
7
+ data.tar.gz: c5f3a1447cf33d250f5819895d59cc74bd4168b0bccc49371cde8efdd377c54ae98a554e30ac817d7c5d597e92dea3c0c0b37e2ad3b6b058e390613db50a25a6
data/CHANGES.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-14 v1.53.0
4
+
5
+ - Added `stringify_keys_recursive` and `stringify_keys_recursive!` methods to convert hash keys from symbols to strings
6
+ - Renamed `_symbolize_keys_recursive` to `_transform_keys_recursive` to
7
+ support both `:to_sym` and `:to_s` transformations
8
+ - Updated `symbolize_keys_recursive` to use the new
9
+ `_transform_keys_recursive` with `transform: :to_sym`
10
+ - Added comprehensive tests for the new `stringify_keys_recursive` methods
11
+ including circular reference handling
12
+ - Updated YARD documentation for all new and modified methods
13
+ - Made `Token#bits` immutable from outside by changing `attr_accessor
14
+ :bits` to `attr_reader :bits` and using direct instance variable
15
+ assignment
16
+ - Bump `s.rubygems_version` from **4.0.3** to **4.0.10** in `tins.gemspec`
17
+
3
18
  ## 2026-02-23 v1.52.0
4
19
 
5
20
  - Renamed `BASE32_EXTENDED_HEX_ALPHABET` to
@@ -49,7 +49,23 @@ module Tins
49
49
  # # => { name: "John", self: "[Circular]" }
50
50
  def symbolize_keys_recursive(circular: nil)
51
51
  self.seen = {}
52
- _symbolize_keys_recursive(self, circular: circular)
52
+ _transform_keys_recursive(self, circular: circular, transform: :to_sym)
53
+ ensure
54
+ self.seen = nil
55
+ end
56
+
57
+ # Converts all keys in the hash (and nested hashes) to strings.
58
+ #
59
+ # @param circular [Object] The value to return for circular references.
60
+ # @return [Hash] A new hash with all keys converted to strings.
61
+ #
62
+ # @example
63
+ # hash = { name: "John", address: { city: "NYC" } }
64
+ # hash.stringify_keys_recursive
65
+ # # => { "name" => "John", "address" => { "city" => "NYC" } }
66
+ def stringify_keys_recursive(circular: nil)
67
+ self.seen = {}
68
+ _transform_keys_recursive(self, circular: circular, transform: :to_s)
53
69
  ensure
54
70
  self.seen = nil
55
71
  end
@@ -70,14 +86,28 @@ module Tins
70
86
  replace symbolize_keys_recursive(circular: circular)
71
87
  end
72
88
 
89
+ # Converts all keys in the hash (and nested hashes) to strings in place.
90
+ #
91
+ # @param circular [Object] The value to return for circular references.
92
+ # @return [Hash] The same hash with all keys converted to strings.
93
+ #
94
+ # @example
95
+ # hash = { name: "John", address: { city: "NYC" } }
96
+ # hash.stringify_keys_recursive!
97
+ # # => { "name" => "John", "address" => { "city" => "NYC" } }
98
+ def stringify_keys_recursive!(circular: nil)
99
+ replace stringify_keys_recursive(circular: circular)
100
+ end
101
+
73
102
  private
74
103
 
75
- # Performs the actual recursive symbolization work
104
+ # Performs the actual recursive transformation work
76
105
  #
77
106
  # @param object [Object] The object to process
78
107
  # @param circular [Object] The value to return for circular references
79
- # @return [Object] The processed object with symbolized keys
80
- def _symbolize_keys_recursive(object, circular: nil)
108
+ # @param transform [Symbol] The transformation to apply to keys (`:to_sym` or `:to_s`).
109
+ # @return [Object] The processed object with transformed keys
110
+ def _transform_keys_recursive(object, circular: nil, transform:)
81
111
  case
82
112
  when seen[object.__id__]
83
113
  object = circular
@@ -87,7 +117,8 @@ module Tins
87
117
  new_object = object.class.new
88
118
  seen[new_object.__id__] = true
89
119
  object.each do |k, v|
90
- new_object[k.to_s.to_sym] = _symbolize_keys_recursive(v, circular: circular)
120
+ new_object[k.to_s.__send__(transform)] =
121
+ _transform_keys_recursive(v, circular: circular, transform:)
91
122
  end
92
123
  object = new_object
93
124
  when object.respond_to?(:to_ary)
@@ -96,7 +127,7 @@ module Tins
96
127
  new_object = object.class.new(object.size)
97
128
  seen[new_object.__id__] = true
98
129
  object.each_with_index do |v, i|
99
- new_object[i] = _symbolize_keys_recursive(v, circular: circular)
130
+ new_object[i] = _transform_keys_recursive(v, circular: circular, transform:)
100
131
  end
101
132
  object = new_object
102
133
  end
data/lib/tins/token.rb CHANGED
@@ -87,7 +87,7 @@ module Tins
87
87
  bits > 0 or raise ArgumentError, 'bits has to be positive'
88
88
  length = (Math.log(1 << bits) / Math.log(alphabet.size)).ceil
89
89
  end
90
- self.bits = self.class.analyze(alphabet:, length:)
90
+ @bits = self.class.analyze(alphabet:, length:)
91
91
  token = +''
92
92
  length.times { token << alphabet[random.random_number(alphabet.size)] }
93
93
  super token
@@ -96,7 +96,7 @@ module Tins
96
96
  # The bit length of the token.
97
97
  #
98
98
  # @return [Integer] the number of bits of entropy in the token
99
- attr_accessor :bits
99
+ attr_reader :bits
100
100
 
101
101
  # The analyze method calculates the bit length of a token based on its
102
102
  # alphabet and length.
data/lib/tins/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Tins
2
2
  # Tins version
3
- VERSION = '1.52.0'
3
+ VERSION = '1.53.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -59,5 +59,61 @@ module Tins
59
59
  hash.symbolize_keys_recursive(circular: :circular)
60
60
  )
61
61
  end
62
+
63
+ def test_stringify
64
+ hash = {
65
+ :key => [
66
+ {
67
+ :key => {
68
+ :key => true
69
+ },
70
+ :o => Object.new,
71
+ }
72
+ ],
73
+ }
74
+ hash2 = hash.stringify_keys_recursive
75
+ assert hash2["key"][0]["key"]["key"]
76
+ hash.stringify_keys_recursive!
77
+ assert hash["key"][0]["key"]["key"]
78
+ end
79
+
80
+ def test_stringify_bang
81
+ hash = { :foo => 'bar' }
82
+ hash.stringify_keys_recursive!
83
+ assert_equal({ "foo" => 'bar' }, hash)
84
+ end
85
+
86
+ def test_stringify_with_circular_array
87
+ circular_array = [].tap { |a| a << a }
88
+ assert_equal(
89
+ { "foo" => [ nil ] },
90
+ { :foo => circular_array }.stringify_keys_recursive
91
+ )
92
+ assert_equal(
93
+ { "foo" => [ :circular ] },
94
+ { :foo => circular_array }.stringify_keys_recursive(circular: :circular)
95
+ )
96
+ end
97
+
98
+ def test_stringify_with_circular_hash
99
+ circular_hash = {}.tap { |h| h[:foo] = h }
100
+ circular_hash_string = {}.tap { |h| h['foo'] = nil }
101
+ assert_equal(
102
+ { "bar" => circular_hash_string },
103
+ { :bar => circular_hash }.stringify_keys_recursive
104
+ )
105
+ assert_equal(
106
+ { "bar" => { "foo" => :circular } },
107
+ { :bar => circular_hash }.stringify_keys_recursive(circular: :circular)
108
+ )
109
+ end
110
+
111
+ def test_stringify_deeper_nesting
112
+ hash = { :foo => [ true, [ { :bar => {}.tap { |h| h[:foo] = h } }, 3.141, [].tap { |arr| arr << arr } ] ] }
113
+ assert_equal(
114
+ {"foo"=> [true, [{"bar"=> {"foo"=> :circular}}, 3.141, [:circular]]]},
115
+ hash.stringify_keys_recursive(circular: :circular)
116
+ )
117
+ end
62
118
  end
63
- end
119
+ end
data/tins.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: tins 1.52.0 ruby lib
2
+ # stub: tins 1.53.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "tins".freeze
6
- s.version = "1.52.0".freeze
6
+ s.version = "1.53.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.licenses = ["MIT".freeze]
18
18
  s.rdoc_options = ["--title".freeze, "Tins - Useful stuff.".freeze, "--main".freeze, "README.md".freeze]
19
19
  s.required_ruby_version = Gem::Requirement.new(">= 3.1".freeze)
20
- s.rubygems_version = "4.0.3".freeze
20
+ s.rubygems_version = "4.0.10".freeze
21
21
  s.summary = "Useful stuff.".freeze
22
22
  s.test_files = ["tests/annotate_test.rb".freeze, "tests/ask_and_send_test.rb".freeze, "tests/attempt_test.rb".freeze, "tests/bijection_test.rb".freeze, "tests/blank_full_test.rb".freeze, "tests/case_predicate_test.rb".freeze, "tests/concern_test.rb".freeze, "tests/date_dummy_test.rb".freeze, "tests/date_time_dummy_test.rb".freeze, "tests/deep_dup_test.rb".freeze, "tests/delegate_test.rb".freeze, "tests/deprecate_test.rb".freeze, "tests/dslkit_test.rb".freeze, "tests/duration_test.rb".freeze, "tests/dynamic_scope_test.rb".freeze, "tests/expose_test.rb".freeze, "tests/extract_last_argument_options_test.rb".freeze, "tests/file_binary_test.rb".freeze, "tests/find_test.rb".freeze, "tests/from_module_test.rb".freeze, "tests/generator_test.rb".freeze, "tests/go_test.rb".freeze, "tests/hash_bfs_test.rb".freeze, "tests/hash_dfs_test.rb".freeze, "tests/hash_symbolize_keys_recursive_test.rb".freeze, "tests/hash_union_test.rb".freeze, "tests/if_predicate_test.rb".freeze, "tests/implement_test.rb".freeze, "tests/limited_test.rb".freeze, "tests/lines_file_test.rb".freeze, "tests/lru_cache_test.rb".freeze, "tests/memoize_test.rb".freeze, "tests/method_description_test.rb".freeze, "tests/minimize_test.rb".freeze, "tests/module_group_test.rb".freeze, "tests/named_set_test.rb".freeze, "tests/named_test.rb".freeze, "tests/null_test.rb".freeze, "tests/p_test.rb".freeze, "tests/partial_application_test.rb".freeze, "tests/proc_compose_test.rb".freeze, "tests/proc_prelude_test.rb".freeze, "tests/range_plus_test.rb".freeze, "tests/require_maybe_test.rb".freeze, "tests/responding_test.rb".freeze, "tests/rotate_test.rb".freeze, "tests/scope_test.rb".freeze, "tests/secure_write_test.rb".freeze, "tests/sexy_singleton_test.rb".freeze, "tests/string_byte_order_mark_test.rb".freeze, "tests/string_camelize_test.rb".freeze, "tests/string_named_placeholders.rb".freeze, "tests/string_underscore_test.rb".freeze, "tests/string_version_test.rb".freeze, "tests/subhash_test.rb".freeze, "tests/temp_io_test.rb".freeze, "tests/test_helper.rb".freeze, "tests/time_dummy_test.rb".freeze, "tests/time_freezer_test.rb".freeze, "tests/to_test.rb".freeze, "tests/token_test.rb".freeze, "tests/unit_test.rb".freeze, "tests/annotate_test.rb".freeze, "tests/ask_and_send_test.rb".freeze, "tests/attempt_test.rb".freeze, "tests/bijection_test.rb".freeze, "tests/blank_full_test.rb".freeze, "tests/case_predicate_test.rb".freeze, "tests/concern_test.rb".freeze, "tests/date_dummy_test.rb".freeze, "tests/date_time_dummy_test.rb".freeze, "tests/deep_dup_test.rb".freeze, "tests/delegate_test.rb".freeze, "tests/deprecate_test.rb".freeze, "tests/dslkit_test.rb".freeze, "tests/duration_test.rb".freeze, "tests/dynamic_scope_test.rb".freeze, "tests/expose_test.rb".freeze, "tests/extract_last_argument_options_test.rb".freeze, "tests/file_binary_test.rb".freeze, "tests/find_test.rb".freeze, "tests/from_module_test.rb".freeze, "tests/generator_test.rb".freeze, "tests/go_test.rb".freeze, "tests/hash_bfs_test.rb".freeze, "tests/hash_dfs_test.rb".freeze, "tests/hash_symbolize_keys_recursive_test.rb".freeze, "tests/hash_union_test.rb".freeze, "tests/if_predicate_test.rb".freeze, "tests/implement_test.rb".freeze, "tests/limited_test.rb".freeze, "tests/lines_file_test.rb".freeze, "tests/lru_cache_test.rb".freeze, "tests/memoize_test.rb".freeze, "tests/method_description_test.rb".freeze, "tests/minimize_test.rb".freeze, "tests/module_group_test.rb".freeze, "tests/named_set_test.rb".freeze, "tests/named_test.rb".freeze, "tests/null_test.rb".freeze, "tests/p_test.rb".freeze, "tests/partial_application_test.rb".freeze, "tests/proc_compose_test.rb".freeze, "tests/proc_prelude_test.rb".freeze, "tests/range_plus_test.rb".freeze, "tests/require_maybe_test.rb".freeze, "tests/responding_test.rb".freeze, "tests/rotate_test.rb".freeze, "tests/scope_test.rb".freeze, "tests/secure_write_test.rb".freeze, "tests/sexy_singleton_test.rb".freeze, "tests/string_byte_order_mark_test.rb".freeze, "tests/string_camelize_test.rb".freeze, "tests/string_underscore_test.rb".freeze, "tests/string_version_test.rb".freeze, "tests/subhash_test.rb".freeze, "tests/temp_io_test.rb".freeze, "tests/time_dummy_test.rb".freeze, "tests/time_freezer_test.rb".freeze, "tests/to_test.rb".freeze, "tests/token_test.rb".freeze, "tests/unit_test.rb".freeze]
23
23
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tins
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.52.0
4
+ version: 1.53.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -503,7 +503,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
503
503
  - !ruby/object:Gem::Version
504
504
  version: '0'
505
505
  requirements: []
506
- rubygems_version: 4.0.3
506
+ rubygems_version: 4.0.10
507
507
  specification_version: 4
508
508
  summary: Useful stuff.
509
509
  test_files: