tins 1.47.0 → 1.49.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: 37dea3f4959ecf698b1908647ef0a7e1c19abe61aa669bbc63aa65fde10714e4
4
- data.tar.gz: 78d9256391b2a6dd105be5bc8e0b37aef0508516ddc2cbc578e4766a4f02a50c
3
+ metadata.gz: fa1d017de1e131e88ad3f54ae37abc4ff5020399f48a5fd97d3fd19a3ffca6e9
4
+ data.tar.gz: 50233d748b6362c332e51089923a6ef49f7e2e07044fa7f5843761adac219b0f
5
5
  SHA512:
6
- metadata.gz: 04d75c6e6264659e08574a21bf0a2899702a7765ca90e32baec72056b6a95a639b35aeef7c0ad0d81a35287b3b076b9185f029be9115ae1d0b009236a3a4ca2a
7
- data.tar.gz: df69723660df31a08011a5209d460d55a6422cc1999067e2739365866ce30f4f2135a81484d722ae9ac9d83a0ed1c9cdbfe53d1f76ee6060457ad292717cd126
6
+ metadata.gz: 6318e15f121a8924c548d793f92f28b1eaae0688b0c26a347501fd57f0e493c49edeff0501a5bc0b977ecde21d1eadc7a4adae335a3de9f542cedaf6956e2289
7
+ data.tar.gz: 768135b3fc2f635a728fcc14c5fc4d0648cfba85c973072a53557ae5c60fb00587af96944066a4bd9df0773b0dab066d540f0197e040b861064eedceaf27231e
data/CHANGES.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changes
2
2
 
3
+ ## 2025-12-05 v1.48.0
4
+
5
+ - Added `Tins::Token.analyze` class method to calculate bit strength
6
+ - Moved bit calculation logic from `initialize` to `analyze` method for reuse
7
+ - Implemented bit strength calculation using formula: `length ×
8
+ log₂(alphabet_size)`
9
+ - Added comprehensive tests for the `analyze` method with various alphabets
10
+ - Support both token string and length-based analysis
11
+ - Implemented proper error handling for required parameters
12
+ - Updated `initialize` method to use the new `analyze` method
13
+ - Test cases verify bit strength for **BASE16**, **BASE64**, and **BASE32**
14
+ alphabets
15
+ - Method returns integer bit strength for cryptographic token analysis
16
+
3
17
  ## 2025-11-14 v1.47.0
4
18
 
5
19
  - Tins::GO
data/lib/tins/token.rb CHANGED
@@ -81,7 +81,7 @@ module Tins
81
81
  bits > 0 or raise ArgumentError, 'bits has to be positive'
82
82
  length = (Math.log(1 << bits) / Math.log(alphabet.size)).ceil
83
83
  end
84
- self.bits = (Math.log(alphabet.size ** length) / Math.log(2)).floor
84
+ self.bits = self.class.analyze(alphabet:, length:)
85
85
  token = +''
86
86
  length.times { token << alphabet[random.random_number(alphabet.size)] }
87
87
  super token
@@ -91,5 +91,22 @@ module Tins
91
91
  #
92
92
  # @return [Integer] the number of bits of entropy in the token
93
93
  attr_accessor :bits
94
+
95
+ # The analyze method calculates the bit length of a token based on its
96
+ # alphabet and length.
97
+ #
98
+ # @param alphabet [String] the alphabet used for token generation, defaults
99
+ # to Tins::Token::DEFAULT_ALPHABET
100
+ # @param token [String, nil] the token string to analyze, optional
101
+ # @param length [Integer, nil] the length of the token, optional
102
+ #
103
+ # @return [Integer] the calculated bit length of the token
104
+ #
105
+ # @raise [ArgumentError] if neither token nor length is provided, or if both are provided
106
+ def self.analyze(alphabet: Tins::Token::DEFAULT_ALPHABET, token: nil, length: nil)
107
+ token.nil? ^ length.nil? or raise ArgumentError, 'either token or length is required'
108
+ length ||= token.length
109
+ (Math.log(alphabet.size ** length) / Math.log(2)).floor
110
+ end
94
111
  end
95
112
  end
data/lib/tins/unit.rb CHANGED
@@ -26,6 +26,18 @@ module Tins
26
26
  '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y',
27
27
  ].each_with_index.map { |n, i| Prefix.new(n.freeze, 1024, 1024 ** i, false) }.freeze
28
28
 
29
+ # An array of prefix objects for uppercase binary prefixes (Ki, Mi, Gi...) based
30
+ # on 1024-step increments.
31
+ PREFIX_IEC_UC = [
32
+ '', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi',
33
+ ].each_with_index.map { |n, i| Prefix.new(n.freeze, 1024, 1024 ** i, false) }.freeze
34
+
35
+ # An array of prefix objects for uppercase SI unit prefixes (K, M, G...) based
36
+ # on 1000-step increments.
37
+ PREFIX_SI_UC = [
38
+ '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y',
39
+ ].each_with_index.map { |n, i| Prefix.new(n.freeze, 1000, 1000 ** i, false) }.freeze
40
+
29
41
  # An array of prefix objects for fractional prefixes (m, µ, n...) based on
30
42
  # 1000-step decrements.
