ruby-ulid 0.0.19 → 0.1.4
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 +4 -4
- data/README.md +48 -11
- data/lib/ulid.rb +118 -51
- data/lib/ulid/crockford_base32.rb +17 -0
- data/lib/ulid/monotonic_generator.rb +41 -20
- data/lib/ulid/uuid.rb +1 -1
- data/lib/ulid/version.rb +1 -1
- data/sig/ulid.rbs +445 -24
- metadata +198 -2
@@ -51,6 +51,15 @@ class ULID
|
|
51
51
|
CROCKFORD_BASE32_CHAR_BY_N32_CHAR = N32_CHAR_BY_CROCKFORD_BASE32_CHAR.invert.freeze
|
52
52
|
N32_CHAR_PATTERN = /[#{CROCKFORD_BASE32_CHAR_BY_N32_CHAR.keys.join}]/.freeze
|
53
53
|
|
54
|
+
VARIANT_BY_STANDARD = {
|
55
|
+
'L' => '1',
|
56
|
+
'I' => '1',
|
57
|
+
'O' => '0',
|
58
|
+
'-' => ''
|
59
|
+
}.freeze
|
60
|
+
VARIANT_PATTERN = /[#{VARIANT_BY_STANDARD.keys.join}]/.freeze
|
61
|
+
|
62
|
+
# @api private
|
54
63
|
# @param [String] string
|
55
64
|
# @return [Integer]
|
56
65
|
def self.decode(string)
|
@@ -58,11 +67,19 @@ class ULID
|
|
58
67
|
n32encoded.to_i(32)
|
59
68
|
end
|
60
69
|
|
70
|
+
# @api private
|
61
71
|
# @param [Integer] integer
|
62
72
|
# @return [String]
|
63
73
|
def self.encode(integer)
|
64
74
|
n32encoded = integer.to_s(32)
|
65
75
|
n32encoded.upcase.gsub(N32_CHAR_PATTERN, CROCKFORD_BASE32_CHAR_BY_N32_CHAR).rjust(ENCODED_LENGTH, '0')
|
66
76
|
end
|
77
|
+
|
78
|
+
# @api private
|
79
|
+
# @param [String] string
|
80
|
+
# @return [String]
|
81
|
+
def self.normalize(string)
|
82
|
+
string.upcase.gsub(VARIANT_PATTERN, VARIANT_BY_STANDARD)
|
83
|
+
end
|
67
84
|
end
|
68
85
|
end
|
@@ -4,40 +4,61 @@
|
|
4
4
|
|
5
5
|
class ULID
|
6
6
|
class MonotonicGenerator
|
7
|
-
|
8
|
-
|
7
|
+
include MonitorMixin
|
8
|
+
|
9
|
+
# @return [ULID, nil]
|
10
|
+
attr_reader :prev
|
11
|
+
|
12
|
+
undef_method :instance_variable_set
|
9
13
|
|
10
14
|
def initialize
|
11
|
-
|
12
|
-
|
15
|
+
super()
|
16
|
+
@prev = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [String]
|
20
|
+
def inspect
|
21
|
+
"ULID::MonotonicGenerator(prev: #{@prev.inspect})"
|
13
22
|
end
|
23
|
+
alias_method :to_s, :inspect
|
14
24
|
|
15
25
|
# @param [Time, Integer] moment
|
16
26
|
# @return [ULID]
|
17
27
|
# @raise [OverflowError] if the entropy part is larger than the ULID limit in same milliseconds
|
18
|
-
# @raise [
|
28
|
+
# @raise [UnexpectedError] if the generated ULID is an invalid value in monotonicity spec.
|
29
|
+
# Basically will not happen. Just means this feature prefers error rather than invalid value.
|
19
30
|
def generate(moment: ULID.current_milliseconds)
|
20
|
-
|
21
|
-
|
31
|
+
synchronize do
|
32
|
+
unless @prev
|
33
|
+
@prev = ULID.generate(moment: moment)
|
34
|
+
return @prev
|
35
|
+
end
|
36
|
+
|
37
|
+
milliseconds = ULID.milliseconds_from_moment(moment)
|
22
38
|
|
23
|
-
|
24
|
-
|
25
|
-
@latest_milliseconds = milliseconds
|
26
|
-
@latest_entropy = ULID.reasonable_entropy
|
39
|
+
ulid = if @prev.milliseconds < milliseconds
|
40
|
+
ULID.generate(moment: milliseconds)
|
27
41
|
else
|
28
|
-
@
|
42
|
+
ULID.from_milliseconds_and_entropy(milliseconds: @prev.milliseconds, entropy: @prev.entropy.succ)
|
29
43
|
end
|
30
|
-
|
44
|
+
|
45
|
+
unless ulid > @prev
|
46
|
+
base_message = "monotonicity broken from unexpected reasons # generated: #{ulid.inspect}, prev: #{@prev.inspect}"
|
47
|
+
additional_information = if Thread.list == [Thread.main]
|
48
|
+
'# NOTE: looks single thread only exist'
|
49
|
+
else
|
50
|
+
'# NOTE: ran on multi threads, so this might from concurrency issue'
|
51
|
+
end
|
52
|
+
|
53
|
+
raise UnexpectedError, base_message + additional_information
|
54
|
+
end
|
55
|
+
|
56
|
+
@prev = ulid
|
57
|
+
ulid
|
31
58
|
end
|
32
59
|
end
|
33
60
|
|
34
|
-
|
35
|
-
# @return [void]
|
36
|
-
def reset
|
37
|
-
@latest_milliseconds = 0
|
38
|
-
@latest_entropy = ULID.reasonable_entropy
|
39
|
-
nil
|
40
|
-
end
|
61
|
+
undef_method :freeze
|
41
62
|
|
42
63
|
# @raise [TypeError] always raises exception and does not freeze self
|
43
64
|
# @return [void]
|
data/lib/ulid/uuid.rb
CHANGED
@@ -18,7 +18,7 @@ class ULID
|
|
18
18
|
uuid = String.try_convert(uuid)
|
19
19
|
raise ArgumentError, 'ULID.from_uuidv4 takes only strings' unless uuid
|
20
20
|
|
21
|
-
prefix_trimmed = uuid.
|
21
|
+
prefix_trimmed = uuid.delete_prefix('urn:uuid:')
|
22
22
|
unless UUIDV4_PATTERN.match?(prefix_trimmed)
|
23
23
|
raise ParserError, "given `#{uuid}` does not match to `#{UUIDV4_PATTERN.inspect}`"
|
24
24
|
end
|
data/lib/ulid/version.rb
CHANGED
data/sig/ulid.rbs
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
class ULID
|
1
|
+
class ULID < Object
|
3
2
|
VERSION: String
|
4
3
|
CROCKFORD_BASE32_ENCODING_STRING: String
|
5
4
|
TIMESTAMP_ENCODED_LENGTH: 10
|
@@ -33,6 +32,9 @@ class ULID
|
|
33
32
|
class ParserError < Error
|
34
33
|
end
|
35
34
|
|
35
|
+
class UnexpectedError < Error
|
36
|
+
end
|
37
|
+
|
36
38
|
module CrockfordBase32
|
37
39
|
class SetupError < ScriptError
|
38
40
|
end
|
@@ -41,78 +43,497 @@ class ULID
|
|
41
43
|
CROCKFORD_BASE32_CHAR_PATTERN: Regexp
|
42
44
|
CROCKFORD_BASE32_CHAR_BY_N32_CHAR: Hash[String, String]
|
43
45
|
N32_CHAR_PATTERN: Regexp
|
46
|
+
VARIANT_BY_STANDARD: Hash[String, String]
|
47
|
+
VARIANT_PATTERN: Regexp
|
44
48
|
|
49
|
+
# A pribate API. Should not be used in your code.
|
45
50
|
def self.encode: (Integer integer) -> String
|
51
|
+
|
52
|
+
# A pribate API. Should not be used in your code.
|
46
53
|
def self.decode: (String string) -> Integer
|
54
|
+
|
55
|
+
# A pribate API. Should not be used in your code.
|
56
|
+
def self.normalize: (String string) -> String
|
47
57
|
end
|
48
58
|
|
49
59
|
class MonotonicGenerator
|
50
|
-
|
51
|
-
|
60
|
+
include MonitorMixin
|
61
|
+
|
62
|
+
# Returned value is `basically not` Thread-safety
|
63
|
+
# If you want to keep Thread-safety, keep to call {#generate} only in same {#synchronize} block
|
64
|
+
#
|
65
|
+
# ```ruby
|
66
|
+
# generator.synchronize do
|
67
|
+
# generator.prev
|
68
|
+
# generator.inspect
|
69
|
+
# generator.generate
|
70
|
+
# end
|
71
|
+
# ```
|
72
|
+
attr_reader prev: ULID | nil
|
73
|
+
|
74
|
+
# A pribate API. Should not be used in your code.
|
52
75
|
def initialize: -> void
|
76
|
+
|
77
|
+
# See [How to keep `Sortable` even if in same timestamp](https://github.com/kachick/ruby-ulid#how-to-keep-sortable-even-if-in-same-timestamp)
|
78
|
+
# The `Thread-safety` is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
|
53
79
|
def generate: (?moment: moment) -> ULID
|
54
|
-
|
80
|
+
|
81
|
+
# Returned value is `basically not` Thread-safety
|
82
|
+
# If you want to keep Thread-safety, keep to call {#generate} only in same {#synchronize} block
|
83
|
+
#
|
84
|
+
# ```ruby
|
85
|
+
# generator.synchronize do
|
86
|
+
# generator.prev
|
87
|
+
# generator.inspect
|
88
|
+
# generator.generate
|
89
|
+
# end
|
90
|
+
# ```
|
91
|
+
def inspect: -> String
|
92
|
+
alias to_s inspect
|
55
93
|
def freeze: -> void
|
56
94
|
end
|
57
95
|
|
96
|
+
interface _ToULID
|
97
|
+
def to_ulid: () -> ULID
|
98
|
+
end
|
99
|
+
|
58
100
|
type octets = [Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer]
|
59
101
|
type timestamp_octets = [Integer, Integer, Integer, Integer, Integer, Integer]
|
60
102
|
type randomness_octets = [Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer]
|
61
103
|
type period = Range[Time] | Range[nil] | Range[ULID]
|
62
104
|
|
63
|
-
@milliseconds: Integer
|
64
|
-
@entropy: Integer
|
65
105
|
@string: String?
|
66
|
-
@integer: Integer
|
106
|
+
@integer: Integer
|
67
107
|
@timestamp: String?
|
68
108
|
@randomness: String?
|
69
109
|
@inspect: String?
|
70
110
|
@time: Time?
|
71
111
|
|
72
|
-
|
73
|
-
|
112
|
+
# Retuns a ULID
|
113
|
+
#
|
114
|
+
# They are sortable when generated in different timestamp with milliseconds precision
|
115
|
+
#
|
116
|
+
# ```ruby
|
117
|
+
# ulids = 1000.times.map do
|
118
|
+
# sleep(0.001)
|
119
|
+
# ULID.generate
|
120
|
+
# end
|
121
|
+
# ulids.uniq(&:to_time).size #=> 1000
|
122
|
+
# ulids.sort == ulids #=> true
|
123
|
+
# ```
|
124
|
+
#
|
125
|
+
# `ULID.generate` can take fixed `Time` instance.
|
126
|
+
# See also the short hand [ULID.at](https://kachick.github.io/ruby-ulid/ULID.html#at-class_method)
|
127
|
+
#
|
128
|
+
# ```ruby
|
129
|
+
# time = Time.at(946684800).utc #=> 2000-01-01 00:00:00 UTC
|
130
|
+
# ULID.generate(moment: time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB00N018DCPJA4H9379P)
|
131
|
+
# ULID.generate(moment: time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB006WQT3JTMN0T14EBP)
|
132
|
+
# ```
|
133
|
+
#
|
134
|
+
# The basic generator prefers `randomness`, it does not guarantee `sortable` for same milliseconds ULIDs.
|
135
|
+
#
|
136
|
+
# ```ruby
|
137
|
+
# ulids = 10000.times.map do
|
138
|
+
# ULID.generate
|
139
|
+
# end
|
140
|
+
# ulids.uniq(&:to_time).size #=> 35 (the size is not fixed, might be changed in environment)
|
141
|
+
# ulids.sort == ulids #=> false
|
142
|
+
# ```
|
143
|
+
#
|
144
|
+
# If you want to keep sortable even if in same timestamp, See also [ULID::MonotonicGenerator](https://github.com/kachick/ruby-ulid#how-to-keep-sortable-even-if-in-same-timestamp)
|
145
|
+
#
|
146
|
+
def self.generate: (?moment: moment, ?entropy: Integer) -> self
|
147
|
+
|
148
|
+
# Shorthand of `ULID.generate(moment: Time)`
|
149
|
+
# See also [ULID.generate](https://kachick.github.io/ruby-ulid/ULID.html#generate-class_method)
|
150
|
+
#
|
151
|
+
# ```ruby
|
152
|
+
# time = Time.at(946684800).utc #=> 2000-01-01 00:00:00 UTC
|
153
|
+
# ULID.at(time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB002W5BGWWKN76N22H6)
|
154
|
+
#
|
155
|
+
# ulids = 1000.times.map do |n|
|
156
|
+
# ULID.at(time + n)
|
157
|
+
# end
|
158
|
+
# ulids.sort == ulids #=> true
|
159
|
+
# ```
|
160
|
+
def self.at: (Time time) -> self
|
161
|
+
|
162
|
+
# A pribate API. Should not be used in your code.
|
74
163
|
def self.current_milliseconds: -> Integer
|
164
|
+
|
165
|
+
# A pribate API. Should not be used in your code.
|
75
166
|
def self.milliseconds_from_moment: (moment moment) -> Integer
|
167
|
+
|
168
|
+
# `ULID` can be element of the `Range`. If you generated the IDs in monotonic generator, ID based filtering is easy and reliable
|
169
|
+
#
|
170
|
+
# ```ruby
|
171
|
+
# include_end = ulid1..ulid2
|
172
|
+
# exclude_end = ulid1...ulid2
|
173
|
+
#
|
174
|
+
# ulids.grep(one_of_the_above)
|
175
|
+
# ulids.grep_v(one_of_the_above)
|
176
|
+
# ```
|
177
|
+
#
|
178
|
+
# When want to filter ULIDs with `Time`, we should consider to handle the precision.
|
179
|
+
# So this gem provides `ULID.range` to generate reasonable `Range[ULID]` from `Range[Time]`
|
180
|
+
#
|
181
|
+
# ```ruby
|
182
|
+
# # Both of below, The begin of `Range[ULID]` will be the minimum in the floored milliseconds of the time1
|
183
|
+
# include_end = ULID.range(time1..time2) #=> The end of `Range[ULID]` will be the maximum in the floored milliseconds of the time2
|
184
|
+
# exclude_end = ULID.range(time1...time2) #=> The end of `Range[ULID]` will be the minimum in the floored milliseconds of the time2
|
185
|
+
#
|
186
|
+
# # Below patterns are acceptable
|
187
|
+
# pinpointing = ULID.range(time1..time1) #=> This will match only for all IDs in `time1`
|
188
|
+
# until_the_end = ULID.range(..time1) #=> This will match only for all IDs upto `time1` (The `nil` starting `Range` can be used since Ruby 2.7)
|
189
|
+
# until_the_end = ULID.range(ULID.min.to_time..time1) #=> This is same as above for Ruby 2.6
|
190
|
+
# until_the_ulid_limit = ULID.range(time1..) # This will match only for all IDs from `time1` to max value of the ULID limit
|
191
|
+
#
|
192
|
+
# # So you can use the generated range objects as below
|
193
|
+
# ulids.grep(one_of_the_above)
|
194
|
+
# ulids.grep_v(one_of_the_above)
|
195
|
+
# #=> I hope the results should be actually you want!
|
196
|
+
# ```
|
197
|
+
#
|
76
198
|
def self.range: (period period) -> Range[ULID]
|
199
|
+
|
200
|
+
# Returns new `Time` with truncating excess precisions in ULID spec.
|
201
|
+
#
|
202
|
+
# ```ruby
|
203
|
+
# time = Time.at(946684800, Rational('123456.789')).utc
|
204
|
+
# #=> 2000-01-01 00:00:00.123456789 UTC
|
205
|
+
# ULID.floor(time) #=> 2000-01-01 00:00:00.123 UTC
|
206
|
+
# ```
|
77
207
|
def self.floor: (Time time) -> Time
|
78
|
-
|
79
|
-
|
208
|
+
|
209
|
+
# Get ULID instance from encoded String.
|
210
|
+
#
|
211
|
+
# ```ruby
|
212
|
+
# ulid = ULID.parse('01ARZ3NDEKTSV4RRFFQ69G5FAV')
|
213
|
+
# #=> ULID(2016-07-30 23:54:10.259 UTC: 01ARZ3NDEKTSV4RRFFQ69G5FAV)
|
214
|
+
# ```
|
215
|
+
def self.parse: (_ToStr string) -> self
|
216
|
+
|
217
|
+
# ```ruby
|
218
|
+
# # Currently experimental feature, so needed to load the extension.
|
219
|
+
# require 'ulid/uuid'
|
220
|
+
#
|
221
|
+
# # Basically reversible
|
222
|
+
# ulid = ULID.from_uuidv4('0983d0a2-ff15-4d83-8f37-7dd945b5aa39')
|
223
|
+
# #=> ULID(2301-07-10 00:28:28.821 UTC: 09GF8A5ZRN9P1RYDVXV52VBAHS)
|
224
|
+
# ulid.to_uuidv4 #=> "0983d0a2-ff15-4d83-8f37-7dd945b5aa39"
|
225
|
+
# ```
|
226
|
+
#
|
227
|
+
# See also [Why this is experimental?](https://github.com/kachick/ruby-ulid/issues/76)
|
80
228
|
def self.from_uuidv4: (String uuid) -> ULID
|
81
|
-
def self.from_integer: (Integer integer) ->
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
229
|
+
def self.from_integer: (Integer integer) -> self
|
230
|
+
|
231
|
+
# Returns termination values for ULID spec.
|
232
|
+
#
|
233
|
+
# ```ruby
|
234
|
+
# ULID.min
|
235
|
+
# #=> ULID(1970-01-01 00:00:00.000 UTC: 00000000000000000000000000)
|
236
|
+
# ```
|
237
|
+
#
|
238
|
+
# It can take `Time` instance as an optional argument.
|
239
|
+
# Then returns ULID that has minimum value of randomness part in the timestamp.
|
240
|
+
#
|
241
|
+
# ```ruby
|
242
|
+
# time = Time.at(946684800, Rational('123456.789')).utc
|
243
|
+
# #=> 2000-01-01 00:00:00.123456789 UTC
|
244
|
+
# ULID.min(time)
|
245
|
+
# #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3V0000000000000000)
|
246
|
+
# ```
|
247
|
+
#
|
248
|
+
# See also [ULID.max](https://kachick.github.io/ruby-ulid/ULID.html#max-class_method)
|
249
|
+
def self.min: (?moment moment) -> ULID
|
250
|
+
|
251
|
+
# Returns termination values for ULID spec.
|
252
|
+
#
|
253
|
+
# ```ruby
|
254
|
+
# ULID.max
|
255
|
+
# #=> ULID(10889-08-02 05:31:50.655 UTC: 7ZZZZZZZZZZZZZZZZZZZZZZZZZ)
|
256
|
+
# ```
|
257
|
+
#
|
258
|
+
# It can take `Time` instance as an optional argument.
|
259
|
+
# Then returns ULID that has maximum value of randomness part in the timestamp.
|
260
|
+
#
|
261
|
+
# ```ruby
|
262
|
+
# time = Time.at(946684800, Rational('123456.789')).utc
|
263
|
+
# #=> 2000-01-01 00:00:00.123456789 UTC
|
264
|
+
# ULID.max(time)
|
265
|
+
# #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3VZZZZZZZZZZZZZZZZ)
|
266
|
+
# ```
|
267
|
+
#
|
268
|
+
# See also [ULID.min](https://kachick.github.io/ruby-ulid/ULID.html#min-class_method)
|
269
|
+
def self.max: (?moment moment) -> ULID
|
270
|
+
|
271
|
+
# Returns random ULIDs.
|
272
|
+
#
|
273
|
+
# Basically ignores generating time.
|
274
|
+
#
|
275
|
+
# ```ruby
|
276
|
+
# ULID.sample #=> ULID(2545-07-26 06:51:20.085 UTC: 0GGKQ45GMNMZR6N8A8GFG0ZXST)
|
277
|
+
# ULID.sample #=> ULID(5098-07-26 21:31:06.946 UTC: 2SSBNGGYA272J7BMDCG4Z6EEM5)
|
278
|
+
# ULID.sample(0) #=> []
|
279
|
+
# ULID.sample(1) #=> [ULID(2241-04-16 03:31:18.440 UTC: 07S52YWZ98AZ8T565MD9VRYMQH)]
|
280
|
+
# ULID.sample(5)
|
281
|
+
# #=>
|
282
|
+
# #[ULID(5701-04-29 12:41:19.647 UTC: 3B2YH2DV0ZYDDATGTYSKMM1CMT),
|
283
|
+
# # ULID(2816-08-01 01:21:46.612 UTC: 0R9GT6RZKMK3RG02Q2HAFVKEY2),
|
284
|
+
# # ULID(10408-10-05 17:06:27.848 UTC: 7J6CPTEEC86Y24EQ4F1Y93YYN0),
|
285
|
+
# # ULID(2741-09-02 16:24:18.803 UTC: 0P4Q4V34KKAJW46QW47WQB5463),
|
286
|
+
# # ULID(2665-03-16 14:50:22.724 UTC: 0KYFW9DWM4CEGFNTAC6YFAVVJ6)]
|
287
|
+
# ```
|
288
|
+
#
|
289
|
+
# You can specify a range object for the timestamp restriction, See also [ULID.range](https://kachick.github.io/ruby-ulid/ULID.html#range-class_method).
|
290
|
+
#
|
291
|
+
# ```ruby
|
292
|
+
# ulid1 = ULID.parse('01F4A5Y1YAQCYAYCTC7GRMJ9AA') #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
293
|
+
# ulid2 = ULID.parse('01F4PTVCSN9ZPFKYTY2DDJVRK4') #=> ULID(2021-05-02 15:23:48.917 UTC: 01F4PTVCSN9ZPFKYTY2DDJVRK4)
|
294
|
+
# ulids = ULID.sample(1000, period: ulid1..ulid2)
|
295
|
+
# ulids.uniq.size #=> 1000
|
296
|
+
# ulids.take(10)
|
297
|
+
# #=>
|
298
|
+
# #[ULID(2021-05-02 06:57:19.954 UTC: 01F4NXW02JNB8H0J0TK48JD39X),
|
299
|
+
# # ULID(2021-05-02 07:06:07.458 UTC: 01F4NYC372GVP7NS0YAYQGT4VZ),
|
300
|
+
# # ULID(2021-05-01 06:16:35.791 UTC: 01F4K94P6F6P68K0H64WRDSFKW),
|
301
|
+
# # ULID(2021-04-27 22:17:37.844 UTC: 01F4APHGSMFJZQTGXKZBFFBPJP),
|
302
|
+
# # ULID(2021-04-28 20:17:55.357 UTC: 01F4D231MXQJXAR8G2JZHEJNH3),
|
303
|
+
# # ULID(2021-04-30 07:18:54.307 UTC: 01F4GTA2332AS2VPHC4FMKC7R5),
|
304
|
+
# # ULID(2021-05-02 12:26:03.480 UTC: 01F4PGNXARG554Y3HYVBDW4T9S),
|
305
|
+
# # ULID(2021-04-29 09:52:15.107 UTC: 01F4EGP483ZX2747FQPWQNPPMW),
|
306
|
+
# # ULID(2021-04-29 03:18:24.152 UTC: 01F4DT4Z4RA0QV8WFQGRAG63EH),
|
307
|
+
# # ULID(2021-05-02 13:27:16.394 UTC: 01F4PM605ABF5SDVMEHBH8JJ9R)]
|
308
|
+
# ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
|
309
|
+
# #=>
|
310
|
+
# # [ULID(2021-04-29 06:44:41.513 UTC: 01F4E5YPD9XQ3MYXWK8ZJKY8SW),
|
311
|
+
# # ULID(2021-05-01 00:35:06.629 UTC: 01F4JNKD85SVK1EAEYSJGF53A2),
|
312
|
+
# # ULID(2021-05-02 12:45:28.408 UTC: 01F4PHSEYRG9BWBEWMRW1XE6WW),
|
313
|
+
# # ULID(2021-05-01 03:06:09.130 UTC: 01F4JY7ZBABCBMX16XH2Q4JW4W),
|
314
|
+
# # ULID(2021-04-29 21:38:58.109 UTC: 01F4FS45DX4049JEQK4W6TER6G),
|
315
|
+
# # ULID(2021-04-29 17:14:14.116 UTC: 01F4F9ZDQ449BE8BBZFEHYQWG2),
|
316
|
+
# # ULID(2021-04-30 16:18:08.205 UTC: 01F4HS5DPD1HWDVJNJ6YKJXKSK),
|
317
|
+
# # ULID(2021-04-30 10:31:33.602 UTC: 01F4H5ATF2A1CSQF0XV5NKZ288),
|
318
|
+
# # ULID(2021-04-28 16:49:06.484 UTC: 01F4CP4PDM214Q6H3KJP7DYJRR),
|
319
|
+
# # ULID(2021-04-28 15:05:06.808 UTC: 01F4CG68ZRST94T056KRZ5K9S4)]
|
320
|
+
# ```
|
321
|
+
def self.sample: (?period: period) -> self
|
322
|
+
| (Integer number, ?period: period) -> Array[self]
|
323
|
+
def self.valid?: (untyped) -> bool
|
324
|
+
|
325
|
+
# Returns normalized string
|
326
|
+
#
|
327
|
+
# ```ruby
|
328
|
+
# ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
|
329
|
+
# ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
|
330
|
+
# ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
|
331
|
+
# ```
|
332
|
+
#
|
333
|
+
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
334
|
+
def self.normalize: (_ToStr string) -> String
|
335
|
+
|
336
|
+
# Returns `true` if it is normalized string
|
337
|
+
#
|
338
|
+
# ```ruby
|
339
|
+
# ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
|
340
|
+
# ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
|
341
|
+
# ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
|
342
|
+
# ```
|
343
|
+
#
|
344
|
+
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
345
|
+
def self.normalized?: (untyped) -> bool
|
346
|
+
|
347
|
+
# Returns parsed ULIDs from given String for rough operations.
|
348
|
+
#
|
349
|
+
# ```ruby
|
350
|
+
# json =<<'EOD'
|
351
|
+
# {
|
352
|
+
# "id": "01F4GNAV5ZR6FJQ5SFQC7WDSY3",
|
353
|
+
# "author": {
|
354
|
+
# "id": "01F4GNBXW1AM2KWW52PVT3ZY9X",
|
355
|
+
# "name": "kachick"
|
356
|
+
# },
|
357
|
+
# "title": "My awesome blog post",
|
358
|
+
# "comments": [
|
359
|
+
# {
|
360
|
+
# "id": "01F4GNCNC3CH0BCRZBPPDEKBKS",
|
361
|
+
# "commenter": {
|
362
|
+
# "id": "01F4GNBXW1AM2KWW52PVT3ZY9X",
|
363
|
+
# "name": "kachick"
|
364
|
+
# }
|
365
|
+
# },
|
366
|
+
# {
|
367
|
+
# "id": "01F4GNCXAMXQ1SGBH5XCR6ZH0M",
|
368
|
+
# "commenter": {
|
369
|
+
# "id": "01F4GND4RYYSKNAADHQ9BNXAWJ",
|
370
|
+
# "name": "pankona"
|
371
|
+
# }
|
372
|
+
# }
|
373
|
+
# ]
|
374
|
+
# }
|
375
|
+
# EOD
|
376
|
+
#
|
377
|
+
# ULID.scan(json).to_a
|
378
|
+
# #=>
|
379
|
+
# # [ULID(2021-04-30 05:51:57.119 UTC: 01F4GNAV5ZR6FJQ5SFQC7WDSY3),
|
380
|
+
# # ULID(2021-04-30 05:52:32.641 UTC: 01F4GNBXW1AM2KWW52PVT3ZY9X),
|
381
|
+
# # ULID(2021-04-30 05:52:56.707 UTC: 01F4GNCNC3CH0BCRZBPPDEKBKS),
|
382
|
+
# # ULID(2021-04-30 05:52:32.641 UTC: 01F4GNBXW1AM2KWW52PVT3ZY9X),
|
383
|
+
# # ULID(2021-04-30 05:53:04.852 UTC: 01F4GNCXAMXQ1SGBH5XCR6ZH0M),
|
384
|
+
# # ULID(2021-04-30 05:53:12.478 UTC: 01F4GND4RYYSKNAADHQ9BNXAWJ)]
|
385
|
+
# ```
|
386
|
+
def self.scan: (_ToStr string) -> Enumerator[self, singleton(ULID)]
|
387
|
+
| (_ToStr string) { (self ulid) -> void } -> singleton(ULID)
|
388
|
+
def self.from_milliseconds_and_entropy: (milliseconds: Integer, entropy: Integer) -> self
|
389
|
+
def self.try_convert: (_ToULID) -> ULID
|
390
|
+
| (untyped) -> nil
|
391
|
+
|
392
|
+
# ```ruby
|
393
|
+
# ulid = ULID.generate
|
394
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
395
|
+
# ulid.milliseconds #=> 1619544442826
|
396
|
+
# ```
|
90
397
|
attr_reader milliseconds: Integer
|
91
398
|
attr_reader entropy: Integer
|
92
|
-
|
399
|
+
|
400
|
+
# ```ruby
|
401
|
+
# ulid = ULID.generate
|
402
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
403
|
+
# ulid.to_s #=> "01F4A5Y1YAQCYAYCTC7GRMJ9AA"
|
404
|
+
# ```
|
93
405
|
def to_s: -> String
|
406
|
+
|
407
|
+
# ```ruby
|
408
|
+
# ulid = ULID.generate
|
409
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
410
|
+
# ulid.to_i #=> 1957909092946624190749577070267409738
|
411
|
+
# ```
|
94
412
|
def to_i: -> Integer
|
95
413
|
alias hash to_i
|
414
|
+
|
415
|
+
# Basically same as String based sort.
|
416
|
+
#
|
417
|
+
# ```ruby
|
418
|
+
# ulids = ULID.sample(10000); nil
|
419
|
+
# ulids.map(&:to_s).sort == ulids.sort.map(&:to_s)
|
420
|
+
# #=> true
|
421
|
+
# ```
|
422
|
+
#
|
423
|
+
# To be precise, this sorting unaffected with `case sensitive or not` and might handle [ulid/spec#57](https://github.com/ulid/spec/pull/57) in future. So preferable than `lexicographically sortable` in actual case.
|
424
|
+
#
|
96
425
|
def <=>: (ULID other) -> Integer
|
97
426
|
| (untyped other) -> nil
|
427
|
+
|
428
|
+
# ```ruby
|
429
|
+
# ulid = ULID.generate
|
430
|
+
# ulid.inspect #=> "ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)"
|
431
|
+
# ```
|
98
432
|
def inspect: -> String
|
433
|
+
|
434
|
+
# ```ruby
|
435
|
+
# ULID.parse('4NNB20D9C1ME2NGMTX51ERZJX0') == ULID.parse('4nnb20d9c1me2ngmtx51erzjx0')
|
436
|
+
# #=> true
|
437
|
+
# ```
|
99
438
|
def eql?: (untyped other) -> bool
|
100
439
|
alias == eql?
|
101
440
|
def ===: (untyped other) -> bool
|
441
|
+
|
442
|
+
# ```ruby
|
443
|
+
# ulid = ULID.generate
|
444
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
445
|
+
# ulid.to_time #=> 2021-04-27 17:27:22.826 UTC
|
446
|
+
# ```
|
102
447
|
def to_time: -> Time
|
448
|
+
|
449
|
+
# ```ruby
|
450
|
+
# ulid = ULID.generate
|
451
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
452
|
+
# ulid.timestamp #=> "01F4A5Y1YA"
|
453
|
+
# ```
|
103
454
|
def timestamp: -> String
|
455
|
+
|
456
|
+
# ```ruby
|
457
|
+
# ulid = ULID.generate
|
458
|
+
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
459
|
+
# ulid.randomness #=> "QCYAYCTC7GRMJ9AA"
|
460
|
+
# ```
|
104
461
|
def randomness: -> String
|
462
|
+
|
463
|
+
# Intentionally avoiding to use `Record type` ref: https://github.com/ruby/rbs/blob/4fb4c33b2325d1a73d79ff7aaeb49f21cec1e0e5/docs/syntax.md#record-type
|
464
|
+
# Because the returning values are not fixed.
|
105
465
|
def patterns: -> Hash[Symbol, Regexp | String]
|
106
466
|
def octets: -> octets
|
107
467
|
def timestamp_octets: -> timestamp_octets
|
108
468
|
def randomness_octets: -> randomness_octets
|
469
|
+
|
470
|
+
# ```ruby
|
471
|
+
# # Currently experimental feature, so needed to load the extension.
|
472
|
+
# require 'ulid/uuid'
|
473
|
+
#
|
474
|
+
# # Basically reversible
|
475
|
+
# ulid = ULID.from_uuidv4('0983d0a2-ff15-4d83-8f37-7dd945b5aa39')
|
476
|
+
# #=> ULID(2301-07-10 00:28:28.821 UTC: 09GF8A5ZRN9P1RYDVXV52VBAHS)
|
477
|
+
# ulid.to_uuidv4 #=> "0983d0a2-ff15-4d83-8f37-7dd945b5aa39"
|
478
|
+
# ```
|
479
|
+
#
|
480
|
+
# See also [Why this is experimental?](https://github.com/kachick/ruby-ulid/issues/76)
|
109
481
|
def to_uuidv4: -> String
|
110
|
-
|
111
|
-
|
482
|
+
|
483
|
+
# Returns next(successor) ULID.
|
484
|
+
# Especially `ULID#succ` makes it possible `Range[ULID]#each`.
|
485
|
+
#
|
486
|
+
# NOTE: But basically `Range[ULID]#each` should not be used, incrementing 128 bits IDs are not reasonable operation in most case
|
487
|
+
#
|
488
|
+
# ```ruby
|
489
|
+
# ULID.parse('01BX5ZZKBKZZZZZZZZZZZZZZZY').next.to_s #=> "01BX5ZZKBKZZZZZZZZZZZZZZZZ"
|
490
|
+
# ULID.parse('01BX5ZZKBKZZZZZZZZZZZZZZZZ').next.to_s #=> "01BX5ZZKBM0000000000000000"
|
491
|
+
# ULID.parse('7ZZZZZZZZZZZZZZZZZZZZZZZZZ').next #=> nil
|
492
|
+
# ```
|
493
|
+
#
|
494
|
+
# See also [ULID#pred](https://kachick.github.io/ruby-ulid/ULID.html#pred-instance_method)
|
495
|
+
def succ: -> ULID?
|
496
|
+
alias next succ
|
497
|
+
|
498
|
+
# Returns predecessor ULID.
|
499
|
+
#
|
500
|
+
# ```ruby
|
501
|
+
# ULID.parse('01BX5ZZKBK0000000000000001').pred.to_s #=> "01BX5ZZKBK0000000000000000"
|
502
|
+
# ULID.parse('01BX5ZZKBK0000000000000000').pred.to_s #=> "01BX5ZZKBJZZZZZZZZZZZZZZZZ"
|
503
|
+
# ULID.parse('00000000000000000000000000').pred #=> nil
|
504
|
+
# ```
|
505
|
+
#
|
506
|
+
# See also [ULID#succ](https://kachick.github.io/ruby-ulid/ULID.html#succ-instance_method)
|
112
507
|
def pred: -> ULID?
|
113
508
|
def freeze: -> self
|
114
509
|
|
510
|
+
# Returns `self`
|
511
|
+
def to_ulid: -> self
|
512
|
+
|
513
|
+
# Returns `self`. Not a new instance.
|
514
|
+
def dup: -> self
|
515
|
+
|
516
|
+
# Same API as [Object#clone](https://github.com/ruby/rbs/blob/4fb4c33b2325d1a73d79ff7aaeb49f21cec1e0e5/core/object.rbs#L79)
|
517
|
+
# But actually returns `self`. Not a new instance.
|
518
|
+
def clone: (?freeze: bool) -> self
|
519
|
+
|
115
520
|
private
|
521
|
+
|
522
|
+
# A pribate API. Should not be used in your code.
|
523
|
+
def self.new: (milliseconds: Integer, entropy: Integer, integer: Integer) -> self
|
524
|
+
|
525
|
+
# A pribate API. Should not be used in your code.
|
526
|
+
def self.reasonable_entropy: -> Integer
|
527
|
+
|
528
|
+
# A pribate API. Should not be used in your code.
|
116
529
|
def self.milliseconds_from_time: (Time time) -> Integer
|
530
|
+
|
531
|
+
# A pribate API. Should not be used in your code.
|
532
|
+
def self.safe_get_class_name: (untyped object) -> String
|
533
|
+
|
534
|
+
# A pribate API. Should not be used in your code.
|
535
|
+
def initialize: (milliseconds: Integer, entropy: Integer, integer: Integer) -> void
|
536
|
+
|
537
|
+
# A pribate API. Should not be used in your code.
|
117
538
|
def cache_all_instance_variables: -> void
|
118
539
|
end
|