ruby-ulid 0.1.3 → 0.1.4

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
  SHA256:
3
- metadata.gz: f4101c27c1bd3f61d9882bb06444cb929975461e4e8258d44869e40a564a8ede
4
- data.tar.gz: 716df050e1cff54368ad826d04065eea06e7fdcca9973509bdd69c980ce2c347
3
+ metadata.gz: 2a390455a27395fd77ef398b0613e72b321b96d44e8454c8ab9346ae15eddfdc
4
+ data.tar.gz: 1150658ae26cc591f3946898ccb356ce1c6135292de0600ef0604aceb7a00554
5
5
  SHA512:
6
- metadata.gz: c4e70f2f648e8cb165cf03014a35d8c83a879a037eecc89f4b0d91717ccc3107a19ae12372dd6788ae601abbc6498a01e0cad08247f684d1bc5b72c0a43d017c
7
- data.tar.gz: 821bdac8833a3034b5842133961d8bb1c8e6c9f67c487ec25533c0ee23f3933a6bc71ef0b995cda957706f3bf6813c08a3e7e1d4f1ab8d749522db76892101ed
6
+ metadata.gz: 4ffb5c69ec1327bacbb54b4afdd6718f8cc9b5afd450f739588d8e414c645eca9c1090c77efb464293f0e8e1b960cf4df75289785d3cd7b489404e31c24ecc8a
7
+ data.tar.gz: bf6a08216e0745d0727c356a5a239126bac8518f8fbb57f295b417e14ed0878c8f0c32774b83137b1feb58d8230140492cb469bb18dc9d5df5db5aa088410ffb
data/README.md CHANGED
@@ -28,7 +28,7 @@ Instead, herein is proposed ULID:
28
28
  - 1.21e+24 unique ULIDs per millisecond
29
29
  - Lexicographically sortable!
30
30
  - Canonically encoded as a 26 character string, as opposed to the 36 character UUID