31
43
  PREFIX_F = [
@@ -51,10 +63,14 @@ module Tins
51
63
  case identifier
52
64
  when :uppercase, :uc, 1024
53
65
  PREFIX_UC
66
+ when :iec_uppercase, :iec_uc
67
+ PREFIX_IEC_UC
54
68
  when :lowercase, :lc, 1000
55
69
  PREFIX_LC
56
- when :fraction, :f, 0.001
70
+ when :fraction, :f, :si_greek, 0.001
57
71
  PREFIX_F
72
+ when :si_uc, :si_uppercase
73
+ PREFIX_SI_UC
58
74
  when Array
59
75
  identifier
60
76
  end
data/lib/tins/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Tins
2
2
  # Tins version
3
- VERSION = '1.47.0'
3
+ VERSION = '1.49.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:
data/tests/token_test.rb CHANGED
@@ -32,6 +32,37 @@ module Tins
32
32
  assert_equal 128, token.length
33
33
  assert_equal 256, token.bits
34
34
  end
35
+
36
+ def test_analyze_method
37
+ # Test with default alphabet and length
38
+ bits = Tins::Token.analyze(alphabet: Tins::Token::DEFAULT_ALPHABET, length: 22)
39
+ assert_equal 130, bits
40
+
41
+ # Test with hex alphabet and length
42
+ bits = Tins::Token.analyze(alphabet: Tins::Token::BASE16_LOWERCASE_ALPHABET, length: 32)
43
+ assert_equal 128, bits # 32 × 4 = 128 bits
44
+
45
+ # Test with base64 alphabet and length
46
+ bits = Tins::Token.analyze(alphabet: Tins::Token::BASE64_ALPHABET, length: 44)
47
+ assert_equal 264, bits # 44 × 6 = 264 bits
48
+
49
+ # Test with base32 alphabet and length
50
+ bits = Tins::Token.analyze(alphabet: Tins::Token::BASE32_ALPHABET, length: 52)
51
+ assert_equal 260, bits # 52 × 5 = 260 bits
52
+
53
+ # Test with token string instead of length
54
+ token = "5f4dcc3b5aa765d61d8327deb882cf99"
55
+ bits = Tins::Token.analyze(alphabet: Tins::Token::BASE16_LOWERCASE_ALPHABET, token: token)
56
+ assert_equal 128, bits
57
+
58
+ # Test error handling
59
+ assert_raise(ArgumentError) do
60
+ Tins::Token.analyze(alphabet: Tins::Token::DEFAULT_ALPHABET)
61
+ end
62
+
63
+ assert_raise(ArgumentError) do
64
+ Tins::Token.analyze(alphabet: Tins::Token::DEFAULT_ALPHABET, token: "test", length: 5)
65
+ end
66
+ end
35
67
  end
36
68
  end
37
-
data/tests/unit_test.rb CHANGED
@@ -15,6 +15,11 @@ module Tins
15
15
  assert_equal Tins::Unit::PREFIX_F, prefixes(0.001)
16
16
  assert_equal Tins::Unit::PREFIX_F, prefixes(:f)
17
17
  assert_equal Tins::Unit::PREFIX_F, prefixes(:fraction)
18
+ assert_equal Tins::Unit::PREFIX_F, prefixes(:si_greek)
19
+ assert_equal Tins::Unit::PREFIX_SI_UC, prefixes(:si_uc)
20
+ assert_equal Tins::Unit::PREFIX_SI_UC, prefixes(:si_uppercase)
21
+ assert_equal Tins::Unit::PREFIX_IEC_UC, prefixes(:iec_uc)
22
+ assert_equal Tins::Unit::PREFIX_IEC_UC, prefixes(:iec_uppercase)
18
23
  assert_equal nil, prefixes(:nix)
19
24
  end
20
25
 
@@ -42,6 +47,19 @@ module Tins
42
47
  format(0.000_000_123, format: '%.3f %U', prefix: :f, unit: ?F)
43
48
  end
44
49
 
50
+ def test_format_si_multipliers
51
+ assert_equal '23 KHz',
52
+ format(23 * 1000, format: '%d %U', prefix: :si_uc, unit: 'Hz')
53
+ assert_equal '-23 KHz',
54
+ format(-23 * 1000, format: '%d %U', prefix: :si_uc, unit: 'Hz')
55
+ assert_equal '23.1 KHz',
56
+ format(23 * 1000 + 111, format: '%.1f %U', prefix: :si_uc, unit: 'Hz')
57
+ assert_equal 'KHz: 23',
58
+ format(23 * 1000, format: '%U: %d', prefix: :si_uc, unit: 'Hz')
59
+ assert_equal 'KHz: 23.12',
60
+ format(23 * 1000 + 120, prefix: :si_uc, format: '%U: %.2f', unit: 'Hz')
61
+ end
62
+
45
63
  def test_parse
46
64
  assert_in_delta 17_301_504, parse('16.5 Mb').to_i, 1e-5
47
65
  assert_in_delta 16_500_000, parse('16.5 mbps', unit: 'bps').to_i, 1e-5
data/tins.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: tins 1.47.0 ruby lib
2
+ # stub: tins 1.49.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "tins".freeze
6
- s.version = "1.47.0".freeze
6
+ s.version = "1.49.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 = "3.7.2".freeze
20
+ s.rubygems_version = "4.0.2".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_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_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.47.0
4
+ version: 1.49.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -484,7 +484,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
484
484
  - !ruby/object:Gem::Version
485
485
  version: '0'
486
486
  requirements: []
487
- rubygems_version: 3.7.2
487
+ rubygems_version: 4.0.2
488
488
  specification_version: 4
489
489
  summary: Useful stuff.
490
490
  test_files: