ruby-ulid 0.0.19 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|