31
- - Uses [Crockford's base32](https://www.crockford.com/base32.html) for better efficiency and readability (5 bits per character) # See also exists issues in [Note](#note)
31
+ - Uses [Crockford's base32](https://www.crockford.com/base32.html) for better efficiency and readability (5 bits per character)
32
32
  - Case insensitive
33
33
  - No special characters (URL safe)
34
34
  - Monotonic sort order (correctly detects and handles the same millisecond)
@@ -49,7 +49,7 @@ Should be installed!
49
49
  Add this line to your application/library's `Gemfile` is needed in basic use-case
50
50
 
51
51
  ```ruby
52
- gem 'ruby-ulid', '>= 0.1.3', '< 0.2.0'
52
+ gem 'ruby-ulid', '>= 0.1.4', '< 0.2.0'
53
53
  ```
54
54
 
55
55
  ### Generator and Parser
@@ -146,7 +146,7 @@ sample_ulids_by_the_time.take(5) #=>
146
146
  ulids.sort == ulids #=> true
147
147
  ```
148
148
 
149
- Same generator does not generate duplicated ULIDs even in multi threads environment. It is implemented with [Thread::Mutex](https://github.com/ruby/ruby/blob/5f8bca32571fa9c651f6903d36f66082363f8879/thread_sync.c#L1572-L1582)
149
+ Same generator does not generate duplicated ULIDs even in multi threads environment. It is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
150
150
 
151
151
  ### Filtering IDs with `Time`
152
152
 
@@ -326,6 +326,34 @@ ULID.sample(10, period: ulid1.to_time..ulid2.to_time)
326
326
  # ULID(2021-04-28 15:05:06.808 UTC: 01F4CG68ZRST94T056KRZ5K9S4)]
327
327
  ```
328
328
 
329
+ ### ULID specification ambiguity around orthographical variants of the format
330
+
331
+ 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.
332
+
333
+ >Uses Crockford's base32 for better efficiency and readability (5 bits per character)
334
+
335
+ The original `Crockford's base32` maps `I`, `L` to `1`, `O` to `0`.
336
+ And accepts freestyle inserting `Hyphens (-)`.
337
+ To consider this patterns or not is different in each implementations.
338
+
339
+ Current parser/validator/matcher aims to cover `subset of Crockford's base32`.
340
+ I have suggested it would be clarified in [ulid/spec#57](https://github.com/ulid/spec/pull/57).
341
+
342
+ >Case insensitive
343
+
344
+ I can understand it might be considered in actual use-case.
345
+ But it is a controversial point, discussing in [ulid/spec#3](https://github.com/ulid/spec/issues/3).
346
+
347
+ Be that as it may, this gem provides API for handling the nasty possibilities.
348
+
349
+ `ULID.normalize` and `ULID.normalized?`
350
+
351
+ ```ruby
352
+ ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
353
+ ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
354
+ ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
355
+ ```
356
+
329
357
  ### UUIDv4 converter for migration use-cases
330
358
 
331
359
  `ULID.from_uuidv4` and `ULID#to_uuidv4` is the converter.
@@ -418,4 +446,3 @@ The results are not something to be proud of.
418
446
  ## Note
419
447
 
420
448
  - Another choices for sortable and randomness IDs, [UUIDv6, UUIDv7, UUIDv8 might be the one. (But they are still in draft state)](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-01.html), I will track them in [ruby-ulid#37](https://github.com/kachick/ruby-ulid/issues/37)
421
- - Current parser/validator/matcher aims to cover `subset of Crockford's base32`. Suggesting it in [ulid/spec#57](https://github.com/ulid/spec/pull/57). Be that as it may, I might provide special handler or converter for the exception in [ruby-ulid#57](https://github.com/kachick/ruby-ulid/issues/57) and/or [ruby-ulid#78](https://github.com/kachick/ruby-ulid/issues/78)
data/lib/ulid.rb CHANGED
@@ -259,6 +259,27 @@ class ULID
259
259
  from_integer(CrockfordBase32.decode(string))
260
260
  end
261
261
 
262
+ # @param [String, #to_str] string
263
+ # @return [String]
264
+ # @raise [ParserError] if the given format is not correct for ULID specs, even if ignored `orthographical variants of the format`
265
+ def self.normalize(string)
266
+ string = String.try_convert(string)
267
+ raise ArgumentError, 'ULID.normalize takes only strings' unless string
268
+
269
+ normalized_in_crockford = CrockfordBase32.normalize(string)
270
+ # Ensure the ULID correctness, because CrockfordBase32 does not always mean to satisfy ULID format
271
+ parse(normalized_in_crockford).to_s
272
+ end
273
+
274
+ # @return [Boolean]
275
+ def self.normalized?(object)
276
+ normalized = normalize(object)
277
+ rescue Exception
278
+ false
279
+ else
280
+ normalized == object
281
+ end
282
+
262
283
  # @return [Boolean]
263
284
  def self.valid?(object)
264
285
  string = String.try_convert(object)
@@ -51,6 +51,14 @@ class ULID
51
51
  CROCKFORD_BASE32_CHAR_BY_N32_CHAR = N32_CHAR_BY_CROCKFORD_BASE32_CHAR.invert.freeze
52
52
  N32_CHAR_PATTERN = /[#{CROCKFORD_BASE32_CHAR_BY_N32_CHAR.keys.join}]/.freeze
53
53
 
54
+ VARIANT_BY_STANDARD = {
55
+ 'L' => '1',
56
+ 'I' => '1',
57
+ 'O' => '0',
58
+ '-' => ''
59
+ }.freeze
60
+ VARIANT_PATTERN = /[#{VARIANT_BY_STANDARD.keys.join}]/.freeze
61
+
54
62
  # @api private
55
63
  # @param [String] string
56
64
  # @return [Integer]
@@ -66,5 +74,12 @@ class ULID
66
74
  n32encoded = integer.to_s(32)
67
75
  n32encoded.upcase.gsub(N32_CHAR_PATTERN, CROCKFORD_BASE32_CHAR_BY_N32_CHAR).rjust(ENCODED_LENGTH, '0')
68
76
  end
77
+
78
+ # @api private
79
+ # @param [String] string
80
+ # @return [String]
81
+ def self.normalize(string)
82
+ string.upcase.gsub(VARIANT_PATTERN, VARIANT_BY_STANDARD)
83
+ end
69
84
  end
70
85
  end
@@ -4,13 +4,15 @@
4
4
 
5
5
  class ULID
6
6
  class MonotonicGenerator
7
+ include MonitorMixin
8
+
7
9
  # @return [ULID, nil]
8
10
  attr_reader :prev
9
11
 
10
12
  undef_method :instance_variable_set
11
13
 
12
14
  def initialize
13
- @mutex = Thread::Mutex.new
15
+ super()
14
16
  @prev = nil
15
17
  end
16
18
 
@@ -26,7 +28,7 @@ class ULID
26
28
  # @raise [UnexpectedError] if the generated ULID is an invalid value in monotonicity spec.
27
29
  # Basically will not happen. Just means this feature prefers error rather than invalid value.
28
30
  def generate(moment: ULID.current_milliseconds)
29
- @mutex.synchronize do
31
+ synchronize do
30
32
  unless @prev
31
33
  @prev = ULID.generate(moment: moment)
32
34
  return @prev
data/lib/ulid/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class ULID
5
- VERSION = '0.1.3'
5
+ VERSION = '0.1.4'
6
6
  end
data/sig/ulid.rbs CHANGED
@@ -43,27 +43,51 @@ class ULID < Object
43
43
  CROCKFORD_BASE32_CHAR_PATTERN: Regexp
44
44
  CROCKFORD_BASE32_CHAR_BY_N32_CHAR: Hash[String, String]
45
45
  N32_CHAR_PATTERN: Regexp
46
+ VARIANT_BY_STANDARD: Hash[String, String]
47
+ VARIANT_PATTERN: Regexp
46
48
 
47
49
  # A pribate API. Should not be used in your code.
48
50
  def self.encode: (Integer integer) -> String
49
51
 
50
52
  # A pribate API. Should not be used in your code.
51
53
  def self.decode: (String string) -> Integer
54
+
55
+ # A pribate API. Should not be used in your code.
56
+ def self.normalize: (String string) -> String
52
57
  end
53
58
 
54
59
  class MonotonicGenerator
55
- @mutex: Thread::Mutex
56
-
57
- # The returned value is `not` Thready-safety
60
+ include MonitorMixin
61
+
62
+ # Returned value is `basically not` Thread-safety
63
+ # If you want to keep Thread-safety, keep to call {#generate} only in same {#synchronize} block
64
+ #
65
+ # ```ruby
66
+ # generator.synchronize do
67
+ # generator.prev
68
+ # generator.inspect
69
+ # generator.generate
70
+ # end
71
+ # ```
58
72
  attr_reader prev: ULID | nil
59
73
 
60
74
  # A pribate API. Should not be used in your code.
61
75
  def initialize: -> void
62
76
 
63
77
  # 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)
78
+ # The `Thread-safety` is implemented with [Monitor](https://bugs.ruby-lang.org/issues/16255)
64
79
  def generate: (?moment: moment) -> ULID
65
80
 
66
- # The returned value is `not` Thready-safety
81
+ # Returned value is `basically not` Thread-safety
82
+ # If you want to keep Thread-safety, keep to call {#generate} only in same {#synchronize} block
83
+ #
84
+ # ```ruby
85
+ # generator.synchronize do
86
+ # generator.prev
87
+ # generator.inspect
88
+ # generator.generate
89
+ # end
90
+ # ```
67
91
  def inspect: -> String
68
92
  alias to_s inspect
69
93
  def freeze: -> void
@@ -298,6 +322,28 @@ class ULID < Object
298
322
  | (Integer number, ?period: period) -> Array[self]
299
323
  def self.valid?: (untyped) -> bool
300
324
 
325
+ # Returns normalized string
326
+ #
327
+ # ```ruby
328
+ # ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
329
+ # ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
330
+ # ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
331
+ # ```
332
+ #
333
+ # See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
334
+ def self.normalize: (_ToStr string) -> String
335
+
336
+ # Returns `true` if it is normalized string
337
+ #
338
+ # ```ruby
339
+ # ULID.normalize('-olarz3-noekisv4rrff-q6ig5fav--') #=> "01ARZ3N0EK1SV4RRFFQ61G5FAV"
340
+ # ULID.normalized?('-olarz3-noekisv4rrff-q6ig5fav--') #=> false
341
+ # ULID.normalized?('01ARZ3N0EK1SV4RRFFQ61G5FAV') #=> true
342
+ # ```
343
+ #
344
+ # See also [ulid/spec#57](https://github.com/ulid/spec/pull/57) and [ulid/spec#3](https://github.com/ulid/spec/issues/3)
345
+ def self.normalized?: (untyped) -> bool
346
+
301
347
  # Returns parsed ULIDs from given String for rough operations.
302
348
  #
303
349
  # ```ruby
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.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenichi Kamiya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-16 00:00:00.000000000 Z
11
+ date: 2021-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit