Module: Philiprehberger::IdGen
- Defined in:
- lib/philiprehberger/id_gen.rb,
lib/philiprehberger/id_gen/ulid.rb,
lib/philiprehberger/id_gen/uuid.rb,
lib/philiprehberger/id_gen/cuid2.rb,
lib/philiprehberger/id_gen/hashid.rb,
lib/philiprehberger/id_gen/nanoid.rb,
lib/philiprehberger/id_gen/encoder.rb,
lib/philiprehberger/id_gen/version.rb,
lib/philiprehberger/id_gen/prefixed.rb,
lib/philiprehberger/id_gen/snowflake.rb
Defined Under Namespace
Modules: Cuid2, Encoder, Hashid, Nanoid, Prefixed, Snowflake, Ulid, Uuid
Classes: Error
Constant Summary
collapse
- VERSION =
'0.4.0'
Class Method Summary
collapse
-
.cuid2(length: 24) ⇒ Object
-
.cuid2_batch(count, length: 24) ⇒ Object
-
.decode(string, alphabet: Encoder::DEFAULT_ALPHABET) ⇒ Object
-
.detect_format(id) ⇒ Symbol?
Detect the format of an ID by probing the format-specific validators.
-
.encode(integer, alphabet: Encoder::DEFAULT_ALPHABET) ⇒ Object
-
.hashid(integer, salt: '', min_length: 8) ⇒ Object
-
.nanoid(size = 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Object
-
.nanoid_batch(count, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Object
-
.parse_ulid(string) ⇒ Object
-
.prefixed(prefix) ⇒ Object
-
.prefixed_batch(prefix, count) ⇒ Object
-
.snowflake(worker_id: 0, epoch: nil) ⇒ Object
-
.snowflake_timestamp(id, epoch: nil) ⇒ Object
-
.ulid ⇒ Object
-
.ulid_batch(count) ⇒ Object
Batch generation methods.
-
.ulid_monotonic ⇒ Object
-
.ulid_timestamp(ulid_string) ⇒ Object
-
.uuid_v7 ⇒ Object
-
.uuid_v7_batch(count) ⇒ Object
-
.uuid_v7_timestamp(uuid_string) ⇒ Object
-
.valid_cuid2?(string, length: 24) ⇒ Boolean
-
.valid_nanoid?(string, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Boolean
-
.valid_snowflake?(id) ⇒ Boolean
-
.valid_ulid?(string) ⇒ Boolean
-
.valid_uuid_v7?(string) ⇒ Boolean
Class Method Details
.cuid2(length: 24) ⇒ Object
68
69
70
|
# File 'lib/philiprehberger/id_gen.rb', line 68
def self.cuid2(length: 24)
Cuid2.generate(length)
end
|
.cuid2_batch(count, length: 24) ⇒ Object
72
73
74
75
|
# File 'lib/philiprehberger/id_gen.rb', line 72
def self.cuid2_batch(count, length: 24)
validate_batch_count!(count)
Array.new(count) { Cuid2.generate(length) }
end
|
.decode(string, alphabet: Encoder::DEFAULT_ALPHABET) ⇒ Object
Detect the format of an ID by probing the format-specific validators. Probing order (most specific first): ULID, UUID v7, Snowflake (Integer or numeric String), CUID2, Nanoid. Returns a Symbol identifying the format (‘:ulid`, `:uuid_v7`, `:snowflake`, `:cuid2`, `:nanoid`) or `nil` when nothing matches.
Nanoid intentionally runs last because its default alphabet overlaps with many others — treat ‘:nanoid` as a fallback identification only.
160
161
162
163
164
165
166
167
168
169
|
# File 'lib/philiprehberger/id_gen.rb', line 160
def self.detect_format(id)
return :ulid if id.is_a?(String) && valid_ulid?(id)
return :uuid_v7 if id.is_a?(String) && valid_uuid_v7?(id)
return :snowflake if valid_snowflake?(id)
return :snowflake if id.is_a?(String) && id.match?(/\A\d+\z/) && valid_snowflake?(id.to_i)
return :cuid2 if id.is_a?(String) && valid_cuid2?(id)
return :nanoid if id.is_a?(String) && valid_nanoid?(id)
nil
end
|
.encode(integer, alphabet: Encoder::DEFAULT_ALPHABET) ⇒ Object
.hashid(integer, salt: '', min_length: 8) ⇒ Object
93
94
95
|
# File 'lib/philiprehberger/id_gen.rb', line 93
def self.hashid(integer, salt: '', min_length: 8)
Hashid.encode(integer, salt: salt, min_length: min_length)
end
|
.nanoid(size = 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Object
.nanoid_batch(count, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Object
104
105
106
107
|
# File 'lib/philiprehberger/id_gen.rb', line 104
def self.nanoid_batch(count, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET)
validate_batch_count!(count)
Array.new(count) { Nanoid.generate(size, alphabet: alphabet) }
end
|
.parse_ulid(string) ⇒ Object
173
174
175
176
177
178
179
180
181
182
|
# File 'lib/philiprehberger/id_gen.rb', line 173
def self.parse_ulid(string)
raise Error, 'Invalid ULID format' unless valid_ulid?(string)
timestamp = Ulid.timestamp(string)
random_part = string[10, 16]
random_value = Ulid.send(:decode_crockford, random_part)
random_hex = format('%020x', random_value)
{ timestamp: timestamp, random: random_hex }
end
|
.prefixed(prefix) ⇒ Object
33
34
35
|
# File 'lib/philiprehberger/id_gen.rb', line 33
def self.prefixed(prefix)
Prefixed.generate(prefix)
end
|
.prefixed_batch(prefix, count) ⇒ Object
114
115
116
117
|
# File 'lib/philiprehberger/id_gen.rb', line 114
def self.prefixed_batch(prefix, count)
validate_batch_count!(count)
Array.new(count) { Prefixed.generate(prefix) }
end
|
.snowflake(worker_id: 0, epoch: nil) ⇒ Object
37
38
39
40
41
42
43
44
45
46
47
48
49
|
# File 'lib/philiprehberger/id_gen.rb', line 37
def self.snowflake(worker_id: 0, epoch: nil)
if epoch
epoch_ms = (epoch.to_f * 1000).to_i
key = [worker_id, epoch_ms]
@snowflake_custom_generators ||= {}
@snowflake_custom_generators[key] ||= Snowflake::Generator.new(worker_id: worker_id, epoch: epoch)
@snowflake_custom_generators[key].generate
else
@snowflake_generators ||= {}
@snowflake_generators[worker_id] ||= Snowflake::Generator.new(worker_id: worker_id)
@snowflake_generators[worker_id].generate
end
end
|
.snowflake_timestamp(id, epoch: nil) ⇒ Object
51
52
53
54
55
56
57
58
|
# File 'lib/philiprehberger/id_gen.rb', line 51
def self.snowflake_timestamp(id, epoch: nil)
if epoch
epoch_ms = (epoch.to_f * 1000).to_i
Snowflake.timestamp(id, epoch_ms: epoch_ms)
else
Snowflake.timestamp(id)
end
end
|
.ulid ⇒ Object
17
18
19
|
# File 'lib/philiprehberger/id_gen.rb', line 17
def self.ulid
Ulid.generate
end
|
.ulid_batch(count) ⇒ Object
99
100
101
102
|
# File 'lib/philiprehberger/id_gen.rb', line 99
def self.ulid_batch(count)
validate_batch_count!(count)
Array.new(count) { Ulid.generate }
end
|
.ulid_monotonic ⇒ Object
21
22
23
|
# File 'lib/philiprehberger/id_gen.rb', line 21
def self.ulid_monotonic
Ulid.monotonic
end
|
.ulid_timestamp(ulid_string) ⇒ Object
25
26
27
|
# File 'lib/philiprehberger/id_gen.rb', line 25
def self.ulid_timestamp(ulid_string)
Ulid.timestamp(ulid_string)
end
|
.uuid_v7 ⇒ Object
60
61
62
|
# File 'lib/philiprehberger/id_gen.rb', line 60
def self.uuid_v7
Uuid.generate_v7
end
|
.uuid_v7_batch(count) ⇒ Object
109
110
111
112
|
# File 'lib/philiprehberger/id_gen.rb', line 109
def self.uuid_v7_batch(count)
validate_batch_count!(count)
Array.new(count) { Uuid.generate_v7 }
end
|
.uuid_v7_timestamp(uuid_string) ⇒ Object
64
65
66
|
# File 'lib/philiprehberger/id_gen.rb', line 64
def self.uuid_v7_timestamp(uuid_string)
Uuid.timestamp_v7(uuid_string)
end
|
.valid_cuid2?(string, length: 24) ⇒ Boolean
77
78
79
80
81
82
83
|
# File 'lib/philiprehberger/id_gen.rb', line 77
def self.valid_cuid2?(string, length: 24)
return false unless string.is_a?(String)
return false unless string.length == length
return false unless string[0].match?(/[a-z]/)
string.match?(/\A[a-z0-9]+\z/)
end
|
.valid_nanoid?(string, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET) ⇒ Boolean
128
129
130
131
132
133
134
|
# File 'lib/philiprehberger/id_gen.rb', line 128
def self.valid_nanoid?(string, size: 21, alphabet: Nanoid::DEFAULT_ALPHABET)
return false unless string.is_a?(String)
return false unless string.length == size
escaped = Regexp.escape(alphabet)
string.match?(/\A[#{escaped}]+\z/)
end
|
.valid_snowflake?(id) ⇒ Boolean
140
141
142
143
144
145
146
147
|
# File 'lib/philiprehberger/id_gen.rb', line 140
def self.valid_snowflake?(id)
return false unless id.is_a?(Integer)
return false unless id.positive?
timestamp_ms = (id >> Snowflake::TIMESTAMP_SHIFT) + Snowflake::CUSTOM_EPOCH
timestamp_ms.positive? && timestamp_ms < (Snowflake::CUSTOM_EPOCH + (100 * 365.25 * 24 * 60 * 60 * 1000).to_i)
end
|
.valid_ulid?(string) ⇒ Boolean
121
122
123
124
125
126
|
# File 'lib/philiprehberger/id_gen.rb', line 121
def self.valid_ulid?(string)
return false unless string.is_a?(String)
return false unless string.length == 26
string.match?(/\A[0-9A-HJKMNP-TV-Z]+\z/)
end
|
.valid_uuid_v7?(string) ⇒ Boolean
136
137
138
|
# File 'lib/philiprehberger/id_gen.rb', line 136
def self.valid_uuid_v7?(string)
Uuid.valid_v7?(string)
end
|