cool_id 0.1.1 → 0.1.3

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cool_id/version.rb +1 -1
  3. data/lib/cool_id.rb +75 -43
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b8bf372b8ba519b55df6abcae1fa6de344364a77ca7c9d6f69e86257debac10
4
- data.tar.gz: bfe555391aca0355a559243dc3e9ebd96bf02ee39ab141152941ee613d0cbdce
3
+ metadata.gz: 6a61d8d06c3414dcec52ecd9a3f28696d0fafb683b2b206e025c33a1deb03de9
4
+ data.tar.gz: bc13a903ed6d5239eae6ee216f5da45699a525d755e914f9f9c2b81b6e33d26c
5
5
  SHA512:
6
- metadata.gz: e0d61a8a41f45d8e204a5690e07f8be25a05463783d52ef289e3bfe4f98614159e682d79d2fc889719efe983a2f7cc57db901f3111d89005bfdf50f3322dcc04
7
- data.tar.gz: ea9cf71b9c7fc2296eb48e1bf7c80f278ddbcf5113d08e6e1e7de113b1419a7889af698fe9a19427bf22ca89762ece47295f89ad3dc0b31d2affa5e6882ce578
6
+ metadata.gz: 77aac33c12253962d7beabffc5d7101379f40d991b580c67ea0a306cd82f8d2befda21b23fbd3c3735a516863ef4c3565b18084f67ed001172b7a395527f3f4a
7
+ data.tar.gz: d3c269343bd10098fdd902424c10c22e676a0cea67d5dff404628863ea4d085319017b31d6c602364da024d36c30a470e1bd3ade7b687379bbbd3f011a72191c
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CoolId
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/cool_id.rb CHANGED
@@ -3,76 +3,90 @@
3
3
  require_relative "cool_id/version"
4
4
  require "nanoid"
5
5
  require "active_support/concern"
6
- require "active_record"
7
6
 
8
7
  module CoolId
9
8
  class Error < StandardError; end
10
9
 
10
+ # defaults based on https://planetscale.com/blog/why-we-chose-nanoids-for-planetscales-api
11
+ DEFAULT_SEPARATOR = "_"
12
+ DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"
13
+ DEFAULT_LENGTH = 12
14
+
15
+ Id = Struct.new(:key, :prefix, :id, :model_class)
16
+
11
17
  class << self
12
- attr_accessor :separator
18
+ attr_accessor :separator, :alphabet, :length
13
19
 
14
20
  def configure
15
21
  yield self
16
22
  end
17
23
 
24
+ def reset_configuration
25
+ self.separator = DEFAULT_SEPARATOR
26
+ self.alphabet = DEFAULT_ALPHABET
27
+ self.length = DEFAULT_LENGTH
28
+ end
29
+
18
30
  def registry
19
- @registry ||= Registry.new
31
+ @prefix_map ||= Registry.new
20
32
  end
21
33
 
22
34
  def generate_id(config)
23
- id = Nanoid.generate(size: config.length, alphabet: config.alphabet)
24
- [config.prefix, id].reject(&:empty?).join(@separator)
35
+ alphabet = config.alphabet || @alphabet
36
+ length = config.length || @length
37
+ id = Nanoid.generate(size: length, alphabet: alphabet)
38
+
39
+ "#{config.prefix}#{separator}#{id}"
25
40
  end
26
41
  end
27
42
 
28
- self.separator = "_"
43
+ self.separator = DEFAULT_SEPARATOR
44
+ self.alphabet = DEFAULT_ALPHABET
45
+ self.length = DEFAULT_LENGTH
29
46
 
30
47
  class Registry
31
48
  def initialize
32
- @registry = {}
49
+ @prefix_map = {}
33
50
  end
34
51
 
35
52
  def register(prefix, model_class)
36
- @registry[prefix] = model_class
53
+ @prefix_map[prefix] = model_class
37
54
  end
38
55
 
39
- def find_model(prefix)
40
- @registry[prefix]
56
+ def locate(id)
57
+ parsed = parse(id)
58
+ parsed&.model_class&.find_by(id: id)
41
59
  end
42
60
 
