cool_id 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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