ruby-ulid 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0aff39d0f8044f373d8dcdea149f26501e0118dfc0876f060b1b757a4d2a49e
4
- data.tar.gz: 02df0ea7a5fe5f8dabd1179988cfe4c2574debf3ad7200d11445eef932dd7443
3
+ metadata.gz: 01dca4f18f5bb3168b135847b6a1171d00a6ceb03b1d2ef68b6df212975cafc1
4
+ data.tar.gz: e1b0cb033ded88591d4817395507f517f46b7d3dd3d3a72021a216dcfef09d12
5
5
  SHA512:
6
- metadata.gz: ab036ed40e4f2740de9d37e44d2c6d4d233fa0071f95383accb2334c4d1f85b30b24eea902e0e29c34fefc8749b8caf5d1f9df6c52f93fe2e76c89aa0912d11e
7
- data.tar.gz: d8ac11f63e5b301ed8b1eacd0d1211fd4b3a0bd79ccae8fe87050833cf305a7345da1dc136b95ecccfcafc6110cf9a281afb0f15db1fe2e01984bf320f82b7e5
6
+ metadata.gz: c9c1a60687c05cfa99ce37f4e692938bff96dd15afa6b0adce40de5b897303b6e57301f069299c06d726bdd7a425e1ed581b7b60e15efc88d69abc417c577005
7
+ data.tar.gz: 71f333e7a6d6169f346b0e8fba65c9413fa24c32ce6799623e11b789544fb057fa0f67f83ed94a896cbac9df123ee4f9c9598735953217bd6fec332df659ee9f
File without changes
data/README.md CHANGED
@@ -10,7 +10,7 @@ Also providing [ruby/rbs](https://github.com/ruby/rbs) signature files.
10
10
 
11
11
  ![ULIDlogo](https://raw.githubusercontent.com/kachick/ruby-ulid/main/logo.png)
12
12
 
13
- ![Build Status](https://github.com/kachick/ruby-ulid/actions/workflows/test.yml/badge.svg?branch=main)
13
+ ![Build Status](https://github.com/kachick/ruby-ulid/actions/workflows/test_behaviors.yml/badge.svg?branch=main)
14
14
  [![Gem Version](https://badge.fury.io/rb/ruby-ulid.png)](http://badge.fury.io/rb/ruby-ulid)
15
15
 
16
16
  ## Universally Unique Lexicographically Sortable Identifier
@@ -28,7 +28,7 @@ Instead, herein is proposed ULID:
28
28
  - 1.21e+24 unique ULIDs per millisecond
29
29
  - Lexicographically sortable!
30
30
  - Canonically encoded as a 26 character string, as opposed to the 36 character UUID
31
- - Uses [Crockford's base32](https://www.crockford.com/base32.html) for better efficiency and readability (5 bits per character) # See also exists issues in [Note](#note)
31
+ - Uses [Crockford's base32](https://www.crockford.com/base32.html) for better efficiency and readability (5 bits per character)
32
32
  - Case insensitive
33
33
  - No special characters (URL safe)
34
34
  - Monotonic sort order (correctly detects and handles the same millisecond)
@@ -49,7 +49,7 @@ Should be installed!
49
49
  Add this line to your application/library's `Gemfile` is needed in basic use-case
50
50
 
51
51
  ```ruby
52
- gem 'ruby-ulid', '>= 0.1.0', '< 0.2.0'
52
+ gem 'ruby-ulid', '>= 0.1.5', '< 0.2.0'
53
53
  ```
54
54
 
55
55
  ### Generator and Parser
@@ -146,6 +146,8 @@ sample_ulids_by_the_time.take(5) #=>
146
146
  ulids.sort == ulids #=> true
147
147
  ```
148
148
 
149
+ Same generator does not generate duplicated ULIDs even in multi threads environment. It is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
150
+
149
151
  ### Filtering IDs with `Time`
150
152
 
151
153
  `ULID` can be element of the `Range`. If you generated the IDs in monotonic generator, ID based filtering is easy and reliable
@@ -168,7 +170,7 @@ exclude_end = ULID.range(time1...time2) #=> The end of `Range[ULID]` will be the
168
170
 
169
171
  # Below patterns are acceptable
170
172
  pinpointing = ULID.range(time1..time1) #=> This will match only for all IDs in `time1`
171
- 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)
173
+ # 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)
172
174
  until_the_end = ULID.range(ULID.min.to_time..time1) #=> This is same as above for Ruby 2.6
173
175
  until_the_ulid_limit = ULID.range(time1..) # This will match only for all IDs from `time1` to max value of the ULID limit
174
176
 
@@ -190,7 +192,7 @@ ULID.floor(time) #=> 2000-01-01 00:00:00.123 UTC
190
192
  For rough operations, `ULID.scan` might be useful.
191
193
 
192
194
  ```ruby
193
- json =<<'EOD'
195
+ json = <<'JSON'
194
196
  {
195
197
  "id": "01F4GNAV5ZR6FJQ5SFQC7WDSY3",
196
198
  "author": {
@@ -215,7 +217,7 @@ json =<<'EOD'
215
217
  }
216
218
  ]
217
219
  }
218
- EOD
220
+ JSON
219
221
 
220
222
  ULID.scan(json).to_a
221
223
  #=>
@@ -311,7 +313,7 @@ ulids.take(10)
311
313
  # ULID(2021-04-29 03:18:24.152 UTC: 01F4DT4Z4RA0QV8WFQGRAG63EH),
312
314
  # ULID(2021-05-02 13:27:16.394 UTC: 01F4PM605ABF5SDVMEHBH8JJ9R)]
313
315
  ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
314
- #=>
316
+ #=>
315
317
  # [ULID(2021-04-29 06:44:41.513 UTC: 01F4E5YPD9XQ3MYXWK8ZJKY8SW),
316
318
  # ULID(2021-05-01 00:35:06.629 UTC: 01F4JNKD85SVK1EAEYSJGF53A2),
317
319
  # ULID(2021-05-02 12:45:28.408 UTC: 01F4PHSEYRG9BWBEWMRW1XE6WW),
@@ -324,6 +326,34 @@ ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
324
326
  # ULID(2021-04-28 15:05:06.808 UTC: 01F4CG68ZRST94T056KRZ5K9S4)]
325
327
  ```
326
328
 
329
+ ### ULID specification ambiguity around orthographical variants of the format
330
+
331
+ I'm afraid so, we should consider [Current ULID spec](https://github.com/ulid/spec/tree/d0c7170df4517939e70129b4d6462cc162f2d5bf#universally-unique-lexicographically-sortable-identifier) has `orthographical variants of the format` possibilities.
332
+
333
+ >Uses Crockford's base32 for better efficiency and readability (5 bits per character)
334
+
335
+ The original `Crockford's base32` maps `I`, `L` to `1`, `O` to `0`.
336
+ And accepts freestyle inserting `Hyphens (-)`.
337
+ To consider this patterns or not is different in each implementations.
338
+
339
+ Current parser/validator/matcher aims to cover `subset of Crockford's base32`.
340
+ I have suggested it would be clarified in [ulid/spec#57](https://github.com/ulid/spec/pull/57).
341
+
342
+ >Case insensitive
343
+
344
+ I can understand it might be considered in actual use-case.
345
+ But it is a controversial point, discussing in [ulid/spec#3](https://github.com/ulid/spec/issues/3).
346
+
347
+ Be that as it may, this gem provides API for handling the nasty possibilities.
348
+
349
+ `ULID.normalize` and `ULID.normalized?`
350
+
351
+ ```ruby
352
+ ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
353
+ ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
354
+ ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
355
+ ```
356
+
327
357
  ### UUIDv4 converter for migration use-cases
328
358
 
329
359
  `ULID.from_uuidv4` and `ULID#to_uuidv4` is the converter.
@@ -333,7 +363,7 @@ The imported timestamp is meaningless. So ULID's benefit will lost.
333
363
  # Currently experimental feature, so needed to load the extension.
334
364
  require 'ulid/uuid'
335
365
 
336
- # Basically reversible
366
+ # Basically reversible
337
367
  ulid = ULID.from_uuidv4('0983d0a2-ff15-4d83-8f37-7dd945b5aa39') #=> ULID(2301-07-10 00:28:28.821 UTC: 09GF8A5ZRN9P1RYDVXV52VBAHS)
338
368
  ulid.to_uuidv4 #=> "0983d0a2-ff15-4d83-8f37-7dd945b5aa39"
339
369
 
@@ -401,6 +431,12 @@ NOTE: It is still having precision issue similar as `ulid gem` in the both gener
401
431
  1. [Fix to handle timestamp precision in parser](https://github.com/abachman/ulid-ruby/pull/5)
402
432
  1. [Fix to handle timestamp precision in generator](https://github.com/abachman/ulid-ruby/pull/4)
403
433
 
434
+ ### Compare performance with them
435
+
436
+ See [Benchmark](https://github.com/kachick/ruby-ulid/wiki/Benchmark).
437
+
438
+ The results are not something to be proud of.
439
+
404
440
  ## References
405
441
 
406
442
  - [Repository](https://github.com/kachick/ruby-ulid)
@@ -410,4 +446,3 @@ NOTE: It is still having precision issue similar as `ulid gem` in the both gener
410
446
  ## Note
411
447
 
412
448
  - Another choices for sortable and randomness IDs, [UUIDv6, UUIDv7, UUIDv8 might be the one. (But they are still in draft state)](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-01.html), I will track them in [ruby-ulid#37](https://github.com/kachick/ruby-ulid/issues/37)
413
- - Current parser/validator/matcher aims to cover `subset of Crockford's base32`. Suggesting it in [ulid/spec#57](https://github.com/ulid/spec/pull/57). Be that as it may, I might provide special handler or converter for the exception in [ruby-ulid#57](https://github.com/kachick/ruby-ulid/issues/57) and/or [ruby-ulid#78](https://github.com/kachick/ruby-ulid/issues/78)
data/lib/ulid.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # coding: us-ascii
2
2
  # frozen_string_literal: true
3
+
3
4
  # Copyright (C) 2021 Kenichi Kamiya
4
5
 
5
6
  require 'securerandom'
@@ -15,6 +16,7 @@ class ULID
15
16
  class Error < StandardError; end
16
17
  class OverflowError < Error; end
17
18
  class ParserError < Error; end
19
+ class UnexpectedError < Error; end
18
20
 
19
21
  # Excluded I, L, O, U, -.
20
22
  # This is the encoding patterns.
@@ -59,6 +61,7 @@ class ULID
59
61
  # @return [ULID]
60
62
  def self.at(time)
61
63
  raise ArgumentError, 'ULID.at takes only `Time` instance' unless Time === time
64
+
62
65
  from_milliseconds_and_entropy(milliseconds: milliseconds_from_time(time), entropy: reasonable_entropy)
63
66
  end
64
67
 
@@ -90,19 +93,21 @@ class ULID
90
93
  # * Do not take random generator for the arguments
91
94
  # * Raising error instead of truncating elements for the given number
92
95
  def self.sample(*args, period: nil)
93
- int_generator = if period
94
- ulid_range = range(period)
95
- min, max, exclude_end = ulid_range.begin.to_i, ulid_range.end.to_i, ulid_range.exclude_end?
96
+ int_generator = (
97
+ if period
98
+ ulid_range = range(period)
99
+ min, max, exclude_end = ulid_range.begin.to_i, ulid_range.end.to_i, ulid_range.exclude_end?
96
100
 
97
- possibilities = (max - min) + (exclude_end ? 0 : 1)
98
- raise ArgumentError, "given range `#{ulid_range.inspect}` does not have possibilities" unless possibilities.positive?
101
+ possibilities = (max - min) + (exclude_end ? 0 : 1)
102
+ raise ArgumentError, "given range `#{ulid_range.inspect}` does not have possibilities" unless possibilities.positive?
99
103
 
100
- -> {
101
- SecureRandom.random_number(possibilities) + min
102
- }
103
- else
104
- RANDOM_INTEGER_GENERATOR
105
- end
104
+ -> {
105
+ SecureRandom.random_number(possibilities) + min
106
+ }
107
+ else
108
+ RANDOM_INTEGER_GENERATOR
109
+ end
110
+ )
106
111
 
107
112
  case args.size
108
113
  when 0
@@ -133,6 +138,7 @@ class ULID
133
138
  string = String.try_convert(string)
134
139
  raise ArgumentError, 'ULID.scan takes only strings' unless string
135
140
  return to_enum(__callee__, string) unless block_given?
141
+
136
142
  string.scan(SCANNING_PATTERN) do |matched|
137
143
  yield parse(matched)
138
144
  end
@@ -155,7 +161,7 @@ class ULID
155
161
  milliseconds = n32encoded_timestamp.to_i(32)
156
162
  entropy = n32encoded_randomness.to_i(32)
157
163
 
158
- new milliseconds: milliseconds, entropy: entropy, integer: integer
164
+ new(milliseconds: milliseconds, entropy: entropy, integer: integer)
159
165
  end
160
166
 
161
167
  # @param [Range<Time>, Range<nil>, Range[ULID]] period
@@ -163,6 +169,7 @@ class ULID
163
169
  # @raise [ArgumentError] if the given period is not a `Range[Time]`, `Range[nil]` or `Range[ULID]`
164
170
  def self.range(period)
165
171
  raise ArgumentError, 'ULID.range takes only `Range[Time]`, `Range[nil]` or `Range[ULID]`' unless Range === period
172
+
166
173
  begin_element, end_element, exclude_end = period.begin, period.end, period.exclude_end?
167
174
  return period if self === begin_element && self === end_element
168
175
 
@@ -179,11 +186,7 @@ class ULID
179
186
 
180
187
  case end_element
181
188
  when Time
182
- if exclude_end
183
- end_ulid = min(end_element)
184
- else
185
- end_ulid = max(end_element)
186
- end
189
+ end_ulid = exclude_end ? min(end_element) : max(end_element)
187
190
  when nil
188
191
  # The end should be max and include end, because nil end means to cover endless ULIDs until the limit
189
192
  end_ulid = MAX
@@ -239,9 +242,8 @@ class ULID
239
242
  end
240
243
  end
241
244
 
242
- # @api private
243
245
  # @return [Integer]
244
- def self.reasonable_entropy
246
+ private_class_method def self.reasonable_entropy
245
247
  SecureRandom.random_number(MAX_ENTROPY)
246
248
  end
247
249
 
@@ -260,12 +262,65 @@ class ULID
260
262
  end
261
263
 
262
264
  # @param [String, #to_str] string
263
- # @return [Boolean]
264
- def self.valid?(string)
265
+ # @return [String]
266
+ # @raise [ParserError] if the given format is not correct for ULID specs, even if ignored `orthographical variants of the format`
267
+ def self.normalize(string)
265
268
  string = String.try_convert(string)
269
+ raise ArgumentError, 'ULID.normalize takes only strings' unless string
270
+
271
+ normalized_in_crockford = CrockfordBase32.normalize(string)
272
+ # Ensure the ULID correctness, because CrockfordBase32 does not always mean to satisfy ULID format
273
+ parse(normalized_in_crockford).to_s
274
+ end
275
+
276
+ # @return [Boolean]
277
+ def self.normalized?(object)
278
+ normalized = normalize(object)
279
+ rescue Exception
280
+ false
281
+ else
282
+ normalized == object
283
+ end
284
+
285
+ # @return [Boolean]
286
+ def self.valid?(object)
287
+ string = String.try_convert(object)
266
288
  string ? STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET.match?(string) : false
267
289
  end
268
290
 
291
+ # @param [ULID, #to_ulid] object
292
+ # @return [ULID, nil]
293
+ # @raise [TypeError] if `object.to_ulid` did not return ULID instance
294
+ def self.try_convert(object)
295
+ begin
296
+ converted = object.to_ulid
297
+ rescue NoMethodError
298
+ nil
299
+ else
300
+ if ULID === converted
301
+ converted
302
+ else
303
+ object_class_name = safe_get_class_name(object)
304
+ converted_class_name = safe_get_class_name(converted)
305
+ raise TypeError, "can't convert #{object_class_name} to ULID (#{object_class_name}#to_ulid gives #{converted_class_name})"
306
+ end
307
+ end
308
+ end
309
+
310
+ # @param [BasicObject] object
311
+ # @return [String]
312
+ private_class_method def self.safe_get_class_name(object)
313
+ fallback = 'UnknownObject'
314
+
315
+ begin
316
+ name = String.try_convert(object.class.name)
317
+ rescue Exception
318
+ fallback
319
+ else
320
+ name || fallback
321
+ end
322
+ end
323
+
269
324
  # @api private
270
325
  # @param [Integer] milliseconds
271
326
  # @param [Integer] entropy
@@ -282,7 +337,7 @@ class ULID
282
337
  n32encoded_randomness = entropy.to_s(32).rjust(RANDOMNESS_ENCODED_LENGTH, '0')
283
338
  integer = (n32encoded_timestamp + n32encoded_randomness).to_i(32)
284
339
 
285
- new milliseconds: milliseconds, entropy: entropy, integer: integer
340
+ new(milliseconds: milliseconds, entropy: entropy, integer: integer)
286
341
  end
287
342
 
288
343
  attr_reader :milliseconds, :entropy
@@ -353,7 +408,7 @@ class ULID
353
408
  def octets
354
409
  digits = @integer.digits(256)
355
410
  (OCTETS_LENGTH - digits.size).times do
356
- digits.push 0
411
+ digits.push(0)
357
412
  end
358
413
  digits.reverse!
359
414
  end
@@ -424,6 +479,25 @@ class ULID
424
479
  super
425
480
  end
426
481
 
482
+ # @api private
483
+ # @return [Integer]
484
+ def marshal_dump
485
+ @integer
486
+ end
487
+
488
+ # @api private
489
+ # @param [Integer] integer
490
+ # @return [void]
491
+ def marshal_load(integer)
492
+ unmarshaled = ULID.from_integer(integer)
493
+ initialize(integer: unmarshaled.to_i, milliseconds: unmarshaled.milliseconds, entropy: unmarshaled.entropy)
494
+ end
495
+
496
+ # @return [self]
497
+ def to_ulid
498
+ self
499
+ end
500
+
427
501
  # @return [self]
428
502
  def dup
429
503
  self
@@ -1,9 +1,12 @@
1
1
  # coding: us-ascii
2
2
  # frozen_string_literal: true
3
+
3
4
  # Copyright (C) 2021 Kenichi Kamiya
4
5
 
5
6
  class ULID
6
- # Currently supporting only for `subset` for actual use-case`
7
+ # @see https://www.crockford.com/base32.html
8
+ #
9
+ # This module supporting only `subset of original crockford for actual use-case` in ULID context.
7
10
  # Original decoding spec allows other characters.
8
11
  # But I think ULID should allow `subset` of Crockford's Base32.
9
12
  # See below
@@ -46,11 +49,24 @@ class ULID
46
49
  end
47
50
  end.freeze
48
51
  raise SetupError, 'obvious bug exists in the mapping algorithm' unless N32_CHAR_BY_CROCKFORD_BASE32_CHAR.keys == crockford_base32_mappings.keys
52
+
49
53
  CROCKFORD_BASE32_CHAR_PATTERN = /[#{N32_CHAR_BY_CROCKFORD_BASE32_CHAR.keys.join}]/.freeze
50
54
 
51
55
  CROCKFORD_BASE32_CHAR_BY_N32_CHAR = N32_CHAR_BY_CROCKFORD_BASE32_CHAR.invert.freeze
52
56
  N32_CHAR_PATTERN = /[#{CROCKFORD_BASE32_CHAR_BY_N32_CHAR.keys.join}]/.freeze
53
57
 
58
+ STANDARD_BY_VARIANT = {
59
+ 'L' => '1',
60
+ 'l' => '1',
61
+ 'I' => '1',
62
+ 'i' => '1',
63
+ 'O' => '0',
64
+ 'o' => '0',
65
+ '-' => ''
66
+ }.freeze
67
+ VARIANT_PATTERN = /[#{STANDARD_BY_VARIANT.keys.join}]/.freeze
68
+
69
+ # @api private
54
70
  # @param [String] string
55
71
  # @return [Integer]
56
72
  def self.decode(string)
@@ -58,11 +74,19 @@ class ULID
58
74
  n32encoded.to_i(32)
59
75
  end
60
76
 
77
+ # @api private
61
78
  # @param [Integer] integer
62
79
  # @return [String]
63
80
  def self.encode(integer)
64
81
  n32encoded = integer.to_s(32)
65
82
  n32encoded.upcase.gsub(N32_CHAR_PATTERN, CROCKFORD_BASE32_CHAR_BY_N32_CHAR).rjust(ENCODED_LENGTH, '0')
66
83
  end
84
+
85
+ # @api private
86
+ # @param [String] string
87
+ # @return [String]
88
+ def self.normalize(string)
89
+ string.gsub(VARIANT_PATTERN, STANDARD_BY_VARIANT)
90
+ end
67
91
  end
68
92
  end
@@ -1,43 +1,69 @@
1
1
  # coding: us-ascii
2
2
  # frozen_string_literal: true
3
+
3
4
  # Copyright (C) 2021 Kenichi Kamiya
4
5
 
5
6
  class ULID
6
7
  class MonotonicGenerator
7
- # @api private
8
- attr_accessor :latest_milliseconds, :latest_entropy
8
+ include MonitorMixin
9
+
10
+ # @return [ULID, nil]
11
+ attr_reader :prev
12
+
13
+ undef_method :instance_variable_set
9
14
 
10
15
  def initialize
11
- @mutex = Thread::Mutex.new
12
- reset
16
+ super()
17
+ @prev = nil
13
18
  end
14
19
 
20
+ # @return [String]
21
+ def inspect
22
+ "ULID::MonotonicGenerator(prev: #{@prev.inspect})"
23
+ end
24
+ alias_method :to_s, :inspect
25
+
15
26
  # @param [Time, Integer] moment
16
27
  # @return [ULID]
17
28
  # @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
29
+ # @raise [UnexpectedError] if the generated ULID is an invalid value in monotonicity spec.
30
+ # Basically will not happen. Just means this feature prefers error rather than invalid value.
19
31
  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?
22
-
23
- @mutex.synchronize do
24
- if @latest_milliseconds < milliseconds
25
- @latest_milliseconds = milliseconds
26
- @latest_entropy = ULID.reasonable_entropy
27
- else
28
- @latest_entropy += 1
32
+ synchronize do
33
+ unless @prev
34
+ @prev = ULID.generate(moment: moment)
35
+ return @prev
29
36
  end
30
- ULID.from_milliseconds_and_entropy(milliseconds: @latest_milliseconds, entropy: @latest_entropy)
37
+
38
+ milliseconds = ULID.milliseconds_from_moment(moment)
39
+
40
+ ulid = (
41
+ if @prev.milliseconds < milliseconds
42
+ ULID.generate(moment: milliseconds)
43
+ else
44
+ ULID.from_milliseconds_and_entropy(milliseconds: @prev.milliseconds, entropy: @prev.entropy.succ)
45
+ end
46
+ )
47
+
48
+ unless ulid > @prev
49
+ base_message = "monotonicity broken from unexpected reasons # generated: #{ulid.inspect}, prev: #{@prev.inspect}"
50
+ additional_information = (
51
+ if Thread.list == [Thread.main]
52
+ '# NOTE: looks single thread only exist'
53
+ else
54
+ '# NOTE: ran on multi threads, so this might from concurrency issue'
55
+ end
56
+ )
57
+
58
+ raise UnexpectedError, base_message + additional_information
59
+ end
60
+
61
+ @prev = ulid
62
+ ulid
31
63
  end
32
64
  end
33
65
 
34
- # @api private
35
- # @return [void]
36
- def reset
37
- @latest_milliseconds = 0
38
- @latest_entropy = ULID.reasonable_entropy
39
- nil
40
- end
66
+ undef_method :freeze
41
67
 
42
68
  # @raise [TypeError] always raises exception and does not freeze self
43
69
  # @return [void]