ulid-ruby 0.1.1 → 1.0.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 +13 -6
- data/lib/ulid/generate.rb +17 -4
- data/lib/ulid/identifier.rb +1 -1
- data/lib/ulid/parse.rb +10 -4
- data/lib/ulid/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b33ec732493540f7f7ccd651a3ca4e36a901423
|
4
|
+
data.tar.gz: 3fb34fa672516f5bca5d2ba9a371244104ce22e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce0fea3b8a2db1694e3c5c7be1b912a661ac6d8e5cb8afd1951879f823bb339dd18e7dddb40a2c34b778b4770fdb69e29fc9c57d0e48e4ee2e1a546ada9f5c94
|
7
|
+
data.tar.gz: 820f5d5804d4a8f364216ee75da1b8acc4eb26ec96ea90632aa053fa6cb5b435e0dee78803b80cfcec57c8c42d393d48c48ebd74f5fb9880044f551e1c022cbc
|
data/README.md
CHANGED
@@ -7,16 +7,13 @@
|
|
7
7
|
<br>
|
8
8
|
</h1>
|
9
9
|
|
10
|
-
## -- unofficial --
|
11
|
-
|
12
10
|
# ULID
|
13
11
|
|
14
12
|
A ULID is a "Universally Unique Lexicographically-sortable Identifier." In its string form, a ULID is a compact, URL-friendly, Base32, unique ID string that encodes its time of creation and sorts according the time value it encodes. [Crockford's Base32](https://en.wikipedia.org/wiki/Base32#Crockford.27s_Base32) alphabet is used in encoding because it's easy to sort, unambiguous in its choice of letters, and like most Base32 encoding schemes is case-insensitive.
|
15
13
|
|
14
|
+
This is a Ruby library for **generating** and **parsing** ULID values. This code is based on the original concept presented at https://github.com/alizain/ulid and in part based on code from the C# and Go projects at https://github.com/RobThree/NUlid and https://github.com/oklog/ulid respectively.
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
**NOTE:** while the ULID values generated are compatible with the existing Ruby ULID library located at https://github.com/rafaelsales/ulid, this library is not code-compatible and it provides additinal features. While working on Adafruit IO, we needed to generate time-based, lexicographically sortable IDs _and_ we needed to be able to get the time value back out. At one point we used Cassandra and its native Time UUID type, but that didn't translate well to DynamoDB and its use of sort keys. ULIDs were found to be an acceptable choice and it was easier to just rebuild the existing functionality of [rafaelsales/ulid](https://github.com/rafaelsales/ulid) while adding parsing. This tool may not be useful for anyone else but it's working for us in production at https://io.adafruit.com.
|
16
|
+
**NOTE:** while the ULID values generated are compatible with the original Ruby ULID library located at https://github.com/rafaelsales/ulid, this library is not code-compatible and it provides additional features. While working on Adafruit IO, we needed to generate time-based, lexicographically sortable IDs _and_ we needed to be able to get the time value back out. At one point we used Cassandra and its native Time UUID type, but that didn't translate well to DynamoDB and its use of sort keys. ULIDs were found to be an acceptable choice and it was easier to just rebuild the existing functionality of [rafaelsales/ulid](https://github.com/rafaelsales/ulid) while adding parsing. This tool may not be useful for anyone else but it's working for us in production at https://io.adafruit.com.
|
20
17
|
|
21
18
|
|
22
19
|
A ULID string looks like this:
|
@@ -52,6 +49,12 @@ The two parts of a ULID are **Timestamp** and **Entropy**.
|
|
52
49
|
|
53
50
|
The left-most character must be sorted first, and the right-most character sorted last (lexical order). The default ASCII character set must be used. Within the same millisecond, sort order is not guaranteed.
|
54
51
|
|
52
|
+
## What is good for?
|
53
|
+
|
54
|
+
Uniquely identifying records and ordering them by time, with precision of 1 millisecond in a distributed system. Unlike time-based UUIDs, ULIDs are lexically sortable. They're also shorter, which is nice.
|
55
|
+
|
56
|
+
We're using it in [Adafruit IO](https://io.adafruit.com) to generate time-based IDs for an [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) table. We're using ULIDs for the sort key (part of the table's composite primary key) on a table that's holding time-series data, which means that because DynamoDB sorts lexically and we only care about the data in time order, ULIDs give us unique, mostly unguessable ID, time-ordered data without any secondary indexes.
|
57
|
+
|
55
58
|
## Installation
|
56
59
|
|
57
60
|
Add this line to your application's Gemfile:
|
@@ -85,8 +88,12 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
85
88
|
|
86
89
|
Bug reports and pull requests are welcome on GitHub at https://github.com/abachman/ulid-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
87
90
|
|
88
|
-
|
89
91
|
## License
|
90
92
|
|
91
93
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
92
94
|
|
95
|
+
## Changes
|
96
|
+
|
97
|
+
#### 1.0.0
|
98
|
+
|
99
|
+
- fixes incorrect string packing / unpacking which caused incompatible ULID generation and parsing. This is a critical bug and any ULIDs generated with version < 1.0.0 will sort incorrectly.
|
data/lib/ulid/generate.rb
CHANGED
@@ -60,12 +60,25 @@ module ULID
|
|
60
60
|
SecureRandom.random_bytes(10)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
(@time.to_f *
|
63
|
+
def millisecond_time
|
64
|
+
(@time.to_f * 1_000).to_i
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
# THIS IS CORRECT (to the ULID spec)
|
68
|
+
def time_bytes
|
69
|
+
id = []
|
70
|
+
|
71
|
+
t = millisecond_time
|
72
|
+
|
73
|
+
# via https://github.com/oklog/ulid/blob/c3c01856f7e43fa64133819126887124d5f05e39/ulid.go#L295
|
74
|
+
id << [t >> 40].pack('c')
|
75
|
+
id << [t >> 32].pack('c')
|
76
|
+
id << [t >> 24].pack('c')
|
77
|
+
id << [t >> 16].pack('c')
|
78
|
+
id << [t >> 8].pack('c')
|
79
|
+
id << [t].pack('c')
|
80
|
+
|
81
|
+
id.join
|
69
82
|
end
|
70
83
|
end
|
71
84
|
end
|
data/lib/ulid/identifier.rb
CHANGED
data/lib/ulid/parse.rb
CHANGED
@@ -39,13 +39,19 @@ module ULID
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def unpack_decoded_bytes(packed_bytes)
|
42
|
-
time_bytes = packed_bytes[0..5]
|
42
|
+
time_bytes = packed_bytes[0..5].bytes.map(&:to_i)
|
43
43
|
seed = packed_bytes[6..-1]
|
44
44
|
|
45
45
|
# and unpack it immedieately into the original milliseconds timestamp
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
# via https://github.com/oklog/ulid/blob/c3c01856f7e43fa64133819126887124d5f05e39/ulid.go#L265
|
47
|
+
time_int = time_bytes[5].to_i |
|
48
|
+
(time_bytes[4].to_i << 8) |
|
49
|
+
(time_bytes[3].to_i << 16) |
|
50
|
+
(time_bytes[2].to_i << 24) |
|
51
|
+
(time_bytes[1].to_i << 32) |
|
52
|
+
(time_bytes[0].to_i << 40)
|
53
|
+
|
54
|
+
[ Time.at( time_int * 0.001 ).utc, seed ]
|
49
55
|
end
|
50
56
|
|
51
57
|
end
|
data/lib/ulid/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ulid-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Bachman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|