prettyid 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +58 -0
- data/README.md +100 -0
- data/Rakefile +24 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/pretty_id/generator.rb +25 -0
- data/lib/pretty_id/sec_random.rb +42 -0
- data/lib/pretty_id/version.rb +3 -0
- data/lib/pretty_id.rb +35 -0
- data/pretty_id.gemspec +30 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5f1d1eaec32642fac2fb8040eab5029eba0e11dac498e661ee1f220c8628f32e
|
4
|
+
data.tar.gz: 56399f1ad4530619fbda6e71cced771336c351ddb4704a9062c127ec03c87813
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d4bb5c9a4676b3454d9e30d93d46c9d9c90a298ba0e1197896504b91150c454c37dc1711ace222135e847005de2a7822b1d38f479814c5acd74bf475cc82b8c
|
7
|
+
data.tar.gz: 6a1930e2c2cec62139a846f0c6456c90d13f3a76e433275e7a2e39742af991fec9a5d442cd48777b2c2d9b624bb10389c95a29446006543555a7aa43d67b86b5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pretty_id (0.1.0)
|
5
|
+
activerecord (>= 4.2.0)
|
6
|
+
activesupport (>= 4.2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (5.2.0)
|
12
|
+
activesupport (= 5.2.0)
|
13
|
+
activerecord (5.2.0)
|
14
|
+
activemodel (= 5.2.0)
|
15
|
+
activesupport (= 5.2.0)
|
16
|
+
arel (>= 9.0)
|
17
|
+
activesupport (5.2.0)
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
19
|
+
i18n (>= 0.7, < 2)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
tzinfo (~> 1.1)
|
22
|
+
arel (9.0.0)
|
23
|
+
concurrent-ruby (1.0.5)
|
24
|
+
diff-lcs (1.3)
|
25
|
+
i18n (1.0.1)
|
26
|
+
concurrent-ruby (~> 1.0)
|
27
|
+
minitest (5.11.3)
|
28
|
+
rake (12.3.1)
|
29
|
+
rspec (3.7.0)
|
30
|
+
rspec-core (~> 3.7.0)
|
31
|
+
rspec-expectations (~> 3.7.0)
|
32
|
+
rspec-mocks (~> 3.7.0)
|
33
|
+
rspec-core (3.7.1)
|
34
|
+
rspec-support (~> 3.7.0)
|
35
|
+
rspec-expectations (3.7.0)
|
36
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
+
rspec-support (~> 3.7.0)
|
38
|
+
rspec-mocks (3.7.0)
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
+
rspec-support (~> 3.7.0)
|
41
|
+
rspec-support (3.7.1)
|
42
|
+
sqlite3 (1.3.13)
|
43
|
+
thread_safe (0.3.6)
|
44
|
+
tzinfo (1.2.5)
|
45
|
+
thread_safe (~> 0.1)
|
46
|
+
|
47
|
+
PLATFORMS
|
48
|
+
ruby
|
49
|
+
|
50
|
+
DEPENDENCIES
|
51
|
+
bundler
|
52
|
+
pretty_id!
|
53
|
+
rake
|
54
|
+
rspec
|
55
|
+
sqlite3
|
56
|
+
|
57
|
+
BUNDLED WITH
|
58
|
+
1.16.1
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# PrettyId
|
2
|
+
|
3
|
+
How does Stripe generate object ids?
|
4
|
+
|
5
|
+
**[Patrick Collison](https://twitter.com/patrickc)**, Stripe CEO:
|
6
|
+
> They're randomly generated by our Ruby application code. We use the ```ch_```-style prefixes because we find it really useful to be able to immediately recognize the type of an ID when looking at logs or stacktraces.
|
7
|
+
|
8
|
+
[source](https://www.quora.com/How-does-Stripe-generate-object-ids)
|
9
|
+
|
10
|
+
With PrettyId you can generate Stripe-like IDs for your ActiveRecord models.
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
For each model when you create table inside migration, you have to:
|
15
|
+
|
16
|
+
1. tell AR to not automatically add primary key column.
|
17
|
+
1. create ```id``` column as string
|
18
|
+
2. add unique index for ```id``` column
|
19
|
+
|
20
|
+
```
|
21
|
+
create_table :users, id: false do |t|
|
22
|
+
t.string :id, null: false
|
23
|
+
|
24
|
+
# your other columns
|
25
|
+
end
|
26
|
+
|
27
|
+
add_index(:users, :id, unique: true)
|
28
|
+
```
|
29
|
+
|
30
|
+
Inside model class just include PrettyId module:
|
31
|
+
|
32
|
+
```
|
33
|
+
class User < ActiveRecord::Base
|
34
|
+
include PrettyId
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
By default first 3 letters of model class will be taken as id prefix. You can change it by specifying your own value:
|
39
|
+
|
40
|
+
```
|
41
|
+
class User < ActiveRecord::Base
|
42
|
+
include PrettyId
|
43
|
+
|
44
|
+
self.id_prefix = 'usr'
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Or, if you want to add some tricky logic for id prefix (let's say for test account it should be ```acc_test``` and for live account it should be ```acc_live```) you can provide a Proc that will return id prefix:
|
49
|
+
|
50
|
+
```
|
51
|
+
class Account < ActiveRecord::Base
|
52
|
+
include PrettyId
|
53
|
+
|
54
|
+
attr_accessor :type
|
55
|
+
|
56
|
+
self.id_prefix = -> (model) { model.type == 'test' ? 'acc_test' : 'acc_live' }
|
57
|
+
end
|
58
|
+
|
59
|
+
account = Account.new
|
60
|
+
account.type = 'test'
|
61
|
+
account.save
|
62
|
+
|
63
|
+
account.id #=> acc_test_....
|
64
|
+
```
|
65
|
+
|
66
|
+
## Installation
|
67
|
+
|
68
|
+
Add this line to your application's Gemfile:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
gem 'prettyid', require: 'pretty_id'
|
72
|
+
```
|
73
|
+
|
74
|
+
And then execute:
|
75
|
+
|
76
|
+
$ bundle
|
77
|
+
|
78
|
+
Or install it yourself as:
|
79
|
+
|
80
|
+
$ gem install prettyid
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
## Perfomance
|
85
|
+
|
86
|
+
If you care about performance, it's better to measure it yourself :) I have measured method that generates id (```rake bm```). Here are results for 1M calls:
|
87
|
+
|
88
|
+
user system total real
|
89
|
+
PrettyId::Generator#id: 12.880000 0.020000 12.900000 ( 12.907587)
|
90
|
+
|
91
|
+
|
92
|
+
## Contributing
|
93
|
+
|
94
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/alovak/pretty_id.
|
95
|
+
|
96
|
+
## License
|
97
|
+
|
98
|
+
This code is available under [MIT license](/LICENSE).
|
99
|
+
|
100
|
+
© Pavel Gabriel, 2018
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require 'benchmark'
|
4
|
+
require 'pretty_id'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
task :bm do
|
11
|
+
n = 1_000_000
|
12
|
+
|
13
|
+
class One
|
14
|
+
def self.id_prefix
|
15
|
+
'one'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
generator = PrettyId::Generator.new(One.new)
|
20
|
+
|
21
|
+
Benchmark.bm(20) do |x|
|
22
|
+
x.report("PrettyId::Generator#id:") { n.times { generator.id } }
|
23
|
+
end
|
24
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pretty_id"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module PrettyId
|
2
|
+
class Generator
|
3
|
+
attr_reader :record
|
4
|
+
|
5
|
+
def initialize(record)
|
6
|
+
@record = record
|
7
|
+
end
|
8
|
+
|
9
|
+
def id
|
10
|
+
"#{prefix}_#{SecRandom.alphanumeric(length)}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def length
|
14
|
+
12
|
15
|
+
end
|
16
|
+
|
17
|
+
def prefix
|
18
|
+
if record.class.id_prefix.is_a? Proc
|
19
|
+
record.class.id_prefix.call(record)
|
20
|
+
else
|
21
|
+
record.class.id_prefix
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module PrettyId
|
4
|
+
# taken from Ruby 2.5 implementation
|
5
|
+
class SecRandom
|
6
|
+
ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
|
7
|
+
|
8
|
+
def self.alphanumeric(n=nil)
|
9
|
+
n = 16 if n.nil?
|
10
|
+
choose(ALPHANUMERIC, n)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.choose(source, n)
|
14
|
+
size = source.size
|
15
|
+
m = 1
|
16
|
+
limit = size
|
17
|
+
while limit * size <= 0x100000000
|
18
|
+
limit *= size
|
19
|
+
m += 1
|
20
|
+
end
|
21
|
+
result = ''.dup
|
22
|
+
while m <= n
|
23
|
+
rs = SecureRandom.random_number(limit)
|
24
|
+
is = rs.digits(size)
|
25
|
+
(m-is.length).times { is << 0 }
|
26
|
+
result << source.values_at(*is).join('')
|
27
|
+
n -= m
|
28
|
+
end
|
29
|
+
if 0 < n
|
30
|
+
rs = SecureRandom.random_number(limit)
|
31
|
+
is = rs.digits(size)
|
32
|
+
if is.length < n
|
33
|
+
(n-is.length).times { is << 0 }
|
34
|
+
else
|
35
|
+
is.pop while n < is.length
|
36
|
+
end
|
37
|
+
result.concat source.values_at(*is).join('')
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/pretty_id.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "pretty_id/version"
|
2
|
+
require "pretty_id/sec_random"
|
3
|
+
require "pretty_id/generator"
|
4
|
+
require 'active_support/concern'
|
5
|
+
|
6
|
+
module PrettyId
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def id_prefix=(prefix)
|
11
|
+
@id_prefix = prefix
|
12
|
+
end
|
13
|
+
|
14
|
+
def id_prefix
|
15
|
+
@id_prefix || name.downcase[0, 3]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def _create_record(*)
|
20
|
+
attempt ||= 1
|
21
|
+
set_pretty_id
|
22
|
+
super
|
23
|
+
rescue ActiveRecord::RecordNotUnique => e
|
24
|
+
attempt += 1
|
25
|
+
retry if attempt < 4
|
26
|
+
|
27
|
+
raise
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def set_pretty_id
|
33
|
+
self.id = PrettyId::Generator.new(self).id
|
34
|
+
end
|
35
|
+
end
|
data/pretty_id.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "pretty_id/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "prettyid"
|
8
|
+
spec.version = PrettyId::VERSION
|
9
|
+
spec.authors = ["Pavel Gabriel"]
|
10
|
+
spec.email = ["alovak@gmail.com"]
|
11
|
+
spec.licenses = ['MIT']
|
12
|
+
|
13
|
+
spec.summary = %q{Generate Stripe-like ids for your ActiveRecord models}
|
14
|
+
spec.description = %q{Generate Stripe-like ids for your ActiveRecord models}
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "sqlite3"
|
27
|
+
|
28
|
+
spec.add_dependency "activerecord", ">= 4.2.0"
|
29
|
+
spec.add_dependency "activesupport", ">= 4.2.0"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prettyid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pavel Gabriel
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activerecord
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 4.2.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 4.2.0
|
97
|
+
description: Generate Stripe-like ids for your ActiveRecord models
|
98
|
+
email:
|
99
|
+
- alovak@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- Gemfile
|
108
|
+
- Gemfile.lock
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/console
|
112
|
+
- bin/setup
|
113
|
+
- lib/pretty_id.rb
|
114
|
+
- lib/pretty_id/generator.rb
|
115
|
+
- lib/pretty_id/sec_random.rb
|
116
|
+
- lib/pretty_id/version.rb
|
117
|
+
- pretty_id.gemspec
|
118
|
+
homepage:
|
119
|
+
licenses:
|
120
|
+
- MIT
|
121
|
+
metadata: {}
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
requirements: []
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 2.7.5
|
139
|
+
signing_key:
|
140
|
+
specification_version: 4
|
141
|
+
summary: Generate Stripe-like ids for your ActiveRecord models
|
142
|
+
test_files: []
|