opaque_id 1.4.0 → 1.6.0

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: 9c8c508626e3cd753337a4a0ca5a6a7eecdce926bd0532f709bbbb19b2626975
4
- data.tar.gz: cee4cdec34b43245b1abb4f35924498c034c9060648f9500705132a9e8742cb1
3
+ metadata.gz: 016b3d2bbd7ae3af1ba38973c0b590164d7be1a4bd60a8c0e0379cfca1c9dc0f
4
+ data.tar.gz: 2924779f8769585995732ce79da51b8a1171c0b22fd33636c6476f77815adb44
5
5
  SHA512:
6
- metadata.gz: 72d0b70b4f3285b14e9522adf8682691c59d82db7457c468ceed724b4c381da8d297921cc891eeda749333f4f81f1170b69b33587e7ef8a0485f948492dea40a
7
- data.tar.gz: 71f986687e83368d0a34ae4ce692a526a17c17c55ef3e77edd462e7f0ae9503c5dd943417bc4166e0a8f775eea897b2c93a06dedddf9fc267f5680af869acbab
6
+ metadata.gz: 82206f53378e08c302fbb9bd56caf94238e3b0780b6a271732d00d04f0e7e37136c1c6c941ef58fe6c6fffd154c7ce1b82c0b12b76240d23399007d34d81a0bd
7
+ data.tar.gz: b5d588f50a7a2337b42fc4e021b9aef658cf3e9f92c64fe5c21c7bf901560d5575b48c05fe72edefa77112175357562b0497c4c3d2ba73dd23be2165b6eadd87
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.4.0"
2
+ ".": "1.6.0"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -5,6 +5,122 @@ All notable changes to the OpaqueId gem will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.6.0](https://github.com/nyaggah/opaque_id/compare/opaque_id-v1.5.0...opaque_id/v1.6.0) (2025-10-03)
9
+
10
+
11
+ ### Features
12
+
13
+ * add external links to sidebar using JavaScript ([cd77079](https://github.com/nyaggah/opaque_id/commit/cd770795936ca76633a18f80cba8482ec09db8e2))
14
+ * add SLUG_LIKE_ALPHABET as default for URL-safe IDs ([1e52b17](https://github.com/nyaggah/opaque_id/commit/1e52b174d70ca72b74badf399401605b307e3604))
15
+ * add Table of Contents to all documentation pages ([9472175](https://github.com/nyaggah/opaque_id/commit/94721752270211d5b7db460da61d79a8a81218b2))
16
+ * complete Table of Contents implementation ([5b037e4](https://github.com/nyaggah/opaque_id/commit/5b037e42692803204bc4d8991b6d2e0c9639a05c))
17
+ * implement dynamic copyright year ([b86cea6](https://github.com/nyaggah/opaque_id/commit/b86cea66e60939377c6b0a67c1d385c9bf4bece3))
18
+ * improve documentation site theme and navigation ([304f845](https://github.com/nyaggah/opaque_id/commit/304f845a47397ea2a15f12d2c635144b39be431b))
19
+ * improve generator API and add custom column configuration ([5c1a570](https://github.com/nyaggah/opaque_id/commit/5c1a5703dee269f6985d26096942c086787296f3))
20
+ * initial release of OpaqueId gem v0.1.0 ([3a90274](https://github.com/nyaggah/opaque_id/commit/3a9027403552f8160e3aaf413d1e99ce8c63bbe4))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * add frozen string literal comment to docs/Gemfile ([2d653a7](https://github.com/nyaggah/opaque_id/commit/2d653a7bbc071e67e94e63ebc1602768b8d04456))
26
+ * add Release Please manifest and update workflow configuration ([f33ce6c](https://github.com/nyaggah/opaque_id/commit/f33ce6c96805b6c670cd1eedf5ebed2a46e8ffa6))
27
+ * add required permissions for Release Please job ([cdf8d2b](https://github.com/nyaggah/opaque_id/commit/cdf8d2bfc5dbea9a9ec40411a988191ba91913fa))
28
+ * configure just-the-docs theme for GitHub Pages compatibility ([c2fb96c](https://github.com/nyaggah/opaque_id/commit/c2fb96c46e99fd5287520e01c3bc2dd7bd5d4817))
29
+ * correct aux_links configuration format ([61b3fb9](https://github.com/nyaggah/opaque_id/commit/61b3fb9441ce3cfc3cf30637c277d19135f89dab))
30
+ * correct release-please tag format ([b4c31e5](https://github.com/nyaggah/opaque_id/commit/b4c31e5d0f4878878dd728e82fe9f5eb09ce5b82))
31
+ * improve publish workflow trigger reliability ([9c6e240](https://github.com/nyaggah/opaque_id/commit/9c6e2402474d8ecf8a3f754a9f2ca149a63bf1d1))
32
+ * improve statistical test reliability for CI ([c9b0d52](https://github.com/nyaggah/opaque_id/commit/c9b0d52fb4e9559aad489fcf58bdff1917d613a6))
33
+ * remove unsupported Release Please configuration parameters ([e3b0d2a](https://github.com/nyaggah/opaque_id/commit/e3b0d2ac96b905316a78992004fae83423991632))
34
+ * resolve CSS linting warnings ([d01e8c0](https://github.com/nyaggah/opaque_id/commit/d01e8c05628b7f2bd8b39a13325112168cf4e689))
35
+ * resolve dependency version conflicts and improve test robustness ([af43e13](https://github.com/nyaggah/opaque_id/commit/af43e13393a452f11ce32bafb26a267d1460736c))
36
+ * resolve TOC rendering and improve workflow configuration ([244d532](https://github.com/nyaggah/opaque_id/commit/244d5321e5b18091d8599bd772a28f5a30239c80))
37
+ * update deprecated platform specifications in docs/Gemfile ([cf96134](https://github.com/nyaggah/opaque_id/commit/cf9613499150dd7152bff38aa8f8fe7ab9923eb5))
38
+ * use correct aux_links format ([d4a4bc0](https://github.com/nyaggah/opaque_id/commit/d4a4bc0c11bc66b661034915b471ed762611d821))
39
+
40
+
41
+ ### Documentation
42
+
43
+ * final cleanup of over-inflated claims ([795b5b0](https://github.com/nyaggah/opaque_id/commit/795b5b0071a098f718a40e84e81ceba4525b8d3b))
44
+ * implement comprehensive documentation site with dark theme ([19cc9e3](https://github.com/nyaggah/opaque_id/commit/19cc9e30c584658559c5404a4518e871039cc223))
45
+ * implement comprehensive documentation site with dark theme ([a249c6a](https://github.com/nyaggah/opaque_id/commit/a249c6ad2253439f0d070620a914ff87597cf7cb))
46
+ * tone down over-inflated claims and remove unsubstantiated benchmarks ([6536b87](https://github.com/nyaggah/opaque_id/commit/6536b87f9a9c2049497328319641ff21368c6032))
47
+ * tone down pretentious language in algorithms intro ([58c0caf](https://github.com/nyaggah/opaque_id/commit/58c0caf116228401b6218ec589a35b350d068b49))
48
+
49
+
50
+ ### Styles
51
+
52
+ * improve code formatting in generator ([ce52021](https://github.com/nyaggah/opaque_id/commit/ce52021cd60e3594dc1ee34e5b96d48568008b5a))
53
+
54
+
55
+ ### Miscellaneous Chores
56
+
57
+ * configure just-the-docs theme ([3dfcac8](https://github.com/nyaggah/opaque_id/commit/3dfcac88099e65e61931e558e9242050bdbf0bc9))
58
+ * **main:** release 1.0.0 ([43282c5](https://github.com/nyaggah/opaque_id/commit/43282c5865aae3f136c9eaa49f013066a2359826))
59
+ * **main:** release 1.0.0 ([b8271ad](https://github.com/nyaggah/opaque_id/commit/b8271ad43cf6fab4687276258f0105c06a87bff7))
60
+ * **main:** release 1.0.1 ([4ee2e2c](https://github.com/nyaggah/opaque_id/commit/4ee2e2c69905e71d6c5048617af09b65cbb9e12a))
61
+ * **main:** release 1.0.1 ([e6cd2f8](https://github.com/nyaggah/opaque_id/commit/e6cd2f8f8ff545ad3010598488f71956e36a88c5))
62
+ * **main:** release 1.0.2 ([d5c7423](https://github.com/nyaggah/opaque_id/commit/d5c7423cf06ae7638d95cdd29b2631049efed727))
63
+ * **main:** release 1.0.2 ([365dff8](https://github.com/nyaggah/opaque_id/commit/365dff87a044aa967906866d6ace8d1ccad08c78))
64
+ * **main:** release opaque_id 1.1.0 ([df65c79](https://github.com/nyaggah/opaque_id/commit/df65c79d0efaee1dcd89b8af2f1b1c712c3cc2cd))
65
+ * **main:** release opaque_id 1.1.0 ([e2a4ee0](https://github.com/nyaggah/opaque_id/commit/e2a4ee0fd2d31132bc5bc0de6b6115f3ceae8afb))
66
+ * **main:** release opaque_id 1.2.0 ([1987b07](https://github.com/nyaggah/opaque_id/commit/1987b07b3db92216f3fbbe807c3ad66ca105866e))
67
+ * **main:** release opaque_id 1.2.0 ([aacd20a](https://github.com/nyaggah/opaque_id/commit/aacd20aa5eaa1fe2fa76d89cc6bdab26214b744d))
68
+ * **main:** release opaque_id 1.3.0 ([964b1b4](https://github.com/nyaggah/opaque_id/commit/964b1b421b1fac3fe43b15549e0e6b216b600357))
69
+ * **main:** release opaque_id 1.3.0 ([76453ad](https://github.com/nyaggah/opaque_id/commit/76453ad18b2d2b81548e49dafb5dde6fb52abcca))
70
+ * **main:** release opaque_id 1.4.0 ([6c3ccd1](https://github.com/nyaggah/opaque_id/commit/6c3ccd108b3eea0bbf0ac71fda4ccc0e47e97b95))
71
+ * **main:** release opaque_id 1.4.0 ([3d9d818](https://github.com/nyaggah/opaque_id/commit/3d9d818b34771ad1ca729f3f9b443784a6965568))
72
+ * **main:** release opaque_id 1.5.0 ([113af74](https://github.com/nyaggah/opaque_id/commit/113af74dda07330bf7108977147362385dc806ae))
73
+ * **main:** release opaque_id 1.5.0 ([ff14fe9](https://github.com/nyaggah/opaque_id/commit/ff14fe92d94cf4ecbe5aaeb31ad6cd044bfa89d0))
74
+ * remove tasks/ directory from source control ([e007ead](https://github.com/nyaggah/opaque_id/commit/e007ead90fa3fbb62ab17e334563e69899afb259))
75
+ * sync version to 1.0.2 ([2f870c8](https://github.com/nyaggah/opaque_id/commit/2f870c89d486f0a5cda8ef37e5544c29c8fa2919))
76
+ * update author name and GitHub URLs ([e911548](https://github.com/nyaggah/opaque_id/commit/e911548e89e1e60ac3281157059f7c7b812750bd))
77
+ * update bundle and add Linux platform support ([661842f](https://github.com/nyaggah/opaque_id/commit/661842f0ba66ce36962bb11f75a1b0e35eb5a3e7))
78
+ * update Gemfile.lock after dependency check ([058281f](https://github.com/nyaggah/opaque_id/commit/058281f6e07f3c9a1057c6fbeb0200bccf221558))
79
+
80
+
81
+ ### Code Refactoring
82
+
83
+ * improve generator code quality and resolve RuboCop issues ([b658bbc](https://github.com/nyaggah/opaque_id/commit/b658bbcb29f6c0134f2bf256b24c5b3c2bccb265))
84
+ * integrate Release Please into main CI workflow ([8a0b189](https://github.com/nyaggah/opaque_id/commit/8a0b189a8bfbfcc07275c9bdda3397ff367b2054))
85
+ * simplify external links implementation ([5cb84c1](https://github.com/nyaggah/opaque_id/commit/5cb84c1e8952a0fd1aa4b9089b9ff11829dc397c))
86
+
87
+
88
+ ### Tests
89
+
90
+ * add test for lowercase model names ([8ef4675](https://github.com/nyaggah/opaque_id/commit/8ef4675a0698d2cda054084360c9e80d956ddb14))
91
+ * update tests for SLUG_LIKE_ALPHABET defaults ([d7296c7](https://github.com/nyaggah/opaque_id/commit/d7296c77b1b7a995e7a42b3ba546fdeb8e41c297))
92
+ * update tests for SLUG_LIKE_ALPHABET defaults ([d1f8f26](https://github.com/nyaggah/opaque_id/commit/d1f8f26e7be80f6cbefc98563c0ffa45033372dc))
93
+
94
+ ## [1.5.0](https://github.com/nyaggah/opaque_id/compare/opaque_id/v1.4.0...opaque_id/v1.5.0) (2025-10-03)
95
+
96
+
97
+ ### Features
98
+
99
+ * add SLUG_LIKE_ALPHABET as default for URL-safe IDs ([1e52b17](https://github.com/nyaggah/opaque_id/commit/1e52b174d70ca72b74badf399401605b307e3604))
100
+
101
+
102
+ ### Bug Fixes
103
+
104
+ * resolve TOC rendering and improve workflow configuration ([244d532](https://github.com/nyaggah/opaque_id/commit/244d5321e5b18091d8599bd772a28f5a30239c80))
105
+
106
+
107
+ ### Documentation
108
+
109
+ * final cleanup of over-inflated claims ([795b5b0](https://github.com/nyaggah/opaque_id/commit/795b5b0071a098f718a40e84e81ceba4525b8d3b))
110
+ * tone down over-inflated claims and remove unsubstantiated benchmarks ([6536b87](https://github.com/nyaggah/opaque_id/commit/6536b87f9a9c2049497328319641ff21368c6032))
111
+ * tone down pretentious language in algorithms intro ([58c0caf](https://github.com/nyaggah/opaque_id/commit/58c0caf116228401b6218ec589a35b350d068b49))
112
+
113
+
114
+ ### Miscellaneous Chores
115
+
116
+ * remove tasks/ directory from source control ([e007ead](https://github.com/nyaggah/opaque_id/commit/e007ead90fa3fbb62ab17e334563e69899afb259))
117
+
118
+
119
+ ### Tests
120
+
121
+ * update tests for SLUG_LIKE_ALPHABET defaults ([d7296c7](https://github.com/nyaggah/opaque_id/commit/d7296c77b1b7a995e7a42b3ba546fdeb8e41c297))
122
+ * update tests for SLUG_LIKE_ALPHABET defaults ([d1f8f26](https://github.com/nyaggah/opaque_id/commit/d1f8f26e7be80f6cbefc98563c0ffa45033372dc))
123
+
8
124
  ## [1.4.0](https://github.com/nyaggah/opaque_id/compare/opaque_id/v1.3.0...opaque_id/v1.4.0) (2025-10-02)
9
125
 
10
126
 
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
5
5
  [![Gem Downloads](https://img.shields.io/gem/dt/opaque_id)](https://rubygems.org/gems/opaque_id)
6
6
 
7
- A Ruby gem for generating cryptographically secure, collision-free opaque IDs for ActiveRecord models. OpaqueId provides a drop-in replacement for `nanoid.rb` using Ruby's built-in `SecureRandom` methods with optimized algorithms for unbiased distribution.
7
+ A simple Ruby gem for generating secure, opaque IDs for ActiveRecord models. OpaqueId provides a drop-in replacement for `nanoid.rb` using Ruby's built-in `SecureRandom` methods, with slug-like IDs as the default for optimal URL safety and user experience.
8
8
 
9
9
  ## Table of Contents
10
10
 
@@ -87,12 +87,12 @@ A Ruby gem for generating cryptographically secure, collision-free opaque IDs fo
87
87
  ## Features
88
88
 
89
89
  - **🔐 Cryptographically Secure**: Uses Ruby's `SecureRandom` for secure ID generation
90
- - **⚡ High Performance**: Optimized algorithms with fast paths for 64-character alphabets
91
- - **🎯 Collision-Free**: Built-in collision detection with configurable retry attempts
90
+ - **⚡ Performance Optimized**: Efficient algorithms with fast paths for 64-character alphabets
91
+ - **🎯 Collision Resistant**: Built-in collision detection with configurable retry attempts
92
92
  - **🔧 Highly Configurable**: Customizable alphabet, length, column name, and validation rules
93
- - **🚀 Rails Integration**: Seamless ActiveRecord integration with automatic ID generation
93
+ - **🚀 Rails Integration**: ActiveRecord integration with automatic ID generation
94
94
  - **📦 Rails Generator**: One-command setup with `rails generate opaque_id:install`
95
- - **🧪 Well Tested**: Comprehensive test suite with statistical uniformity tests
95
+ - **🧪 Tested**: Includes test suite with statistical uniformity tests
96
96
  - **📚 Rails 8.0+ Compatible**: Built for modern Rails applications
97
97
 
98
98
  ## Installation
@@ -176,15 +176,34 @@ end
176
176
 
177
177
  # IDs are automatically generated on creation
178
178
  user = User.create!(name: "John Doe")
179
- puts user.opaque_id # => "V1StGXR8_Z5jdHi6B-myT"
179
+ puts user.opaque_id # => "izkpm55j334u8x9y2"
180
180
 
181
181
  # Find by opaque ID
182
- user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
183
- user = User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT") # raises if not found
182
+ user = User.find_by_opaque_id("izkpm55j334u8x9y2")
183
+ user = User.find_by_opaque_id!("izkpm55j334u8x9y2") # raises if not found
184
184
  ```
185
185
 
186
186
  ## Usage
187
187
 
188
+ ### URL-Safe, Double-Click Selectable IDs
189
+
190
+ OpaqueId defaults to generating **slug-like IDs** that are perfect for URLs and user-facing identifiers:
191
+
192
+ - **URL-safe**: No special characters that need encoding
193
+ - **Double-click selectable**: Users can easily select the entire ID
194
+ - **Shorter than UUIDs**: 18 characters vs 36 for UUIDs
195
+ - **Collision resistant**: Built on Ruby's `SecureRandom` for security
196
+
197
+ ```ruby
198
+ # Default generation creates slug-like IDs
199
+ id = OpaqueId.generate
200
+ # => "izkpm55j334u8x9y2" # Perfect for URLs and user selection
201
+
202
+ # Compare to UUIDs
203
+ uuid = SecureRandom.uuid
204
+ # => "7cb776c5-8c12-4b1a-84aa-9941b815d873" # Harder to select, longer
205
+ ```
206
+
188
207
  ### Standalone ID Generation
189
208
 
190
209
  OpaqueId can be used independently of ActiveRecord for generating secure IDs in any Ruby application:
@@ -192,13 +211,13 @@ OpaqueId can be used independently of ActiveRecord for generating secure IDs in
192
211
  #### Basic Usage
193
212
 
194
213
  ```ruby
195
- # Generate with default settings (21 characters, alphanumeric)
214
+ # Generate with default settings (18 characters, slug-like)
196
215
  id = OpaqueId.generate
197
- # => "V1StGXR8_Z5jdHi6B-myT"
216
+ # => "izkpm55j334u8x9y2"
198
217
 
199
218
  # Custom length
200
219
  id = OpaqueId.generate(size: 10)
201
- # => "V1StGXR8_Z5"
220
+ # => "izkpm55j334u"
202
221
 
203
222
  # Custom alphabet
204
223
  id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
@@ -210,7 +229,7 @@ id = OpaqueId.generate(size: 8, alphabet: "ABCDEFGH")
210
229
 
211
230
  # Generate multiple IDs
212
231
  ids = 5.times.map { OpaqueId.generate(size: 8) }
213
- # => ["V1StGXR8", "Z5jdHi6B", "myT12345", "ABCdefGH", "IJKlmnoP"]
232
+ # => ["izkpm55j", "334u8x9y", "2abc1234", "def5678g", "hij9klmn"]
214
233
  ```
215
234
 
216
235
  #### Standalone Use Cases
@@ -229,7 +248,7 @@ class BackgroundJob
229
248
  end
230
249
 
231
250
  job_id = BackgroundJob.enqueue(ProcessDataJob, user_id: 123)
232
- # => "V1StGXR8_Z5jd"
251
+ # => "izkpm55j334u8x9y2"
233
252
  ```
234
253
 
235
254
  ##### Temporary File Names
@@ -243,7 +262,7 @@ def create_temp_file(content)
243
262
  end
244
263
 
245
264
  filename = create_temp_file("Hello World")
246
- # => "temp_V1StGXR8.txt"
265
+ # => "temp_izkpm55j334u8x9y2.txt"
247
266
  ```
248
267
 
249
268
  ##### Cache Keys
@@ -264,7 +283,7 @@ user_key = CacheManager.user_cache_key(123)
264
283
  # => "user:V1StGX:123"
265
284
 
266
285
  session_key = CacheManager.session_cache_key
267
- # => "session:V1StGXR8_Z5jdHi6B"
286
+ # => "session:izkpm55j334u8x9y2"
268
287
  ```
269
288
 
270
289
  ##### Webhook Signatures
@@ -281,7 +300,7 @@ class WebhookService
281
300
  end
282
301
 
283
302
  signature = WebhookService.generate_signature({ user_id: 123 })
284
- # => "1703123456:V1StGXR8_Z5jdHi6B:1234567890"
303
+ # => "1703123456:izkpm55j334u8x9y2:1234567890"
285
304
  ```
286
305
 
287
306
  ##### Database Migration IDs
@@ -309,7 +328,7 @@ class EmailService
309
328
  end
310
329
 
311
330
  tracking_id = EmailService.tracking_pixel_id
312
- # => "V1StGXR8Z5jdHi6BmyT12"
331
+ # => "izkpm55j334u8x9y2abc"
313
332
 
314
333
  # Use in email template
315
334
  # <img src="https://example.com/track/#{tracking_id}" width="1" height="1" />
@@ -328,7 +347,7 @@ class ApiLogger
328
347
  end
329
348
 
330
349
  request_id = ApiLogger.log_request("/api/users", { page: 1 })
331
- # => "V1StGXR8_Z5jd"
350
+ # => "izkpm55j334u8x9y2"
332
351
  ```
333
352
 
334
353
  ##### Batch Processing IDs
@@ -350,9 +369,9 @@ class BatchProcessor
350
369
  end
351
370
 
352
371
  batch_id = BatchProcessor.process_batch([1, 2, 3, 4, 5])
353
- # => "V1StGXR8_Z5"
354
- # => Processing item V1StGXR8_Z5_000: 1
355
- # => Processing item V1StGXR8_Z5_001: 2
372
+ # => "izkpm55j334u8x9y2"
373
+ # => Processing item izkpm55j334u8x9y2_000: 1
374
+ # => Processing item izkpm55j334u8x9y2_001: 2
356
375
  # => ...
357
376
  ```
358
377
 
@@ -417,7 +436,7 @@ end
417
436
 
418
437
  # Create a new post - opaque_id is automatically generated
419
438
  post = Post.create!(title: "Hello World", content: "This is my first post")
420
- puts post.opaque_id # => "V1StGXR8_Z5jdHi6B-myT"
439
+ puts post.opaque_id # => "izkpm55j334u8x9y2"
421
440
 
422
441
  # Create multiple posts
423
442
  posts = Post.create!([
@@ -427,9 +446,9 @@ posts = Post.create!([
427
446
  ])
428
447
 
429
448
  posts.each { |p| puts "#{p.title}: #{p.opaque_id}" }
430
- # => Post 1: V1StGXR8_Z5jdHi6B-myT
431
- # => Post 2: Z5jdHi6B-myT12345
432
- # => Post 3: myT12345-ABCdefGH
449
+ # => Post 1: izkpm55j334u8x9y2
450
+ # => Post 2: 334u8x9y2abc1234
451
+ # => Post 3: abc1234def5678gh
433
452
  ```
434
453
 
435
454
  #### Custom Configuration
@@ -482,7 +501,7 @@ class ApiKey < ApplicationRecord
482
501
  self.opaque_id_max_retry = 10
483
502
  end
484
503
 
485
- # Generated API keys will look like: "V1StGXR8Z5jdHi6BmyT1234567890AB"
504
+ # Generated API keys will look like: "izkpm55j334u8x9y2abc1234def5678gh"
486
505
  ```
487
506
 
488
507
  ##### Short URL Configuration
@@ -529,7 +548,7 @@ class Upload < ApplicationRecord
529
548
  self.opaque_id_purge_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
530
549
  end
531
550
 
532
- # Generated filenames will look like: "V1StGXR8-Z5jd"
551
+ # Generated filenames will look like: "izkpm55j334u8x9y2"
533
552
  ```
534
553
 
535
554
  ##### Session Token Configuration
@@ -554,7 +573,7 @@ class Session < ApplicationRecord
554
573
  self.opaque_id_max_retry = 8
555
574
  end
556
575
 
557
- # Generated session tokens will look like: "V1StGXR8_Z5jdHi6B-myT123"
576
+ # Generated session tokens will look like: "izkpm55j334u8x9y2abc123"
558
577
  ```
559
578
 
560
579
  ##### Custom Alphabet Examples
@@ -592,7 +611,7 @@ end
592
611
 
593
612
  ```ruby
594
613
  # Find by opaque ID (returns nil if not found)
595
- user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
614
+ user = User.find_by_opaque_id("izkpm55j334u8x9y2")
596
615
  if user
597
616
  puts "Found user: #{user.name}"
598
617
  else
@@ -600,14 +619,14 @@ else
600
619
  end
601
620
 
602
621
  # Find by opaque ID (raises ActiveRecord::RecordNotFound if not found)
603
- user = User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT")
622
+ user = User.find_by_opaque_id!("izkpm55j334u8x9y2")
604
623
  puts "Found user: #{user.name}"
605
624
 
606
625
  # Use in controllers for public-facing URLs
607
626
  class PostsController < ApplicationController
608
627
  def show
609
628
  @post = Post.find_by_opaque_id!(params[:id])
610
- # This allows URLs like /posts/V1StGXR8_Z5jdHi6B-myT
629
+ # This allows URLs like /posts/izkpm55j334u8x9y2
611
630
  end
612
631
  end
613
632
 
@@ -672,8 +691,8 @@ OpaqueId provides comprehensive configuration options to customize ID generation
672
691
  - **Performance**: Longer IDs are more secure but use more storage
673
692
  - **Examples**:
674
693
  - `6` → Short URLs: `"V1StGX"`
675
- - `21` → Default: `"V1StGXR8_Z5jdHi6B-myT"`
676
- - `32` → API Keys: `"V1StGXR8_Z5jdHi6B-myT1234567890AB"`
694
+ - `18` → Default: `"izkpm55j334u8x9y2"`
695
+ - `32` → API Keys: `"izkpm55j334u8x9y2abc1234def5678gh"`
677
696
 
678
697
  #### `opaque_id_alphabet`
679
698
 
@@ -691,7 +710,7 @@ OpaqueId provides comprehensive configuration options to customize ID generation
691
710
  - **Purpose**: Ensures IDs start with a letter for better readability
692
711
  - **Use Cases**: When IDs are user-facing or need to be easily readable
693
712
  - **Performance**: Slight overhead due to rejection sampling
694
- - **Example**: `true` → `"V1StGXR8_Z5jdHi6B-myT"`, `false` → `"1StGXR8_Z5jdHi6B-myT"`
713
+ - **Example**: `true` → `"izkpm55j334u8x9y2"`, `false` → `"zkpm55j334u8x9y2"`
695
714
 
696
715
  #### `opaque_id_purge_chars`
697
716
 
@@ -744,7 +763,7 @@ OpaqueId::ALPHANUMERIC_ALPHABET
744
763
 
745
764
  ```ruby
746
765
  OpaqueId.generate(size: 8, alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
747
- # => "V1StGXR8"
766
+ # => "izkpm55j"
748
767
  ```
749
768
 
750
769
  ### `STANDARD_ALPHABET`
@@ -932,41 +951,14 @@ def generate(size:, alphabet:)
932
951
  end
933
952
  ```
934
953
 
935
- ## Performance Benchmarks
936
-
937
- ### Generation Speed (IDs per second)
938
-
939
- | Alphabet Size | Algorithm | Performance | Relative Speed |
940
- | ------------- | --------- | ------------------ | --------------- |
941
- | 64 characters | Fast Path | ~2,500,000 IDs/sec | 100% (baseline) |
942
- | 62 characters | Unbiased | ~1,200,000 IDs/sec | 48% |
943
- | 36 characters | Unbiased | ~1,100,000 IDs/sec | 44% |
944
- | 26 characters | Unbiased | ~1,000,000 IDs/sec | 40% |
945
- | 10 characters | Unbiased | ~900,000 IDs/sec | 36% |
946
-
947
- _Benchmarks run on Ruby 3.2.0, generating 21-character IDs_
948
-
949
- ### Memory Usage
950
-
951
- | Algorithm | Memory per ID | Memory per 1M IDs |
952
- | --------- | ------------- | ----------------- |
953
- | Fast Path | ~21 bytes | ~21 MB |
954
- | Unbiased | ~21 bytes | ~21 MB |
955
-
956
- _Memory usage is consistent regardless of algorithm choice_
957
-
958
- ### Collision Probability
959
-
960
- For 21-character IDs with different alphabets:
954
+ ## Performance Characteristics
961
955
 
962
- | Alphabet | Characters | Collision Probability (1 in) |
963
- | --------------------- | ---------- | ---------------------------- |
964
- | STANDARD_ALPHABET | 64 | 2.9 × 10^37 |
965
- | ALPHANUMERIC_ALPHABET | 62 | 1.4 × 10^37 |
966
- | Numeric (0-9) | 10 | 1.0 × 10^21 |
967
- | Binary (0-1) | 2 | 2.1 × 10^6 |
956
+ OpaqueId is designed for efficient ID generation with different performance characteristics based on alphabet size:
968
957
 
969
- _Collision probability calculated using birthday paradox formula_
958
+ - **64-character alphabets**: Use optimized bitwise operations for faster generation
959
+ - **Other alphabets**: Use rejection sampling for unbiased distribution with slight overhead
960
+ - **Memory usage**: Scales linearly with ID length
961
+ - **Collision resistance**: Extremely low probability for typical use cases
970
962
 
971
963
  ### Performance Characteristics
972
964
 
@@ -975,7 +967,7 @@ _Collision probability calculated using birthday paradox formula_
975
967
  - **Time Complexity**: O(n) where n = ID length
976
968
  - **Space Complexity**: O(n)
977
969
  - **Rejection Rate**: 0% (no rejections)
978
- - **Distribution**: Perfect uniform
970
+ - **Distribution**: Uniform distribution
979
971
  - **Best For**: High-performance applications, short URLs
980
972
 
981
973
  #### Unbiased Path (other alphabets)
@@ -983,7 +975,7 @@ _Collision probability calculated using birthday paradox formula_
983
975
  - **Time Complexity**: O(n × (1 + rejection_rate)) where rejection_rate ≈ 0.01
984
976
  - **Space Complexity**: O(n)
985
977
  - **Rejection Rate**: <1% for most alphabet sizes
986
- - **Distribution**: Perfect uniform (mathematically proven)
978
+ - **Distribution**: Uniform distribution using rejection sampling
987
979
  - **Best For**: General-purpose applications, custom alphabets
988
980
 
989
981
  ### Real-World Performance
data/docs/_config.yml CHANGED
@@ -88,6 +88,8 @@ kramdown:
88
88
  block:
89
89
  line_numbers: false
90
90
  start_line: 1
91
+ auto_id: true
92
+ table_of_contents: true
91
93
 
92
94
  # Custom head includes
93
95
  head_scripts:
data/docs/algorithms.md CHANGED
@@ -8,7 +8,7 @@ permalink: /algorithms/
8
8
 
9
9
  # Algorithms
10
10
 
11
- OpaqueId uses sophisticated algorithms to generate cryptographically secure, collision-free opaque IDs. This guide explains the technical details behind the generation process, optimization strategies, and mathematical foundations.
11
+ OpaqueId builds on Ruby's built-in `SecureRandom` methods to generate cryptographically secure, collision-free opaque IDs. This guide explains the technical details behind the generation process, optimization strategies, and mathematical foundations.
12
12
 
13
13
  - TOC
14
14
  {:toc}
@@ -45,10 +45,10 @@ end
45
45
 
46
46
  ### Key Features
47
47
 
48
- - **Bitwise Operations**: Uses `byte & 63` instead of `byte % 64` for faster computation
48
+ - **Bitwise Operations**: Uses `byte & 63` instead of `byte % 64` for efficient computation
49
49
  - **No Modulo Bias**: 64 is a power of 2, so bitwise AND provides uniform distribution
50
50
  - **Single Random Call**: One `SecureRandom.random_bytes(1)` call per character
51
- - **Maximum Performance**: Optimized for speed with 64-character alphabets
51
+ - **Performance Optimized**: Designed for speed with 64-character alphabets
52
52
 
53
53
  ### Mathematical Foundation
54
54
 
@@ -60,7 +60,7 @@ For a 64-character alphabet:
60
60
 
61
61
  ### Performance Characteristics
62
62
 
63
- - **Optimized for speed**: Uses bitwise operations for maximum performance
63
+ - **Optimized for speed**: Uses bitwise operations for efficient performance
64
64
  - **No rejection sampling**: All generated bytes are used efficiently
65
65
  - **Linear time complexity**: O(n) where n is the ID length
66
66
 
data/docs/index.md CHANGED
@@ -12,7 +12,7 @@ permalink: /
12
12
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
13
13
  [![Gem Downloads](https://img.shields.io/badge/gem%20downloads-opaque_id-blue)](https://rubygems.org/gems/opaque_id)
14
14
 
15
- A Ruby gem for generating cryptographically secure, collision-free opaque IDs for ActiveRecord models. OpaqueId provides a drop-in replacement for `nanoid.rb` using Ruby's built-in `SecureRandom` methods with optimized algorithms for unbiased distribution.
15
+ A simple Ruby gem for generating secure, opaque IDs for ActiveRecord models. OpaqueId provides a drop-in replacement for `nanoid.rb` using Ruby's built-in `SecureRandom` methods, with slug-like IDs as the default for optimal URL safety and user experience.
16
16
 
17
17
  - TOC
18
18
  {:toc}
@@ -57,10 +57,10 @@ end
57
57
 
58
58
  # Create a user - opaque_id is automatically generated
59
59
  user = User.create!(name: "John Doe")
60
- puts user.opaque_id # => "V1StGXR8_Z5jdHi6B-myT"
60
+ puts user.opaque_id # => "izkpm55j334u8x9y2"
61
61
 
62
62
  # Find by opaque_id
63
- user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
63
+ user = User.find_by_opaque_id("izkpm55j334u8x9y2")
64
64
  ```
65
65
 
66
66
  ## Why OpaqueId?
data/docs/performance.md CHANGED
@@ -8,7 +8,7 @@ permalink: /performance/
8
8
 
9
9
  # Performance
10
10
 
11
- OpaqueId is designed for high performance with optimized algorithms and efficient memory usage. This guide covers benchmarks, optimization strategies, and scalability considerations.
11
+ OpaqueId is designed for efficient ID generation with optimized algorithms and memory usage. This guide covers performance characteristics, optimization strategies, and scalability considerations.
12
12
 
13
13
  - TOC
14
14
  {:toc}
@@ -17,11 +17,11 @@ OpaqueId is designed for high performance with optimized algorithms and efficien
17
17
 
18
18
  ### Generation Speed
19
19
 
20
- OpaqueId is designed for high performance with optimized algorithms for different alphabet sizes and ID lengths.
20
+ OpaqueId is designed for efficient ID generation with optimized algorithms for different alphabet sizes and ID lengths.
21
21
 
22
22
  #### Algorithm Performance
23
23
 
24
- - **Fast Path (64-character alphabets)**: Uses bitwise operations for maximum speed with no rejection sampling overhead
24
+ - **Fast Path (64-character alphabets)**: Uses bitwise operations for efficient generation with no rejection sampling overhead
25
25
  - **Unbiased Path (Other alphabets)**: Uses rejection sampling for unbiased distribution with slight performance overhead
26
26
  - **Performance scales linearly** with ID length and batch size
27
27
 
data/docs/usage.md CHANGED
@@ -20,9 +20,9 @@ OpaqueId can be used independently of ActiveRecord for generating secure, random
20
20
  ### Basic Usage
21
21
 
22
22
  ```ruby
23
- # Generate a default opaque ID (21 characters, alphanumeric)
23
+ # Generate a default opaque ID (18 characters, slug-like)
24
24
  id = OpaqueId.generate
25
- # => "V1StGXR8_Z5jdHi6B-myT"
25
+ # => "izkpm55j334u8x9y2"
26
26
 
27
27
  # Generate multiple IDs
28
28
  ids = 5.times.map { OpaqueId.generate }
@@ -34,15 +34,15 @@ ids = 5.times.map { OpaqueId.generate }
34
34
  ```ruby
35
35
  # Custom length
36
36
  id = OpaqueId.generate(size: 10)
37
- # => "V1StGXR8_Z5"
37
+ # => "izkpm55j334u"
38
38
 
39
39
  # Custom alphabet
40
40
  id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
41
- # => "V1StGXR8_Z5jdHi6B-myT"
41
+ # => "izkpm55j334u8x9y2"
42
42
 
43
43
  # Both custom length and alphabet
44
44
  id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
45
- # => "V1StGXR8_Z5jdHi"
45
+ # => "izkpm55j334u8x9y"
46
46
  ```
47
47
 
48
48
  ### Built-in Alphabets
@@ -50,11 +50,11 @@ id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
50
50
  ```ruby
51
51
  # Alphanumeric alphabet (default) - A-Z, a-z, 0-9
52
52
  id = OpaqueId.generate(alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
53
- # => "V1StGXR8_Z5jdHi6B-myT"
53
+ # => "izkpm55j334u8x9y2"
54
54
 
55
55
  # Standard alphabet - A-Z, a-z, 0-9, -, _
56
56
  id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
57
- # => "V1StGXR8_Z5jdHi6B-myT"
57
+ # => "izkpm55j334u8x9y2"
58
58
  ```
59
59
 
60
60
  ### Custom Alphabets
@@ -73,7 +73,7 @@ id = OpaqueId.generate(size: 16, alphabet: hex_alphabet)
73
73
  # URL-safe characters
74
74
  url_safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
75
75
  id = OpaqueId.generate(size: 12, alphabet: url_safe)
76
- # => "V1StGXR8_Z5j"
76
+ # => "izkpm55j334u8x"
77
77
  ```
78
78
 
79
79
  ## ActiveRecord Integration
@@ -94,7 +94,7 @@ end
94
94
  # Create a new user - opaque_id is automatically generated
95
95
  user = User.create!(name: "John Doe", email: "john@example.com")
96
96
  puts user.opaque_id
97
- # => "V1StGXR8_Z5jdHi6B-myT"
97
+ # => "izkpm55j334u8x9y2"
98
98
 
99
99
  # The ID is generated before the record is saved
100
100
  user = User.new(name: "Jane Smith")
@@ -110,10 +110,10 @@ puts user.opaque_id
110
110
 
111
111
  ```ruby
112
112
  # Find by opaque_id (returns nil if not found)
113
- user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
113
+ user = User.find_by_opaque_id("izkpm55j334u8x9y2")
114
114
 
115
115
  # Find by opaque_id (raises exception if not found)
116
- user = User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT")
116
+ user = User.find_by_opaque_id!("izkpm55j334u8x9y2")
117
117
  # => ActiveRecord::RecordNotFound if not found
118
118
 
119
119
  # Use in scopes
@@ -123,7 +123,7 @@ class User < ApplicationRecord
123
123
  scope :by_opaque_id, ->(id) { where(opaque_id: id) }
124
124
  end
125
125
 
126
- users = User.by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
126
+ users = User.by_opaque_id("izkpm55j334u8x9y2")
127
127
  ```
128
128
 
129
129
  ### Custom Column Names
@@ -139,7 +139,7 @@ end
139
139
  # Now the methods use the custom column name
140
140
  user = User.create!(name: "John Doe")
141
141
  puts user.public_id
142
- # => "V1StGXR8_Z5jdHi6B-myT"
142
+ # => "izkpm55j334u8x9y2"
143
143
 
144
144
  user = User.find_by_public_id("V1StGXR8_Z5jdHi6B-myT")
145
145
  ```
@@ -198,7 +198,7 @@ end
198
198
  # Create an order
199
199
  order = Order.create!(user_id: 1, total: 99.99)
200
200
  puts order.opaque_id
201
- # => "V1StGXR8_Z5j"
201
+ # => "izkpm55j334u8x"
202
202
 
203
203
  # Use in URLs
204
204
  order_url(order.opaque_id)
@@ -259,7 +259,7 @@ end
259
259
  # Create a user
260
260
  user = User.create!(name: "John Doe", email: "john@example.com")
261
261
  puts user.opaque_id
262
- # => "V1StGXR8_Z5jdHi6B-myT" (starts with letter)
262
+ # => "izkpm55j334u8x9y2" (starts with letter)
263
263
 
264
264
  # Use in user profiles
265
265
  user_url(user.opaque_id)