ruby-ulid 0.3.0 → 0.6.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 +98 -116
- data/lib/ruby-ulid.rb +1 -0
- data/lib/ulid/crockford_base32.rb +53 -46
- data/lib/ulid/errors.rb +10 -0
- data/lib/ulid/monotonic_generator.rb +9 -2
- data/lib/ulid/ractor_unshareable_constants.rb +12 -0
- data/lib/ulid/uuid.rb +1 -0
- data/lib/ulid/version.rb +2 -1
- data/lib/ulid.rb +130 -58
- data/sig/ulid.rbs +118 -38
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82f48c45c124521403b04938ec4498a85bf292645357d75f32173cc2b9613618
|
4
|
+
data.tar.gz: 9c6269cbef649b57df980d120116687cdcc33e505cb45585b4566f4b16f3cdf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 817d5589c2967d8d1b787ce20c147483cd12769eba22a0489ade4002285e1edc31e06f9e5d8dd590d3cf2342d2875c388818e55b95cbd1d72921b1848287483f
|
7
|
+
data.tar.gz: 6bcacebe7955bb247127ddc64df1fec2cc776954e7c86530750c200da5420fd4cbb73d5fd2f0888cb37ff5f097987dd12f372ee591adccb8b35f35e03e4f0538
|
data/README.md
CHANGED
@@ -7,8 +7,7 @@
|
|
7
7
|
|
8
8
|
[ulid/spec](https://github.com/ulid/spec) is useful.
|
9
9
|
Especially possess all `uniqueness`, `randomness`, `extractable timestamps` and `sortable` features.
|
10
|
-
This gem aims to provide the generator,
|
11
|
-
Also providing [ruby/rbs](https://github.com/ruby/rbs) signatures.
|
10
|
+
This gem aims to provide the generator, optional monotonicity, parser and other manipulation features around ULID with included [RBS](https://github.com/ruby/rbs).
|
12
11
|
|
13
12
|
---
|
14
13
|
|
@@ -47,23 +46,43 @@ $ gem install ruby-ulid
|
|
47
46
|
Should be installed!
|
48
47
|
```
|
49
48
|
|
50
|
-
Add this line
|
49
|
+
Add this line in your Gemfile.
|
51
50
|
|
52
51
|
```ruby
|
53
|
-
gem('ruby-ulid', '~> 0.
|
52
|
+
gem('ruby-ulid', '~> 0.6.0')
|
54
53
|
```
|
55
54
|
|
56
|
-
###
|
57
|
-
|
58
|
-
The generated `ULID` is an object not just a string.
|
59
|
-
It means easily get the timestamps and binary formats.
|
55
|
+
### How to use
|
60
56
|
|
61
57
|
```ruby
|
62
58
|
require 'ulid'
|
63
59
|
|
60
|
+
ULID::VERSION
|
61
|
+
# => "0.6.0"
|
62
|
+
```
|
63
|
+
|
64
|
+
NOTE: This README includes info about development version. If you would see released version's one. [Look at the ref](https://github.com/kachick/ruby-ulid/tree/v0.6.0).
|
65
|
+
|
66
|
+
### Generator and Parser
|
67
|
+
|
68
|
+
`ULID.generate` returns `ULID` instance. It is not just a string.
|
69
|
+
|
70
|
+
```ruby
|
64
71
|
ulid = ULID.generate #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
72
|
+
```
|
73
|
+
|
74
|
+
`ULID.parse` returns `ULID` instance from exists encoded ULIDs.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
ulid = ULID.parse('01F4A5Y1YAQCYAYCTC7GRMJ9AA') #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
78
|
+
```
|
79
|
+
|
80
|
+
It is helpful to inspect.
|
81
|
+
|
82
|
+
```ruby
|
65
83
|
ulid.to_time #=> 2021-04-27 17:27:22.826 UTC
|
66
84
|
ulid.milliseconds #=> 1619544442826
|
85
|
+
ulid.encode #=> "01F4A5Y1YAQCYAYCTC7GRMJ9AA"
|
67
86
|
ulid.to_s #=> "01F4A5Y1YAQCYAYCTC7GRMJ9AA"
|
68
87
|
ulid.timestamp #=> "01F4A5Y1YA"
|
69
88
|
ulid.randomness #=> "QCYAYCTC7GRMJ9AA"
|
@@ -71,41 +90,56 @@ ulid.to_i #=> 1957909092946624190749577070267409738
|
|
71
90
|
ulid.octets #=> [1, 121, 20, 95, 7, 202, 187, 60, 175, 51, 76, 60, 49, 73, 37, 74]
|
72
91
|
```
|
73
92
|
|
74
|
-
|
93
|
+
`ULID.generate` can take fixed `Time` instance. `ULID.at` is the shorthand.
|
75
94
|
|
76
95
|
```ruby
|
77
|
-
|
78
|
-
|
96
|
+
time = Time.at(946684800).utc #=> 2000-01-01 00:00:00 UTC
|
97
|
+
ULID.generate(moment: time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB00N018DCPJA4H9379P)
|
98
|
+
ULID.generate(moment: time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB006WQT3JTMN0T14EBP)
|
99
|
+
ULID.at(time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB002W5BGWWKN76N22H6)
|
79
100
|
```
|
80
101
|
|
81
|
-
|
102
|
+
Also `ULID.encode` and `ULID.decode_time` can be used to get primitive values for most usecases.
|
82
103
|
|
83
|
-
|
104
|
+
`ULID.encode` returns [normalized](#variants-of-format) String without ULID object creation.
|
105
|
+
It can take same arguments as `ULID.generate`.
|
84
106
|
|
85
107
|
```ruby
|
86
|
-
|
87
|
-
|
88
|
-
ULID.generate
|
89
|
-
end
|
90
|
-
ulids.uniq(&:to_time).size #=> 1000
|
91
|
-
ulids.sort == ulids #=> true
|
108
|
+
ULID.encode #=> "01G86M42Q6SJ9XQM2ZRM6JRDSF"
|
109
|
+
ULID.encode(moment: Time.at(946684800).utc) #=> "00VHNCZB00SYG7RCEXZC9DA4E1"
|
92
110
|
```
|
93
111
|
|
94
|
-
`ULID.
|
112
|
+
`ULID.decode_time` returns Time. It can take `in` keyarg as same as `Time.at`.
|
95
113
|
|
96
114
|
```ruby
|
97
|
-
|
98
|
-
ULID.
|
99
|
-
|
100
|
-
|
115
|
+
ULID.decode_time('00VHNCZB00SYG7RCEXZC9DA4E1') #=> 2000-01-01 00:00:00 UTC
|
116
|
+
ULID.decode_time('00VHNCZB00SYG7RCEXZC9DA4E1', in: '+09:00') #=> 2000-01-01 09:00:00 +0900
|
117
|
+
```
|
118
|
+
|
119
|
+
This project does not prioritize the speed. However it actually works faster than others! :zap:
|
120
|
+
|
121
|
+
Snapshot on 0.6.0 is below
|
101
122
|
|
102
|
-
|
103
|
-
|
123
|
+
* Generator is 1.4x faster than - [ulid gem](https://github.com/rafaelsales/ulid)
|
124
|
+
* Generator is 1.7x faster than - [ulid-ruby gem](https://github.com/abachman/ulid-ruby)
|
125
|
+
* Parser is 2.6x faster than - [ulid-ruby gem](https://github.com/abachman/ulid-ruby)
|
126
|
+
|
127
|
+
You can see further detail at [Benchmark](https://github.com/kachick/ruby-ulid/wiki/Benchmark).
|
128
|
+
|
129
|
+
### Sortable with the timestamp
|
130
|
+
|
131
|
+
ULIDs are sortable when they are generated in different timestamp with milliseconds precision.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
ulids = 1000.times.map do
|
135
|
+
sleep(0.001)
|
136
|
+
ULID.generate
|
104
137
|
end
|
138
|
+
ulids.uniq(&:to_time).size #=> 1000
|
105
139
|
ulids.sort == ulids #=> true
|
106
140
|
```
|
107
141
|
|
108
|
-
|
142
|
+
Basic generator prefers `randomness`, it does not guarantee `sortable` for same milliseconds ULIDs.
|
109
143
|
|
110
144
|
```ruby
|
111
145
|
ulids = 10000.times.map do
|
@@ -147,11 +181,11 @@ sample_ulids_by_the_time.take(5) #=>
|
|
147
181
|
ulids.sort == ulids #=> true
|
148
182
|
```
|
149
183
|
|
150
|
-
Same
|
184
|
+
Same instance of `ULID::MonotonicGenerator` does not generate duplicated ULIDs even in multi threads environment. It is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255).
|
151
185
|
|
152
186
|
### Filtering IDs with `Time`
|
153
187
|
|
154
|
-
`ULID` can be element of the `Range`. If
|
188
|
+
`ULID` can be element of the `Range`. If they were generated with monotonic generator, ID based filtering is easy and reliable.
|
155
189
|
|
156
190
|
```ruby
|
157
191
|
include_end = ulid1..ulid2
|
@@ -187,7 +221,9 @@ time = Time.at(946684800, Rational('123456.789')).utc #=> 2000-01-01 00:00:00.12
|
|
187
221
|
ULID.floor(time) #=> 2000-01-01 00:00:00.123 UTC
|
188
222
|
```
|
189
223
|
|
190
|
-
###
|
224
|
+
### Tools
|
225
|
+
|
226
|
+
#### Scanner for string (e.g. `JSON`)
|
191
227
|
|
192
228
|
For rough operations, `ULID.scan` might be useful.
|
193
229
|
|
@@ -230,7 +266,7 @@ ULID.scan(json).to_a
|
|
230
266
|
```
|
231
267
|
|
232
268
|
`ULID#patterns` is a util for text based operations.
|
233
|
-
The results and spec are not fixed. Should not be used except snippets/console operation
|
269
|
+
The results and spec are not fixed. Should not be used except snippets/console operation.
|
234
270
|
|
235
271
|
```ruby
|
236
272
|
ULID.parse('01F4GNBXW1AM2KWW52PVT3ZY9X').patterns
|
@@ -241,7 +277,7 @@ ULID.parse('01F4GNBXW1AM2KWW52PVT3ZY9X').patterns
|
|
241
277
|
}
|
242
278
|
```
|
243
279
|
|
244
|
-
|
280
|
+
#### Get boundary ULIDs
|
245
281
|
|
246
282
|
`ULID.min` and `ULID.max` return termination values for ULID spec.
|
247
283
|
|
@@ -256,10 +292,12 @@ ULID.min(time) #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3V0000000000000000)
|
|
256
292
|
ULID.max(time) #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3VZZZZZZZZZZZZZZZZ)
|
257
293
|
```
|
258
294
|
|
295
|
+
#### As element in Enumerable
|
296
|
+
|
259
297
|
`ULID#next` and `ULID#succ` returns next(successor) ULID.
|
260
298
|
Especially `ULID#succ` makes it possible `Range[ULID]#each`.
|
261
299
|
|
262
|
-
NOTE:
|
300
|
+
NOTE: However basically `Range[ULID]#each` should not be used. Incrementing 128 bits IDs are not reasonable operation in most cases.
|
263
301
|
|
264
302
|
```ruby
|
265
303
|
ULID.parse('01BX5ZZKBKZZZZZZZZZZZZZZZY').next.to_s #=> "01BX5ZZKBKZZZZZZZZZZZZZZZZ"
|
@@ -267,7 +305,7 @@ ULID.parse('01BX5ZZKBKZZZZZZZZZZZZZZZZ').next.to_s #=> "01BX5ZZKBM00000000000000
|
|
267
305
|
ULID.parse('7ZZZZZZZZZZZZZZZZZZZZZZZZZ').next #=> nil
|
268
306
|
```
|
269
307
|
|
270
|
-
`ULID#pred` returns predecessor ULID
|
308
|
+
`ULID#pred` returns predecessor ULID.
|
271
309
|
|
272
310
|
```ruby
|
273
311
|
ULID.parse('01BX5ZZKBK0000000000000001').pred.to_s #=> "01BX5ZZKBK0000000000000000"
|
@@ -275,6 +313,8 @@ ULID.parse('01BX5ZZKBK0000000000000000').pred.to_s #=> "01BX5ZZKBJZZZZZZZZZZZZZZ
|
|
275
313
|
ULID.parse('00000000000000000000000000').pred #=> nil
|
276
314
|
```
|
277
315
|
|
316
|
+
#### Test helpers
|
317
|
+
|
278
318
|
`ULID.sample` returns random ULIDs.
|
279
319
|
|
280
320
|
Basically ignores generating time.
|
@@ -300,61 +340,52 @@ ulid1 = ULID.parse('01F4A5Y1YAQCYAYCTC7GRMJ9AA') #=> ULID(2021-04-27 17:27:22.82
|
|
300
340
|
ulid2 = ULID.parse('01F4PTVCSN9ZPFKYTY2DDJVRK4') #=> ULID(2021-05-02 15:23:48.917 UTC: 01F4PTVCSN9ZPFKYTY2DDJVRK4)
|
301
341
|
ulids = ULID.sample(1000, period: ulid1..ulid2)
|
302
342
|
ulids.uniq.size #=> 1000
|
303
|
-
ulids.take(
|
343
|
+
ulids.take(5)
|
304
344
|
#=>
|
305
345
|
#[ULID(2021-05-02 06:57:19.954 UTC: 01F4NXW02JNB8H0J0TK48JD39X),
|
306
346
|
# ULID(2021-05-02 07:06:07.458 UTC: 01F4NYC372GVP7NS0YAYQGT4VZ),
|
307
347
|
# ULID(2021-05-01 06:16:35.791 UTC: 01F4K94P6F6P68K0H64WRDSFKW),
|
308
348
|
# ULID(2021-04-27 22:17:37.844 UTC: 01F4APHGSMFJZQTGXKZBFFBPJP),
|
309
|
-
# ULID(2021-04-28 20:17:55.357 UTC: 01F4D231MXQJXAR8G2JZHEJNH3)
|
310
|
-
|
311
|
-
# ULID(2021-05-02 12:26:03.480 UTC: 01F4PGNXARG554Y3HYVBDW4T9S),
|
312
|
-
# ULID(2021-04-29 09:52:15.107 UTC: 01F4EGP483ZX2747FQPWQNPPMW),
|
313
|
-
# ULID(2021-04-29 03:18:24.152 UTC: 01F4DT4Z4RA0QV8WFQGRAG63EH),
|
314
|
-
# ULID(2021-05-02 13:27:16.394 UTC: 01F4PM605ABF5SDVMEHBH8JJ9R)]
|
315
|
-
ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
|
349
|
+
# ULID(2021-04-28 20:17:55.357 UTC: 01F4D231MXQJXAR8G2JZHEJNH3)]
|
350
|
+
ULID.sample(5, period: ulid1.to_time..ulid2.to_time)
|
316
351
|
#=>
|
317
352
|
# [ULID(2021-04-29 06:44:41.513 UTC: 01F4E5YPD9XQ3MYXWK8ZJKY8SW),
|
318
353
|
# ULID(2021-05-01 00:35:06.629 UTC: 01F4JNKD85SVK1EAEYSJGF53A2),
|
319
354
|
# ULID(2021-05-02 12:45:28.408 UTC: 01F4PHSEYRG9BWBEWMRW1XE6WW),
|
320
355
|
# ULID(2021-05-01 03:06:09.130 UTC: 01F4JY7ZBABCBMX16XH2Q4JW4W),
|
321
|
-
# ULID(2021-04-29 21:38:58.109 UTC: 01F4FS45DX4049JEQK4W6TER6G)
|
322
|
-
# ULID(2021-04-29 17:14:14.116 UTC: 01F4F9ZDQ449BE8BBZFEHYQWG2),
|
323
|
-
# ULID(2021-04-30 16:18:08.205 UTC: 01F4HS5DPD1HWDVJNJ6YKJXKSK),
|
324
|
-
# ULID(2021-04-30 10:31:33.602 UTC: 01F4H5ATF2A1CSQF0XV5NKZ288),
|
325
|
-
# ULID(2021-04-28 16:49:06.484 UTC: 01F4CP4PDM214Q6H3KJP7DYJRR),
|
326
|
-
# ULID(2021-04-28 15:05:06.808 UTC: 01F4CG68ZRST94T056KRZ5K9S4)]
|
356
|
+
# ULID(2021-04-29 21:38:58.109 UTC: 01F4FS45DX4049JEQK4W6TER6G)]
|
327
357
|
```
|
328
358
|
|
329
|
-
|
359
|
+
#### Variants of format
|
330
360
|
|
331
361
|
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
362
|
|
363
|
+
>Case insensitive
|
364
|
+
|
365
|
+
I can understand it might be considered in actual use-case. So `ULID.parse` accepts upcase and downcase.
|
366
|
+
However it is a controversial point, discussing in [ulid/spec#3](https://github.com/ulid/spec/issues/3).
|
367
|
+
|
333
368
|
>Uses Crockford's base32 for better efficiency and readability (5 bits per character)
|
334
369
|
|
335
370
|
The original `Crockford's base32` maps `I`, `L` to `1`, `O` to `0`.
|
336
371
|
And accepts freestyle inserting `Hyphens (-)`.
|
337
372
|
To consider this patterns or not is different in each implementations.
|
338
373
|
|
339
|
-
|
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).
|
374
|
+
I have suggested to clarify `subset of Crockford's base32` in [ulid/spec#57](https://github.com/ulid/spec/pull/57).
|
346
375
|
|
347
|
-
|
376
|
+
This gem provides some methods to handle the nasty possibilities.
|
348
377
|
|
349
|
-
`ULID.normalize` and `ULID.
|
378
|
+
`ULID.normalize`, `ULID.normalized?`, `ULID.valid_as_variant_format?` and `ULID.parse_variant_format`
|
350
379
|
|
351
380
|
```ruby
|
352
|
-
ULID.normalize('-
|
353
|
-
ULID.normalized?('-
|
354
|
-
ULID.normalized?('
|
381
|
+
ULID.normalize('01g70y0y7g-z1xwdarexergsddd') #=> "01G70Y0Y7GZ1XWDAREXERGSDDD"
|
382
|
+
ULID.normalized?('01g70y0y7g-z1xwdarexergsddd') #=> false
|
383
|
+
ULID.normalized?('01G70Y0Y7GZ1XWDAREXERGSDDD') #=> true
|
384
|
+
ULID.valid_as_variant_format?('01g70y0y7g-z1xwdarexergsddd') #=> true
|
385
|
+
ULID.parse_variant_format('01G70Y0Y7G-ZLXWDIREXERGSDoD') #=> ULID(2022-07-03 02:25:22.672 UTC: 01G70Y0Y7GZ1XWD1REXERGSD0D)
|
355
386
|
```
|
356
387
|
|
357
|
-
|
388
|
+
#### UUIDv4 converter (experimental)
|
358
389
|
|
359
390
|
`ULID.from_uuidv4` and `ULID#to_uuidv4` is the converter.
|
360
391
|
The imported timestamp is meaningless. So ULID's benefit will lost.
|
@@ -387,68 +418,19 @@ ULID.min == reversed_min #=> false
|
|
387
418
|
ULID.max == reversed_max #=> false
|
388
419
|
```
|
389
420
|
|
390
|
-
##
|
391
|
-
|
392
|
-
As far as I know, major prior arts are below
|
393
|
-
|
394
|
-
### [ulid gem](https://rubygems.org/gems/ulid) - [rafaelsales/ulid](https://github.com/rafaelsales/ulid)
|
395
|
-
|
396
|
-
It is just providing basic `String` generator only.
|
397
|
-
So you can replace the code as below
|
398
|
-
|
399
|
-
```diff
|
400
|
-
-ULID.generate
|
401
|
-
+ULID.generate.to_s
|
402
|
-
```
|
403
|
-
|
404
|
-
NOTE: In version before `1.3.0`, timestamps might not be correct value.
|
405
|
-
|
406
|
-
1. [Sort order does not respect millisecond ordering](https://github.com/rafaelsales/ulid/issues/22)
|
407
|
-
1. [Fixed in this PR](https://github.com/rafaelsales/ulid/pull/23)
|
408
|
-
1. [Released in 1.3.0](https://github.com/rafaelsales/ulid/compare/1.2.0...v1.3.0)
|
409
|
-
|
410
|
-
### [ulid-ruby gem](https://rubygems.org/gems/ulid-ruby) - [abachman/ulid-ruby](https://github.com/abachman/ulid-ruby)
|
411
|
-
|
412
|
-
It is providing basic generator(except monotonic generator) and parser.
|
413
|
-
Major methods can be replaced as below.
|
414
|
-
|
415
|
-
```diff
|
416
|
-
-ULID.generate
|
417
|
-
+ULID.generate.to_s
|
418
|
-
-ULID.at(time)
|
419
|
-
+ULID.at(time).to_s
|
420
|
-
-ULID.time(string)
|
421
|
-
+ULID.parse(string).to_time
|
422
|
-
-ULID.min_ulid_at(time)
|
423
|
-
+ULID.min(time).to_s
|
424
|
-
-ULID.max_ulid_at(time)
|
425
|
-
+ULID.max(time).to_s
|
426
|
-
```
|
427
|
-
|
428
|
-
NOTE: In version before `1.0.2`, timestamps might not be correct value.
|
429
|
-
|
430
|
-
1. [Parsed time object has more than milliseconds](https://github.com/abachman/ulid-ruby/issues/3)
|
431
|
-
1. [Fix to handle timestamp precision in parser](https://github.com/abachman/ulid-ruby/pull/5)
|
432
|
-
1. [Fix to handle timestamp precision in generator](https://github.com/abachman/ulid-ruby/pull/4)
|
433
|
-
1. [Released in 1.0.2](https://github.com/abachman/ulid-ruby/compare/v1.0.0...v1.0.2)
|
434
|
-
|
435
|
-
### Compare performance with them
|
436
|
-
|
437
|
-
See [Benchmark](https://github.com/kachick/ruby-ulid/wiki/Benchmark).
|
421
|
+
## Migration from other gems
|
438
422
|
|
439
|
-
|
423
|
+
See [wiki page for gem migration](https://github.com/kachick/ruby-ulid/wiki/Gem-migration).
|
440
424
|
|
441
|
-
##
|
425
|
+
## RBS
|
442
426
|
|
443
|
-
|
427
|
+
Try at [examples/rbs_sandbox](https://github.com/kachick/ruby-ulid/tree/main/examples/rbs_sandbox).
|
444
428
|
|
445
|
-
I have checked the behavior with [ruby/rbs@2.6.0](https://github.com/ruby/rbs)
|
429
|
+
I have checked the behavior with [ruby/rbs@2.6.0](https://github.com/ruby/rbs) + [soutaro/steep@1.0.1](https://github.com/soutaro/steep) + [soutaro/steep-vscode](https://github.com/soutaro/steep-vscode).
|
446
430
|
|
447
431
|
* 
|
448
432
|
* 
|
449
433
|
* 
|
450
|
-
* 
|
451
|
-
* 
|
452
434
|
|
453
435
|
## References
|
454
436
|
|
data/lib/ruby-ulid.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
+
# shareable_constant_value: literal
|
3
4
|
|
4
5
|
# Copyright (C) 2021 Kenichi Kamiya
|
5
6
|
|
@@ -14,63 +15,62 @@ class ULID
|
|
14
15
|
# * https://github.com/kachick/ruby-ulid/issues/57
|
15
16
|
# * https://github.com/kachick/ruby-ulid/issues/78
|
16
17
|
module CrockfordBase32
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
'
|
30
|
-
'
|
31
|
-
'
|
32
|
-
'
|
33
|
-
'
|
34
|
-
'
|
35
|
-
'
|
36
|
-
'
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'
|
40
|
-
'
|
41
|
-
'
|
42
|
-
'
|
18
|
+
# Excluded I, L, O, U, - from Base32
|
19
|
+
base32_to_crockford = {
|
20
|
+
'0' => '0',
|
21
|
+
'1' => '1',
|
22
|
+
'2' => '2',
|
23
|
+
'3' => '3',
|
24
|
+
'4' => '4',
|
25
|
+
'5' => '5',
|
26
|
+
'6' => '6',
|
27
|
+
'7' => '7',
|
28
|
+
'8' => '8',
|
29
|
+
'9' => '9',
|
30
|
+
'A' => 'A',
|
31
|
+
'B' => 'B',
|
32
|
+
'C' => 'C',
|
33
|
+
'D' => 'D',
|
34
|
+
'E' => 'E',
|
35
|
+
'F' => 'F',
|
36
|
+
'G' => 'G',
|
37
|
+
'H' => 'H',
|
38
|
+
'I' => 'J',
|
39
|
+
'J' => 'K',
|
40
|
+
'K' => 'M',
|
41
|
+
'L' => 'N',
|
42
|
+
'M' => 'P',
|
43
|
+
'N' => 'Q',
|
44
|
+
'O' => 'R',
|
45
|
+
'P' => 'S',
|
46
|
+
'Q' => 'T',
|
47
|
+
'R' => 'V',
|
48
|
+
'S' => 'W',
|
49
|
+
'T' => 'X',
|
50
|
+
'U' => 'Y',
|
51
|
+
'V' => 'Z'
|
43
52
|
}.freeze
|
53
|
+
BASE32_TR_PATTERN = base32_to_crockford.keys.join.freeze
|
54
|
+
ENCODING_STRING = CROCKFORD_BASE32_TR_PATTERN = base32_to_crockford.values.freeze.join.freeze
|
44
55
|
|
45
|
-
|
46
|
-
if n = crockford_base32_mappings[encoding_char]
|
47
|
-
char_32 = n32_char_by_number.fetch(n)
|
48
|
-
map[encoding_char] = char_32
|
49
|
-
end
|
50
|
-
end.freeze
|
51
|
-
raise(SetupError, 'obvious bug exists in the mapping algorithm') unless N32_CHAR_BY_CROCKFORD_BASE32_CHAR.keys == crockford_base32_mappings.keys
|
52
|
-
|
53
|
-
CROCKFORD_BASE32_CHAR_PATTERN = /[#{N32_CHAR_BY_CROCKFORD_BASE32_CHAR.keys.join}]/.freeze
|
54
|
-
|
55
|
-
CROCKFORD_BASE32_CHAR_BY_N32_CHAR = N32_CHAR_BY_CROCKFORD_BASE32_CHAR.invert.freeze
|
56
|
-
N32_CHAR_PATTERN = /[#{CROCKFORD_BASE32_CHAR_BY_N32_CHAR.keys.join}]/.freeze
|
57
|
-
|
58
|
-
STANDARD_BY_VARIANT = {
|
56
|
+
normarized_by_variant = {
|
59
57
|
'L' => '1',
|
60
58
|
'l' => '1',
|
61
59
|
'I' => '1',
|
62
60
|
'i' => '1',
|
63
61
|
'O' => '0',
|
64
|
-
'o' => '0'
|
65
|
-
'-' => ''
|
62
|
+
'o' => '0'
|
66
63
|
}.freeze
|
67
|
-
|
64
|
+
VARIANT_TR_PATTERN = normarized_by_variant.keys.join.freeze
|
65
|
+
NORMALIZED_TR_PATTERN = normarized_by_variant.values.join.freeze
|
66
|
+
|
67
|
+
# @note Avoid to depend regex as possible. `tr(string, string)` is almost 2x Faster than `gsub(regex, hash)` in Ruby 3.1
|
68
68
|
|
69
69
|
# @api private
|
70
70
|
# @param [String] string
|
71
71
|
# @return [Integer]
|
72
72
|
def self.decode(string)
|
73
|
-
n32encoded = string.upcase.
|
73
|
+
n32encoded = string.upcase.tr(CROCKFORD_BASE32_TR_PATTERN, BASE32_TR_PATTERN)
|
74
74
|
n32encoded.to_i(32)
|
75
75
|
end
|
76
76
|
|
@@ -79,14 +79,21 @@ class ULID
|
|
79
79
|
# @return [String]
|
80
80
|
def self.encode(integer)
|
81
81
|
n32encoded = integer.to_s(32)
|
82
|
-
n32encoded
|
82
|
+
from_n32(n32encoded).rjust(ENCODED_LENGTH, '0')
|
83
83
|
end
|
84
84
|
|
85
85
|
# @api private
|
86
86
|
# @param [String] string
|
87
87
|
# @return [String]
|
88
88
|
def self.normalize(string)
|
89
|
-
string.
|
89
|
+
string.delete('-').tr(VARIANT_TR_PATTERN, NORMALIZED_TR_PATTERN)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
# @param [String] n32encoded
|
94
|
+
# @return [String]
|
95
|
+
def self.from_n32(n32encoded)
|
96
|
+
n32encoded.upcase.tr(BASE32_TR_PATTERN, CROCKFORD_BASE32_TR_PATTERN)
|
90
97
|
end
|
91
98
|
end
|
92
99
|
end
|
data/lib/ulid/errors.rb
ADDED
@@ -1,13 +1,15 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
+
# shareable_constant_value: literal
|
3
4
|
|
4
5
|
# Copyright (C) 2021 Kenichi Kamiya
|
5
6
|
|
6
7
|
class ULID
|
7
8
|
class MonotonicGenerator
|
9
|
+
# @note When use https://github.com/ko1/ractor-tvar might realize Ractor based thread safe monotonic generator.
|
10
|
+
# However it is a C extention, I'm pending to use it for now.
|
8
11
|
include(MonitorMixin)
|
9
12
|
|
10
|
-
# @dynamic prev
|
11
13
|
# @return [ULID, nil]
|
12
14
|
attr_reader(:prev)
|
13
15
|
|
@@ -22,7 +24,6 @@ class ULID
|
|
22
24
|
def inspect
|
23
25
|
"ULID::MonotonicGenerator(prev: #{@prev.inspect})"
|
24
26
|
end
|
25
|
-
# @dynamic to_s
|
26
27
|
alias_method(:to_s, :inspect)
|
27
28
|
|
28
29
|
# @param [Time, Integer] moment
|
@@ -67,6 +68,12 @@ class ULID
|
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
71
|
+
# @param [Time, Integer] moment
|
72
|
+
# @return [String]
|
73
|
+
def encode(moment: ULID.current_milliseconds)
|
74
|
+
generate(moment: moment).encode
|
75
|
+
end
|
76
|
+
|
70
77
|
undef_method(:freeze)
|
71
78
|
|
72
79
|
# @raise [TypeError] always raises exception and does not freeze self
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# coding: us-ascii
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
class ULID
|
5
|
+
min = parse('00000000000000000000000000').freeze
|
6
|
+
max = parse('7ZZZZZZZZZZZZZZZZZZZZZZZZZ').freeze
|
7
|
+
|
8
|
+
ractor_can_make_shareable_time = RUBY_VERSION >= '3.1'
|
9
|
+
|
10
|
+
MIN = ractor_can_make_shareable_time ? Ractor.make_shareable(min) : min
|
11
|
+
MAX = ractor_can_make_shareable_time ? Ractor.make_shareable(max) : max
|
12
|
+
end
|
data/lib/ulid/uuid.rb
CHANGED
data/lib/ulid/version.rb
CHANGED
data/lib/ulid.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
+
# shareable_constant_value: experimental_everything
|
3
4
|
|
4
5
|
# Copyright (C) 2021 Kenichi Kamiya
|
5
6
|
|
6
7
|
require('securerandom')
|
7
8
|
|
9
|
+
require_relative('ulid/version')
|
10
|
+
require_relative('ulid/errors')
|
11
|
+
require_relative('ulid/crockford_base32')
|
12
|
+
require_relative('ulid/monotonic_generator')
|
13
|
+
|
8
14
|
# @see https://github.com/ulid/spec
|
9
15
|
# @!attribute [r] milliseconds
|
10
16
|
# @return [Integer]
|
@@ -13,16 +19,6 @@ require('securerandom')
|
|
13
19
|
class ULID
|
14
20
|
include(Comparable)
|
15
21
|
|
16
|
-
class Error < StandardError; end
|
17
|
-
class OverflowError < Error; end
|
18
|
-
class ParserError < Error; end
|
19
|
-
class UnexpectedError < Error; end
|
20
|
-
|
21
|
-
# Excluded I, L, O, U, -.
|
22
|
-
# This is the encoding patterns.
|
23
|
-
# The decoding issue is written in ULID::CrockfordBase32
|
24
|
-
CROCKFORD_BASE32_ENCODING_STRING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
|
25
|
-
|
26
22
|
TIMESTAMP_ENCODED_LENGTH = 10
|
27
23
|
RANDOMNESS_ENCODED_LENGTH = 16
|
28
24
|
ENCODED_LENGTH = 26
|
@@ -37,13 +33,12 @@ class ULID
|
|
37
33
|
|
38
34
|
# @see https://github.com/ulid/spec/pull/57
|
39
35
|
# Currently not used as a constant, but kept as a reference for now.
|
40
|
-
PATTERN_WITH_CROCKFORD_BASE32_SUBSET = /(?<timestamp>[0-7][#{
|
36
|
+
PATTERN_WITH_CROCKFORD_BASE32_SUBSET = /(?<timestamp>[0-7][#{CrockfordBase32::ENCODING_STRING}]{#{TIMESTAMP_ENCODED_LENGTH - 1}})(?<randomness>[#{CrockfordBase32::ENCODING_STRING}]{#{RANDOMNESS_ENCODED_LENGTH}})/i.freeze
|
41
37
|
|
42
38
|
STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET = /\A#{PATTERN_WITH_CROCKFORD_BASE32_SUBSET.source}\z/i.freeze
|
43
39
|
|
44
40
|
# Optimized for `ULID.scan`, might be changed the definition with gathered `ULID.scan` spec changed.
|
45
|
-
|
46
|
-
SCANNING_PATTERN = /[0-7][#{CROCKFORD_BASE32_ENCODING_STRING}]{#{TIMESTAMP_ENCODED_LENGTH - 1}}[#{CROCKFORD_BASE32_ENCODING_STRING}]{#{RANDOMNESS_ENCODED_LENGTH}}/i.freeze
|
41
|
+
SCANNING_PATTERN = /\b[0-7][#{CrockfordBase32::ENCODING_STRING}]{#{TIMESTAMP_ENCODED_LENGTH - 1}}[#{CrockfordBase32::ENCODING_STRING}]{#{RANDOMNESS_ENCODED_LENGTH}}\b/i.freeze
|
47
42
|
|
48
43
|
# Similar as Time#inspect since Ruby 2.7, however it is NOT same.
|
49
44
|
# Time#inspect trancates needless digits. Keeping full milliseconds with "%3N" will fit for ULID.
|
@@ -60,6 +55,16 @@ class ULID
|
|
60
55
|
from_milliseconds_and_entropy(milliseconds: milliseconds_from_moment(moment), entropy: entropy)
|
61
56
|
end
|
62
57
|
|
58
|
+
# Almost same as [.generate] except directly returning String without needless object creation
|
59
|
+
#
|
60
|
+
# @param [Integer, Time] moment
|
61
|
+
# @param [Integer] entropy
|
62
|
+
# @return [String]
|
63
|
+
def self.encode(moment: current_milliseconds, entropy: reasonable_entropy)
|
64
|
+
n32_encoded = encode_n32(milliseconds: milliseconds_from_moment(moment), entropy: entropy)
|
65
|
+
CrockfordBase32.from_n32(n32_encoded)
|
66
|
+
end
|
67
|
+
|
63
68
|
# Short hand of `ULID.generate(moment: time)`
|
64
69
|
# @param [Time] time
|
65
70
|
# @return [ULID]
|
@@ -83,7 +88,7 @@ class ULID
|
|
83
88
|
|
84
89
|
RANDOM_INTEGER_GENERATOR = -> {
|
85
90
|
SecureRandom.random_number(MAX_INTEGER)
|
86
|
-
}
|
91
|
+
}.freeze
|
87
92
|
|
88
93
|
# @param [Range<Time>, Range<nil>, Range[ULID], nil] period
|
89
94
|
# @overload sample(number, period: nil)
|
@@ -166,7 +171,12 @@ class ULID
|
|
166
171
|
milliseconds = n32encoded_timestamp.to_i(32)
|
167
172
|
entropy = n32encoded_randomness.to_i(32)
|
168
173
|
|
169
|
-
new(
|
174
|
+
new(
|
175
|
+
milliseconds: milliseconds,
|
176
|
+
entropy: entropy,
|
177
|
+
integer: integer,
|
178
|
+
encoded: CrockfordBase32.from_n32(n32encoded).freeze
|
179
|
+
)
|
170
180
|
end
|
171
181
|
|
172
182
|
# @param [Range<Time>, Range<nil>, Range[ULID]] period
|
@@ -231,9 +241,9 @@ class ULID
|
|
231
241
|
# @api private
|
232
242
|
# @param [Time] time
|
233
243
|
# @return [Integer]
|
234
|
-
private_class_method
|
244
|
+
private_class_method def self.milliseconds_from_time(time)
|
235
245
|
(time.to_r * 1000).to_i
|
236
|
-
end
|
246
|
+
end
|
237
247
|
|
238
248
|
# @api private
|
239
249
|
# @param [Time, Integer] moment
|
@@ -250,9 +260,20 @@ class ULID
|
|
250
260
|
end
|
251
261
|
|
252
262
|
# @return [Integer]
|
253
|
-
private_class_method
|
263
|
+
private_class_method def self.reasonable_entropy
|
254
264
|
SecureRandom.random_number(MAX_ENTROPY)
|
255
|
-
end
|
265
|
+
end
|
266
|
+
|
267
|
+
private_class_method def self.encode_n32(milliseconds:, entropy:)
|
268
|
+
raise(ArgumentError, 'milliseconds and entropy should be an `Integer`') unless Integer === milliseconds && Integer === entropy
|
269
|
+
raise(OverflowError, "timestamp overflow: given #{milliseconds}, max: #{MAX_MILLISECONDS}") unless milliseconds <= MAX_MILLISECONDS
|
270
|
+
raise(OverflowError, "entropy overflow: given #{entropy}, max: #{MAX_ENTROPY}") unless entropy <= MAX_ENTROPY
|
271
|
+
raise(ArgumentError, 'milliseconds and entropy should not be negative') if milliseconds.negative? || entropy.negative?
|
272
|
+
|
273
|
+
n32encoded_timestamp = milliseconds.to_s(32).rjust(TIMESTAMP_ENCODED_LENGTH, '0')
|
274
|
+
n32encoded_randomness = entropy.to_s(32).rjust(RANDOMNESS_ENCODED_LENGTH, '0')
|
275
|
+
"#{n32encoded_timestamp}#{n32encoded_randomness}"
|
276
|
+
end
|
256
277
|
|
257
278
|
# @param [String, #to_str] string
|
258
279
|
# @return [ULID]
|
@@ -268,6 +289,36 @@ class ULID
|
|
268
289
|
from_integer(CrockfordBase32.decode(string))
|
269
290
|
end
|
270
291
|
|
292
|
+
# @param [String, #to_str] string
|
293
|
+
# @return [ULID]
|
294
|
+
# @raise [ParserError] if the given format is not correct for ULID specs
|
295
|
+
def self.parse_variant_format(string)
|
296
|
+
string = String.try_convert(string)
|
297
|
+
raise(ArgumentError, 'ULID.parse_variant_format takes only strings') unless string
|
298
|
+
|
299
|
+
normalized_in_crockford = CrockfordBase32.normalize(string)
|
300
|
+
parse(normalized_in_crockford)
|
301
|
+
end
|
302
|
+
|
303
|
+
# Almost same as `ULID.parse(string).to_time` except directly returning Time instance without needless object creation
|
304
|
+
#
|
305
|
+
# @param [String, #to_str] string
|
306
|
+
# @return [Time]
|
307
|
+
# @raise [ParserError] if the given format is not correct for ULID specs
|
308
|
+
def self.decode_time(string, in: 'UTC')
|
309
|
+
in_for_time_at = binding.local_variable_get(:in) # Needed because `in` is a reserved word.
|
310
|
+
string = String.try_convert(string)
|
311
|
+
raise(ArgumentError, 'ULID.decode_time takes only strings') unless string
|
312
|
+
|
313
|
+
unless STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET.match?(string)
|
314
|
+
raise(ParserError, "given `#{string}` does not match to `#{STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET.inspect}`")
|
315
|
+
end
|
316
|
+
|
317
|
+
timestamp = string.slice(0, TIMESTAMP_ENCODED_LENGTH).freeze || raise(UnexpectedError)
|
318
|
+
|
319
|
+
Time.at(0, CrockfordBase32.decode(timestamp), :millisecond, in: in_for_time_at)
|
320
|
+
end
|
321
|
+
|
271
322
|
# @param [String, #to_str] string
|
272
323
|
# @return [String]
|
273
324
|
# @raise [ParserError] if the given format is not correct for ULID specs, even if ignored `orthographical variants of the format`
|
@@ -275,23 +326,40 @@ class ULID
|
|
275
326
|
string = String.try_convert(string)
|
276
327
|
raise(ArgumentError, 'ULID.normalize takes only strings') unless string
|
277
328
|
|
278
|
-
normalized_in_crockford = CrockfordBase32.normalize(string)
|
279
329
|
# Ensure the ULID correctness, because CrockfordBase32 does not always mean to satisfy ULID format
|
280
|
-
|
330
|
+
parse_variant_format(string).to_s
|
281
331
|
end
|
282
332
|
|
333
|
+
# @param [String, #to_str] string
|
283
334
|
# @return [Boolean]
|
284
|
-
def self.normalized?(
|
285
|
-
normalized = normalize(
|
335
|
+
def self.normalized?(string)
|
336
|
+
normalized = normalize(string)
|
286
337
|
rescue Exception
|
287
338
|
false
|
288
339
|
else
|
289
|
-
normalized ==
|
340
|
+
normalized == string
|
290
341
|
end
|
291
342
|
|
343
|
+
# @param [String, #to_str] string
|
292
344
|
# @return [Boolean]
|
293
|
-
def self.
|
294
|
-
string
|
345
|
+
def self.valid_as_variant_format?(string)
|
346
|
+
parse_variant_format(string)
|
347
|
+
rescue Exception
|
348
|
+
false
|
349
|
+
else
|
350
|
+
true
|
351
|
+
end
|
352
|
+
|
353
|
+
# @deprecated Use [.valid_as_variant_format?] or [.normalized?] instead
|
354
|
+
#
|
355
|
+
# Returns `true` if it is normalized string.
|
356
|
+
# Basically the difference of normalized? is to accept downcase or not. This returns true for downcased ULIDs.
|
357
|
+
#
|
358
|
+
# @return [Boolean]
|
359
|
+
def self.valid?(string)
|
360
|
+
warn_kwargs = (RUBY_VERSION >= '3.0') ? { category: :deprecated } : {}
|
361
|
+
Warning.warn('ULID.valid? is deprecated. Use ULID.valid_as_variant_format? or ULID.normalized? instead.', **warn_kwargs)
|
362
|
+
string = String.try_convert(string)
|
295
363
|
string ? STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET.match?(string) : false
|
296
364
|
end
|
297
365
|
|
@@ -316,7 +384,7 @@ class ULID
|
|
316
384
|
|
317
385
|
# @param [BasicObject] object
|
318
386
|
# @return [String]
|
319
|
-
private_class_method
|
387
|
+
private_class_method def self.safe_get_class_name(object)
|
320
388
|
fallback = 'UnknownObject'
|
321
389
|
|
322
390
|
# This class getter implementation used https://github.com/rspec/rspec-support/blob/4ad8392d0787a66f9c351d9cf6c7618e18b3d0f2/lib/rspec/support.rb#L83-L89 as a reference, thank you!
|
@@ -325,7 +393,7 @@ class ULID
|
|
325
393
|
begin
|
326
394
|
object.class
|
327
395
|
rescue NoMethodError
|
328
|
-
# steep can't correctly handle
|
396
|
+
# steep can't correctly handle singleton class assign. See https://github.com/soutaro/steep/pull/586 for further detail
|
329
397
|
# So this annotation is hack for the type infer.
|
330
398
|
# @type var object: BasicObject
|
331
399
|
# @type var singleton_class: untyped
|
@@ -341,7 +409,7 @@ class ULID
|
|
341
409
|
else
|
342
410
|
name || fallback
|
343
411
|
end
|
344
|
-
end
|
412
|
+
end
|
345
413
|
|
346
414
|
# @api private
|
347
415
|
# @param [Integer] milliseconds
|
@@ -350,37 +418,36 @@ class ULID
|
|
350
418
|
# @raise [OverflowError] if the given value is larger than the ULID limit
|
351
419
|
# @raise [ArgumentError] if the given milliseconds and/or entropy is negative number
|
352
420
|
def self.from_milliseconds_and_entropy(milliseconds:, entropy:)
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
integer = (n32encoded_timestamp + n32encoded_randomness).to_i(32)
|
361
|
-
|
362
|
-
new(milliseconds: milliseconds, entropy: entropy, integer: integer)
|
421
|
+
n32_encoded = encode_n32(milliseconds: milliseconds, entropy: entropy)
|
422
|
+
new(
|
423
|
+
milliseconds: milliseconds,
|
424
|
+
entropy: entropy,
|
425
|
+
integer: n32_encoded.to_i(32),
|
426
|
+
encoded: CrockfordBase32.from_n32(n32_encoded).upcase.freeze
|
427
|
+
)
|
363
428
|
end
|
364
429
|
|
365
|
-
# @dynamic milliseconds, entropy
|
366
430
|
attr_reader(:milliseconds, :entropy)
|
367
431
|
|
368
432
|
# @api private
|
369
433
|
# @param [Integer] milliseconds
|
370
434
|
# @param [Integer] entropy
|
371
435
|
# @param [Integer] integer
|
436
|
+
# @param [String] encoded
|
372
437
|
# @return [void]
|
373
|
-
def initialize(milliseconds:, entropy:, integer:)
|
438
|
+
def initialize(milliseconds:, entropy:, integer:, encoded:)
|
374
439
|
# All arguments check should be done with each constructors, not here
|
375
440
|
@integer = integer
|
441
|
+
@encoded = encoded
|
376
442
|
@milliseconds = milliseconds
|
377
443
|
@entropy = entropy
|
378
444
|
end
|
379
445
|
|
380
446
|
# @return [String]
|
381
|
-
def
|
382
|
-
@
|
447
|
+
def encode
|
448
|
+
@encoded
|
383
449
|
end
|
450
|
+
alias_method(:to_s, :encode)
|
384
451
|
|
385
452
|
# @return [Integer]
|
386
453
|
def to_i
|
@@ -392,30 +459,40 @@ class ULID
|
|
392
459
|
[ULID, @integer].hash
|
393
460
|
end
|
394
461
|
|
395
|
-
# @return [
|
462
|
+
# @return [-1, 0, 1, nil]
|
396
463
|
def <=>(other)
|
397
464
|
(ULID === other) ? (@integer <=> other.to_i) : nil
|
398
465
|
end
|
399
466
|
|
400
467
|
# @return [String]
|
401
468
|
def inspect
|
402
|
-
@inspect ||= "ULID(#{to_time.strftime(TIME_FORMAT_IN_INSPECT)}: #{
|
469
|
+
@inspect ||= "ULID(#{to_time.strftime(TIME_FORMAT_IN_INSPECT)}: #{@encoded})".freeze
|
403
470
|
end
|
404
471
|
|
405
472
|
# @return [Boolean]
|
406
473
|
def eql?(other)
|
407
474
|
equal?(other) || (ULID === other && @integer == other.to_i)
|
408
475
|
end
|
409
|
-
# @dynamic ==
|
410
476
|
alias_method(:==, :eql?)
|
411
477
|
|
478
|
+
# Return `true` for same value of ULID, variant formats of strings, same Time in ULID precision(msec).
|
479
|
+
# Do not consider integer, octets and partial strings, then returns `false`.
|
480
|
+
#
|
412
481
|
# @return [Boolean]
|
482
|
+
# @see .normalize
|
483
|
+
# @see .floor
|
413
484
|
def ===(other)
|
414
485
|
case other
|
415
486
|
when ULID
|
416
487
|
@integer == other.to_i
|
417
488
|
when String
|
418
|
-
|
489
|
+
begin
|
490
|
+
to_i == ULID.parse_variant_format(other).to_i
|
491
|
+
rescue Exception
|
492
|
+
false
|
493
|
+
end
|
494
|
+
when Time
|
495
|
+
to_time == ULID.floor(other)
|
419
496
|
else
|
420
497
|
false
|
421
498
|
end
|
@@ -447,12 +524,12 @@ class ULID
|
|
447
524
|
|
448
525
|
# @return [String]
|
449
526
|
def timestamp
|
450
|
-
@timestamp ||= (
|
527
|
+
@timestamp ||= (@encoded.slice(0, TIMESTAMP_ENCODED_LENGTH).freeze || raise(UnexpectedError))
|
451
528
|
end
|
452
529
|
|
453
530
|
# @return [String]
|
454
531
|
def randomness
|
455
|
-
@randomness ||= (
|
532
|
+
@randomness ||= (@encoded.slice(TIMESTAMP_ENCODED_LENGTH, RANDOMNESS_ENCODED_LENGTH).freeze || raise(UnexpectedError))
|
456
533
|
end
|
457
534
|
|
458
535
|
# @note Providing for rough operations. The keys and values is not fixed.
|
@@ -478,7 +555,6 @@ class ULID
|
|
478
555
|
ULID.from_integer(succ_int)
|
479
556
|
end
|
480
557
|
end
|
481
|
-
# @dynamic next
|
482
558
|
alias_method(:next, :succ)
|
483
559
|
|
484
560
|
# @return [ULID, nil] when called on ULID as `00000000000000000000000000`, returns `nil` instead of ULID
|
@@ -513,7 +589,7 @@ class ULID
|
|
513
589
|
# @return [void]
|
514
590
|
def marshal_load(integer)
|
515
591
|
unmarshaled = ULID.from_integer(integer)
|
516
|
-
initialize(integer: unmarshaled.to_i, milliseconds: unmarshaled.milliseconds, entropy: unmarshaled.entropy)
|
592
|
+
initialize(integer: unmarshaled.to_i, milliseconds: unmarshaled.milliseconds, entropy: unmarshaled.entropy, encoded: unmarshaled.to_s)
|
517
593
|
end
|
518
594
|
|
519
595
|
# @return [self]
|
@@ -543,13 +619,9 @@ class ULID
|
|
543
619
|
end
|
544
620
|
end
|
545
621
|
|
546
|
-
require_relative('ulid/
|
547
|
-
require_relative('ulid/crockford_base32')
|
548
|
-
require_relative('ulid/monotonic_generator')
|
622
|
+
require_relative('ulid/ractor_unshareable_constants')
|
549
623
|
|
550
624
|
class ULID
|
551
|
-
|
552
|
-
MAX
|
553
|
-
|
554
|
-
private_constant(:TIME_FORMAT_IN_INSPECT, :MIN, :MAX, :RANDOM_INTEGER_GENERATOR, :CROCKFORD_BASE32_ENCODING_STRING)
|
625
|
+
# Do not write as `ULID.private_constant` for avoiding YARD warnings `[warn]: in YARD::Handlers::Ruby::PrivateConstantHandler: Undocumentable private constants:`
|
626
|
+
private_constant(:TIME_FORMAT_IN_INSPECT, :MIN, :MAX, :RANDOM_INTEGER_GENERATOR)
|
555
627
|
end
|
data/sig/ulid.rbs
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
class ULID < Object
|
2
2
|
VERSION: String
|
3
|
-
CROCKFORD_BASE32_ENCODING_STRING: String
|
4
3
|
TIMESTAMP_ENCODED_LENGTH: 10
|
5
4
|
RANDOMNESS_ENCODED_LENGTH: 16
|
6
5
|
ENCODED_LENGTH: 26
|
@@ -39,12 +38,11 @@ class ULID < Object
|
|
39
38
|
class SetupError < UnexpectedError
|
40
39
|
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
VARIANT_PATTERN: Regexp
|
41
|
+
ENCODING_STRING: String
|
42
|
+
CROCKFORD_BASE32_TR_PATTERN: String
|
43
|
+
BASE32_TR_PATTERN: String
|
44
|
+
VARIANT_TR_PATTERN: String
|
45
|
+
NORMALIZED_TR_PATTERN: String
|
48
46
|
|
49
47
|
# A private API. Should not be used in your code.
|
50
48
|
def self.encode: (Integer integer) -> String
|
@@ -54,6 +52,9 @@ class ULID < Object
|
|
54
52
|
|
55
53
|
# A private API. Should not be used in your code.
|
56
54
|
def self.normalize: (String string) -> String
|
55
|
+
|
56
|
+
# A private API. Should not be used in your code.
|
57
|
+
def self.from_n32: (String n32encoded) -> String
|
57
58
|
end
|
58
59
|
|
59
60
|
class MonotonicGenerator
|
@@ -78,6 +79,9 @@ class ULID < Object
|
|
78
79
|
# The `Thread-safety` is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
|
79
80
|
def generate: (?moment: moment) -> ULID
|
80
81
|
|
82
|
+
# Just providing similar api as `ULID.generate` and `ULID.encode` relation. No performance benefit exists in monotonic generator's one.
|
83
|
+
def encode: (?moment: moment) -> String
|
84
|
+
|
81
85
|
# Returned value is `basically not` Thread-safety
|
82
86
|
# If you want to keep Thread-safety, keep to call {#generate} only in same {#synchronize} block
|
83
87
|
#
|
@@ -102,8 +106,8 @@ class ULID < Object
|
|
102
106
|
type randomness_octets = [Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer] | Array[Integer]
|
103
107
|
type period = Range[Time] | Range[nil] | Range[ULID]
|
104
108
|
|
105
|
-
@string: String?
|
106
109
|
@integer: Integer
|
110
|
+
@encoded: String
|
107
111
|
@timestamp: String?
|
108
112
|
@randomness: String?
|
109
113
|
@inspect: String?
|
@@ -145,6 +149,16 @@ class ULID < Object
|
|
145
149
|
#
|
146
150
|
def self.generate: (?moment: moment, ?entropy: Integer) -> ULID
|
147
151
|
|
152
|
+
# Retuns encoded and normalzied String.
|
153
|
+
# It has same arguments signatures as `.generate`. So can be used for just ID creation usecases without needless object creation.
|
154
|
+
#
|
155
|
+
# NOTE: Difference of ULID#encode, returned String is NOT frozen.
|
156
|
+
#
|
157
|
+
def self.encode: (?moment: moment, ?entropy: Integer) -> String
|
158
|
+
|
159
|
+
# A private API. Should not be used in your code.
|
160
|
+
def self.encode_n32: (milliseconds: Integer, entropy: Integer) -> String
|
161
|
+
|
148
162
|
# Shorthand of `ULID.generate(moment: Time)`
|
149
163
|
# See also [ULID.generate](https://kachick.github.io/ruby-ulid/ULID.html#generate-class_method)
|
150
164
|
#
|
@@ -205,7 +219,7 @@ class ULID < Object
|
|
205
219
|
# ```
|
206
220
|
def self.floor: (Time time) -> Time
|
207
221
|
|
208
|
-
#
|
222
|
+
# Return ULID instance from encoded String.
|
209
223
|
#
|
210
224
|
# ```ruby
|
211
225
|
# ulid = ULID.parse('01ARZ3NDEKTSV4RRFFQ69G5FAV')
|
@@ -213,6 +227,32 @@ class ULID < Object
|
|
213
227
|
# ```
|
214
228
|
def self.parse: (_ToStr string) -> ULID
|
215
229
|
|
230
|
+
# Return Time instance from encoded String.
|
231
|
+
# See also `ULID.encode` for similar purpose.
|
232
|
+
#
|
233
|
+
# NOTE: Difference of ULID#to_time, returned Time is NOT frozen.
|
234
|
+
#
|
235
|
+
# ```ruby
|
236
|
+
# time = ULID.decode_time('01ARZ3NDEKTSV4RRFFQ69G5FAV')
|
237
|
+
# #=> 2016-07-30 23:54:10.259 UTC
|
238
|
+
# ```
|
239
|
+
def self.decode_time: (_ToStr string, ?in: String | Integer | nil) -> Time
|
240
|
+
|
241
|
+
# Get ULID instance from unnormalized String that encoded in Crockford's base32.
|
242
|
+
#
|
243
|
+
# http://www.crockford.com/base32.html
|
244
|
+
#
|
245
|
+
# * Ignore Hyphens (-)
|
246
|
+
# * Mapping 0 O o => 0, 1 I i L l => 1
|
247
|
+
#
|
248
|
+
# ```ruby
|
249
|
+
# ulid = ULID.parse_variant_format('01G70Y0Y7G-ZLXWDIREXERGSDoD')
|
250
|
+
# #=> ULID(2022-07-03 02:25:22.672 UTC: 01G70Y0Y7GZ1XWD1REXERGSD0D)
|
251
|
+
# ```
|
252
|
+
#
|
253
|
+
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
254
|
+
def self.parse_variant_format: (_ToStr string) -> ULID
|
255
|
+
|
216
256
|
# ```ruby
|
217
257
|
# # Currently experimental feature, so needed to load the extension.
|
218
258
|
# require 'ulid/uuid'
|
@@ -292,41 +332,30 @@ class ULID < Object
|
|
292
332
|
# ulid2 = ULID.parse('01F4PTVCSN9ZPFKYTY2DDJVRK4') #=> ULID(2021-05-02 15:23:48.917 UTC: 01F4PTVCSN9ZPFKYTY2DDJVRK4)
|
293
333
|
# ulids = ULID.sample(1000, period: ulid1..ulid2)
|
294
334
|
# ulids.uniq.size #=> 1000
|
295
|
-
# ulids.take(
|
335
|
+
# ulids.take(5)
|
296
336
|
# #=>
|
297
337
|
# #[ULID(2021-05-02 06:57:19.954 UTC: 01F4NXW02JNB8H0J0TK48JD39X),
|
298
338
|
# # ULID(2021-05-02 07:06:07.458 UTC: 01F4NYC372GVP7NS0YAYQGT4VZ),
|
299
339
|
# # ULID(2021-05-01 06:16:35.791 UTC: 01F4K94P6F6P68K0H64WRDSFKW),
|
300
340
|
# # ULID(2021-04-27 22:17:37.844 UTC: 01F4APHGSMFJZQTGXKZBFFBPJP),
|
301
|
-
# # ULID(2021-04-28 20:17:55.357 UTC: 01F4D231MXQJXAR8G2JZHEJNH3)
|
302
|
-
# # ULID(2021-04-30 07:18:54.307 UTC: 01F4GTA2332AS2VPHC4FMKC7R5),
|
303
|
-
# # ULID(2021-05-02 12:26:03.480 UTC: 01F4PGNXARG554Y3HYVBDW4T9S),
|
304
|
-
# # ULID(2021-04-29 09:52:15.107 UTC: 01F4EGP483ZX2747FQPWQNPPMW),
|
305
|
-
# # ULID(2021-04-29 03:18:24.152 UTC: 01F4DT4Z4RA0QV8WFQGRAG63EH),
|
306
|
-
# # ULID(2021-05-02 13:27:16.394 UTC: 01F4PM605ABF5SDVMEHBH8JJ9R)]
|
341
|
+
# # ULID(2021-04-28 20:17:55.357 UTC: 01F4D231MXQJXAR8G2JZHEJNH3)]
|
307
342
|
# ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
|
308
343
|
# #=>
|
309
344
|
# # [ULID(2021-04-29 06:44:41.513 UTC: 01F4E5YPD9XQ3MYXWK8ZJKY8SW),
|
310
345
|
# # ULID(2021-05-01 00:35:06.629 UTC: 01F4JNKD85SVK1EAEYSJGF53A2),
|
311
346
|
# # ULID(2021-05-02 12:45:28.408 UTC: 01F4PHSEYRG9BWBEWMRW1XE6WW),
|
312
347
|
# # ULID(2021-05-01 03:06:09.130 UTC: 01F4JY7ZBABCBMX16XH2Q4JW4W),
|
313
|
-
# # ULID(2021-04-29 21:38:58.109 UTC: 01F4FS45DX4049JEQK4W6TER6G)
|
314
|
-
# # ULID(2021-04-29 17:14:14.116 UTC: 01F4F9ZDQ449BE8BBZFEHYQWG2),
|
315
|
-
# # ULID(2021-04-30 16:18:08.205 UTC: 01F4HS5DPD1HWDVJNJ6YKJXKSK),
|
316
|
-
# # ULID(2021-04-30 10:31:33.602 UTC: 01F4H5ATF2A1CSQF0XV5NKZ288),
|
317
|
-
# # ULID(2021-04-28 16:49:06.484 UTC: 01F4CP4PDM214Q6H3KJP7DYJRR),
|
318
|
-
# # ULID(2021-04-28 15:05:06.808 UTC: 01F4CG68ZRST94T056KRZ5K9S4)]
|
348
|
+
# # ULID(2021-04-29 21:38:58.109 UTC: 01F4FS45DX4049JEQK4W6TER6G)]
|
319
349
|
# ```
|
320
350
|
def self.sample: (?period: period) -> ULID
|
321
351
|
| (Integer number, ?period: period?) -> Array[ULID]
|
322
|
-
def self.valid?: (untyped) -> bool
|
323
352
|
|
324
353
|
# Returns normalized string
|
325
354
|
#
|
326
355
|
# ```ruby
|
356
|
+
# ULID.normalize('01G70Y0Y7G-Z1XWDAREXERGSDDD') #=> "01G70Y0Y7GZ1XWDAREXERGSDDD"
|
327
357
|
# ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
|
328
|
-
# ULID.
|
329
|
-
# ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
|
358
|
+
# ULID.normalize('01G70Y0Y7G_Z1XWDAREXERGSDDD') #=> ULID::ParserError
|
330
359
|
# ```
|
331
360
|
#
|
332
361
|
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
@@ -335,13 +364,40 @@ class ULID < Object
|
|
335
364
|
# Returns `true` if it is normalized string
|
336
365
|
#
|
337
366
|
# ```ruby
|
338
|
-
# ULID.
|
339
|
-
# ULID.normalized?('-
|
340
|
-
# ULID.normalized?(
|
367
|
+
# ULID.normalized?('01G70Y0Y7GZ1XWDAREXERGSDDD') #=> true
|
368
|
+
# ULID.normalized?('01G70Y0Y7G-Z1XWDAREXERGSDDD') #=> false
|
369
|
+
# ULID.normalized?(ULID.generate.to_s.downcase) #=> false
|
370
|
+
# ULID.normalized?('01G70Y0Y7G_Z1XWDAREXERGSDDD') #=> false (Not raising ULID::ParserError)
|
341
371
|
# ```
|
342
372
|
#
|
343
373
|
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
344
|
-
def self.normalized?: (
|
374
|
+
def self.normalized?: (_ToStr string) -> bool
|
375
|
+
| (untyped) -> false
|
376
|
+
|
377
|
+
# Returns `true` if it is valid in ULID format variants
|
378
|
+
#
|
379
|
+
# ```ruby
|
380
|
+
# ULID.valid_as_variant_format?(ULID.generate.to_s.downcase) #=> true
|
381
|
+
# ULID.valid_as_variant_format?('01G70Y0Y7G-Z1XWDAREXERGSDDD') #=> true
|
382
|
+
# ULID.valid_as_variant_format?('01G70Y0Y7G_Z1XWDAREXERGSDDD') #=> false
|
383
|
+
# ```
|
384
|
+
#
|
385
|
+
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
386
|
+
def self.valid_as_variant_format?: (_ToStr string) -> bool
|
387
|
+
| (untyped) -> false
|
388
|
+
|
389
|
+
# DEPRECATED Use valid_as_variant_format? instead
|
390
|
+
#
|
391
|
+
# Returns `true` if it is normalized string.
|
392
|
+
# Basically the difference of normalized? is to accept downcase or not. This returns true for downcased ULIDs.
|
393
|
+
#
|
394
|
+
# ```ruby
|
395
|
+
# ULID.valid?(ULID.generate.to_s.downcase) #=> true
|
396
|
+
# ```
|
397
|
+
#
|
398
|
+
# See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
|
399
|
+
def self.valid?: (_ToStr string) -> bool
|
400
|
+
| (untyped) -> false
|
345
401
|
|
346
402
|
# Returns parsed ULIDs from given String for rough operations.
|
347
403
|
#
|
@@ -399,9 +455,12 @@ class ULID < Object
|
|
399
455
|
# ```ruby
|
400
456
|
# ulid = ULID.generate
|
401
457
|
# #=> ULID(2021-04-27 17:27:22.826 UTC: 01F4A5Y1YAQCYAYCTC7GRMJ9AA)
|
402
|
-
# ulid.
|
458
|
+
# ulid.encode #=> "01F4A5Y1YAQCYAYCTC7GRMJ9AA"
|
459
|
+
# ulid.encode.frozen? #=> true
|
460
|
+
# ulid.encode.equal?(ulid.to_s) #=> true
|
403
461
|
# ```
|
404
|
-
def
|
462
|
+
def encode: -> String
|
463
|
+
alias to_s encode
|
405
464
|
|
406
465
|
# ```ruby
|
407
466
|
# ulid = ULID.generate
|
@@ -421,7 +480,12 @@ class ULID < Object
|
|
421
480
|
# #=> true
|
422
481
|
# ```
|
423
482
|
#
|
424
|
-
# 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.
|
483
|
+
# 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.
|
484
|
+
# So preferable than `lexicographically sortable` in actual case.
|
485
|
+
#
|
486
|
+
# This returns -1 | 0 | 1 for ULIDs. However defined as returning Integer. It is caused on ruby/rbs current definition.
|
487
|
+
# https://github.com/ruby/ruby/blob/cd34f56d450f2310cceaf4c5f34d23eddfda58e8/numeric.c#L4646-L4660
|
488
|
+
# https://github.com/ruby/rbs/blob/14abbbae8885a09a2ed82de2ef31d67a9c0a108d/core/integer.rbs#L461-L462
|
425
489
|
#
|
426
490
|
def <=>: (ULID other) -> Integer
|
427
491
|
| (untyped other) -> nil
|
@@ -436,9 +500,28 @@ class ULID < Object
|
|
436
500
|
# ULID.parse('4NNB20D9C1ME2NGMTX51ERZJX0') == ULID.parse('4nnb20d9c1me2ngmtx51erzjx0')
|
437
501
|
# #=> true
|
438
502
|
# ```
|
439
|
-
def eql?: (
|
503
|
+
def eql?: (ULID other) -> bool
|
504
|
+
| (untyped other) -> false
|
440
505
|
alias == eql?
|
441
|
-
|
506
|
+
|
507
|
+
# Return `true` for same value of ULID, variant formats of strings, same Time in ULID precision(msec).
|
508
|
+
# Do not consider integer, octets and partial strings, then returns `false`.
|
509
|
+
#
|
510
|
+
# ```ruby
|
511
|
+
# ulid = ULID.parse('01G6Z7Q4RSH97E6QHAC7VK19G2')
|
512
|
+
# ulid === ULID.parse(ulid.to_s)
|
513
|
+
# #=> true
|
514
|
+
# ulid === ulid.to_s.downcase
|
515
|
+
# #=> true
|
516
|
+
# ulid === ulid.to_time
|
517
|
+
# #=> true
|
518
|
+
# ulid === ulid.to_i
|
519
|
+
# #=> false
|
520
|
+
# ulid === ulid.next
|
521
|
+
# #=> false
|
522
|
+
# ```
|
523
|
+
def ===: (ULID | String | Time other) -> bool
|
524
|
+
| (untyped other) -> false
|
442
525
|
|
443
526
|
# ```ruby
|
444
527
|
# ulid = ULID.generate
|
@@ -526,9 +609,6 @@ class ULID < Object
|
|
526
609
|
|
527
610
|
private
|
528
611
|
|
529
|
-
# A private API. Should not be used in your code.
|
530
|
-
def self.new: (milliseconds: Integer, entropy: Integer, integer: Integer) -> ULID
|
531
|
-
|
532
612
|
# A private API. Should not be used in your code.
|
533
613
|
def self.reasonable_entropy: -> Integer
|
534
614
|
|
@@ -539,7 +619,7 @@ class ULID < Object
|
|
539
619
|
def self.safe_get_class_name: (untyped object) -> String
|
540
620
|
|
541
621
|
# A private API. Should not be used in your code.
|
542
|
-
def initialize: (milliseconds: Integer, entropy: Integer, integer: Integer) -> void
|
622
|
+
def initialize: (milliseconds: Integer, entropy: Integer, integer: Integer, encoded: String) -> void
|
543
623
|
|
544
624
|
# A private API. Should not be used in your code.
|
545
625
|
def cache_all_instance_variables: -> void
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ulid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.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: 2022-
|
11
|
+
date: 2022-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: " generator,
|
14
|
-
|
13
|
+
description: " generator, optional monotonicity, parser and tools for ULID (RBS
|
14
|
+
included)\n"
|
15
15
|
email:
|
16
16
|
- kachick1+ruby@gmail.com
|
17
17
|
executables: []
|
@@ -23,7 +23,9 @@ files:
|
|
23
23
|
- lib/ruby-ulid.rb
|
24
24
|
- lib/ulid.rb
|
25
25
|
- lib/ulid/crockford_base32.rb
|
26
|
+
- lib/ulid/errors.rb
|
26
27
|
- lib/ulid/monotonic_generator.rb
|
28
|
+
- lib/ulid/ractor_unshareable_constants.rb
|
27
29
|
- lib/ulid/uuid.rb
|
28
30
|
- lib/ulid/version.rb
|
29
31
|
- sig/ulid.rbs
|