ruby_xid 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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ruby_xid.rb +145 -0
  3. data/lib/xid/base32.rb +141 -0
  4. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '08ba94c6fc740af7f91b899eb0459764ff1dcd7512eac6a575f33bdc6ee8c255'
4
+ data.tar.gz: 7b5eac75b7a82f8b2e67b4df57f5d85d3b451ad62ee4235e97df5f1c1a87675c
5
+ SHA512:
6
+ metadata.gz: '072618ecba2040867b4a04c95d844ddf8e0e50bdbc744455aa096de2e16ae931b0dbdeb6f35ebce103d061d3e52dc49fed82a109300ca342cf17182c5aa58c25'
7
+ data.tar.gz: 3f7061a4a6893c6f77cfb738b39f135ba0b1c66c7ce97014d30e7be9fc1e7e0c95ffe5bc02b10bbc6938ffaa7719b9e623059682bffb91bbf6a7c792e629124e
data/lib/ruby_xid.rb ADDED
@@ -0,0 +1,145 @@
1
+ # Xid implementatin in Ruby
2
+ class Xid
3
+ require 'socket'
4
+ require 'securerandom'
5
+ require 'date'
6
+
7
+ RAW_LEN = 12
8
+ TRIM_LEN = 20
9
+
10
+ def initialize(id = nil)
11
+ @mutex = Mutex.new
12
+ init_rand_int
13
+ @pid = Process.pid
14
+ unless id.nil?
15
+ # Decoded array
16
+ @value = id
17
+ else
18
+ @value = generate_xid
19
+ end
20
+ end
21
+
22
+ def next_xid
23
+ @value = generate_xid
24
+ string
25
+ end
26
+
27
+ def pid
28
+ # type: () -> int
29
+ (@value[7] << 8 | @value[8])
30
+ end
31
+
32
+ def counter
33
+ # type: () -> int
34
+ @value[9] << 16 | @value[10] << 8 | @value[11]
35
+ end
36
+
37
+ def machine
38
+ # type: () -> str
39
+ @value[4..7].map(&:chr)
40
+ end
41
+
42
+ def datetime
43
+ Time.at(time).to_datetime
44
+ end
45
+
46
+ def time
47
+ # type: () -> int
48
+ @value[0] << 24 | @value[1] << 16 | @value[2] << 8 | @value[3]
49
+ end
50
+
51
+ def machine_id
52
+ @machine_id ||= real_machine_id
53
+ end
54
+
55
+ def string
56
+ # type: () -> str
57
+ byte_value = bytes
58
+ Base32.b32encode(byte_value).downcase[0..TRIM_LEN - 1]
59
+ end
60
+
61
+ def bytes
62
+ # type: () -> str
63
+ @value.map(&:chr).join('')
64
+ end
65
+
66
+ def init_rand_int
67
+ # type: () -> int
68
+ @rand_int = begin
69
+ buford = SecureRandom.hex(3).scan(/.{2}/m).map(&:hex)
70
+ buford[0] << 16 | buford[1] << 8 | buford[2]
71
+ end
72
+ end
73
+
74
+ def ==(other_xid)
75
+ # type: (Xid) -> bool
76
+ string < other_xid.string
77
+ end
78
+
79
+ def <(other_xid)
80
+ # type: (Xid) -> bool
81
+ string < other_xid.string
82
+ end
83
+
84
+ def >(other_xid)
85
+ # type: (Xid) -> bool
86
+ string > other_xid.string
87
+ end
88
+
89
+ def self.from_string(str)
90
+ val = Base32.b32decode(str)
91
+ value_check = val.select { |x| x >= 0 && x < 255 }
92
+
93
+ (value_check.length..RAW_LEN - 1).each do |i|
94
+ value_check[i] = false
95
+ end
96
+
97
+ raise 'Invalid Xid' unless value_check.all?
98
+
99
+ Object.const_get(name).new(val)
100
+ end
101
+
102
+ private
103
+
104
+ def real_machine_id
105
+ # type: () -> List[int]
106
+ hostname = Socket.gethostname.encode('utf-8')
107
+ md5 = Digest::MD5.new
108
+ md5 << hostname
109
+ val = md5.digest[0..3]
110
+ val.scan(/.{1}/m).map(&:ord)
111
+ rescue
112
+ SecureRandom.hex(3).scan(/.{2}/m).map(&:hex)
113
+ end
114
+
115
+ def generate_xid
116
+ # type: () -> List[int]
117
+ now = Time.now.to_i
118
+ id = [0] * RAW_LEN
119
+
120
+ id[0] = (now >> 24) & 0xff
121
+ id[1] = (now >> 16) & 0xff
122
+ id[2] = (now >> 8) & 0xff
123
+ id[3] = now & 0xff
124
+
125
+ id[4] = machine_id[0]
126
+ id[5] = machine_id[1]
127
+ id[6] = machine_id[2]
128
+
129
+ id[7] = (@pid >> 8) & 0xff
130
+ id[8] = @pid & 0xff
131
+
132
+ @mutex.synchronize do
133
+ @rand_int += 1
134
+ end
135
+ i = @rand_int
136
+
137
+ id[9] = (i >> 16) & 0xff
138
+ id[10] = (i >> 8) & 0xff
139
+ id[11] = i & 0xff
140
+
141
+ id
142
+ end
143
+ end
144
+
145
+ require_relative 'xid/base32'
data/lib/xid/base32.rb ADDED
@@ -0,0 +1,141 @@
1
+
2
+ class Xid::Base32
3
+
4
+ ENCODE_HEX = '0123456789abcdefghijklmnopqrstuv'.freeze
5
+ PAD_CHAR = '='.freeze
6
+
7
+ # Start class methods
8
+ class << self
9
+
10
+ def decode_hex_map
11
+ Hash[ENCODE_HEX.chars.each_with_index.map { |x, i| [x, i] }]
12
+ end
13
+
14
+ def b32encode(src)
15
+ src = src.scan(/.{1}/m).map(&:ord)
16
+ encode(src, ENCODE_HEX)
17
+ end
18
+
19
+ def b32decode(src)
20
+ decode(src, ENCODE_HEX)
21
+ end
22
+
23
+ def encode(src_str, str_map)
24
+ return '' if src_str.empty?
25
+
26
+ dst = []
27
+ src_len = 0
28
+ while src_str && !src_str.empty?
29
+ src_len = src_str.length
30
+ next_byte = [0] * 8
31
+
32
+ if src_len > 4
33
+ next_byte[7] = src_str[4] & 0x1f
34
+ next_byte[6] = src_str[4] >> 5
35
+ end
36
+ if src_len > 3
37
+ next_byte[6] = next_byte[6] | (src_str[3] << 3) & 0x1f
38
+ next_byte[5] = (src_str[3] >> 2) & 0x1f
39
+ next_byte[4] = src_str[3] >> 7
40
+ end
41
+ if src_len > 2
42
+ next_byte[4] = next_byte[4] | (src_str[2] << 1) & 0x1f
43
+ next_byte[3] = (src_str[2] >> 4) & 0x1f
44
+ end
45
+ if src_len > 1
46
+ next_byte[3] = next_byte[3] | (src_str[1] << 4) & 0x1f
47
+ next_byte[2] = (src_str[1] >> 1) & 0x1f
48
+ next_byte[1] = (src_str[1] >> 6) & 0x1f
49
+ end
50
+ if src_len > 0
51
+ next_byte[1] = next_byte[1] | (src_str[0] << 2) & 0x1f
52
+ next_byte[0] = src_str[0] >> 3
53
+ end
54
+
55
+ next_byte.each do |nb|
56
+ dst << str_map[nb]
57
+ end
58
+ src_str = src_str[5..src_str.length]
59
+ end
60
+
61
+ dst[-1] = '=' if src_len < 5
62
+ if src_len < 4
63
+ dst[-2] = '='
64
+ dst[-3] = '='
65
+ end
66
+ if src_len < 3
67
+ dst[-4] = '='
68
+ end
69
+ if src_len < 2
70
+ dst[-5] = '='
71
+ dst[-6] = '='
72
+ end
73
+
74
+ dst.join('')
75
+ end
76
+
77
+ def decode(src, str_map)
78
+ src.downcase!
79
+
80
+ end_loop = false
81
+ result = []
82
+ while src && !src.empty? && !end_loop
83
+ dst = [0] * 5
84
+ dbuf = [0] * 8
85
+ src_len = 8
86
+
87
+ (0..8).each do |i|
88
+ if i >= src.length
89
+ src_len = i
90
+ end_loop = true
91
+ break
92
+ end
93
+ char = src[i]
94
+ if char == PAD_CHAR
95
+ end_loop = true
96
+ src_len = i
97
+ break
98
+ else
99
+ dbuf[i] = decode_hex_map[char]
100
+ end
101
+ end
102
+
103
+ if src_len >= 8
104
+ dst[4] = (dbuf[6] << 5) | (dbuf[7])
105
+ end
106
+ if src_len >= 7
107
+ dst[3] = (dbuf[4] << 7) | (dbuf[5] << 2) | (dbuf[6] >> 3)
108
+ end
109
+ if src_len >= 5
110
+ dst[2] = (dbuf[3] << 4) | (dbuf[4] >> 1)
111
+ end
112
+ if src_len >= 4
113
+ dst[1] = (dbuf[1] << 6) | (dbuf[2] << 1) | (dbuf[3] >> 4)
114
+ end
115
+ if src_len >= 2
116
+ dst[0] = (dbuf[0] << 3) | (dbuf[1] >> 2)
117
+ end
118
+
119
+ dst = dst.map { |x| x & 0xff }
120
+
121
+ if src_len == 2
122
+ dst = dst[0]
123
+ elsif src_len == 4
124
+ dst = dst[0..1]
125
+ elsif src_len == 5
126
+ dst = dst[0..2]
127
+ elsif src_len == 7
128
+ dst = dst[0..3]
129
+ elsif src_len == 8
130
+ dst = dst[0..4]
131
+ end
132
+
133
+ result += dst
134
+ src = src[8..src.length]
135
+ end
136
+
137
+ result
138
+ end
139
+ end
140
+ # END - Class methods
141
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_xid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Valarpiraichandran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: a.valarpirai@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/ruby_xid.rb
20
+ - lib/xid/base32.rb
21
+ homepage: http://github.com/valarpirai/ruby_xid
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubygems_version: 3.0.6
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Ruby xid implementation
44
+ test_files: []