acts_as_identifier 0.2.0 → 1.0.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 +4 -4
- data/README.md +21 -15
- data/lib/acts_as_identifier.rb +31 -18
- data/lib/acts_as_identifier/encoder.rb +36 -0
- data/lib/acts_as_identifier/version.rb +1 -1
- data/lib/acts_as_identifier/xbase_integer.rb +23 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5eb6246b99ed8a6b043f1b86f7280676f22107154a2b885b9414058e44d8e11d
|
4
|
+
data.tar.gz: e7ebde2dc53be641c11f26fffefc450568fd2775fe5382e352b16945c7965741
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e88efefec94d938295a34dadb93b29ec350ac7680b997d36499a2f6b2e81c3244dec7142800576752b8b25056e3df1c83c5c237e80546822c1f044136f408e7
|
7
|
+
data.tar.gz: 5a61dcbb7a9f9d114768a82e28cfe68c3a57834cfc93f154f007774b84554bcf68d4df9cbc3cafafa2a068ef0412d69ced5ab0178eb09c0739508a00056a44f6
|
data/README.md
CHANGED
@@ -6,29 +6,30 @@ Automatically generate unique secure random string for one or more columns of Ac
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
> `ActsAsIdentifier` only generate identifier `
|
9
|
+
> `ActsAsIdentifier` only generate identifier `after_create_commit`
|
10
10
|
|
11
11
|
```ruby
|
12
12
|
class Account < ActiveRecord::Base
|
13
13
|
#
|
14
14
|
# Note: without Rails, should include ActsAsIdentifier
|
15
15
|
#
|
16
|
-
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
16
|
+
# def acts_as_identifier(attr = :identifier,
|
17
|
+
# length: 6,
|
18
|
+
# prefix: '',
|
19
|
+
# id_column: :id,
|
20
|
+
# chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.chars,
|
21
|
+
# mappings: '3NjncZg82M5fe1PuSABJG9kiRQOqlVa0ybKXYDmtTxCp6Lh7rsIFUWd4vowzHE'.chars)
|
22
|
+
#
|
23
23
|
acts_as_identifier
|
24
|
-
|
25
|
-
|
26
|
-
acts_as_identifier :slug, length: 8, case_sensitive: false, max_loop: 1000, scope: [:tenant_id]
|
24
|
+
# or customize options:
|
25
|
+
acts_as_identifier :slug, length: 6, prefix: 's-'
|
27
26
|
end
|
28
|
-
# => [Account(id: integer, name: string, tenant_id: string,
|
27
|
+
# => [Account(id: integer, name: string, tenant_id: string, slug: string)]
|
29
28
|
|
30
29
|
Account.create
|
31
|
-
# => #<Account:0x00007fcdb90830c0 id: 1, name: nil, tenant_id: nil,
|
30
|
+
# => #<Account:0x00007fcdb90830c0 id: 1, name: nil, tenant_id: nil, slug: "s-HuF2Od">
|
31
|
+
Account.create
|
32
|
+
# => #<Account:0x00007fcdb90830c0 id: 2, name: nil, tenant_id: nil, slug: "s-g3SIB8">
|
32
33
|
|
33
34
|
```
|
34
35
|
|
@@ -41,5 +42,10 @@ bundle add acts_as_identifier
|
|
41
42
|
## Contributing
|
42
43
|
Contribution directions go here.
|
43
44
|
|
44
|
-
##
|
45
|
-
|
45
|
+
## Testing
|
46
|
+
|
47
|
+
```shell
|
48
|
+
bundle exec rspec
|
49
|
+
# or test specific range
|
50
|
+
EXTRA_TEST=100000,1000000 bundle exec rspec
|
51
|
+
```
|
data/lib/acts_as_identifier.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'securerandom'
|
4
4
|
require 'acts_as_identifier/version'
|
5
|
+
require 'acts_as_identifier/xbase_integer'
|
6
|
+
require 'acts_as_identifier/encoder'
|
5
7
|
|
6
8
|
module ActsAsIdentifier
|
7
9
|
LoopTooManyTimesError = Class.new(StandardError)
|
@@ -12,28 +14,39 @@ module ActsAsIdentifier
|
|
12
14
|
|
13
15
|
module ClassMethods
|
14
16
|
#
|
15
|
-
# == Automatically generate unique
|
17
|
+
# == Automatically generate unique string based on id
|
16
18
|
#
|
17
19
|
# @param attr [String, Symbol] column name, default: :identifier
|
18
20
|
# @param length [Integer] length of identifier, default: 6
|
19
|
-
# @param case_sensitive [Boolean] Case-sensitive? default: true
|
20
|
-
# @param max_loop [Integer] max loop count to generate unique identifier, in case of running endless loop, default: 100
|
21
|
-
# @param scope [Array<Symbol,String>] scope of identifier, default: []
|
22
21
|
# @params prefix [String, Symbol] add prefix to value, default: ''
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
22
|
+
# @params id_column [String, Symbol] column name of id, default: :id
|
23
|
+
# @params chars [Array<String>] chars
|
24
|
+
# @params mappings [Array<String>] mappings must have the same characters as chars
|
25
|
+
def acts_as_identifier(attr = :identifier,
|
26
|
+
length: 6,
|
27
|
+
prefix: '',
|
28
|
+
id_column: :id,
|
29
|
+
chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.chars,
|
30
|
+
mappings: '3NjncZg82M5fe1PuSABJG9kiRQOqlVa0ybKXYDmtTxCp6Lh7rsIFUWd4vowzHE'.chars)
|
31
|
+
raise 'chars must be an array' unless chars.is_a?(Array)
|
32
|
+
raise 'mappings must be an array' unless mappings.is_a?(Array)
|
33
|
+
unless (chars - mappings).empty? && (mappings - chars).empty?
|
34
|
+
raise 'chars and mappings must have the same characters'
|
35
|
+
end
|
36
|
+
|
37
|
+
encoder = Encoder.new(chars: chars, mappings: mappings, length: length)
|
38
|
+
|
39
|
+
define_singleton_method "decode_#{attr}" do |str|
|
40
|
+
encoder.decode(str[prefix.length..-1])
|
41
|
+
end
|
42
|
+
|
43
|
+
define_singleton_method "encode_#{attr}" do |num|
|
44
|
+
"#{prefix}#{encoder.encode(num)}"
|
45
|
+
end
|
46
|
+
|
47
|
+
before_commit do |record|
|
48
|
+
if record.previous_changes.key?(id_column.to_s) && !record.destroyed?
|
49
|
+
record.update_column attr, self.class.send("encode_#{attr}", record.send(id_column))
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActsAsIdentifier
|
2
|
+
class Encoder
|
3
|
+
attr_reader :max, :base, :chars, :mappings, :length
|
4
|
+
|
5
|
+
def initialize(chars:, mappings:, length:)
|
6
|
+
@chars = chars.dup
|
7
|
+
@mappings = mappings.dup
|
8
|
+
@length = length
|
9
|
+
@xbase_integer = XbaseInteger.new(chars)
|
10
|
+
@base = @xbase_integer.to_i("#{chars[1]}#{chars[0] * (length - 1)}")
|
11
|
+
@max = @xbase_integer.to_i(chars[-1] * length) - @base
|
12
|
+
end
|
13
|
+
|
14
|
+
def encode(num)
|
15
|
+
str = @xbase_integer.to_x(num + base)
|
16
|
+
(str.length - 1).downto(1).each do |i|
|
17
|
+
idx = @mappings.index(str[i])
|
18
|
+
idx2 = (@mappings.index(str[i - 1]) + idx) % @mappings.size
|
19
|
+
str[i] = @chars.at(idx)
|
20
|
+
str[i - 1] = @chars.at(idx2)
|
21
|
+
end
|
22
|
+
str
|
23
|
+
end
|
24
|
+
|
25
|
+
def decode(str)
|
26
|
+
str = str.dup
|
27
|
+
0.upto(str.length - 2).each do |i|
|
28
|
+
idx = @chars.index(str[i + 1])
|
29
|
+
idx2 = (@chars.index(str[i]) - idx + @chars.size) % @chars.size
|
30
|
+
str[i] = @mappings.at(idx2)
|
31
|
+
str[i + 1] = @mappings.at(idx)
|
32
|
+
end
|
33
|
+
@xbase_integer.to_i(str) - base
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActsAsIdentifier
|
2
|
+
class XbaseInteger
|
3
|
+
attr_reader :chars
|
4
|
+
def initialize(chars)
|
5
|
+
@chars = chars.dup
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_i(str)
|
9
|
+
sum = 0
|
10
|
+
str.chars.reverse.each_with_index do |char, i|
|
11
|
+
sum += chars.index(char) * chars.size**i
|
12
|
+
end
|
13
|
+
sum
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_x(num)
|
17
|
+
str = chars.at(num % chars.size)
|
18
|
+
num /= chars.size
|
19
|
+
str = "#{to_x(num)}#{str}" if num > 0
|
20
|
+
str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_identifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- xiaohui
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -48,8 +48,10 @@ files:
|
|
48
48
|
- MIT-LICENSE
|
49
49
|
- README.md
|
50
50
|
- lib/acts_as_identifier.rb
|
51
|
+
- lib/acts_as_identifier/encoder.rb
|
51
52
|
- lib/acts_as_identifier/railtie.rb
|
52
53
|
- lib/acts_as_identifier/version.rb
|
54
|
+
- lib/acts_as_identifier/xbase_integer.rb
|
53
55
|
homepage: https://github.com/xiaohui-zhangxh/acts_as_identifier
|
54
56
|
licenses:
|
55
57
|
- MIT
|