make_id 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -33
  3. data/lib/make_id/version.rb +1 -1
  4. data/lib/make_id.rb +125 -102
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90cbe0cbac923318d4badd6c848042404633a27c6fbecdd7e2509aee6c31ab5c
4
- data.tar.gz: 41f946d9367bb73257ac31ffce792bd309f2e707c44b39003d66dcc3d1890a49
3
+ metadata.gz: 2448e655a9a006abb23272b2b54c6b4fc537f702407c931afcf106b82c468b04
4
+ data.tar.gz: 9852758f34e12c2be8aa90149cdded09e011f2ab879320089fc1bfb3f577d849
5
5
  SHA512:
6
- metadata.gz: da8822e1194eb4ed1e51f1090f120db17cdd421fc330f84dbe4b4556c1dd71eac4dc33dff678768999cee03ad21749a9f3bbb5a2949ced4f83c7f7afd802128a
7
- data.tar.gz: '038ae0b3bc50252cd75eec5fb7283feb27381e3362bd2681fbba6ff225865727ef4fa560f84d24e8c4703f5ba96ce168c9278462b9469b97323ab981869e387d'
6
+ metadata.gz: 108e40b61bfdcc00ac5e550b4afb14fb8f7298df617d10b7179975b2be8f6f04c6b4693fc6909de26f42e6a9977333d12f7ecc5c5846b1317b3ab728b6e6d04d
7
+ data.tar.gz: 25c7229af03bc353707c2ee832f00c2ad63243318156ffa51bcd197f328a2cae865eaf37fa0949d7c8d98bcf9e583b4ec8f2fb2563317d7584b906b9f3c8cf08
data/README.md CHANGED
@@ -40,18 +40,19 @@ numeric codes.
40
40
 
41
41
  Bases supported are:
42
42
 
43
- - Base62: digits, upper, and lower-case letters. No special characters
43
+ - Base94: Base64 (Upper, Lower, Digits) with 30 extra special characters
44
+ - Base64: Url-Safe version. Base64 but swaps the plus and slash by dash and underscore respectively.
45
+ - Base62: digits, upper, and lower-case letters. No special characters. The default.
44
46
  - Base32: digits and upper case without ambiguous characters "1lI" or "oO0"
45
47
  - Base 2 through 36 (except 32): Ruby's `Integer#to_s(base)` is used
46
- - Base64: Uses the `Base64.urlsafe_encode64` such has 2 special characters.
47
- - Base63: It is not implemented.
48
48
 
49
- The Base32 may seem out of place, but is useful for alpha-numeric codes the users are required to type, such as redemption codes.
50
- All letter are folded to upper-case, and ambiguous characters are converted to the canonical ones.
49
+ The Base32 may seem out of place, but is useful for alpha-numeric codes the users are required to type or speak,
50
+ such as serial numbers or license codes.
51
+ All letters are upper-case, and ambiguous characters are converted to the canonical ones.
51
52
 
52
- MakeId.int_to_base(123456789, 32) #=> "3nqk8n"
53
- MakeId.from_base("3nqk8n", 10) #=> 123456789
54
- MakeId.int_to_base(123456789, 32) #=> "3nqk8n"
53
+ MakeId.int_to_base(123456789, 32) #=> "3NQK8N"
54
+ MakeId.from_base("3NQK8N", 10) #=> 123456789
55
+ MakeId.int_to_base(123456789, 32) #=> "3NQK8N"
55
56
  MakeId.verify_base32_id("...") #=> corrected_id or nil if error
56
57
 
57
58
  ### Random Integer
@@ -60,8 +61,14 @@ MakeId can return a random (8-byte by default) integer. You can request it retur
60
61
  and with an optional check_digit.
61
62
  Usually, you would use the integer returned, and call `int_to_base` to format for a URL or code.
62
63
 
63
- MakeId.random_id() #=> 15379918763975837985ZZ
64
- MakeId.random_id(base: 62, check_digit: true) #=> "2984biEwRT1"
64
+ MakeId.id() #=> 15379918763975837985ZZ
65
+ MakeId.id(base: 62, check_digit: true) #=> "2984biEwRT1"
66
+
67
+ Nano Id's are shorter unique strings generated from random characters, usually as a friendlier alternative
68
+ to UUID's. These are 8-byte numeric identifiers in extended bases, such as 36 or 62.
69
+
70
+ MakeId.nano_id() #=> "iZnLn96FVcjivEJA" (Base-62 be default)
71
+ MakeId.nano_id(base: 36) #=> "sf8kqb8ekn7k98rq"
65
72
 
66
73
  ### UUID
67
74
 
@@ -75,16 +82,28 @@ can be used to transform a long UUID into a possibly more palettable base repres
75
82
  MakeId.uuid_to_base(u, 62) #=> "fWJtuXEQJnkjxroWjkmei" (21 characters)
76
83
 
77
84
  Note that some databases support a UUID type which makes storing UUID's easier, and since they are stored as a binary
78
- field, consume less space.ZZ
85
+ field, consume less space.
79
86
 
80
- ### Nano Id
87
+ ### Tokens
81
88
 
82
- Nano Id's are shorter unique strings generated from random characters, usually as a friendlier alternative
83
- to UUID's. They also can be of any size, depending on the key range you require. Pay attention to the keyspace,
84
- ensuring you have enough characters to avoid predictable collisions in the future.
89
+ Tokens are randomly-generated strings of the character set of the requested base.
90
+ The default size is 16 characters of the Base-62 character set.
91
+
92
+ MakeId.token() #=> "Na4VX61PBFVZWL6Y"
93
+ MakeId.token(8, base:36) #=> "BK0ZTL9H"
94
+
95
+ ### Codes
85
96
 
86
- MakeId.nano_id(size: 16) #=> "iZnLn96FVcjivEJA"
87
- MakeId.nano_id(size: 16, base: 32) #=> "sf8kqb8ekn7k98rq"
97
+ Codes are string tokens to send to users for input. They have no ambiguous characters to avoid confusion.
98
+ This is useful for verifications such as two-factor authentication codes, or license numbers.
99
+ This returns an 8-character string by default. Specify a group (size) and delimiter (default is a hyphen)
100
+ to make long codes readable.
101
+
102
+ MakeId.code #=> "22E0D18F"
103
+ MakeId.code(20) #=> "Y41Q24AG7DYZYTAZWQZX"
104
+ MakeId.code(20, group: 4, delimiter: "-") #=> "9975-V5VM-KKSR-4PQ6-7F4G"
105
+
106
+ ### Temporal Identifiers
88
107
 
89
108
  A `request_id` is a nano_id that can be used to track requests and jobs. It is a 16-byte string, the same
90
109
  storage as a UUID, but with columnar values. The substring of 3 for 8 is a short (8 character) version that
@@ -95,9 +114,7 @@ can be used as well, is easier to read, sortable within a day, and unique enough
95
114
  id[3,8] #=> "f1272t01"
96
115
  #-------------------------->Hsssuuqq
97
116
 
98
- ### Snowflake Id
99
-
100
- Snowflakes were invented at Twitter to stamp an identifier for a tweet or direct message.
117
+ Snowflake Id's were invented at Twitter to stamp an identifier for a tweet or direct message.
101
118
  It is an 8-byte integer intended to be time-sorted and unique across the fleet of servers saving messages.
102
119
  It is a bit-mapped integer consisting of these parts:
103
120
 
@@ -120,7 +137,7 @@ You can also pass in options to return it as a different base, and with a check
120
137
 
121
138
  MakeId.app_worker_id = 234
122
139
  MakeId.snowflake_id => 618905333721374720
123
- MakeId.snowflake_id(worker_id: 12, base: 32, sequence_method: :random) #=> "2tmxk6ne81jd5"
140
+ MakeId.snowflake_id(worker_id: 12, base: 32, sequence_method: :random) #=> "2TMXK6NE81JD5"
124
141
 
125
142
  The `snowflake_uuid` method provides a time-based identifier, great for sorting just as sequential numbers, but unique enough to fit the bill.
126
143
 
