ruby-ulid 0.0.19 → 0.1.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 +4 -4
- data/README.md +7 -5
- data/lib/ulid.rb +56 -47
- data/lib/ulid/monotonic_generator.rb +1 -1
- data/lib/ulid/version.rb +1 -1
- data/sig/ulid.rbs +16 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0aff39d0f8044f373d8dcdea149f26501e0118dfc0876f060b1b757a4d2a49e
|
4
|
+
data.tar.gz: 02df0ea7a5fe5f8dabd1179988cfe4c2574debf3ad7200d11445eef932dd7443
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab036ed40e4f2740de9d37e44d2c6d4d233fa0071f95383accb2334c4d1f85b30b24eea902e0e29c34fefc8749b8caf5d1f9df6c52f93fe2e76c89aa0912d11e
|
7
|
+
data.tar.gz: d8ac11f63e5b301ed8b1eacd0d1211fd4b3a0bd79ccae8fe87050833cf305a7345da1dc136b95ecccfcafc6110cf9a281afb0f15db1fe2e01984bf320f82b7e5
|
data/README.md
CHANGED
@@ -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.0.
|
52
|
+
gem 'ruby-ulid', '>= 0.1.0', '< 0.2.0'
|
53
53
|
```
|
54
54
|
|
55
55
|
### Generator and Parser
|
@@ -243,13 +243,15 @@ ULID.parse('01F4GNBXW1AM2KWW52PVT3ZY9X').patterns
|
|
243
243
|
|
244
244
|
`ULID.min` and `ULID.max` return termination values for ULID spec.
|
245
245
|
|
246
|
+
It can take `Time` instance as an optional argument. Then returns min/max ID that has limit of randomness part in the time.
|
247
|
+
|
246
248
|
```ruby
|
247
249
|
ULID.min #=> ULID(1970-01-01 00:00:00.000 UTC: 00000000000000000000000000)
|
248
250
|
ULID.max #=> ULID(10889-08-02 05:31:50.655 UTC: 7ZZZZZZZZZZZZZZZZZZZZZZZZZ)
|
249
251
|
|
250
252
|
time = Time.at(946684800, Rational('123456.789')).utc #=> 2000-01-01 00:00:00.123456789 UTC
|
251
|
-
ULID.min(
|
252
|
-
ULID.max(
|
253
|
+
ULID.min(time) #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3V0000000000000000)
|
254
|
+
ULID.max(time) #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3VZZZZZZZZZZZZZZZZ)
|
253
255
|
```
|
254
256
|
|
255
257
|
`ULID#next` and `ULID#succ` returns next(successor) ULID.
|
@@ -388,9 +390,9 @@ Major methods can be replaced as below.
|
|
388
390
|
-ULID.time(string)
|
389
391
|
+ULID.parse(string).to_time
|
390
392
|
-ULID.min_ulid_at(time)
|
391
|
-
+ULID.min(
|
393
|
+
+ULID.min(time).to_s
|
392
394
|
-ULID.max_ulid_at(time)
|
393
|
-
+ULID.max(
|
395
|
+
+ULID.max(time).to_s
|
394
396
|
```
|
395
397
|
|
396
398
|
NOTE: It is still having precision issue similar as `ulid gem` in the both generator and parser. I sent PRs.
|
data/lib/ulid.rb
CHANGED
@@ -51,7 +51,7 @@ class ULID
|
|
51
51
|
# @param [Integer] entropy
|
52
52
|
# @return [ULID]
|
53
53
|
def self.generate(moment: current_milliseconds, entropy: reasonable_entropy)
|
54
|
-
|
54
|
+
from_milliseconds_and_entropy(milliseconds: milliseconds_from_moment(moment), entropy: entropy)
|
55
55
|
end
|
56
56
|
|
57
57
|
# Short hand of `ULID.generate(moment: time)`
|
@@ -59,18 +59,18 @@ class ULID
|
|
59
59
|
# @return [ULID]
|
60
60
|
def self.at(time)
|
61
61
|
raise ArgumentError, 'ULID.at takes only `Time` instance' unless Time === time
|
62
|
-
|
62
|
+
from_milliseconds_and_entropy(milliseconds: milliseconds_from_time(time), entropy: reasonable_entropy)
|
63
63
|
end
|
64
64
|
|
65
|
-
# @param [
|
65
|
+
# @param [Time, Integer] moment
|
66
66
|
# @return [ULID]
|
67
|
-
def self.min(moment
|
67
|
+
def self.min(moment=0)
|
68
68
|
0.equal?(moment) ? MIN : generate(moment: moment, entropy: 0)
|
69
69
|
end
|
70
70
|
|
71
|
-
# @param [
|
71
|
+
# @param [Time, Integer] moment
|
72
72
|
# @return [ULID]
|
73
|
-
def self.max(moment
|
73
|
+
def self.max(moment=MAX_MILLISECONDS)
|
74
74
|
MAX_MILLISECONDS.equal?(moment) ? MAX : generate(moment: moment, entropy: MAX_ENTROPY)
|
75
75
|
end
|
76
76
|
|
@@ -112,11 +112,11 @@ class ULID
|
|
112
112
|
raise ArgumentError, 'accepts no argument or integer only' unless Integer === number
|
113
113
|
|
114
114
|
if number > MAX_INTEGER || number.negative?
|
115
|
-
raise ArgumentError, "given number
|
115
|
+
raise ArgumentError, "given number `#{number}` is larger than ULID limit `#{MAX_INTEGER}` or negative"
|
116
116
|
end
|
117
117
|
|
118
118
|
if period && (number > possibilities)
|
119
|
-
raise ArgumentError, "given number
|
119
|
+
raise ArgumentError, "given number `#{number}` is larger than given possibilities `#{possibilities}`"
|
120
120
|
end
|
121
121
|
|
122
122
|
Array.new(number) { from_integer(int_generator.call) }
|
@@ -139,12 +139,12 @@ class ULID
|
|
139
139
|
self
|
140
140
|
end
|
141
141
|
|
142
|
-
# @param [Integer
|
142
|
+
# @param [Integer] integer
|
143
143
|
# @return [ULID]
|
144
144
|
# @raise [OverflowError] if the given integer is larger than the ULID limit
|
145
145
|
# @raise [ArgumentError] if the given integer is negative number
|
146
146
|
def self.from_integer(integer)
|
147
|
-
|
147
|
+
raise ArgumentError, 'ULID.from_integer takes only `Integer`' unless Integer === integer
|
148
148
|
raise OverflowError, "integer overflow: given #{integer}, max: #{MAX_INTEGER}" unless integer <= MAX_INTEGER
|
149
149
|
raise ArgumentError, "integer should not be negative: given: #{integer}" if integer.negative?
|
150
150
|
|
@@ -160,29 +160,29 @@ class ULID
|
|
160
160
|
|
161
161
|
# @param [Range<Time>, Range<nil>, Range[ULID]] period
|
162
162
|
# @return [Range<ULID>]
|
163
|
-
# @raise [ArgumentError] if the given period is not a `Range[Time]` or `Range[
|
163
|
+
# @raise [ArgumentError] if the given period is not a `Range[Time]`, `Range[nil]` or `Range[ULID]`
|
164
164
|
def self.range(period)
|
165
|
-
raise ArgumentError, 'ULID.range takes only `Range[Time]` or `Range[
|
165
|
+
raise ArgumentError, 'ULID.range takes only `Range[Time]`, `Range[nil]` or `Range[ULID]`' unless Range === period
|
166
166
|
begin_element, end_element, exclude_end = period.begin, period.end, period.exclude_end?
|
167
167
|
return period if self === begin_element && self === end_element
|
168
168
|
|
169
169
|
case begin_element
|
170
170
|
when Time
|
171
|
-
begin_ulid = min(
|
171
|
+
begin_ulid = min(begin_element)
|
172
172
|
when nil
|
173
173
|
begin_ulid = MIN
|
174
174
|
when self
|
175
175
|
begin_ulid = begin_element
|
176
176
|
else
|
177
|
-
raise ArgumentError, "ULID.range takes only `Range[Time]` or `Range[
|
177
|
+
raise ArgumentError, "ULID.range takes only `Range[Time]`, `Range[nil]` or `Range[ULID]`, given: #{period.inspect}"
|
178
178
|
end
|
179
179
|
|
180
180
|
case end_element
|
181
181
|
when Time
|
182
182
|
if exclude_end
|
183
|
-
end_ulid = min(
|
183
|
+
end_ulid = min(end_element)
|
184
184
|
else
|
185
|
-
end_ulid = max(
|
185
|
+
end_ulid = max(end_element)
|
186
186
|
end
|
187
187
|
when nil
|
188
188
|
# The end should be max and include end, because nil end means to cover endless ULIDs until the limit
|
@@ -191,7 +191,7 @@ class ULID
|
|
191
191
|
when self
|
192
192
|
end_ulid = end_element
|
193
193
|
else
|
194
|
-
raise ArgumentError, "ULID.range takes only `Range[Time]` or `Range[
|
194
|
+
raise ArgumentError, "ULID.range takes only `Range[Time]`, `Range[nil]` or `Range[ULID]`, given: #{period.inspect}"
|
195
195
|
end
|
196
196
|
|
197
197
|
begin_ulid.freeze
|
@@ -218,6 +218,7 @@ class ULID
|
|
218
218
|
milliseconds_from_time(Time.now)
|
219
219
|
end
|
220
220
|
|
221
|
+
# @api private
|
221
222
|
# @param [Time] time
|
222
223
|
# @return [Integer]
|
223
224
|
private_class_method def self.milliseconds_from_time(time)
|
@@ -266,11 +267,22 @@ class ULID
|
|
266
267
|
end
|
267
268
|
|
268
269
|
# @api private
|
269
|
-
# @param [
|
270
|
+
# @param [Integer] milliseconds
|
271
|
+
# @param [Integer] entropy
|
270
272
|
# @return [ULID]
|
271
|
-
|
272
|
-
|
273
|
-
|
273
|
+
# @raise [OverflowError] if the given value is larger than the ULID limit
|
274
|
+
# @raise [ArgumentError] if the given milliseconds and/or entropy is negative number
|
275
|
+
def self.from_milliseconds_and_entropy(milliseconds:, entropy:)
|
276
|
+
raise ArgumentError, 'milliseconds and entropy should be an `Integer`' unless Integer === milliseconds && Integer === entropy
|
277
|
+
raise OverflowError, "timestamp overflow: given #{milliseconds}, max: #{MAX_MILLISECONDS}" unless milliseconds <= MAX_MILLISECONDS
|
278
|
+
raise OverflowError, "entropy overflow: given #{entropy}, max: #{MAX_ENTROPY}" unless entropy <= MAX_ENTROPY
|
279
|
+
raise ArgumentError, 'milliseconds and entropy should not be negative' if milliseconds.negative? || entropy.negative?
|
280
|
+
|
281
|
+
n32encoded_timestamp = milliseconds.to_s(32).rjust(TIMESTAMP_ENCODED_LENGTH, '0')
|
282
|
+
n32encoded_randomness = entropy.to_s(32).rjust(RANDOMNESS_ENCODED_LENGTH, '0')
|
283
|
+
integer = (n32encoded_timestamp + n32encoded_randomness).to_i(32)
|
284
|
+
|
285
|
+
new milliseconds: milliseconds, entropy: entropy, integer: integer
|
274
286
|
end
|
275
287
|
|
276
288
|
attr_reader :milliseconds, :entropy
|
@@ -280,42 +292,27 @@ class ULID
|
|
280
292
|
# @param [Integer] entropy
|
281
293
|
# @param [Integer] integer
|
282
294
|
# @return [void]
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
if integer
|
287
|
-
@integer = integer
|
288
|
-
else
|
289
|
-
milliseconds = milliseconds.to_int
|
290
|
-
entropy = entropy.to_int
|
291
|
-
|
292
|
-
raise OverflowError, "timestamp overflow: given #{milliseconds}, max: #{MAX_MILLISECONDS}" unless milliseconds <= MAX_MILLISECONDS
|
293
|
-
raise OverflowError, "entropy overflow: given #{entropy}, max: #{MAX_ENTROPY}" unless entropy <= MAX_ENTROPY
|
294
|
-
raise ArgumentError, 'milliseconds and entropy should not be negative' if milliseconds.negative? || entropy.negative?
|
295
|
-
end
|
296
|
-
|
295
|
+
def initialize(milliseconds:, entropy:, integer:)
|
296
|
+
# All arguments check should be done with each constructors, not here
|
297
|
+
@integer = integer
|
297
298
|
@milliseconds = milliseconds
|
298
299
|
@entropy = entropy
|
299
300
|
end
|
300
301
|
|
301
302
|
# @return [String]
|
302
303
|
def to_s
|
303
|
-
@string ||= CrockfordBase32.encode(
|
304
|
+
@string ||= CrockfordBase32.encode(@integer).freeze
|
304
305
|
end
|
305
306
|
|
306
307
|
# @return [Integer]
|
307
308
|
def to_i
|
308
|
-
@integer
|
309
|
-
n32encoded_timestamp = milliseconds.to_s(32).rjust(TIMESTAMP_ENCODED_LENGTH, '0')
|
310
|
-
n32encoded_randomness = entropy.to_s(32).rjust(RANDOMNESS_ENCODED_LENGTH, '0')
|
311
|
-
(n32encoded_timestamp + n32encoded_randomness).to_i(32)
|
312
|
-
end
|
309
|
+
@integer
|
313
310
|
end
|
314
311
|
alias_method :hash, :to_i
|
315
312
|
|
316
313
|
# @return [Integer, nil]
|
317
314
|
def <=>(other)
|
318
|
-
(ULID === other) ? (
|
315
|
+
(ULID === other) ? (@integer <=> other.to_i) : nil
|
319
316
|
end
|
320
317
|
|
321
318
|
# @return [String]
|
@@ -325,7 +322,7 @@ class ULID
|
|
325
322
|
|
326
323
|
# @return [Boolean]
|
327
324
|
def eql?(other)
|
328
|
-
equal?(other) || (ULID === other &&
|
325
|
+
equal?(other) || (ULID === other && @integer == other.to_i)
|
329
326
|
end
|
330
327
|
alias_method :==, :eql?
|
331
328
|
|
@@ -333,7 +330,7 @@ class ULID
|
|
333
330
|
def ===(other)
|
334
331
|
case other
|
335
332
|
when ULID
|
336
|
-
|
333
|
+
@integer == other.to_i
|
337
334
|
when String
|
338
335
|
to_s == other.upcase
|
339
336
|
else
|
@@ -354,7 +351,7 @@ class ULID
|
|
354
351
|
|
355
352
|
# @return [Array(Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer)]
|
356
353
|
def octets
|
357
|
-
digits =
|
354
|
+
digits = @integer.digits(256)
|
358
355
|
(OCTETS_LENGTH - digits.size).times do
|
359
356
|
digits.push 0
|
360
357
|
end
|
@@ -393,7 +390,7 @@ class ULID
|
|
393
390
|
|
394
391
|
# @return [ULID, nil] when called on ULID as `7ZZZZZZZZZZZZZZZZZZZZZZZZZ`, returns `nil` instead of ULID
|
395
392
|
def succ
|
396
|
-
succ_int =
|
393
|
+
succ_int = @integer.succ
|
397
394
|
if succ_int >= MAX_INTEGER
|
398
395
|
if succ_int == MAX_INTEGER
|
399
396
|
MAX
|
@@ -408,7 +405,7 @@ class ULID
|
|
408
405
|
|
409
406
|
# @return [ULID, nil] when called on ULID as `00000000000000000000000000`, returns `nil` instead of ULID
|
410
407
|
def pred
|
411
|
-
pred_int =
|
408
|
+
pred_int = @integer.pred
|
412
409
|
if pred_int <= 0
|
413
410
|
if pred_int == 0
|
414
411
|
MIN
|
@@ -427,6 +424,18 @@ class ULID
|
|
427
424
|
super
|
428
425
|
end
|
429
426
|
|
427
|
+
# @return [self]
|
428
|
+
def dup
|
429
|
+
self
|
430
|
+
end
|
431
|
+
|
432
|
+
# @return [self]
|
433
|
+
def clone(freeze: true)
|
434
|
+
self
|
435
|
+
end
|
436
|
+
|
437
|
+
undef_method :instance_variable_set
|
438
|
+
|
430
439
|
private
|
431
440
|
|
432
441
|
# @return [void]
|
data/lib/ulid/version.rb
CHANGED
data/sig/ulid.rbs
CHANGED
@@ -63,33 +63,33 @@ class ULID
|
|
63
63
|
@milliseconds: Integer
|
64
64
|
@entropy: Integer
|
65
65
|
@string: String?
|
66
|
-
@integer: Integer
|
66
|
+
@integer: Integer
|
67
67
|
@timestamp: String?
|
68
68
|
@randomness: String?
|
69
69
|
@inspect: String?
|
70
70
|
@time: Time?
|
71
71
|
|
72
|
-
def self.generate: (?moment: moment, ?entropy: Integer) ->
|
73
|
-
def self.at: (Time time) ->
|
72
|
+
def self.generate: (?moment: moment, ?entropy: Integer) -> self
|
73
|
+
def self.at: (Time time) -> self
|
74
74
|
def self.current_milliseconds: -> Integer
|
75
75
|
def self.milliseconds_from_moment: (moment moment) -> Integer
|
76
76
|
def self.range: (period period) -> Range[ULID]
|
77
77
|
def self.floor: (Time time) -> Time
|
78
78
|
def self.reasonable_entropy: -> Integer
|
79
|
-
def self.parse: (String string) ->
|
79
|
+
def self.parse: (String string) -> self
|
80
80
|
def self.from_uuidv4: (String uuid) -> ULID
|
81
|
-
def self.from_integer: (Integer integer) ->
|
82
|
-
def self.min: (?moment
|
83
|
-
def self.max: (?moment
|
84
|
-
def self.sample: (?period: period) ->
|
85
|
-
| (Integer number, ?period: period) -> Array[
|
81
|
+
def self.from_integer: (Integer integer) -> self
|
82
|
+
def self.min: (?moment moment) -> ULID
|
83
|
+
def self.max: (?moment moment) -> ULID
|
84
|
+
def self.sample: (?period: period) -> self
|
85
|
+
| (Integer number, ?period: period) -> Array[self]
|
86
86
|
def self.valid?: (untyped string) -> bool
|
87
|
-
def self.scan: (String string) -> Enumerator[
|
88
|
-
| (String string) { (
|
89
|
-
def self.
|
87
|
+
def self.scan: (String string) -> Enumerator[self, singleton(ULID)]
|
88
|
+
| (String string) { (self ulid) -> void } -> singleton(ULID)
|
89
|
+
def self.from_milliseconds_and_entropy: (milliseconds: Integer, entropy: Integer) -> self
|
90
90
|
attr_reader milliseconds: Integer
|
91
91
|
attr_reader entropy: Integer
|
92
|
-
def initialize: (milliseconds: Integer, entropy: Integer,
|
92
|
+
def initialize: (milliseconds: Integer, entropy: Integer, integer: Integer) -> void
|
93
93
|
def to_s: -> String
|
94
94
|
def to_i: -> Integer
|
95
95
|
alias hash to_i
|
@@ -111,6 +111,9 @@ class ULID
|
|
111
111
|
alias succ next
|
112
112
|
def pred: -> ULID?
|
113
113
|
def freeze: -> self
|
114
|
+
def dup: -> self
|
115
|
+
# Same as https://github.com/ruby/rbs/blob/4fb4c33b2325d1a73d79ff7aaeb49f21cec1e0e5/core/object.rbs#L79
|
116
|
+
def clone: (?freeze: bool) -> self
|
114
117
|
|
115
118
|
private
|
116
119
|
def self.milliseconds_from_time: (Time time) -> Integer
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ulid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenichi Kamiya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|