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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8396615efbd1df02008002962daa558d35055a4
4
- data.tar.gz: f941d284e3b2016ff39beb8cabf1f8f278e7adf1
3
+ metadata.gz: 9b33ec732493540f7f7ccd651a3ca4e36a901423
4
+ data.tar.gz: 3fb34fa672516f5bca5d2ba9a371244104ce22e3
5
5
  SHA512:
6
- metadata.gz: dcf9a90061bb217099b723dc60045f709d261697f76deef858b5397def088b7ce0c21ae1ab33bf77aae9a08287223d5e6b7b6a519d0bc0aa5ba666b6561d510e
7
- data.tar.gz: 2c09e47a2e235835fe1588dbeba56f7e89de60dfd00660a4ef348c6bd819df78d53ea4b5e73f5aa06a717fe3c3b15605d2e19fadfccf3a51e20330f5931d2da3
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
- This is a thin 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.
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.
@@ -60,12 +60,25 @@ module ULID
60
60
  SecureRandom.random_bytes(10)
61
61
  end
62
62
 
63
- def hundred_micro_time
64
- (@time.to_f * 10_000).to_i
63
+ def millisecond_time
64
+ (@time.to_f * 1_000).to_i
65
65
  end
66
66
 
67
- def time_48bit
68
- [hundred_micro_time].pack("Q>")[2..-1]
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
@@ -52,7 +52,7 @@ module ULID
52
52
 
53
53
  if @bytes.nil?
54
54
  # an ASCII_8BIT encoded string, should be 16 bytes
55
- @bytes = time_48bit + @seed
55
+ @bytes = time_bytes + @seed
56
56
  end
57
57
 
58
58
  if @ulid.nil?
@@ -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
- time_int = ("\x00\x00" + time_bytes).unpack('Q>')[0]
47
-
48
- [ Time.at( time_int / 10_000.0 ).utc, seed ]
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
@@ -1,4 +1,4 @@
1
1
  module ULID
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0"
3
3
  end
4
4
 
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.1.1
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-05 00:00:00.000000000 Z
11
+ date: 2017-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler