lite-uxid 1.5.2 → 2.0.1
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/.rubocop.yml +2 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/README.md +34 -40
- data/benchmarks/compare.rb +15 -7
- data/lib/generators/lite/uxid/templates/install.rb +1 -0
- data/lib/lite/uxid/base.rb +58 -0
- data/lib/lite/uxid/configuration.rb +10 -4
- data/lib/lite/uxid/irreversible/base.rb +33 -0
- data/lib/lite/uxid/irreversible/nanoid.rb +44 -0
- data/lib/lite/uxid/irreversible/ulid.rb +47 -0
- data/lib/lite/uxid/irreversible/uuid.rb +20 -0
- data/lib/lite/uxid/record/hashid.rb +13 -12
- data/lib/lite/uxid/record/nanoid.rb +6 -8
- data/lib/lite/uxid/record/obfuscateid.rb +54 -0
- data/lib/lite/uxid/record/ulid.rb +6 -8
- data/lib/lite/uxid/record/uuid.rb +6 -8
- data/lib/lite/uxid/reversible/base.rb +30 -0
- data/lib/lite/uxid/reversible/hashid.rb +52 -0
- data/lib/lite/uxid/reversible/obfuscateid.rb +68 -0
- data/lib/lite/uxid/version.rb +1 -1
- data/lib/lite/uxid.rb +10 -6
- metadata +11 -8
- data/lib/lite/uxid/base/irreversible.rb +0 -78
- data/lib/lite/uxid/base/reversible.rb +0 -36
- data/lib/lite/uxid/hashid.rb +0 -50
- data/lib/lite/uxid/nanoid.rb +0 -42
- data/lib/lite/uxid/ulid.rb +0 -45
- data/lib/lite/uxid/uuid.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9078e4e13dc6877ed30a6a0028ad4327ff95d3056a5303f789137272e2bb0f12
|
4
|
+
data.tar.gz: c25e8acbb22ad4e4381bf9b07018eaf12daaf8e1d0123cee24f5fa9c8af8e87a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd5d7ef2cd4c425fb798dea874a7f395e20e5514ca07fb807d673feb75187e8a236236bd7f833084983a820d71a05a7a27c80d72138a13f888fb5b088a4c869f
|
7
|
+
data.tar.gz: 24462c53958076c1435e1012f3608002d23fdb01b3d59d00ac9d7d78c81f8f1d91b3a80fcac78d9a6a9ce358d9db728af6dd6df3d6815037a1c7dfa25515ba3f
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [2.0.1] - 2024-09-23
|
10
|
+
### Changed
|
11
|
+
- Renamed `Scatterid` to `Obfuscateid`
|
12
|
+
### Removed
|
13
|
+
- Removed prefix option from obfuscateid
|
14
|
+
|
15
|
+
## [2.0.0] - 2024-09-23
|
16
|
+
### Added
|
17
|
+
- Scatterid reversible lib
|
18
|
+
### Changed
|
19
|
+
- Reorganize generators into better namespaces
|
20
|
+
- Fixed issue where nanoid would return without the prefix
|
21
|
+
- Moved charsets to constants
|
22
|
+
|
9
23
|
## [1.5.2] - 2024-09-20
|
10
24
|
### Changed
|
11
25
|
- Fixed nanoid of differing length error
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -27,8 +27,9 @@ Or install it yourself as:
|
|
27
27
|
|
28
28
|
* [Configuration](#configuration)
|
29
29
|
* [Usage](#usage)
|
30
|
-
* [
|
30
|
+
* [HashID](#hashid)
|
31
31
|
* [NanoID](#nanoid)
|
32
|
+
* [ObfuscateID](#obfuscateid)
|
32
33
|
* [ULID](#ulid)
|
33
34
|
* [UUID](#uuid)
|
34
35
|
* [Options](#options)
|
@@ -41,13 +42,17 @@ Or install it yourself as:
|
|
41
42
|
`config/initalizers/lite_uxid.rb`
|
42
43
|
|
43
44
|
```ruby
|
45
|
+
Lite::Uxid::ALPHANUMERIC = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
46
|
+
Lite::Uxid::COCKFORDS_32 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
47
|
+
Lite::Uxid::WEB_SAFE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
|
48
|
+
|
44
49
|
Lite::Uxid.configure do |config|
|
45
|
-
config.hashid_charset =
|
50
|
+
config.hashid_charset = ALPHANUMERIC
|
46
51
|
config.hashid_salt = 1_369_136
|
47
52
|
config.hashid_size = 16
|
48
|
-
config.nanoid_charset =
|
53
|
+
config.nanoid_charset = WEB_SAFE
|
49
54
|
config.nanoid_size = 21
|
50
|
-
config.ulid_charset =
|
55
|
+
config.ulid_charset = COCKFORDS_32
|
51
56
|
config.ulid_size = 26
|
52
57
|
config.uuid_version = 4
|
53
58
|
end
|
@@ -57,22 +62,22 @@ end
|
|
57
62
|
|
58
63
|
#### Instance
|
59
64
|
```ruby
|
60
|
-
coder = Lite::Uxid::Hashid.new(10, size: 12)
|
65
|
+
coder = Lite::Uxid::Reversible::Hashid.new(10, size: 12)
|
61
66
|
coder.encode #=> '67wGI0'
|
62
67
|
```
|
63
68
|
|
64
69
|
#### Class
|
65
70
|
```ruby
|
66
|
-
Lite::Uxid::Hashid.decode('67wGI0', size: 12) #=> 10
|
71
|
+
Lite::Uxid::Reversible::Hashid.decode('67wGI0', size: 12) #=> 10
|
67
72
|
```
|
68
73
|
|
69
|
-
##
|
74
|
+
## HashID
|
70
75
|
|
71
76
|
[More information](https://hashids.org)
|
72
77
|
|
73
78
|
```ruby
|
74
|
-
Lite::Uxid::Hashid.encode(10) #=> '1zWr1m0'
|
75
|
-
Lite::Uxid::Hashid.decode('1zWr1m0') #=> 10
|
79
|
+
Lite::Uxid::Reversible::Hashid.encode(10) #=> '1zWr1m0'
|
80
|
+
Lite::Uxid::Reversible::Hashid.decode('1zWr1m0') #=> 10
|
76
81
|
```
|
77
82
|
|
78
83
|
## NanoID
|
@@ -80,7 +85,16 @@ Lite::Uxid::Hashid.decode('1zWr1m0') #=> 10
|
|
80
85
|
[More information](https://github.com/ai/nanoid)
|
81
86
|
|
82
87
|
```ruby
|
83
|
-
Lite::Uxid::Nanoid.encode #=> 'sMuNUa3Cegn6r5GRQ4Ij2'
|
88
|
+
Lite::Uxid::Irreversible::Nanoid.encode #=> 'sMuNUa3Cegn6r5GRQ4Ij2'
|
89
|
+
```
|
90
|
+
|
91
|
+
## ObfuscateID
|
92
|
+
|
93
|
+
[More information](https://github.com/namick/scatter_swap)
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Lite::Uxid::Reversible::Obfuscateid.encode(10) #=> '2056964183'
|
97
|
+
Lite::Uxid::Reversible::Obfuscateid.decode(2056964183) #=> 10
|
84
98
|
```
|
85
99
|
|
86
100
|
## ULID
|
@@ -88,7 +102,7 @@ Lite::Uxid::Nanoid.encode #=> 'sMuNUa3Cegn6r5GRQ4Ij2'
|
|
88
102
|
[More information](https://github.com/ulid/spec)
|
89
103
|
|
90
104
|
```ruby
|
91
|
-
Lite::Uxid::Ulid.encode #=> '01GJAY9KGR539EZF4QWYEJGSN7'
|
105
|
+
Lite::Uxid::Irreversible::Ulid.encode #=> '01GJAY9KGR539EZF4QWYEJGSN7'
|
92
106
|
```
|
93
107
|
|
94
108
|
## UUID
|
@@ -96,7 +110,7 @@ Lite::Uxid::Ulid.encode #=> '01GJAY9KGR539EZF4QWYEJGSN7'
|
|
96
110
|
Implements `v4` and `v7` of the specification. [More information](https://en.wikipedia.org/wiki/Universally_unique_identifier)
|
97
111
|
|
98
112
|
```ruby
|
99
|
-
Lite::Uxid::Uuid.encode #=> '4376a67e-1189-44b3-a599-7f7566bf105b'
|
113
|
+
Lite::Uxid::Irreversible::Uuid.encode #=> '4376a67e-1189-44b3-a599-7f7566bf105b'
|
100
114
|
```
|
101
115
|
|
102
116
|
## Options
|
@@ -104,7 +118,7 @@ Lite::Uxid::Uuid.encode #=> '4376a67e-1189-44b3-a599-7f7566bf105b'
|
|
104
118
|
Local options can be passed to override global options.
|
105
119
|
|
106
120
|
```ruby
|
107
|
-
Lite::Uxid::Ulid.encode(charset: 'abc123', size: 12) #=> 'a3b12c12c3ca'
|
121
|
+
Lite::Uxid::Irreversible::Ulid.encode(charset: 'abc123', size: 12) #=> 'a3b12c12c3ca'
|
108
122
|
```
|
109
123
|
|
110
124
|
Passable options are:
|
@@ -114,6 +128,7 @@ Passable options are:
|
|
114
128
|
charset: 'string', # Available for: hashid, nanoid, ulid
|
115
129
|
salt: 'string', # Available for: hashid
|
116
130
|
size: 'integer', # Available for: hashid, nanoid, ulid
|
131
|
+
spin: 'integer', # Available for: obfuscateid
|
117
132
|
version: 'integer', # Available for: uuid
|
118
133
|
prefix: 'string' # Available for: hashid, nanoid
|
119
134
|
}
|
@@ -144,27 +159,11 @@ t.uuid :uxid, null: false, index: { unique: true }
|
|
144
159
|
#### HashID
|
145
160
|
```ruby
|
146
161
|
class User < ActiveRecord::Base
|
162
|
+
# Pick one:
|
147
163
|
include Lite::Uxid::Record::Hashid
|
148
|
-
end
|
149
|
-
```
|
150
|
-
|
151
|
-
#### NanoID
|
152
|
-
```ruby
|
153
|
-
class User < ActiveRecord::Base
|
154
164
|
include Lite::Uxid::Record::Nanoid
|
155
|
-
|
156
|
-
```
|
157
|
-
|
158
|
-
#### ULID
|
159
|
-
```ruby
|
160
|
-
class User < ActiveRecord::Base
|
165
|
+
include Lite::Uxid::Record::Obfuscateid
|
161
166
|
include Lite::Uxid::Record::Ulid
|
162
|
-
end
|
163
|
-
```
|
164
|
-
|
165
|
-
#### UUID
|
166
|
-
```ruby
|
167
|
-
class User < ActiveRecord::Base
|
168
167
|
include Lite::Uxid::Record::Uuid
|
169
168
|
end
|
170
169
|
```
|
@@ -176,16 +175,16 @@ class User < ActiveRecord::Base
|
|
176
175
|
include Lite::Uxid::Record::Hashid
|
177
176
|
|
178
177
|
def uxid_prefix
|
179
|
-
"
|
178
|
+
"usr_"
|
180
179
|
end
|
181
180
|
end
|
182
181
|
```
|
183
182
|
|
184
183
|
**Usage**
|
185
184
|
|
186
|
-
Using
|
185
|
+
Using the `hashid` and `nanoid` above provide handy methods to find records by uxid.
|
187
186
|
|
188
|
-
####
|
187
|
+
#### Hashing methods
|
189
188
|
```ruby
|
190
189
|
user = User.new
|
191
190
|
user.id_to_uxid #=> Encodes the records id to uxid
|
@@ -200,15 +199,10 @@ User.find_by_uxid!('x123') #=> Raises an ActiveRecord::RecordNotFound error if n
|
|
200
199
|
|
201
200
|
## Benchmarks
|
202
201
|
|
203
|
-
The classes ranked from fastest to slowest are `UUID`, `
|
202
|
+
The classes ranked from fastest to slowest are `UUID`, `HashID`, `NanoID`, `ULID`, and `ObfuscateID`.
|
204
203
|
|
205
204
|
View how each compares by running the [benchmarks](https://github.com/drexed/lite-uxid/tree/master/benchmarks).
|
206
205
|
|
207
|
-
#### Alternatives
|
208
|
-
|
209
|
-
Learn more about alternative functions and more advance hashing setups:
|
210
|
-
[hashids.org](https://hashids.org)
|
211
|
-
|
212
206
|
## Development
|
213
207
|
|
214
208
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/benchmarks/compare.rb
CHANGED
@@ -8,22 +8,30 @@ require "lite/uxid"
|
|
8
8
|
Benchmark.ips do |x|
|
9
9
|
x.report("Hashid") do
|
10
10
|
id = rand(1..1_000_000)
|
11
|
-
Lite::Uxid::Hashid.encode(id)
|
11
|
+
Lite::Uxid::Reversible::Hashid.encode(id)
|
12
12
|
end
|
13
13
|
|
14
|
+
x.report("Obfuscateid") do
|
15
|
+
id = rand(1..1_000_000)
|
16
|
+
Lite::Uxid::Reversible::Obfuscateid.encode(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
# The irreversible examples include `rand` simulate
|
20
|
+
# the extra work just like reversible examples.
|
21
|
+
|
14
22
|
x.report("NanoID") do
|
15
|
-
_id = rand(1..1_000_000)
|
16
|
-
Lite::Uxid::Nanoid.encode
|
23
|
+
_id = rand(1..1_000_000)
|
24
|
+
Lite::Uxid::Irreversible::Nanoid.encode
|
17
25
|
end
|
18
26
|
|
19
27
|
x.report("ULID") do
|
20
|
-
_id = rand(1..1_000_000)
|
21
|
-
Lite::Uxid::Ulid.encode
|
28
|
+
_id = rand(1..1_000_000)
|
29
|
+
Lite::Uxid::Irreversible::Ulid.encode
|
22
30
|
end
|
23
31
|
|
24
32
|
x.report("UUID") do
|
25
|
-
_id = rand(1..1_000_000)
|
26
|
-
Lite::Uxid::Uuid.encode
|
33
|
+
_id = rand(1..1_000_000)
|
34
|
+
Lite::Uxid::Irreversible::Uuid.encode
|
27
35
|
end
|
28
36
|
|
29
37
|
x.compare!
|
@@ -6,6 +6,7 @@ Lite::Uxid.configure do |config|
|
|
6
6
|
config.hashid_size = 16
|
7
7
|
config.nanoid_charset = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
8
8
|
config.nanoid_size = 21
|
9
|
+
config.obfuscateid_spin = 0
|
9
10
|
config.ulid_charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
10
11
|
config.ulid_size = 26
|
11
12
|
config.uuid_version = 4
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Base
|
6
|
+
|
7
|
+
def encode
|
8
|
+
raise NotImplementedError, "override encode method in #{coder_class}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def decode
|
12
|
+
raise NotImplementedError, "override decode method in #{coder_class}"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def coder_value_for(key)
|
18
|
+
sym_key = :"#{coder_class.downcase}_#{key}"
|
19
|
+
return unless Lite::Uxid.configuration.respond_to?(sym_key)
|
20
|
+
|
21
|
+
opts.delete(key) || Lite::Uxid.configuration.send(sym_key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def coder_charset
|
25
|
+
@coder_charset ||= coder_value_for(:charset)
|
26
|
+
end
|
27
|
+
|
28
|
+
def coder_class
|
29
|
+
@coder_class ||= self.class.name.split("::").last
|
30
|
+
end
|
31
|
+
|
32
|
+
def coder_length
|
33
|
+
@coder_length ||= coder_charset.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def coder_prefix
|
37
|
+
@coder_prefix ||= opts.delete(:prefix)
|
38
|
+
end
|
39
|
+
|
40
|
+
def coder_salt
|
41
|
+
@coder_salt ||= coder_value_for(:salt)
|
42
|
+
end
|
43
|
+
|
44
|
+
def coder_size
|
45
|
+
@coder_size ||= coder_value_for(:size)
|
46
|
+
end
|
47
|
+
|
48
|
+
def coder_spin
|
49
|
+
@coder_spin ||= coder_value_for(:spin)
|
50
|
+
end
|
51
|
+
|
52
|
+
def coder_version
|
53
|
+
@coder_version ||= coder_value_for(:version)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -3,20 +3,26 @@
|
|
3
3
|
module Lite
|
4
4
|
module Uxid
|
5
5
|
|
6
|
+
ALPHANUMERIC = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
7
|
+
COCKFORDS_32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
|
8
|
+
WEB_SAFE = "#{ALPHANUMERIC}-_".freeze
|
9
|
+
|
6
10
|
class Configuration
|
7
11
|
|
8
12
|
attr_accessor :hashid_charset, :hashid_size, :hashid_salt,
|
9
13
|
:nanoid_charset, :nanoid_size,
|
10
|
-
:
|
14
|
+
:obfuscateid_spin,
|
15
|
+
:ulid_charset, :ulid_size,
|
11
16
|
:uuid_version
|
12
17
|
|
13
18
|
def initialize
|
14
|
-
@hashid_charset =
|
19
|
+
@hashid_charset = ALPHANUMERIC
|
15
20
|
@hashid_salt = 1_369_136
|
16
21
|
@hashid_size = 16
|
17
|
-
@nanoid_charset =
|
22
|
+
@nanoid_charset = WEB_SAFE
|
18
23
|
@nanoid_size = 21
|
19
|
-
@
|
24
|
+
@obfuscateid_spin = 0
|
25
|
+
@ulid_charset = COCKFORDS_32
|
20
26
|
@ulid_size = 26
|
21
27
|
@uuid_version = 4
|
22
28
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Irreversible
|
6
|
+
class Base
|
7
|
+
|
8
|
+
include Lite::Uxid::Base
|
9
|
+
|
10
|
+
attr_reader :opts
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
@opts = opts
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.encode(opts = {})
|
17
|
+
klass = new(opts)
|
18
|
+
klass.encode
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.decode(opts = {})
|
22
|
+
klass = new(opts)
|
23
|
+
klass.decode
|
24
|
+
end
|
25
|
+
|
26
|
+
def decode
|
27
|
+
raise "#{coder_class} does not support decoding"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Irreversible
|
6
|
+
class Nanoid < Base
|
7
|
+
|
8
|
+
def encode
|
9
|
+
encoded_id = +""
|
10
|
+
|
11
|
+
loop do
|
12
|
+
cached_bytes = bytes
|
13
|
+
|
14
|
+
(0...step).each do |idx|
|
15
|
+
byte = cached_bytes[idx] & mask
|
16
|
+
char = byte && coder_charset[byte]
|
17
|
+
next unless char
|
18
|
+
|
19
|
+
encoded_id << char
|
20
|
+
return "#{coder_prefix}#{encoded_id}" if encoded_id.size == coder_size
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
"#{coder_prefix}#{encoded_id}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def bytes
|
30
|
+
SecureRandom.random_bytes(coder_size).bytes
|
31
|
+
end
|
32
|
+
|
33
|
+
def mask
|
34
|
+
@mask ||= (2 << (Math.log(coder_length - 1) / Math.log(2))) - 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def step
|
38
|
+
@step = (1.6 * mask * coder_size / coder_length).ceil
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Irreversible
|
6
|
+
class Ulid < Base
|
7
|
+
|
8
|
+
MASK = 0x1f
|
9
|
+
|
10
|
+
def encode
|
11
|
+
encoded_id = "0" * coder_size
|
12
|
+
oct = octect
|
13
|
+
pos = coder_size - 1
|
14
|
+
|
15
|
+
while oct.positive?
|
16
|
+
encoded_id[pos] = coder_charset[oct & MASK]
|
17
|
+
oct >>= 5
|
18
|
+
pos -= 1
|
19
|
+
end
|
20
|
+
|
21
|
+
encoded_id
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def bytes
|
27
|
+
"#{unixtime_48bit}#{SecureRandom.random_bytes(10)}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def octect
|
31
|
+
(hi, lo) = bytes.unpack("Q>Q>")
|
32
|
+
(hi << 64) | lo
|
33
|
+
end
|
34
|
+
|
35
|
+
def unixtime_ms
|
36
|
+
time = Time.respond_to?(:current) ? Time.current : Time.now
|
37
|
+
time.to_i * 1_000
|
38
|
+
end
|
39
|
+
|
40
|
+
def unixtime_48bit
|
41
|
+
[unixtime_ms].pack("Q>")[2..-1]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Irreversible
|
6
|
+
class Uuid < Base
|
7
|
+
|
8
|
+
def encode
|
9
|
+
case coder_version
|
10
|
+
when 7
|
11
|
+
SecureRandom.uuid_v7
|
12
|
+
else
|
13
|
+
SecureRandom.uuid
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,23 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support" unless defined?(ActiveSupport)
|
4
|
-
|
5
3
|
module Lite
|
6
4
|
module Uxid
|
7
5
|
module Record
|
8
6
|
module Hashid
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
base.class_eval do
|
11
|
+
after_commit :callback_generate_uxid!,
|
12
|
+
if: proc { respond_to?(:uxid) && !uxid? },
|
13
|
+
on: :create
|
14
|
+
end
|
16
15
|
end
|
17
16
|
|
18
|
-
|
17
|
+
module ClassMethods
|
18
|
+
|
19
19
|
def find_by_uxid(uxid)
|
20
|
-
decoded_id = Lite::Uxid::Hashid.decode(uxid, prefix: new.uxid_prefix)
|
20
|
+
decoded_id = Lite::Uxid::Reversible::Hashid.decode(uxid, prefix: new.uxid_prefix)
|
21
21
|
find_by(id: decoded_id)
|
22
22
|
end
|
23
23
|
|
@@ -27,18 +27,19 @@ module Lite
|
|
27
27
|
|
28
28
|
raise ActiveRecord::RecordNotFound
|
29
29
|
end
|
30
|
+
|
30
31
|
end
|
31
32
|
|
32
33
|
def id_to_uxid
|
33
34
|
return unless respond_to?(:uxid)
|
34
35
|
|
35
|
-
Lite::Uxid::Hashid.encode(id, prefix: uxid_prefix)
|
36
|
+
Lite::Uxid::Reversible::Hashid.encode(id, prefix: uxid_prefix)
|
36
37
|
end
|
37
38
|
|
38
39
|
def uxid_to_id
|
39
40
|
return unless respond_to?(:uxid)
|
40
41
|
|
41
|
-
Lite::Uxid::Hashid.decode(uxid, prefix: uxid_prefix)
|
42
|
+
Lite::Uxid::Reversible::Hashid.decode(uxid, prefix: uxid_prefix)
|
42
43
|
end
|
43
44
|
|
44
45
|
def uxid_prefix
|
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support" unless defined?(ActiveSupport)
|
4
|
-
|
5
3
|
module Lite
|
6
4
|
module Uxid
|
7
5
|
module Record
|
8
6
|
module Nanoid
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
before_create :callback_generate_uxid!,
|
11
|
+
if: proc { respond_to?(:uxid) && !uxid? }
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
15
|
def uxid_prefix
|
@@ -24,7 +22,7 @@ module Lite
|
|
24
22
|
random_nanoid = nil
|
25
23
|
|
26
24
|
loop do
|
27
|
-
random_nanoid = Lite::Uxid::Nanoid.encode(prefix: uxid_prefix)
|
25
|
+
random_nanoid = Lite::Uxid::Irreversible::Nanoid.encode(prefix: uxid_prefix)
|
28
26
|
break unless self.class.exists?(uxid: random_nanoid)
|
29
27
|
end
|
30
28
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Record
|
6
|
+
module Obfuscateid
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
base.class_eval do
|
11
|
+
after_commit :callback_generate_uxid!,
|
12
|
+
if: proc { respond_to?(:uxid) && !uxid? },
|
13
|
+
on: :create
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
def find_by_uxid(uxid)
|
20
|
+
decoded_id = Lite::Uxid::Reversible::Obfuscateid.decode(uxid)
|
21
|
+
find_by(id: decoded_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_by_uxid!(uxid)
|
25
|
+
record = find_by_uxid(uxid)
|
26
|
+
return record unless record.nil?
|
27
|
+
|
28
|
+
raise ActiveRecord::RecordNotFound
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def id_to_uxid
|
34
|
+
return unless respond_to?(:uxid)
|
35
|
+
|
36
|
+
Lite::Uxid::Reversible::Obfuscateid.encode(id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def uxid_to_id
|
40
|
+
return unless respond_to?(:uxid)
|
41
|
+
|
42
|
+
Lite::Uxid::Reversible::Obfuscateid.decode(uxid)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def callback_generate_uxid!
|
48
|
+
update_column(:uxid, id_to_uxid)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,23 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support" unless defined?(ActiveSupport)
|
4
|
-
|
5
3
|
module Lite
|
6
4
|
module Uxid
|
7
5
|
module Record
|
8
6
|
module Ulid
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
before_create :callback_generate_uxid!,
|
11
|
+
if: proc { respond_to?(:uxid) && !uxid? }
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
15
|
private
|
18
16
|
|
19
17
|
def callback_generate_uxid!
|
20
|
-
self.uxid = Lite::Uxid::Ulid.encode
|
18
|
+
self.uxid = Lite::Uxid::Irreversible::Ulid.encode
|
21
19
|
end
|
22
20
|
|
23
21
|
end
|
@@ -1,23 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support" unless defined?(ActiveSupport)
|
4
|
-
|
5
3
|
module Lite
|
6
4
|
module Uxid
|
7
5
|
module Record
|
8
6
|
module Uuid
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
before_create :callback_generate_uxid!,
|
11
|
+
if: proc { respond_to?(:uxid) && !uxid? }
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
15
|
private
|
18
16
|
|
19
17
|
def callback_generate_uxid!
|
20
|
-
self.uxid = Lite::Uxid::Uuid.encode
|
18
|
+
self.uxid = Lite::Uxid::Irreversible::Uuid.encode
|
21
19
|
end
|
22
20
|
|
23
21
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Reversible
|
6
|
+
class Base
|
7
|
+
|
8
|
+
include Lite::Uxid::Base
|
9
|
+
|
10
|
+
attr_reader :id, :opts
|
11
|
+
|
12
|
+
def initialize(id, opts = {})
|
13
|
+
@id = id
|
14
|
+
@opts = opts
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.encode(id, opts = {})
|
18
|
+
klass = new(id, opts)
|
19
|
+
klass.encode
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.decode(id, opts = {})
|
23
|
+
klass = new(id, opts)
|
24
|
+
klass.decode
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Reversible
|
6
|
+
class Hashid < Base
|
7
|
+
|
8
|
+
def encode
|
9
|
+
encoded_id = encode_chars((id + coder_salt) << coder_size)
|
10
|
+
"#{coder_prefix}#{encoded_id}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def decode
|
14
|
+
encoded_id = id.delete_prefix(coder_prefix.to_s)
|
15
|
+
(decode_chars(encoded_id) >> coder_size) - coder_salt
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def encode_chars(decoded_id)
|
21
|
+
return "0" if decoded_id.zero?
|
22
|
+
return nil if decoded_id.negative?
|
23
|
+
|
24
|
+
str = ""
|
25
|
+
|
26
|
+
while decoded_id.positive?
|
27
|
+
str = "#{coder_charset[decoded_id % coder_length]}#{str}"
|
28
|
+
decoded_id /= coder_length
|
29
|
+
end
|
30
|
+
|
31
|
+
str
|
32
|
+
end
|
33
|
+
|
34
|
+
def decode_chars(encoded_id)
|
35
|
+
pos = 0
|
36
|
+
num = 0
|
37
|
+
len = encoded_id.size
|
38
|
+
max = len - 1
|
39
|
+
|
40
|
+
while pos < len
|
41
|
+
pow = coder_length**(max - pos)
|
42
|
+
num += coder_charset.index(encoded_id[pos]) * pow
|
43
|
+
pos += 1
|
44
|
+
end
|
45
|
+
|
46
|
+
num
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Uxid
|
5
|
+
module Reversible
|
6
|
+
class Obfuscateid < Base
|
7
|
+
|
8
|
+
def encode
|
9
|
+
swap
|
10
|
+
scatter
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
def decode
|
15
|
+
unscatter
|
16
|
+
unswap
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def zero_padded_id
|
23
|
+
@zero_padded_id ||= id.to_s.rjust(10, "0")
|
24
|
+
end
|
25
|
+
|
26
|
+
def coder_array
|
27
|
+
@coder_array ||= zero_padded_id.chars.collect(&:to_i)
|
28
|
+
end
|
29
|
+
|
30
|
+
def result
|
31
|
+
coder_array.join.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def swapper_map(index)
|
35
|
+
array = (0..9).to_a
|
36
|
+
Array.new(10) { |i| array.rotate!((index + i) ^ coder_spin).pop }
|
37
|
+
end
|
38
|
+
|
39
|
+
def swap
|
40
|
+
coder_array.map!.with_index { |digit, i| swapper_map(i)[digit] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def unswap
|
44
|
+
coder_array.map!.with_index { |digit, i| swapper_map(i).rindex(digit) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def scatter
|
48
|
+
sum_of_digits = coder_array.sum.to_i
|
49
|
+
@coder_array = Array.new(10) { coder_array.rotate!(coder_spin ^ sum_of_digits).pop }
|
50
|
+
end
|
51
|
+
|
52
|
+
def unscatter
|
53
|
+
scattered_array = coder_array
|
54
|
+
sum_of_digits = scattered_array.sum.to_i
|
55
|
+
@coder_array = []
|
56
|
+
|
57
|
+
coder_array.tap do |unscatter|
|
58
|
+
10.times do
|
59
|
+
unscatter.push(scattered_array.pop)
|
60
|
+
unscatter.rotate!((sum_of_digits ^ coder_spin) * -1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/lite/uxid/version.rb
CHANGED
data/lib/lite/uxid.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "securerandom" unless defined?(SecureRandom)
|
3
4
|
require "generators/lite/uxid/install_generator" if defined?(Rails::Generators)
|
4
5
|
|
5
6
|
require "lite/uxid/version"
|
6
7
|
require "lite/uxid/configuration"
|
7
|
-
require "lite/uxid/base
|
8
|
-
require "lite/uxid/base
|
8
|
+
require "lite/uxid/base"
|
9
|
+
require "lite/uxid/irreversible/base"
|
10
|
+
require "lite/uxid/irreversible/nanoid"
|
11
|
+
require "lite/uxid/irreversible/ulid"
|
12
|
+
require "lite/uxid/irreversible/uuid"
|
13
|
+
require "lite/uxid/reversible/base"
|
14
|
+
require "lite/uxid/reversible/hashid"
|
15
|
+
require "lite/uxid/reversible/obfuscateid"
|
9
16
|
require "lite/uxid/record/hashid"
|
10
17
|
require "lite/uxid/record/nanoid"
|
18
|
+
require "lite/uxid/record/obfuscateid"
|
11
19
|
require "lite/uxid/record/ulid"
|
12
20
|
require "lite/uxid/record/uuid"
|
13
|
-
require "lite/uxid/hashid"
|
14
|
-
require "lite/uxid/nanoid"
|
15
|
-
require "lite/uxid/ulid"
|
16
|
-
require "lite/uxid/uuid"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lite-uxid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Gomez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -217,17 +217,20 @@ files:
|
|
217
217
|
- lib/generators/lite/uxid/install_generator.rb
|
218
218
|
- lib/generators/lite/uxid/templates/install.rb
|
219
219
|
- lib/lite/uxid.rb
|
220
|
-
- lib/lite/uxid/base
|
221
|
-
- lib/lite/uxid/base/reversible.rb
|
220
|
+
- lib/lite/uxid/base.rb
|
222
221
|
- lib/lite/uxid/configuration.rb
|
223
|
-
- lib/lite/uxid/
|
224
|
-
- lib/lite/uxid/nanoid.rb
|
222
|
+
- lib/lite/uxid/irreversible/base.rb
|
223
|
+
- lib/lite/uxid/irreversible/nanoid.rb
|
224
|
+
- lib/lite/uxid/irreversible/ulid.rb
|
225
|
+
- lib/lite/uxid/irreversible/uuid.rb
|
225
226
|
- lib/lite/uxid/record/hashid.rb
|
226
227
|
- lib/lite/uxid/record/nanoid.rb
|
228
|
+
- lib/lite/uxid/record/obfuscateid.rb
|
227
229
|
- lib/lite/uxid/record/ulid.rb
|
228
230
|
- lib/lite/uxid/record/uuid.rb
|
229
|
-
- lib/lite/uxid/
|
230
|
-
- lib/lite/uxid/
|
231
|
+
- lib/lite/uxid/reversible/base.rb
|
232
|
+
- lib/lite/uxid/reversible/hashid.rb
|
233
|
+
- lib/lite/uxid/reversible/obfuscateid.rb
|
231
234
|
- lib/lite/uxid/version.rb
|
232
235
|
- lite-uxid.gemspec
|
233
236
|
homepage: http://drexed.github.io/lite-uxid
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "securerandom" unless defined?(SecureRandom)
|
4
|
-
|
5
|
-
module Lite
|
6
|
-
module Uxid
|
7
|
-
module Base
|
8
|
-
class Irreversible
|
9
|
-
|
10
|
-
attr_reader :opts
|
11
|
-
|
12
|
-
def initialize(opts = {})
|
13
|
-
@opts = opts
|
14
|
-
end
|
15
|
-
|
16
|
-
class << self
|
17
|
-
|
18
|
-
def encode(opts = {})
|
19
|
-
klass = new(opts)
|
20
|
-
klass.encode
|
21
|
-
end
|
22
|
-
|
23
|
-
def decode(opts = {})
|
24
|
-
klass = new(opts)
|
25
|
-
klass.decode
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def encode
|
31
|
-
raise NotImplementedError, "override method in #{coder_class}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def decode
|
35
|
-
raise NotImplementedError, "coder does not support decoding"
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def coder_value_for(key)
|
41
|
-
sym_key = :"#{coder_class.downcase}_#{key}"
|
42
|
-
return unless Lite::Uxid.configuration.respond_to?(sym_key)
|
43
|
-
|
44
|
-
opts.delete(key) || Lite::Uxid.configuration.send(sym_key)
|
45
|
-
end
|
46
|
-
|
47
|
-
def coder_charset
|
48
|
-
@coder_charset ||= coder_value_for(:charset)
|
49
|
-
end
|
50
|
-
|
51
|
-
def coder_class
|
52
|
-
@coder_class ||= self.class.name.split("::").last
|
53
|
-
end
|
54
|
-
|
55
|
-
def coder_length
|
56
|
-
@coder_length ||= coder_charset.size
|
57
|
-
end
|
58
|
-
|
59
|
-
def coder_prefix
|
60
|
-
@coder_prefix ||= opts.delete(:prefix)
|
61
|
-
end
|
62
|
-
|
63
|
-
def coder_salt
|
64
|
-
@coder_salt ||= coder_value_for(:salt)
|
65
|
-
end
|
66
|
-
|
67
|
-
def coder_size
|
68
|
-
@coder_size ||= coder_value_for(:size)
|
69
|
-
end
|
70
|
-
|
71
|
-
def coder_version
|
72
|
-
@coder_version ||= coder_value_for(:version)
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Uxid
|
5
|
-
module Base
|
6
|
-
class Reversible < Irreversible
|
7
|
-
|
8
|
-
attr_reader :id
|
9
|
-
|
10
|
-
def initialize(id, opts = {})
|
11
|
-
@id = id
|
12
|
-
super(opts)
|
13
|
-
end
|
14
|
-
|
15
|
-
class << self
|
16
|
-
|
17
|
-
def encode(id, opts = {})
|
18
|
-
klass = new(id, opts)
|
19
|
-
klass.encode
|
20
|
-
end
|
21
|
-
|
22
|
-
def decode(id, opts = {})
|
23
|
-
klass = new(id, opts)
|
24
|
-
klass.decode
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def decode
|
30
|
-
raise NotImplementedError, "override method in #{coder_class}"
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/lite/uxid/hashid.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Uxid
|
5
|
-
class Hashid < Base::Reversible
|
6
|
-
|
7
|
-
def encode
|
8
|
-
uxid = encode_chars((id + coder_salt) << coder_size)
|
9
|
-
"#{coder_prefix}#{uxid}"
|
10
|
-
end
|
11
|
-
|
12
|
-
def decode
|
13
|
-
uxid = id.delete_prefix(coder_prefix.to_s)
|
14
|
-
(decode_chars(uxid) >> coder_size) - coder_salt
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def encode_chars(decoded_id)
|
20
|
-
return "0" if decoded_id.zero?
|
21
|
-
return nil if decoded_id.negative?
|
22
|
-
|
23
|
-
str = ""
|
24
|
-
|
25
|
-
while decoded_id.positive?
|
26
|
-
str = "#{coder_charset[decoded_id % coder_length]}#{str}"
|
27
|
-
decoded_id /= coder_length
|
28
|
-
end
|
29
|
-
|
30
|
-
str
|
31
|
-
end
|
32
|
-
|
33
|
-
def decode_chars(encoded_id)
|
34
|
-
pos = 0
|
35
|
-
num = 0
|
36
|
-
len = encoded_id.size
|
37
|
-
max = len - 1
|
38
|
-
|
39
|
-
while pos < len
|
40
|
-
pow = coder_length**(max - pos)
|
41
|
-
num += coder_charset.index(encoded_id[pos]) * pow
|
42
|
-
pos += 1
|
43
|
-
end
|
44
|
-
|
45
|
-
num
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/lite/uxid/nanoid.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Uxid
|
5
|
-
class Nanoid < Base::Irreversible
|
6
|
-
|
7
|
-
def encode
|
8
|
-
uxid = +""
|
9
|
-
|
10
|
-
loop do
|
11
|
-
cached_bytes = bytes
|
12
|
-
|
13
|
-
(0...step).each do |idx|
|
14
|
-
byte = cached_bytes[idx] & mask
|
15
|
-
char = byte && coder_charset[byte]
|
16
|
-
next unless char
|
17
|
-
|
18
|
-
uxid << char
|
19
|
-
return uxid if uxid.size == coder_size
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
"#{coder_prefix}#{uxid}"
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def bytes
|
29
|
-
SecureRandom.random_bytes(coder_size).bytes
|
30
|
-
end
|
31
|
-
|
32
|
-
def mask
|
33
|
-
@mask ||= (2 << (Math.log(coder_length - 1) / Math.log(2))) - 1
|
34
|
-
end
|
35
|
-
|
36
|
-
def step
|
37
|
-
@step = (1.6 * mask * coder_size / coder_length).ceil
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/lite/uxid/ulid.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Uxid
|
5
|
-
class Ulid < Base::Irreversible
|
6
|
-
|
7
|
-
MASK = 0x1f
|
8
|
-
|
9
|
-
def encode
|
10
|
-
oct = octect
|
11
|
-
ele = "0" * coder_size
|
12
|
-
pos = coder_size - 1
|
13
|
-
|
14
|
-
while oct.positive?
|
15
|
-
ele[pos] = coder_charset[oct & MASK]
|
16
|
-
oct >>= 5
|
17
|
-
pos -= 1
|
18
|
-
end
|
19
|
-
|
20
|
-
ele
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def bytes
|
26
|
-
"#{unixtime_48bit}#{SecureRandom.random_bytes(10)}"
|
27
|
-
end
|
28
|
-
|
29
|
-
def octect
|
30
|
-
(hi, lo) = bytes.unpack("Q>Q>")
|
31
|
-
(hi << 64) | lo
|
32
|
-
end
|
33
|
-
|
34
|
-
def unixtime_ms
|
35
|
-
time = Time.respond_to?(:current) ? Time.current : Time.now
|
36
|
-
time.to_i * 1_000
|
37
|
-
end
|
38
|
-
|
39
|
-
def unixtime_48bit
|
40
|
-
[unixtime_ms].pack("Q>")[2..-1]
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
data/lib/lite/uxid/uuid.rb
DELETED