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.
@@ -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
- # @api private
8
- attr_accessor :latest_milliseconds, :latest_entropy
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
- @mutex = Thread::Mutex.new
12
- reset
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 [ArgumentError] if the given moment(milliseconds) is negative number
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
- milliseconds = ULID.milliseconds_from_moment(moment)
21
- raise ArgumentError, "milliseconds should not be negative: given: #{milliseconds}" if milliseconds.negative?
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
- @mutex.synchronize do
24
- if @latest_milliseconds < milliseconds
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
- @latest_entropy += 1
42
+ ULID.from_milliseconds_and_entropy(milliseconds: @prev.milliseconds, entropy: @prev.entropy.succ)
29
43
  end
30
- ULID.from_monotonic_generator(self)
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
- # @api private
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.sub(/\Aurn: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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class ULID
5
- VERSION = '0.0.19'
5
+ VERSION = '0.1.4'
6
6
  end
data/sig/ulid.rbs CHANGED
@@ -1,5 +1,4 @@
1
- # Classes
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
- attr_accessor latest_milliseconds: Integer
51
- attr_accessor latest_entropy: Integer
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
- def reset: -> void
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
- def self.generate: (?moment: moment, ?entropy: Integer) -> ULID
73
- def self.at: (Time time) -> ULID
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
- def self.reasonable_entropy: -> Integer
79
- def self.parse: (String string) -> ULID
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) -> ULID
82
- def self.min: (?moment: moment) -> ULID
83
- def self.max: (?moment: moment) -> ULID
84
- def self.sample: (?period: period) -> ULID
85
- | (Integer number, ?period: period) -> Array[ULID]
86
- def self.valid?: (untyped string) -> bool
87
- def self.scan: (String string) -> Enumerator[ULID, singleton(ULID)]
88
- | (String string) { (ULID ulid) -> void } -> singleton(ULID)
89
- def self.from_monotonic_generator: (MonotonicGenerator generator) -> ULID
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
- def initialize: (milliseconds: Integer, entropy: Integer, ?integer: Integer) -> void
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
- def next: -> ULID?
111
- alias succ next
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