@@ -136,18 +153,6 @@ records or when you need a slowflake ID but have a UUID column to fill.
136
153
  MakeID.snowflake_datetime_uuid #=> "20240904-1418-5332-2000-3a38e61d5582"
137
154
  #------------------------>YYYYMMDD-hhmm-ssuu-uwww-rrrrrrrrrrrr
138
155
 
139
- ## Experimental Id's
140
-
141
- The `event_id` is a string, sortable by creation time, with visible time seperator columns.
142
- It is of the format "YMDhmsuurrrr", using Base62, with an optional check_sum characer.
143
- It also used the application epoch described under `snowflake_id`. "uu" represents the fractional
144
- seconds that can be represented in Base62, and a 4-character random Base64 "nano_id".
145
-
146
- MakeId.epoch = 2020
147
- MakeId.event_id #=> "493KgpQGErTB"
148
- #------------------->YMDhmsuurrrr ()
149
- MakeId.event_id(check_digit: true) #=> "493Kkha6HZa2" (3 random chars + check digit)
150
-
151
156
  ## Development
152
157
 
153
158
  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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MakeId
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/make_id.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require_relative "make_id/version"
4
4
  require "securerandom"
5
- require "base64"
6
5
  require "zlib"
7
6
 
8
7
  # MakeID generates record Identifiers other than sequential integers.
@@ -11,10 +10,27 @@ require "zlib"
11
10
  # Adopt - Copy this file to your application with the above attribution to
12
11
  # allow others to find fixes, documentation, and new features.
13
12
  module MakeId
14
- # class Error < StandardError; end
13
+ class Error < StandardError; end
15
14
 
16
- CHARS32 = "0123456789abcdefghjkmnpqrstvwxyz" # Avoiding ambiguous 0/o i/l/I
17
- CHARS62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
15
+ # Base32 avoids ambiguous letters for 0/o/O and i/I/l/1. This is useful
16
+ # for human-interpreted codes for serial numbers, license keys, etc.
17
+ BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
18
+
19
+ # Ruby's Integer.to_s(2..36) uses extended Hexadecimal: 0-9,a-z.
20
+ # Base62 includes upper-case letters as well, maintaining ASCII cardinality.
21
+ BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
22
+
23
+ # Base64 Does not use ASCII-collating (sort) character set
24
+ BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
25
+
26
+ # Base94 extends Base64 with all printable ASCII special characters.
27
+ # Using Base of 90 won't use quotes, backslash
28
+ BASE94 = BASE64 + %q(!$%&()*,-.:;<=>?@[]^_{|}~#`'"\\)
29
+
30
+ # URL-Encoded Base64 swaps the + and / for - and _ respectively to avoid URL Encoding
31
+ URL_BASE64 = BASE64.tr("+/", "-_")
32
+
33
+ # TWitter Snowflake starts its epoch at this time.
18
34
  EPOCH_TWITTER = Time.utc(2006, 3, 21, 20, 50, 14)
19
35
 
20
36
  @@app_worker_id = ENV.fetch("APP_WORKER_ID", 0)
@@ -57,31 +73,11 @@ module MakeId
57
73
  end
58
74
 
59
75
  ##############################################################################
60
- # Random Strings
61
- ##############################################################################
62
-
63
- # Returns a random alphanumeric string of the given base, default of 62.
64
- # Base 64 uses URL-safe characters. Bases 19-32 and below use a special
65
- # character set that avoids visually ambiguous characters. Other bases
66
- # utilize the full alphanumeric characer set (digits, lower/upper letters).
67
- def self.random(size = 16, base: 62)
68
- raise "Base must be between 2 and 62, or 64, not #{base}" unless base < 63 || base == 64
69
- if base == 62
70
- SecureRandom.alphanumeric(size)
71
- elsif base == 64
72
- SecureRandom.urlsafe_base64(size)
73
- else
74
- alpha = (base <= 32) ? CHARS32 : CHARS62
75
- (1..size).map { alpha[SecureRandom.rand(base - 1)] }.join
76
- end
77
- end
78
-
79
- ##############################################################################
80
- # Integers
76
+ # Numeric Identifiers (of any suported base)
81
77
  ##############################################################################
82
78
 
83
79
  # Random Integer ID
84
- def self.random_id(bytes: 8, base: 10, absolute: true, check_digit: false)
80
+ def self.id(bytes: 8, base: 10, absolute: true, check_digit: false)
85
81
  id = SecureRandom.random_number(2**(bytes * 8) - 2) + 1 # +1 to avoid zero
86
82
  id = id.abs if absolute
87
83
  id = int_to_base(id, base) unless base == 10
@@ -89,11 +85,26 @@ module MakeId
89
85
  id
90
86
  end
91
87
 
88
+ def self.id_password(bytes: 8, base: 10, absolute: true, alpha: nil)
89
+ id = id(bytes: bytes)
90
+ pass = id(bytes: 16)
91
+ [int_to_base(id, base), encode_alphabet(pass, alpha || BASE94, seed: id)]
92
+ end
93
+
94
+ # Generates a 8-byte "nano id", a string of random characters of the given alphabet,
95
+ # suitable for URL's or where you don't want to show a sequential number.
96
+ # A check digit can be added to the end to help prevent typos.
97
+ def self.nano_id(bytes: 8, base: 62, check_digit: true)
98
+ bytes -= 1 if check_digit
99
+ id = id(bytes: bytes, base: base)
100
+ check_digit ? append_check_digit(id, base) : id
101
+ end
102
+
92
103
  ##############################################################################
93
104
  # UUID - Universally Unique Identifier
94
105
  ##############################################################################
95
106
 
96
- # Returns a (securely) random generated UUID v4
107
+ # Returns a 16-byte securely-random generated UUID v4
97
108
  def self.uuid
98
109
  SecureRandom.uuid
99
110
  end
@@ -106,66 +117,57 @@ module MakeId
106
117
  end
107
118
 
108
119
  ##############################################################################
109
- # Nano Id - Simple, secure URL-friendly unique string ID generator
120
+ # Strings Identifiers
110
121
  ##############################################################################
111
122
 
112
- # Generates a "nano id", a string of random characters of the given alphabet,
113
- # suitable for URL's or where you don't want to show a sequential number.
114
- # A check digit is added to the end to help prevent typos.
115
- def self.nano_id(size: 20, base: 62, check_digit: true)
116
- # alpha = (base <= 32) ? CHARS32 : CHARS62
117
- size -= 1 if check_digit
118
- id = random(size, base: base)
119
- check_digit ? append_check_digit(id, base) : id
120
- end
121
-
122
- # Given a nano_id, replaces visually ambiguous characters and verifies the
123
- # check digit. Returns the corrected id or nil if the check digit is invalid.
124
- def self.verify_base32_id(nanoid)
125
- nanoid.gsub!(/[oO]/, "0")
126
- nanoid.gsub!(/[lLiI]/, "1")
127
- nanoid.downcase
128
- valid_check_digit?(nanoid, base: 32)
123
+ # Returns a random alphanumeric string of the given base, default of 62.
124
+ # Base 64 uses URL-safe characters. Bases 19-32 and below use a special
125
+ # character set that avoids visually ambiguous characters. Other bases
126
+ # utilize the full alphanumeric characer set (digits, lower/upper letters).
127
+ def self.token(size = 16, base: 62, chars: nil)
128
+ _, chars = base_characters(base, chars)
129
+ SecureRandom.alphanumeric(size, chars: chars.chars)
129
130
  end
130
131
 
131
- # Manual Id is a code and/or identifier that is manually entered by a user.
132
- # Examples of this would be a Two-Factor Authentication challenge, a code
133
- # used for confirmation, redemption, or a short-term record lookup code
134
- # (like an airline ticket/itenerary code)
135
- # It uses a base-32 (non-ambiguous character set) by default,
136
- def self.manual_id(size: 6, base: 32, check_digit: false)
137
- base = 32 if base > 36 # For upcasing
138
- nano_id(size: size, base: base, check_digit: check_digit).upcase
132
+ # Returns a new, ramdonly-generated Base-32 code (no ambiguous characters).
133
+ # Use this for Two-Factor Authorization, and serial number codes to be
134
+ # input by users. Use verify_code() to "fix" user-input of codes.
135
+ def self.code(size = 8, group: 0, delimiter: "-")
136
+ id = token(size, base: 32)
137
+ id = id.chars.each_slice(group).map(&:join).join(delimiter) if group > 0
138
+ id
139
139
  end
140
140
 
141
- def self.fix_manual_id(id, base: 32, check_digit: false)
142
- if base == 32
143
- id = id.gsub(/[oO]/, "0")
144
- id = id.gsub(/[lLiI]/, "1")
145
- end
146
- id = valid_check_digit?(id.downcase, base: 32) if check_digit
147
- id.upcase
141
+ # Given a nano_id, replaces visually ambiguous characters and verifies the
142
+ # check digit. Returns the corrected id or nil if the check digit is invalid.
143
+ def self.verify_code(nanoid, check_digit: false)
144
+ nanoid = nanoid.gsub(/\W/, "")
145
+ nanoid = nanoid.gsub(/[oO]/, "0")
146
+ nanoid = nanoid.gsub(/[lLiI]/, "1")
147
+ nanoid = nanoid.upcase
148
+ return valid_check_digit?(nanoid, base: 32) if check_digit
149
+ nanoid
148
150
  end
149
151
 
150
152
  ##############################################################################
151
- # Event Id - A nano_id, but timestamped event identifier: YMDHMSUUrrrrc
153
+ # TEMPORAL Identifiers
152
154
  ##############################################################################
153
155
 
154
- # Returns an event timestamp of the form YMDHMSUUrrrrc
156
+ # Event Id - A nano_id, but timestamped event identifier: YMDHMSUUrrrrc
155
157
  def self.event_id(size: 12, check_digit: false, time: nil)
156
158
  time ||= Time.new.utc
157
159
  usec = int_to_base((time.subsec.to_f * 62 * 62).to_i, 62)
158
160
  parts = [
159
- CHARS62[time.year % @@epoch.year],
160
- CHARS62[time.month],
161
- CHARS62[time.day],
162
- CHARS62[time.hour],
163
- CHARS62[time.min],
164
- CHARS62[time.sec],
161
+ BASE62[time.year % @@epoch.year],
162
+ BASE62[time.month],
163
+ BASE62[time.day],
164
+ BASE62[time.hour],
165
+ BASE62[time.min],
166
+ BASE62[time.sec],
165
167
  usec.rjust(2, "0") # 2-chars, 0..3843
166
168
  ]
167
169
  nano_size = size - 8 - (check_digit ? 1 : 0)
168
- parts << nano_id(size: nano_size, base: 62) if nano_size > 0
170
+ parts << token(nano_size, base: 62) if nano_size > 0
169
171
  id = check_digit ? append_check_digit(parts.join, 62) : parts.join
170
172
  id[0, size]
171
173
  end
@@ -183,15 +185,15 @@ module MakeId
183
185
  end
184
186
 
185
187
  [
186
- CHARS62[time.year % @@epoch.year],
187
- CHARS62[time.month],
188
- CHARS62[time.day], # "-",
189
- CHARS62[time.hour].downcase,
188
+ BASE62[time.year % @@epoch.year],
189
+ BASE62[time.month],
190
+ BASE62[time.day], # "-",
191
+ BASE62[time.hour].downcase,
190
192
  int_to_base(seconds, 32).rjust(3, "0"), # 3 chars
191
193
  int_to_base((time.subsec.to_f * 32 * 32).to_i, 32), # 2 chars
192
194
  sequence.to_s(32).rjust(2, "0"), # 2 chars "-",
193
195
  (app_worker_id % 1024).to_s(32).rjust(2, "0"), # 2 chars
194
- random(3, base: 32)
196
+ token(3, base: 32)
195
197
  ].join
196
198
  end
197
199
 
@@ -298,23 +300,9 @@ module MakeId
298
300
  # Ruby's int.to_s(base) only goes to 36. Base 32 is special as it does not
299
301
  # contain visually ambiguous characters (1, not i, I, l, L) and (0, not o or O)
300
302
  # Which is useful for serial numbers or codes the user has to read or type
301
- def self.int_to_base(int, base = 62, check_digit: false)
302
- int = int.to_i
303
- if base == 10
304
- id = int.to_s
305
- elsif base == 64
306
- id = Base64.urlsafe_encode64(int.to_s).delete("=")
307
- elsif base == 32 || base > 36
308
- alpha = (base <= 32) ? CHARS32 : CHARS62
309
- id = ""
310
- while int > (base - 1)
311
- id = alpha[int % base] + id
312
- int /= base
313
- end
314
- id = alpha[int] + id
315
- else
316
- id = int.to_s(base)
317
- end
303
+ def self.int_to_base(int, base = 62, check_digit: false, chars: nil)
304
+ base, chars = base_characters(base, chars)
305
+ id = encode_alphabet(int, chars)
318
306
  check_digit ? append_check_digit(id, base) : id
319
307
  end
320
308
 
@@ -322,21 +310,55 @@ module MakeId
322
310
 
323
311
  # Parses a string as a base n number and returns its decimal integer value
324
312
  def self.base_to_int(string, base = 62, check_digit: false)
325
- # TODO check_digit
326
- if base == 64
327
- int = Base64.urlsafe_decode64(string.to_s + "==")
328
- elsif base == 32 || base > 36
329
- alpha = (base <= 32) ? CHARS32 : CHARS62
330
- string = string.to_s
331
- int = 0
332
- string.each_char { |c| int = int * base + alpha.index(c) }
333
- else
334
- int = string.to_i(base)
313
+ # TODO: check_digit
314
+ _, chars = base_characters(base, chars)
315
+ decode_alphabet(string, chars)
316
+ end
317
+
318
+ singleton_class.alias_method :from_base, :base_to_int
319
+
320
+ def self.encode_alphabet(int, alpha = BASE62, seed: nil)
321
+ base = alpha.size
322
+ alpha = alpha.chars.shuffle(random: Random.new(seed)).join if seed
323
+ id = ""
324
+ while int > (base - 1)
325
+ id = alpha[int % base] + id
326
+ int /= base
335
327
  end
328
+ alpha[int] + id
329
+ end
330
+
331
+ def self.decode_alphabet(string, alpha = BASE32, seed: nil, base: nil)
332
+ base ||= alpha.size
333
+ alpha = alpha.chars.shuffle(random: Random.new(seed)).join if seed
334
+ int = 0
335
+ string.each_char { |c| int = int * base + alpha.index(c) }
336
336
  int
337
+ rescue
338
+ nil
337
339
  end
338
340
 
339
- singleton_class.alias_method :from_base, :base_to_int
341
+ # Returns the refined base and characters used for the base conversions
342
+ def self.base_characters(base, chars = nil, shuffle_seed: nil)
343
+ if chars
344
+ base ||= chars.size
345
+ chars = chars[0..(base - 1)]
346
+ elsif base > 94 || base < 2
347
+ raise Error.new("Base#{base} is not supported")
348
+ elsif base > 64
349
+ chars = BASE94[0..(base - 1)]
350
+ elsif base > 62
351
+ chars = URL_BASE64[0..(base - 1)]
352
+ elsif base == 32
353
+ chars = BASE32
354
+ else
355
+ chars = BASE62[0..(base - 1)]
356
+ end
357
+ chars = chars.chars.shuffle(random: Random.new(shuffle_seed)).join if shuffle_seed
358
+ base = chars.size
359
+
360
+ [base, chars]
361
+ end
340
362
 
341
363
  ##############################################################################
342
364
  # Check Digit
@@ -352,6 +374,7 @@ module MakeId
352
374
  # Uses a pre-defined check_proc if configured. See check_proc=().
353
375
  def self.compute_check_digit(id, base = 10)
354
376
  return @@check_proc.call(id, base) if @@check_proc.is_a?(Proc)
377
+
355
378
  int_to_base(Zlib.crc32(id.to_s) % base, base)
356
379
  end
357
380
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: make_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Allen Fair
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-13 00:00:00.000000000 Z
11
+ date: 2024-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64