ruby-ulid 0.6.1 → 0.7.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 +28 -28
- data/lib/ulid/crockford_base32.rb +13 -12
- data/lib/ulid/monotonic_generator.rb +12 -5
- data/lib/ulid/utils.rb +117 -0
- data/lib/ulid/uuid.rb +3 -1
- data/lib/ulid/version.rb +1 -1
- data/lib/ulid.rb +65 -130
- data/sig/ulid.rbs +33 -37
- metadata +3 -3
- data/lib/ulid/ractor_unshareable_constants.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 637c2b95fc9d18a59e1bc6d23a3791bc80362b146c52ff962c407894c29c782e
|
4
|
+
data.tar.gz: 74a9e3ea4be5d9a541d4cb6dd012997406ef3cb68a08f7a1a42959f40f7ab4e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c39c42f8da0aac22356cb26fefb7d23855d118f68148be90c1e253577847b91135f8a04ef1fdca1af59075bd673e61cf2f492f046f30616f7c6b493e28332174
|
7
|
+
data.tar.gz: 623f7f9b4d46e46c2a47a143330b3d1c2cf83a033e83c8e68ab3af13e56f1ff5a082b3a15f57efcf4a3180fcc5786e18e94a0221fd03c44343322d641b69e31a
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# ruby-ulid
|
2
2
|
|
3
|
-
[![Build Status](https://github.com/kachick/ruby-ulid/actions/workflows/
|
3
|
+
[![Build Status](https://github.com/kachick/ruby-ulid/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/kachick/ruby-ulid/actions/workflows/ci.yml?query=branch%3Amain)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/ruby-ulid.svg)](http://badge.fury.io/rb/ruby-ulid)
|
5
5
|
|
6
6
|
## Overview
|
7
7
|
|
8
|
-
[ulid/spec](https://github.com/ulid/spec)
|
9
|
-
Especially possess all `uniqueness`, `randomness`, `extractable timestamps` and `
|
10
|
-
This gem aims to provide the generator, optional monotonicity, parser and other manipulation
|
8
|
+
[ulid/spec](https://github.com/ulid/spec) has some useful features.\
|
9
|
+
Especially possess all `uniqueness`, `randomness`, `extractable timestamps` and `sortability`.\
|
10
|
+
This gem aims to provide the generator, optional monotonicity, parser and other manipulation ways around ULID with included [RBS](https://github.com/ruby/rbs).
|
11
11
|
|
12
12
|
---
|
13
13
|
|
@@ -49,7 +49,7 @@ Should be installed!
|
|
49
49
|
Add this line in your Gemfile.
|
50
50
|
|
51
51
|
```ruby
|
52
|
-
gem('ruby-ulid', '~> 0.
|
52
|
+
gem('ruby-ulid', '~> 0.7.0')
|
53
53
|
```
|
54
54
|
|
55
55
|
### How to use
|
@@ -58,10 +58,10 @@ gem('ruby-ulid', '~> 0.6.1')
|
|
58
58
|
require 'ulid'
|
59
59
|
|
60
60
|
ULID::VERSION
|
61
|
-
# => "0.
|
61
|
+
# => "0.7.0"
|
62
62
|
```
|
63
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.
|
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.7.0).
|
65
65
|
|
66
66
|
### Generator and Parser
|
67
67
|
|
@@ -99,9 +99,9 @@ ULID.generate(moment: time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB006WQT
|
|
99
99
|
ULID.at(time) #=> ULID(2000-01-01 00:00:00.000 UTC: 00VHNCZB002W5BGWWKN76N22H6)
|
100
100
|
```
|
101
101
|
|
102
|
-
Also `ULID.encode` and `ULID.decode_time` can be used to get primitive values for most usecases.
|
102
|
+
Also `ULID.encode` and `ULID.decode_time` can be used to get primitive values for most usecases.
|
103
103
|
|
104
|
-
`ULID.encode` returns [normalized](#variants-of-format) String without ULID object creation
|
104
|
+
`ULID.encode` returns [normalized](#variants-of-format) String without ULID object creation.\
|
105
105
|
It can take same arguments as `ULID.generate`.
|
106
106
|
|
107
107
|
```ruby
|
@@ -116,13 +116,13 @@ ULID.decode_time('00VHNCZB00SYG7RCEXZC9DA4E1') #=> 2000-01-01 00:00:00 UTC
|
|
116
116
|
ULID.decode_time('00VHNCZB00SYG7RCEXZC9DA4E1', in: '+09:00') #=> 2000-01-01 09:00:00 +0900
|
117
117
|
```
|
118
118
|
|
119
|
-
This project does not prioritize the speed. However it actually works faster than others! :zap:
|
119
|
+
This project does not prioritize on the speed. However it actually works faster than others! :zap:
|
120
120
|
|
121
|
-
Snapshot on 0.
|
121
|
+
Snapshot on 0.7.0 is below
|
122
122
|
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
- Generator is 1.6x faster than - [ulid gem](https://github.com/rafaelsales/ulid)
|
124
|
+
- Generator is 1.9x 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
126
|
|
127
127
|
You can see further detail at [Benchmark](https://github.com/kachick/ruby-ulid/wiki/Benchmark).
|
128
128
|
|
@@ -151,7 +151,7 @@ ulids.sort == ulids #=> false
|
|
151
151
|
|
152
152
|
### How to keep `Sortable` even if in same timestamp
|
153
153
|
|
154
|
-
If you want to prefer `sortable`, Use `MonotonicGenerator` instead. It is called as [Monotonicity](https://github.com/ulid/spec/tree/d0c7170df4517939e70129b4d6462cc162f2d5bf#monotonicity) on the spec
|
154
|
+
If you want to prefer `sortable`, Use `MonotonicGenerator` instead. It is called as [Monotonicity](https://github.com/ulid/spec/tree/d0c7170df4517939e70129b4d6462cc162f2d5bf#monotonicity) on the spec.\
|
155
155
|
(Though it starts with new random value when changed the timestamp)
|
156
156
|
|
157
157
|
```ruby
|
@@ -195,7 +195,7 @@ ulids.grep(one_of_the_above)
|
|
195
195
|
ulids.grep_v(one_of_the_above)
|
196
196
|
```
|
197
197
|
|
198
|
-
When want to filter ULIDs with `Time`, we should consider to handle the precision
|
198
|
+
When want to filter ULIDs with `Time`, we should consider to handle the precision.\
|
199
199
|
So this gem provides `ULID.range` to generate reasonable `Range[ULID]` from `Range[Time]`
|
200
200
|
|
201
201
|
```ruby
|
@@ -294,7 +294,7 @@ ULID.max(time) #=> ULID(2000-01-01 00:00:00.123 UTC: 00VHNCZB3VZZZZZZZZZZZZZZZZ)
|
|
294
294
|
|
295
295
|
#### As element in Enumerable
|
296
296
|
|
297
|
-
`ULID#next` and `ULID#succ` returns next(successor) ULID
|
297
|
+
`ULID#next` and `ULID#succ` returns next(successor) ULID.\
|
298
298
|
Especially `ULID#succ` makes it possible `Range[ULID]#each`.
|
299
299
|
|
300
300
|
NOTE: However basically `Range[ULID]#each` should not be used. Incrementing 128 bits IDs are not reasonable operation in most cases.
|
@@ -360,15 +360,15 @@ ULID.sample(5, period: ulid1.to_time..ulid2.to_time)
|
|
360
360
|
|
361
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.
|
362
362
|
|
363
|
-
>Case insensitive
|
363
|
+
> Case insensitive
|
364
364
|
|
365
|
-
I can understand it might be considered in actual use-case. So `ULID.parse` accepts upcase and downcase
|
365
|
+
I can understand it might be considered in actual use-case. So `ULID.parse` accepts upcase and downcase.\
|
366
366
|
However it is a controversial point, discussing in [ulid/spec#3](https://github.com/ulid/spec/issues/3).
|
367
367
|
|
368
|
-
>Uses Crockford's base32 for better efficiency and readability (5 bits per character)
|
368
|
+
> Uses Crockford's base32 for better efficiency and readability (5 bits per character)
|
369
369
|
|
370
|
-
The original `Crockford's base32` maps `I`, `L` to `1`, `O` to `0
|
371
|
-
And accepts freestyle inserting `Hyphens (-)
|
370
|
+
The original `Crockford's base32` maps `I`, `L` to `1`, `O` to `0`.\
|
371
|
+
And accepts freestyle inserting `Hyphens (-)`.\
|
372
372
|
To consider this patterns or not is different in each implementations.
|
373
373
|
|
374
374
|
I have suggested to clarify `subset of Crockford's base32` in [ulid/spec#57](https://github.com/ulid/spec/pull/57).
|
@@ -387,7 +387,7 @@ ULID.parse_variant_format('01G70Y0Y7G-ZLXWDIREXERGSDoD') #=> ULID(2022-07-03 02:
|
|
387
387
|
|
388
388
|
#### UUIDv4 converter (experimental)
|
389
389
|
|
390
|
-
`ULID.from_uuidv4` and `ULID#to_uuidv4` is the converter
|
390
|
+
`ULID.from_uuidv4` and `ULID#to_uuidv4` is the converter.\
|
391
391
|
The imported timestamp is meaningless. So ULID's benefit will lost.
|
392
392
|
|
393
393
|
```ruby
|
@@ -426,11 +426,11 @@ See [wiki page for gem migration](https://github.com/kachick/ruby-ulid/wiki/Gem-
|
|
426
426
|
|
427
427
|
Try at [examples/rbs_sandbox](https://github.com/kachick/ruby-ulid/tree/main/examples/rbs_sandbox).
|
428
428
|
|
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) +
|
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).
|
430
430
|
|
431
|
-
|
432
|
-
|
433
|
-
|
431
|
+
- ![rbs overview](./assets/ulid-rbs-overview.png?raw=true.png)
|
432
|
+
- ![rbs mix](./assets/ulid-rbs-mix.png?raw=true.png)
|
433
|
+
- ![rbs ng-to_str](./assets/ulid-rbs-ng-to_str.png?raw=true.png)
|
434
434
|
|
435
435
|
## References
|
436
436
|
|
@@ -440,5 +440,5 @@ I have checked the behavior with [ruby/rbs@2.6.0](https://github.com/ruby/rbs) +
|
|
440
440
|
|
441
441
|
## Note
|
442
442
|
|
443
|
-
- [UUIDv6, UUIDv7, UUIDv8](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-01.html) is another choice for sortable and randomness ID
|
443
|
+
- [UUIDv6, UUIDv7, UUIDv8](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-01.html) is another choice for sortable and randomness ID.\
|
444
444
|
However they are stayed in draft state. ref: [ruby-ulid#37](https://github.com/kachick/ruby-ulid/issues/37)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
-
# shareable_constant_value: literal
|
4
3
|
|
5
4
|
# Copyright (C) 2021 Kenichi Kamiya
|
6
5
|
|
6
|
+
require_relative('utils')
|
7
|
+
|
7
8
|
class ULID
|
8
9
|
# @see https://www.crockford.com/base32.html
|
9
10
|
#
|
@@ -68,36 +69,36 @@ class ULID
|
|
68
69
|
VARIANT_TR_PATTERN = variant_to_normarized.keys.join.freeze
|
69
70
|
NORMALIZED_TR_PATTERN = variant_to_normarized.values.join.freeze
|
70
71
|
|
72
|
+
Utils.make_sharable_constantans(self)
|
73
|
+
|
71
74
|
# @note Avoid to depend regex as possible. `tr(string, string)` is almost 2x Faster than `gsub(regex, hash)` in Ruby 3.1
|
72
75
|
|
73
|
-
# @api private
|
74
76
|
# @param [String] string
|
75
77
|
# @return [Integer]
|
76
78
|
def self.decode(string)
|
77
|
-
|
78
|
-
|
79
|
+
base32encoded = string.upcase.tr(CROCKFORD_TR_PATTERN, BASE32_TR_PATTERN)
|
80
|
+
Integer(base32encoded, 32, exception: true)
|
79
81
|
end
|
80
82
|
|
81
|
-
# @api private
|
82
83
|
# @param [Integer] integer
|
83
84
|
# @return [String]
|
84
85
|
def self.encode(integer)
|
85
|
-
|
86
|
-
|
86
|
+
base32encoded = integer.to_s(32)
|
87
|
+
from_base32(base32encoded).rjust(ENCODED_LENGTH, '0')
|
87
88
|
end
|
88
89
|
|
89
|
-
# @api private
|
90
90
|
# @param [String] string
|
91
91
|
# @return [String]
|
92
92
|
def self.normalize(string)
|
93
93
|
string.delete('-').tr(VARIANT_TR_PATTERN, NORMALIZED_TR_PATTERN)
|
94
94
|
end
|
95
95
|
|
96
|
-
# @
|
97
|
-
# @param [String] n32encoded
|
96
|
+
# @param [String] base32encoded
|
98
97
|
# @return [String]
|
99
|
-
def self.
|
100
|
-
|
98
|
+
def self.from_base32(base32encoded)
|
99
|
+
base32encoded.upcase.tr(BASE32_TR_PATTERN, CROCKFORD_TR_PATTERN)
|
101
100
|
end
|
102
101
|
end
|
102
|
+
|
103
|
+
private_constant(:CrockfordBase32)
|
103
104
|
end
|
@@ -4,6 +4,9 @@
|
|
4
4
|
|
5
5
|
# Copyright (C) 2021 Kenichi Kamiya
|
6
6
|
|
7
|
+
require_relative('errors')
|
8
|
+
require_relative('utils')
|
9
|
+
|
7
10
|
class ULID
|
8
11
|
class MonotonicGenerator
|
9
12
|
# @note When use https://github.com/ko1/ractor-tvar might realize Ractor based thread safe monotonic generator.
|
@@ -11,7 +14,8 @@ class ULID
|
|
11
14
|
include(MonitorMixin)
|
12
15
|
|
13
16
|
# @return [ULID, nil]
|
14
|
-
|
17
|
+
attr_accessor(:prev)
|
18
|
+
private(:prev=)
|
15
19
|
|
16
20
|
undef_method(:instance_variable_set)
|
17
21
|
|
@@ -31,7 +35,7 @@ class ULID
|
|
31
35
|
# @raise [OverflowError] if the entropy part is larger than the ULID limit in same milliseconds
|
32
36
|
# @raise [UnexpectedError] if the generated ULID is an invalid value in monotonicity spec.
|
33
37
|
# Basically will not happen. Just means this feature prefers error rather than invalid value.
|
34
|
-
def generate(moment:
|
38
|
+
def generate(moment: Utils.current_milliseconds)
|
35
39
|
synchronize do
|
36
40
|
prev_ulid = @prev
|
37
41
|
unless prev_ulid
|
@@ -40,13 +44,13 @@ class ULID
|
|
40
44
|
return ret
|
41
45
|
end
|
42
46
|
|
43
|
-
milliseconds =
|
47
|
+
milliseconds = Utils.milliseconds_from_moment(moment)
|
44
48
|
|
45
49
|
ulid = (
|
46
50
|
if prev_ulid.milliseconds < milliseconds
|
47
51
|
ULID.generate(moment: milliseconds)
|
48
52
|
else
|
49
|
-
ULID.
|
53
|
+
ULID.generate(moment: prev_ulid.milliseconds, entropy: prev_ulid.entropy.succ)
|
50
54
|
end
|
51
55
|
)
|
52
56
|
|
@@ -68,9 +72,12 @@ class ULID
|
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
75
|
+
# Just providing similar api as `ULID.generate` and `ULID.encode` relation. No performance benefit exists in monotonic generator's one.
|
76
|
+
#
|
77
|
+
# @see https://github.com/kachick/ruby-ulid/pull/220
|
71
78
|
# @param [Time, Integer] moment
|
72
79
|
# @return [String]
|
73
|
-
def encode(moment:
|
80
|
+
def encode(moment: Utils.current_milliseconds)
|
74
81
|
generate(moment: moment).encode
|
75
82
|
end
|
76
83
|
|
data/lib/ulid/utils.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# coding: us-ascii
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# shareable_constant_value: literal
|
4
|
+
|
5
|
+
# Copyright (C) 2021 Kenichi Kamiya
|
6
|
+
|
7
|
+
require('securerandom')
|
8
|
+
|
9
|
+
class ULID
|
10
|
+
# @note I don't have confidence for the naming of `Utils`. However some standard libraries have same name.
|
11
|
+
# https://github.com/ruby/webrick/blob/14612a7540fdd7373344461851c4bfff64985b3e/lib/webrick/utils.rb#L17
|
12
|
+
# https://docs.ruby-lang.org/ja/latest/class/ERB=3a=3aUtil.html
|
13
|
+
# https://github.com/ruby/rss/blob/af1c3c9c9630ec0a48abec48ed1ef348ba82aa13/lib/rss/utils.rb#L9
|
14
|
+
module Utils
|
15
|
+
# @return [Integer]
|
16
|
+
def self.current_milliseconds
|
17
|
+
milliseconds_from_time(Time.now)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [Time] time
|
21
|
+
# @return [Integer]
|
22
|
+
def self.milliseconds_from_time(time)
|
23
|
+
(time.to_r * 1000).to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [Time, Integer] moment
|
27
|
+
# @return [Integer]
|
28
|
+
def self.milliseconds_from_moment(moment)
|
29
|
+
case moment
|
30
|
+
when Integer
|
31
|
+
moment
|
32
|
+
when Time
|
33
|
+
milliseconds_from_time(moment)
|
34
|
+
else
|
35
|
+
raise(ArgumentError, '`moment` should be a `Time` or `Integer as milliseconds`')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Integer]
|
40
|
+
def self.reasonable_entropy
|
41
|
+
SecureRandom.random_number(MAX_ENTROPY)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Integer] milliseconds
|
45
|
+
# @param [Integer] entropy
|
46
|
+
# @return [String]
|
47
|
+
# @raise [OverflowError] if the given value is larger than the ULID limit
|
48
|
+
# @raise [ArgumentError] if the given milliseconds and/or entropy is negative number
|
49
|
+
def self.encode_base32(milliseconds:, entropy:)
|
50
|
+
raise(ArgumentError, 'milliseconds and entropy should be an `Integer`') unless Integer === milliseconds && Integer === entropy
|
51
|
+
raise(OverflowError, "timestamp overflow: given #{milliseconds}, max: #{MAX_MILLISECONDS}") unless milliseconds <= MAX_MILLISECONDS
|
52
|
+
raise(OverflowError, "entropy overflow: given #{entropy}, max: #{MAX_ENTROPY}") unless entropy <= MAX_ENTROPY
|
53
|
+
raise(ArgumentError, 'milliseconds and entropy should not be negative') if milliseconds.negative? || entropy.negative?
|
54
|
+
|
55
|
+
base32encoded_timestamp = milliseconds.to_s(32).rjust(TIMESTAMP_ENCODED_LENGTH, '0')
|
56
|
+
base32encoded_randomness = entropy.to_s(32).rjust(RANDOMNESS_ENCODED_LENGTH, '0')
|
57
|
+
"#{base32encoded_timestamp}#{base32encoded_randomness}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [BasicObject] object
|
61
|
+
# @return [String]
|
62
|
+
def self.safe_get_class_name(object)
|
63
|
+
fallback = 'UnknownObject'
|
64
|
+
|
65
|
+
# This class getter implementation used https://github.com/rspec/rspec-support/blob/4ad8392d0787a66f9c351d9cf6c7618e18b3d0f2/lib/rspec/support.rb#L83-L89 as a reference, thank you!
|
66
|
+
# ref: https://twitter.com/_kachick/status/1400064896759304196
|
67
|
+
klass = (
|
68
|
+
begin
|
69
|
+
object.class
|
70
|
+
rescue NoMethodError
|
71
|
+
# steep can't correctly handle singleton class assign. See https://github.com/soutaro/steep/pull/586 for further detail
|
72
|
+
# So this annotation is hack for the type infer.
|
73
|
+
# @type var object: BasicObject
|
74
|
+
# @type var singleton_class: untyped
|
75
|
+
singleton_class = class << object; self; end
|
76
|
+
(Class === singleton_class) ? singleton_class.ancestors.detect { |ancestor| !ancestor.equal?(singleton_class) } : fallback
|
77
|
+
end
|
78
|
+
)
|
79
|
+
|
80
|
+
begin
|
81
|
+
name = String.try_convert(klass.name)
|
82
|
+
rescue Exception
|
83
|
+
fallback
|
84
|
+
else
|
85
|
+
name || fallback
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.make_sharable_value(value)
|
90
|
+
value.freeze
|
91
|
+
if defined?(Ractor)
|
92
|
+
case value
|
93
|
+
when ULID, Time
|
94
|
+
if ractor_can_make_shareable_time?
|
95
|
+
Ractor.make_shareable(value)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
Ractor.make_shareable(value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @note Call before Module#private_constant
|
104
|
+
def self.make_sharable_constantans(mod)
|
105
|
+
mod.constants.each do |const_name|
|
106
|
+
value = mod.const_get(const_name)
|
107
|
+
make_sharable_value(value)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.ractor_can_make_shareable_time?
|
112
|
+
RUBY_VERSION >= '3.1'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private_constant(:Utils)
|
117
|
+
end
|
data/lib/ulid/uuid.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
-
# shareable_constant_value: literal
|
4
3
|
|
5
4
|
# Copyright (C) 2021 Kenichi Kamiya
|
6
5
|
|
6
|
+
require_relative('errors')
|
7
|
+
|
7
8
|
# Extracted features around UUID from some reasons
|
8
9
|
# ref:
|
9
10
|
# * https://github.com/kachick/ruby-ulid/issues/105
|
@@ -11,6 +12,7 @@
|
|
11
12
|
class ULID
|
12
13
|
# Imported from https://stackoverflow.com/a/38191104/1212807, thank you!
|
13
14
|
UUIDV4_PATTERN = /\A[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i.freeze
|
15
|
+
Utils.make_sharable_value(UUIDV4_PATTERN)
|
14
16
|
private_constant(:UUIDV4_PATTERN)
|
15
17
|
|
16
18
|
# @param [String, #to_str] uuid
|
data/lib/ulid/version.rb
CHANGED
data/lib/ulid.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# coding: us-ascii
|
2
2
|
# frozen_string_literal: true
|
3
|
-
# shareable_constant_value: experimental_everything
|
4
3
|
|
5
4
|
# Copyright (C) 2021 Kenichi Kamiya
|
6
5
|
|
@@ -9,6 +8,7 @@ require('securerandom')
|
|
9
8
|
require_relative('ulid/version')
|
10
9
|
require_relative('ulid/errors')
|
11
10
|
require_relative('ulid/crockford_base32')
|
11
|
+
require_relative('ulid/utils')
|
12
12
|
require_relative('ulid/monotonic_generator')
|
13
13
|
|
14
14
|
# @see https://github.com/ulid/spec
|
@@ -46,13 +46,36 @@ class ULID
|
|
46
46
|
# @see https://github.com/ruby/ruby/blob/744d17ff6c33b09334508e8110007ea2a82252f5/time.c#L4026-L4078
|
47
47
|
TIME_FORMAT_IN_INSPECT = '%Y-%m-%d %H:%M:%S.%3N %Z'
|
48
48
|
|
49
|
+
RANDOM_INTEGER_GENERATOR = -> {
|
50
|
+
SecureRandom.random_number(MAX_INTEGER)
|
51
|
+
}.freeze
|
52
|
+
|
53
|
+
Utils.make_sharable_constantans(self)
|
54
|
+
|
55
|
+
private_constant(
|
56
|
+
:PATTERN_WITH_CROCKFORD_BASE32_SUBSET,
|
57
|
+
:STRICT_PATTERN_WITH_CROCKFORD_BASE32_SUBSET,
|
58
|
+
:SCANNING_PATTERN,
|
59
|
+
:TIME_FORMAT_IN_INSPECT,
|
60
|
+
:RANDOM_INTEGER_GENERATOR
|
61
|
+
)
|
62
|
+
|
49
63
|
private_class_method(:new)
|
50
64
|
|
51
65
|
# @param [Integer, Time] moment
|
52
66
|
# @param [Integer] entropy
|
53
67
|
# @return [ULID]
|
54
|
-
|
55
|
-
|
68
|
+
# @raise [OverflowError] if the given value is larger than the ULID limit
|
69
|
+
# @raise [ArgumentError] if the given milliseconds and/or entropy is negative number
|
70
|
+
def self.generate(moment: Utils.current_milliseconds, entropy: Utils.reasonable_entropy)
|
71
|
+
milliseconds = Utils.milliseconds_from_moment(moment)
|
72
|
+
base32_encoded = Utils.encode_base32(milliseconds: milliseconds, entropy: entropy)
|
73
|
+
new(
|
74
|
+
milliseconds: milliseconds,
|
75
|
+
entropy: entropy,
|
76
|
+
integer: base32_encoded.to_i(32),
|
77
|
+
encoded: CrockfordBase32.from_base32(base32_encoded).freeze
|
78
|
+
)
|
56
79
|
end
|
57
80
|
|
58
81
|
# Almost same as [.generate] except directly returning String without needless object creation
|
@@ -60,9 +83,9 @@ class ULID
|
|
60
83
|
# @param [Integer, Time] moment
|
61
84
|
# @param [Integer] entropy
|
62
85
|
# @return [String]
|
63
|
-
def self.encode(moment: current_milliseconds, entropy: reasonable_entropy)
|
64
|
-
|
65
|
-
CrockfordBase32.
|
86
|
+
def self.encode(moment: Utils.current_milliseconds, entropy: Utils.reasonable_entropy)
|
87
|
+
base32_encoded = Utils.encode_base32(milliseconds: Utils.milliseconds_from_moment(moment), entropy: entropy)
|
88
|
+
CrockfordBase32.from_base32(base32_encoded)
|
66
89
|
end
|
67
90
|
|
68
91
|
# Short hand of `ULID.generate(moment: time)`
|
@@ -71,7 +94,7 @@ class ULID
|
|
71
94
|
def self.at(time)
|
72
95
|
raise(ArgumentError, 'ULID.at takes only `Time` instance') unless Time === time
|
73
96
|
|
74
|
-
|
97
|
+
generate(moment: time)
|
75
98
|
end
|
76
99
|
|
77
100
|
# @param [Time, Integer] moment
|
@@ -86,10 +109,6 @@ class ULID
|
|
86
109
|
MAX_MILLISECONDS.equal?(moment) ? MAX : generate(moment: moment, entropy: MAX_ENTROPY)
|
87
110
|
end
|
88
111
|
|
89
|
-
RANDOM_INTEGER_GENERATOR = -> {
|
90
|
-
SecureRandom.random_number(MAX_INTEGER)
|
91
|
-
}.freeze
|
92
|
-
|
93
112
|
# @param [Range<Time>, Range<nil>, Range[ULID], nil] period
|
94
113
|
# @overload sample(number, period: nil)
|
95
114
|
# @param [Integer] number
|
@@ -162,20 +181,20 @@ class ULID
|
|
162
181
|
raise(OverflowError, "integer overflow: given #{integer}, max: #{MAX_INTEGER}") unless integer <= MAX_INTEGER
|
163
182
|
raise(ArgumentError, "integer should not be negative: given: #{integer}") if integer.negative?
|
164
183
|
|
165
|
-
|
166
|
-
|
167
|
-
|
184
|
+
base32encoded = integer.to_s(32).rjust(ENCODED_LENGTH, '0')
|
185
|
+
base32encoded_timestamp = base32encoded.slice(0, TIMESTAMP_ENCODED_LENGTH)
|
186
|
+
base32encoded_randomness = base32encoded.slice(TIMESTAMP_ENCODED_LENGTH, RANDOMNESS_ENCODED_LENGTH)
|
168
187
|
|
169
|
-
raise(UnexpectedError) unless
|
188
|
+
raise(UnexpectedError) unless base32encoded_timestamp && base32encoded_randomness
|
170
189
|
|
171
|
-
milliseconds =
|
172
|
-
entropy =
|
190
|
+
milliseconds = base32encoded_timestamp.to_i(32)
|
191
|
+
entropy = base32encoded_randomness.to_i(32)
|
173
192
|
|
174
193
|
new(
|
175
194
|
milliseconds: milliseconds,
|
176
195
|
entropy: entropy,
|
177
196
|
integer: integer,
|
178
|
-
encoded: CrockfordBase32.
|
197
|
+
encoded: CrockfordBase32.from_base32(base32encoded).freeze
|
179
198
|
)
|
180
199
|
end
|
181
200
|
|
@@ -232,49 +251,6 @@ class ULID
|
|
232
251
|
time.floor(3)
|
233
252
|
end
|
234
253
|
|
235
|
-
# @api private
|
236
|
-
# @return [Integer]
|
237
|
-
def self.current_milliseconds
|
238
|
-
milliseconds_from_time(Time.now)
|
239
|
-
end
|
240
|
-
|
241
|
-
# @api private
|
242
|
-
# @param [Time] time
|
243
|
-
# @return [Integer]
|
244
|
-
private_class_method def self.milliseconds_from_time(time)
|
245
|
-
(time.to_r * 1000).to_i
|
246
|
-
end
|
247
|
-
|
248
|
-
# @api private
|
249
|
-
# @param [Time, Integer] moment
|
250
|
-
# @return [Integer]
|
251
|
-
def self.milliseconds_from_moment(moment)
|
252
|
-
case moment
|
253
|
-
when Integer
|
254
|
-
moment
|
255
|
-
when Time
|
256
|
-
milliseconds_from_time(moment)
|
257
|
-
else
|
258
|
-
raise(ArgumentError, '`moment` should be a `Time` or `Integer as milliseconds`')
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
# @return [Integer]
|
263
|
-
private_class_method def self.reasonable_entropy
|
264
|
-
SecureRandom.random_number(MAX_ENTROPY)
|
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
|
277
|
-
|
278
254
|
# @param [String, #to_str] string
|
279
255
|
# @return [ULID]
|
280
256
|
# @raise [ParserError] if the given format is not correct for ULID specs
|
@@ -303,6 +279,7 @@ class ULID
|
|
303
279
|
# Almost same as `ULID.parse(string).to_time` except directly returning Time instance without needless object creation
|
304
280
|
#
|
305
281
|
# @param [String, #to_str] string
|
282
|
+
# @param [String, Integer, nil] in
|
306
283
|
# @return [Time]
|
307
284
|
# @raise [ParserError] if the given format is not correct for ULID specs
|
308
285
|
def self.decode_time(string, in: 'UTC')
|
@@ -375,74 +352,15 @@ class ULID
|
|
375
352
|
if ULID === converted
|
376
353
|
converted
|
377
354
|
else
|
378
|
-
object_class_name = safe_get_class_name(object)
|
379
|
-
converted_class_name = safe_get_class_name(converted)
|
355
|
+
object_class_name = Utils.safe_get_class_name(object)
|
356
|
+
converted_class_name = Utils.safe_get_class_name(converted)
|
380
357
|
raise(TypeError, "can't convert #{object_class_name} to ULID (#{object_class_name}#to_ulid gives #{converted_class_name})")
|
381
358
|
end
|
382
359
|
end
|
383
360
|
end
|
384
361
|
|
385
|
-
# @param [BasicObject] object
|
386
|
-
# @return [String]
|
387
|
-
private_class_method def self.safe_get_class_name(object)
|
388
|
-
fallback = 'UnknownObject'
|
389
|
-
|
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!
|
391
|
-
# ref: https://twitter.com/_kachick/status/1400064896759304196
|
392
|
-
klass = (
|
393
|
-
begin
|
394
|
-
object.class
|
395
|
-
rescue NoMethodError
|
396
|
-
# steep can't correctly handle singleton class assign. See https://github.com/soutaro/steep/pull/586 for further detail
|
397
|
-
# So this annotation is hack for the type infer.
|
398
|
-
# @type var object: BasicObject
|
399
|
-
# @type var singleton_class: untyped
|
400
|
-
singleton_class = class << object; self; end
|
401
|
-
(Class === singleton_class) ? singleton_class.ancestors.detect { |ancestor| !ancestor.equal?(singleton_class) } : fallback
|
402
|
-
end
|
403
|
-
)
|
404
|
-
|
405
|
-
begin
|
406
|
-
name = String.try_convert(klass.name)
|
407
|
-
rescue Exception
|
408
|
-
fallback
|
409
|
-
else
|
410
|
-
name || fallback
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
# @api private
|
415
|
-
# @param [Integer] milliseconds
|
416
|
-
# @param [Integer] entropy
|
417
|
-
# @return [ULID]
|
418
|
-
# @raise [OverflowError] if the given value is larger than the ULID limit
|
419
|
-
# @raise [ArgumentError] if the given milliseconds and/or entropy is negative number
|
420
|
-
def self.from_milliseconds_and_entropy(milliseconds:, entropy:)
|
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
|
-
)
|
428
|
-
end
|
429
|
-
|
430
362
|
attr_reader(:milliseconds, :entropy)
|
431
363
|
|
432
|
-
# @api private
|
433
|
-
# @param [Integer] milliseconds
|
434
|
-
# @param [Integer] entropy
|
435
|
-
# @param [Integer] integer
|
436
|
-
# @param [String] encoded
|
437
|
-
# @return [void]
|
438
|
-
def initialize(milliseconds:, entropy:, integer:, encoded:)
|
439
|
-
# All arguments check should be done with each constructors, not here
|
440
|
-
@integer = integer
|
441
|
-
@encoded = encoded
|
442
|
-
@milliseconds = milliseconds
|
443
|
-
@entropy = entropy
|
444
|
-
end
|
445
|
-
|
446
364
|
# @return [String]
|
447
365
|
def encode
|
448
366
|
@encoded
|
@@ -578,18 +496,21 @@ class ULID
|
|
578
496
|
super
|
579
497
|
end
|
580
498
|
|
581
|
-
# @api private
|
582
499
|
# @return [Integer]
|
583
500
|
def marshal_dump
|
584
501
|
@integer
|
585
502
|
end
|
586
503
|
|
587
|
-
# @api private
|
588
504
|
# @param [Integer] integer
|
589
505
|
# @return [void]
|
590
506
|
def marshal_load(integer)
|
591
507
|
unmarshaled = ULID.from_integer(integer)
|
592
|
-
initialize(
|
508
|
+
initialize(
|
509
|
+
integer: unmarshaled.to_i,
|
510
|
+
milliseconds: unmarshaled.milliseconds,
|
511
|
+
entropy: unmarshaled.entropy,
|
512
|
+
encoded: unmarshaled.to_s
|
513
|
+
)
|
593
514
|
end
|
594
515
|
|
595
516
|
# @return [self]
|
@@ -611,17 +532,31 @@ class ULID
|
|
611
532
|
|
612
533
|
private
|
613
534
|
|
535
|
+
# @param [Integer] milliseconds
|
536
|
+
# @param [Integer] entropy
|
537
|
+
# @param [Integer] integer
|
538
|
+
# @param [String] encoded
|
539
|
+
# @return [void]
|
540
|
+
def initialize(milliseconds:, entropy:, integer:, encoded:)
|
541
|
+
# All arguments check should be done with each constructors, not here
|
542
|
+
@integer = integer
|
543
|
+
@encoded = encoded
|
544
|
+
@milliseconds = milliseconds
|
545
|
+
@entropy = entropy
|
546
|
+
end
|
547
|
+
|
614
548
|
# @return [void]
|
615
549
|
def cache_all_instance_variables
|
616
550
|
inspect
|
617
551
|
timestamp
|
618
552
|
randomness
|
619
553
|
end
|
620
|
-
end
|
621
554
|
|
622
|
-
|
555
|
+
MIN = parse('00000000000000000000000000').freeze
|
556
|
+
MAX = parse('7ZZZZZZZZZZZZZZZZZZZZZZZZZ').freeze
|
623
557
|
|
624
|
-
|
625
|
-
|
626
|
-
|
558
|
+
Utils.make_sharable_value(MIN)
|
559
|
+
Utils.make_sharable_value(MAX)
|
560
|
+
|
561
|
+
private_constant(:MIN, :MAX)
|
627
562
|
end
|
data/sig/ulid.rbs
CHANGED
@@ -19,8 +19,8 @@ class ULID < Object
|
|
19
19
|
MAX: ULID
|
20
20
|
include Comparable
|
21
21
|
|
22
|
-
|
23
|
-
type moment = Time |
|
22
|
+
type milliseconds = Integer
|
23
|
+
type moment = Time | milliseconds
|
24
24
|
|
25
25
|
class Error < StandardError
|
26
26
|
end
|
@@ -34,27 +34,42 @@ class ULID < Object
|
|
34
34
|
class UnexpectedError < Error
|
35
35
|
end
|
36
36
|
|
37
|
-
module
|
38
|
-
|
39
|
-
|
37
|
+
# Private module
|
38
|
+
module Utils
|
39
|
+
def self.encode_base32: (milliseconds: milliseconds, entropy: Integer) -> String
|
40
|
+
|
41
|
+
def self.current_milliseconds: -> milliseconds
|
42
|
+
|
43
|
+
def self.milliseconds_from_moment: (moment moment) -> milliseconds
|
44
|
+
|
45
|
+
def self.reasonable_entropy: -> Integer
|
46
|
+
|
47
|
+
def self.milliseconds_from_time: (Time time) -> milliseconds
|
48
|
+
|
49
|
+
def self.safe_get_class_name: (untyped object) -> String
|
40
50
|
|
51
|
+
def self.make_sharable_value: (untyped object) -> void
|
52
|
+
|
53
|
+
def self.make_sharable_constantans: (Module) -> void
|
54
|
+
|
55
|
+
def self.ractor_can_make_shareable_time?: -> bool
|
56
|
+
end
|
57
|
+
|
58
|
+
# Private module
|
59
|
+
module CrockfordBase32
|
41
60
|
ENCODING_STRING: String
|
42
61
|
CROCKFORD_TR_PATTERN: String
|
43
62
|
BASE32_TR_PATTERN: String
|
44
63
|
VARIANT_TR_PATTERN: String
|
45
64
|
NORMALIZED_TR_PATTERN: String
|
46
65
|
|
47
|
-
# A private API. Should not be used in your code.
|
48
66
|
def self.encode: (Integer integer) -> String
|
49
67
|
|
50
|
-
# A private API. Should not be used in your code.
|
51
68
|
def self.decode: (String string) -> Integer
|
52
69
|
|
53
|
-
# A private API. Should not be used in your code.
|
54
70
|
def self.normalize: (String string) -> String
|
55
71
|
|
56
|
-
|
57
|
-
def self.from_n32: (String n32encoded) -> String
|
72
|
+
def self.from_base32: (String base32encoded) -> String
|
58
73
|
end
|
59
74
|
|
60
75
|
class MonotonicGenerator
|
@@ -72,9 +87,6 @@ class ULID < Object
|
|
72
87
|
# ```
|
73
88
|
attr_reader prev: ULID | nil
|
74
89
|
|
75
|
-
# A private API. Should not be used in your code.
|
76
|
-
def initialize: -> void
|
77
|
-
|
78
90
|
# See [How to keep `Sortable` even if in same timestamp](https://github.com/kachick/ruby-ulid#how-to-keep-sortable-even-if-in-same-timestamp)
|
79
91
|
# The `Thread-safety` is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
|
80
92
|
def generate: (?moment: moment) -> ULID
|
@@ -95,6 +107,12 @@ class ULID < Object
|
|
95
107
|
def inspect: -> String
|
96
108
|
alias to_s inspect
|
97
109
|
def freeze: -> void
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def initialize: -> void
|
114
|
+
|
115
|
+
def prev=: (ULID?) -> void
|
98
116
|
end
|
99
117
|
|
100
118
|
interface _ToULID
|
@@ -156,9 +174,6 @@ class ULID < Object
|
|
156
174
|
#
|
157
175
|
def self.encode: (?moment: moment, ?entropy: Integer) -> String
|
158
176
|
|
159
|
-
# A private API. Should not be used in your code.
|
160
|
-
def self.encode_n32: (milliseconds: Integer, entropy: Integer) -> String
|
161
|
-
|
162
177
|
# Shorthand of `ULID.generate(moment: Time)`
|
163
178
|
# See also [ULID.generate](https://kachick.github.io/ruby-ulid/ULID.html#generate-class_method)
|
164
179
|
#
|
@@ -173,12 +188,6 @@ class ULID < Object
|
|
173
188
|
# ```
|
174
189
|
def self.at: (Time time) -> ULID
|
175
190
|
|
176
|
-
# A private API. Should not be used in your code.
|
177
|
-
def self.current_milliseconds: -> Integer
|
178
|
-
|
179
|
-
# A private API. Should not be used in your code.
|
180
|
-
def self.milliseconds_from_moment: (moment moment) -> Integer
|
181
|
-
|
182
191
|
# `ULID` can be element of the `Range`. If you generated the IDs in monotonic generator, ID based filtering is easy and reliable
|
183
192
|
#
|
184
193
|
# ```ruby
|
@@ -440,7 +449,7 @@ class ULID < Object
|
|
440
449
|
# ```
|
441
450
|
def self.scan: (_ToStr string) -> Enumerator[self, singleton(ULID)]
|
442
451
|
| (_ToStr string) { (ULID ulid) -> void } -> singleton(ULID)
|
443
|
-
|
452
|
+
|
444
453
|
def self.try_convert: (_ToULID) -> ULID
|
445
454
|
| (untyped) -> nil
|
446
455
|
|
@@ -591,10 +600,8 @@ class ULID < Object
|
|
591
600
|
def pred: -> ULID?
|
592
601
|
def freeze: -> self
|
593
602
|
|
594
|
-
# A private API. Should not be used in your code.
|
595
603
|
def marshal_dump: -> Integer
|
596
604
|
|
597
|
-
# A private API. Should not be used in your code.
|
598
605
|
def marshal_load: (Integer integer) -> void
|
599
606
|
|
600
607
|
# Returns `self`
|
@@ -609,18 +616,7 @@ class ULID < Object
|
|
609
616
|
|
610
617
|
private
|
611
618
|
|
612
|
-
|
613
|
-
def self.reasonable_entropy: -> Integer
|
614
|
-
|
615
|
-
# A private API. Should not be used in your code.
|
616
|
-
def self.milliseconds_from_time: (Time time) -> Integer
|
617
|
-
|
618
|
-
# A private API. Should not be used in your code.
|
619
|
-
def self.safe_get_class_name: (untyped object) -> String
|
620
|
-
|
621
|
-
# A private API. Should not be used in your code.
|
622
|
-
def initialize: (milliseconds: Integer, entropy: Integer, integer: Integer, encoded: String) -> void
|
619
|
+
def initialize: (milliseconds: milliseconds, entropy: Integer, integer: Integer, encoded: String) -> void
|
623
620
|
|
624
|
-
# A private API. Should not be used in your code.
|
625
621
|
def cache_all_instance_variables: -> void
|
626
622
|
end
|
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.
|
4
|
+
version: 0.7.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-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: " generator, optional monotonicity, parser and tools for ULID (RBS
|
14
14
|
included)\n"
|
@@ -25,7 +25,7 @@ files:
|
|
25
25
|
- lib/ulid/crockford_base32.rb
|
26
26
|
- lib/ulid/errors.rb
|
27
27
|
- lib/ulid/monotonic_generator.rb
|
28
|
-
- lib/ulid/
|
28
|
+
- lib/ulid/utils.rb
|
29
29
|
- lib/ulid/uuid.rb
|
30
30
|
- lib/ulid/version.rb
|
31
31
|
- sig/ulid.rbs
|
@@ -1,12 +0,0 @@
|
|
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
|