43
- def find_record(id)
44
- prefix, _ = id.split(CoolId.separator, 2)
45
- model_class = find_model(prefix)
46
- model_class&.find_by(id: id)
47
- end
48
-
49
- def find_record!(id)
50
- prefix, _ = id.split(CoolId.separator, 2)
51
- model_class = find_model(prefix)
52
- model_class&.find(id)
61
+ def parse(id)
62
+ prefix, key = id.split(CoolId.separator, 2)
63
+ model_class = @prefix_map[prefix]
64
+ return nil unless model_class
65
+ Id.new(key, prefix, id, model_class)
53
66
  end
54
67
  end
55
68
 
56
69
  class Config
57
70
  attr_reader :prefix, :length, :alphabet
58
71
 
59
- def initialize(prefix: "", length: 12, alphabet: "0123456789abcdefghijklmnopqrstuvwxyz")
60
- @prefix = prefix
72
+ def initialize(prefix:, length: nil, alphabet: nil)
61
73
  @length = length
62
- self.alphabet = alphabet
63
- end
64
-
65
- def alphabet=(value)
66
- validate_alphabet(value)
67
- @alphabet = value
74
+ @prefix = validate_prefix(prefix)
75
+ @alphabet = validate_alphabet(alphabet)
68
76
  end
69
77
 
70
78
  private
71
79
 
80
+ def validate_prefix(value)
81
+ raise ArgumentError, "Prefix cannot be nil" if value.nil?
82
+ raise ArgumentError, "Prefix cannot be empty" if value.empty?
83
+ value
84
+ end
85
+
72
86
  def validate_alphabet(value)
73
- if value.include?(CoolId.separator)
74
- raise ArgumentError, "Alphabet cannot include the separator '#{CoolId.separator}'"
75
- end
87
+ return nil if value.nil?
88
+ raise ArgumentError, "Alphabet cannot include the separator '#{CoolId.separator}'" if value.include?(CoolId.separator)
89
+ value
76
90
  end
77
91
  end
78
92
 
@@ -80,39 +94,57 @@ module CoolId
80
94
  extend ActiveSupport::Concern
81
95
 
82
96
  class_methods do
83
- attr_reader :cool_id_config
84
-
85
- def cool_id(options = {})
86
- register_cool_id(options)
87
- end
97
+ attr_accessor :cool_id_config
98
+ attr_accessor :cool_id_setup_required
88
99
 
89
- def register_cool_id(options = {})
90
- raise ArgumentError, "Prefix cannot be empty" if options[:prefix] && options[:prefix].empty?
100
+ def cool_id(options)
91
101
  @cool_id_config = Config.new(**options)
92
102
  CoolId.registry.register(options[:prefix], self)
93
103
  end
94
104
 
95
105
  def generate_cool_id
96
- CoolId.generate_id(@cool_id_config || Config.new)
106
+ CoolId.generate_id(@cool_id_config)
107
+ end
108
+
109
+ def ensure_cool_id_setup
110
+ @cool_id_setup_required = true
111
+ end
112
+
113
+ def skip_cool_id_setup
114
+ @cool_id_setup_required = false
115
+ end
116
+
117
+ def inherited(subclass)
118
+ super
119
+ if @cool_id_setup_required && !subclass.instance_variable_defined?(:@cool_id_setup_required)
120
+ subclass.instance_variable_set(:@cool_id_setup_required, true)
121
+ end
97
122
  end
98
123
  end
99
124
 
100
125
  included do
101
126
  before_create :set_cool_id
127
+ after_initialize :ensure_cool_id_configured
102
128
 
103
129
  private
104
130
 
105
131
  def set_cool_id
106
132
  self.id = self.class.generate_cool_id if id.blank?
107
133
  end
134
+
135
+ def ensure_cool_id_configured
136
+ if self.class.cool_id_setup_required && self.class.cool_id_config.nil?
137
+ raise Error, "CoolId not configured for #{self.class}. Use 'cool_id' to configure or 'skip_cool_id_setup' to opt out."
138
+ end
139
+ end
108
140
  end
109
141
  end
110
142
 
111
- def self.find(id)
112
- registry.find_record(id)
143
+ def self.locate(id)
144
+ registry.locate(id)
113
145
  end
114
146
 
115
- def self.find!(id)
116
- registry.find_record!(id)
147
+ def self.parse(id)
148
+ registry.parse(id)
117
149
  end
118
150
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cool_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Schilling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-16 00:00:00.000000000 Z
11
+ date: 2024-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nanoid