ruby-ulid 0.1.3 → 0.1.4

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 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