uuid-v9 0.1.0 → 1.0.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: a024a7da8e214b43b21edada882b9cf3c8e650cd6bd4f3761ac7dc11cdf6537e
4
- data.tar.gz: 5ad01c5802de9ef13735d1646c847698f3a942fe894b04c146f775cf08c25d3d
3
+ metadata.gz: e91cef6ff913feedd5498b37b4caa47d35289c22f1524bee3318e0e9e178eea3
4
+ data.tar.gz: 8628af9c15b93665e006711d747755d16b893cd6743fe8287214e6b194f4336e
5
5
  SHA512:
6
- metadata.gz: 0fe3a93d1d6a3ed99ad2415685163fb7d5dcc6b00a741b938126cd4eb786f08fa6b6184922e6d44e3edd91c949b8efed2f98b5d8c1d217d3a4b192c8573591a3
7
- data.tar.gz: dd1dcc4ae72986b3b86e82d1a0a90063cd6614c31da8b2e375042fa6fb6a63a0600e2c7d9f70955050ebc0494a02ef4e54ddc0a62c0cb04a3229f8841f59f90e
6
+ metadata.gz: 7057703635d13911723d7ce085975bcb524f1e4c03a3013eee2d3c1ea93f2ba23b5c451444d85eff5f3a7f67ca63f0a15861354b83bc4acccb45e10bbee0de13
7
+ data.tar.gz: a6bb594d12d619499eb4e61388a6294582a1062584b3b27bccb0b466a068c3301948c23e100d2a2f3231245e55ac7d3406cb1bdd3edf3f3ed110aeecdb96ad07
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 JHunt
3
+ Copyright (c) 2023-2026 JHunt
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Fast, lightweight, zero-dependency Ruby implementation of UUID version 9
4
4
 
5
- The v9 UUID supports both sequential (time-based) and non-sequential (random) UUIDs with an optional prefix of up to four bytes, an optional checksum, and sufficient randomness to avoid collisions. It uses the UNIX timestamp for sequential UUIDs and CRC-8 for checksums. A version digit can be added if desired, but is omitted by default.
5
+ The v9 UUID supports both sequential (time-based) and non-sequential (random) UUIDs with an optional prefix of up to four bytes, an optional checksum, and sufficient randomness to avoid collisions. It uses the UNIX timestamp for sequential UUIDs and CRC-8 for checksums. The version can be added if desired, but is omitted by default.
6
6
 
7
7
  To learn more about UUID v9, please visit the website: https://uuidv9.jhunt.dev
8
8
 
@@ -44,4 +44,6 @@ _*Legacy mode adds version and variant digits to immitate v1 or v4 UUIDs dependi
44
44
 
45
45
  ## License
46
46
 
47
- This project is licensed under the [MIT License](LICENSE).
47
+ This project is licensed under the [MIT License](LICENSE).
48
+
49
+ <><
data/lib/uuid-v9.rb CHANGED
@@ -31,8 +31,7 @@ class UUIDv9
31
31
  def self.check_version(uuid, version = nil)
32
32
  version_digit = uuid[14]
33
33
  variant_digit = uuid[19]
34
- (!version || version_digit == version) &&
35
- (version_digit == '9' || (['1', '4'].include?(version_digit) && "89abAB".include?(variant_digit)))
34
+ (!version || (version_digit == version.to_s && "89abAB".include?(variant_digit)))
36
35
  end
37
36
 
38
37
  def self.is_uuid?(uuid)
@@ -42,7 +41,7 @@ class UUIDv9
42
41
  def self.is_valid_uuidv9?(uuid, options)
43
42
  is_uuid?(uuid) &&
44
43
  (!options.key?(:checksum) || !options[:checksum] || verify_checksum(uuid)) &&
45
- (!options.key?(:version) || !options[:version] || check_version(uuid))
44
+ (!options.key?(:version) || !options[:version] || check_version(uuid, options[:version]))
46
45
  end
47
46
 
48
47
  def self.random_bytes(count)
@@ -58,27 +57,39 @@ class UUIDv9
58
57
  end
59
58
 
60
59
  def self.validate_prefix(prefix)
61
- raise ArgumentError, 'Prefix must be a string' if prefix.nil?
60
+ raise ArgumentError, 'Prefix must be a string' unless prefix.is_a?(String) # isinstance?(prefix, str)
62
61
  raise ArgumentError, 'Prefix must be no more than 8 characters' if prefix.length > 8
63
62
  raise ArgumentError, 'Prefix must be only hexadecimal characters' unless is_base16?(prefix)
64
63
  end
65
64
 
65
+ def self.validate_suffix(suffix)
66
+ raise ArgumentError, 'Suffix must be a string' unless suffix.is_a?(String) # isinstance?(suffix, str)
67
+ raise ArgumentError, 'Suffix must be no more than 4 characters' if suffix.length > 4
68
+ raise ArgumentError, 'Suffix must be only hexadecimal characters' unless is_base16?(suffix)
69
+ end
70
+
66
71
  def self.add_dashes(str)
67
72
  "#{str[0, 8]}-#{str[8, 4]}-#{str[12, 4]}-#{str[16, 4]}-#{str[20..]}"
68
73
  end
69
74
 
70
75
  def self.generate(options = {})
71
- prefix = options.fetch(:prefix, nil).to_s
76
+ prefix = options.fetch(:prefix, nil) # .to_s
72
77
  timestamp = options.fetch(:timestamp, true)
73
78
  checksum = options.fetch(:checksum, false)
74
79
  version = options.fetch(:version, false)
75
80
  legacy = options.fetch(:legacy, false)
81
+ suffix = options.fetch(:suffix, nil) # .to_s
76
82
 
77
83
  if prefix && !prefix.empty?
78
84
  validate_prefix(prefix)
79
85
  prefix = prefix.downcase
80
86
  end
81
87
 
88
+ if suffix && !suffix.empty?
89
+ validate_suffix(suffix)
90
+ suffix = suffix.downcase
91
+ end
92
+
82
93
  center = case timestamp
83
94
  when true
84
95
  Time.now.to_i.to_s(16)
@@ -90,15 +101,15 @@ class UUIDv9
90
101
  ''
91
102
  end
92
103
 
93
- suffix_length = 32 - prefix.length - center.length - (checksum ? 2 : 0) - (legacy ? 2 : (version ? 1 : 0))
94
- suffix = random_bytes(suffix_length)
104
+ random_length = 32 - (prefix ? prefix.length : 0) - (suffix ? suffix.length : 0) - center.length - (checksum ? 2 : 0) - ((legacy || version) ? 2 : 0) # (legacy ? 2 : (version ? 1 : 0))
105
+ random = random_bytes(random_length)
95
106
 
96
- joined = "#{prefix}#{center}#{suffix}"
107
+ joined = "#{prefix}#{center}#{random}#{suffix}"
97
108
 
98
109
  if legacy
99
110
  joined = "#{joined[0, 12]}#{center.length > 0 ? '1' : '4'}#{joined[12, 3]}#{random_char('89ab')}#{joined[15..]}"
100
111
  elsif version
101
- joined = "#{joined[0, 12]}9#{joined[12..]}"
112
+ joined = "#{joined[0, 12]}9#{joined[12, 3]}#{random_char('89ab')}#{joined[15..]}" # {joined[12..]}
102
113
  end
103
114
 
104
115
  joined += calc_checksum(joined) if checksum
data/spec/uuid-v9_spec.rb CHANGED
@@ -4,7 +4,7 @@ require_relative '../lib/uuid-v9'
4
4
  UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/
5
5
  UUID_V1_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-1[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/
6
6
  UUID_V4_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/
7
- UUID_V9_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-9[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/
7
+ UUID_V9_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-9[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/
8
8
 
9
9
  describe 'UUIDv9' do
10
10
  it 'should validate as a UUID' do
@@ -109,9 +109,9 @@ describe 'UUIDv9' do
109
109
  id2 = UUIDv9.generate({ timestamp: false, checksum: true })
110
110
  id3 = UUIDv9.generate({ prefix: 'a1b2c3d4', checksum: true })
111
111
  id4 = UUIDv9.generate({ prefix: 'a1b2c3d4', timestamp: false, checksum: true })
112
- id5 = UUIDv9.generate({ checksum: true, version: true })
113
- id6 = UUIDv9.generate({ checksum: true, legacy: true })
114
- id7 = UUIDv9.generate({ timestamp: false, checksum: true, legacy: true })
112
+ id5 = UUIDv9.generate({ checksum: true, legacy: true })
113
+ id6 = UUIDv9.generate({ timestamp: false, checksum: true, legacy: true })
114
+ id7 = UUIDv9.generate({ checksum: true, version: true })
115
115
 
116
116
  expect(UUIDv9.is_uuid?(id1)).to be true
117
117
  expect(UUIDv9.is_uuid?('not-a-real-uuid')).to be false
@@ -119,9 +119,9 @@ describe 'UUIDv9' do
119
119
  expect(UUIDv9.is_valid_uuidv9?(id2, { checksum: true })).to be true
120
120
  expect(UUIDv9.is_valid_uuidv9?(id3, { checksum: true })).to be true
121
121
  expect(UUIDv9.is_valid_uuidv9?(id4, { checksum: true })).to be true
122
- expect(UUIDv9.is_valid_uuidv9?(id5, { checksum: true, version: true })).to be true
123
- expect(UUIDv9.is_valid_uuidv9?(id6, { checksum: true, version: true })).to be true
124
- expect(UUIDv9.is_valid_uuidv9?(id7, { checksum: true, version: true })).to be true
122
+ expect(UUIDv9.is_valid_uuidv9?(id5, { checksum: true, version: 1 })).to be true
123
+ expect(UUIDv9.is_valid_uuidv9?(id6, { checksum: true, version: 4 })).to be true
124
+ expect(UUIDv9.is_valid_uuidv9?(id7, { checksum: true, version: 9 })).to be true
125
125
  expect(UUIDv9.verify_checksum(id1)).to be true
126
126
  expect(UUIDv9.verify_checksum(id2)).to be true
127
127
  expect(UUIDv9.verify_checksum(id3)).to be true
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uuid-v9
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JHunt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2026-05-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: '"The v9 UUID supports both sequential (time-based) and non-sequential
14
14
  (random) UUIDs with an optional prefix of up to four bytes, an optional checksum,
15
15
  and sufficient randomness to avoid collisions. It uses the UNIX timestamp for sequential
16
- UUIDs and CRC-8 for checksums. A version digit can be added if desired, but is omitted
16
+ UUIDs and CRC-8 for checksums. The version can be added if desired, but is omitted
17
17
  by default."'
18
18
  email:
19
- - hello@jhunt.dev
19
+ - mail+uuidv9@jhunt.dev
20
20
  executables: []
21
21
  extensions: []
22
22
  extra_rdoc_files: []