id_coder 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'modalsupport'
4
+ gem 'modalsettings'
5
+
6
+ group :development do
7
+ gem "shoulda", ">= 0"
8
+ gem "rdoc", "~> 3.12"
9
+ gem "bundler", "~> 1"
10
+ gem "jeweler", "~> 1.8.3"
11
+ end
@@ -0,0 +1,32 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.8.3)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rdoc
10
+ json (1.6.6)
11
+ modalsettings (1.0.0)
12
+ modalsupport (>= 0.8.1)
13
+ modalsupport (0.8.3)
14
+ rake (0.9.2.2)
15
+ rdoc (3.12)
16
+ json (~> 1.4)
17
+ shoulda (3.0.1)
18
+ shoulda-context (~> 1.0.0)
19
+ shoulda-matchers (~> 1.0.0)
20
+ shoulda-context (1.0.0)
21
+ shoulda-matchers (1.0.0)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ bundler (~> 1)
28
+ jeweler (~> 1.8.3)
29
+ modalsettings
30
+ modalsupport
31
+ rdoc (~> 3.12)
32
+ shoulda
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Javier Goizueta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,44 @@
1
+ = id_coder
2
+
3
+ Id-codes are relatively short codes to represent externally id internal numbers.
4
+
5
+ A bijection between ids and codes is used to assure uniqueness of codes and to avoid storing the
6
+ codes in the database (codes and ids are computed on-the-fly from each other).
7
+
8
+ Codes are user-visible; they're designed to be the user's identification of some element.
9
+
10
+ Only digits an capital letters are used for the codes, excluding I,O,1,0 to avoid confusion,
11
+ and a check digit can be used to detect most common transcription errors. This makes codes
12
+ viable to be transmitted orally, etc.
13
+
14
+ The number of digits used is scalable: the minimum number of digits and the increment-size can be
15
+ parameterized to render good-looking codes.
16
+
17
+ An IdCoder can be defined passing to it three optional parameters that define the lenght of the codes:
18
+
19
+ IdCoder[:num_digits=>4, :block_digits=>3, :check_digit=>false]
20
+
21
+ An additional parameter can be passed to define which characters will be used as digits for the codes
22
+ and its order; this must be a String of IdCoder::RADIX distinct characters:
23
+
24
+ IdCoder[:code_digits=>"0123456789ABCDEFGHIJKLMNOPQRSTUV"]
25
+
26
+ Alternatively, a seed parameter can be passed to generate a randomized string
27
+
28
+ IdCoder[:seed=>8734112]
29
+
30
+ Since this might produce different results in different Ruby versions, the code_digits produced can be accessed
31
+ and kept for portability:
32
+
33
+ IdCoder[:seed=>8734112].code_digits # -> "9GTFNJSZA6LQWXV3BEKHYMP75U8R24CD"
34
+
35
+ Ids (integers) can be coded and decoded into alphanumeric strings like this:
36
+
37
+ id_coder = IdCoder[]
38
+ id_coder.id_to_code(7) # => "JEQJTE3"
39
+ id_coder.code_to_id("JEQJTE3") # => 7
40
+
41
+ == Copyright
42
+
43
+ Copyright (c) 2012 Javier Goizueta. See LICENSE.txt for
44
+ further details.
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "id_coder"
18
+ gem.homepage = "http://github.com/jgoizueta/id_coder"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Alphanumeric code generator}
21
+ gem.description = %Q{Generates relatively short codes to represent id numbers externally}
22
+ gem.email = "jgoizueta@gmail.com"
23
+ gem.authors = ["Javier Goizueta"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ require 'rdoc/task'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "id_coder #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,203 @@
1
+ require 'rubygems'
2
+ require 'modalsupport'
3
+ require 'modalsettings'
4
+
5
+ # Id-codes are relatively short codes to represent externally id internal numbers.
6
+ #
7
+ # A bijection between ids and codes is used to assure uniqueness of codes and to avoid storing the
8
+ # codes in the database (codes and ids are computed on-the-fly from each other).
9
+ #
10
+ # Codes are user-visible; they're designed to be the user's identification of some element.
11
+ #
12
+ # Only digits an capital letters are used for the codes, excluding I,O,1,0 to avoid confusion,
13
+ # and a check digit can be used to detect most common transcription errors. This makes codes
14
+ # viable to be transmitted orally, etc.
15
+ #
16
+ # The number of digits used is scalable: the minimum number of digits and the increment-size can be
17
+ # parameterized to render good-looking codes.
18
+ #
19
+ # An IdCoder can be defined passing to it three optional parameters that define the lenght of the codes:
20
+ # IdCoder[:num_digits=>4, :block_digits=>3, :check_digit=>false]
21
+ # An additional parameter can be passed to define which characters will be used as digits for the codes
22
+ # and its order; this must be a String of IdCoder::RADIX distinct characters:
23
+ # IdCoder[:code_digits=>"0123456789ABCDEFGHIJKLMNOPQRSTUV"]
24
+ # Alternatively, a seed parameter can be passed to generate a randomized string
25
+ # IdCoder[:seed=>8734112]
26
+ # Since this might produce different results in different Ruby versions, the code_digits produced can be accessed
27
+ # and kept for portability:
28
+ # IdCoder[:seed=>8734112].code_digits # -> "9GTFNJSZA6LQWXV3BEKHYMP75U8R24CD"
29
+ #
30
+ class IdCoder
31
+
32
+ # Internal parameters
33
+ RADIX = 32
34
+ DIGITS = "0123456789abcdefghijklmnopqrstuv" # RADIX-digits used by Integer#to_s(RADIX), String#to_i(RADIX)
35
+ CODE_DIGITS = "BAFTQ4EJCNVYZKDPG37H5S8WML692RXU" # RADIX-digits used for the codes (permutation of 2-9,A-Z except I,O)
36
+
37
+ class InvalidCode < RuntimeError; end
38
+ class InvalidNumber < RuntimeError; end
39
+ class InvalidCodeDigits < RuntimeError; end
40
+
41
+ def initialize(config={})
42
+ config = Settings[config]
43
+ if config.code_digits
44
+ @code_digits = config.code_digits
45
+ raise InvalidCodeDigits, "Invalid digits" if @code_digits.bytes.to_a.uniq.size!=RADIX
46
+ else
47
+ @code_digits = CODE_DIGITS
48
+ if config.seed
49
+ srand config.seed
50
+ @code_digits = @code_digits.bytes.to_a.shuffle.map(&:chr)*""
51
+ end
52
+ end
53
+ @num_digits = (config.num_digits || 6).to_i
54
+ @block_digits = (config.block_digits || 2).to_i
55
+ @check_digit = config.check_digit
56
+ @check_digit = true if @check_digit.nil?
57
+ end
58
+
59
+ include ModalSupport::BracketConstructor
60
+
61
+ include
62
+
63
+ # configurable parameters
64
+
65
+ # Minumum number of digits used; limits the number of valid ids before scaling up to RADIX**num_digits
66
+ def num_digits
67
+ @num_digits
68
+ end
69
+
70
+ # Use a check digit?: this increases the length of codes in one
71
+ def check_digit?
72
+ @check_digit
73
+ end
74
+
75
+ # Number of digits for incremental scaling-up blocks
76
+ def block_digits
77
+ @block_digits
78
+ end
79
+
80
+ # Properties of the codes
81
+
82
+ # mininum code_length
83
+ def code_length
84
+ num_digits + (check_digit? ? 1 : 0)
85
+ end
86
+
87
+ # Number of valid codes before scaling-up
88
+ def num_valid_codes
89
+ RADIX**num_digits
90
+ end
91
+
92
+ def num_digits_for(id)
93
+ if id<num_valid_codes
94
+ num_digits
95
+ else
96
+ # ((Math.log(id)/Math.log(RADIX)-code_length)/block_digits).ceil*block_digits + num_digits
97
+ nd = num_digits
98
+ loop do
99
+ nd += block_digits
100
+ nvc = RADIX**nd
101
+ break if id<nvc
102
+ end
103
+ # check = ((Math.log(id)/Math.log(RADIX)-code_length)/block_digits).ceil*block_digits + num_digits
104
+ # raise "nd=#{nd}; [#{check}] id=#{id}" unless nd==check
105
+ nd
106
+ end
107
+ end
108
+
109
+ def code_length_for(id)
110
+ num_digits_for(id) + (check_digit? ? 1 : 0)
111
+ end
112
+
113
+ def code_digits
114
+ @code_digits
115
+ end
116
+
117
+ def parameters
118
+ { :num_digits=>@num_digits, :block_digits=>@block_digits, :check_digit=>@check_digit, :code_digits=>@code_digits }
119
+ end
120
+
121
+ def inspect
122
+ "IdCoder[#{parameters.inspect.unwrap('[]')}]"
123
+ end
124
+
125
+ # Code generatioon
126
+
127
+ # Direct encoding: generate an Id-Code from an integer id.
128
+ def id_to_code(id)
129
+ raise InvalidNumber, "Numbers to be coded must be passed as integers" unless id.kind_of?(Integer)
130
+ raise InvalidNumber, "Negative numbers cannot be encoded: #{id}" if id<0
131
+ nd = num_digits_for(id)
132
+ v = id.to_s(RADIX)
133
+ v = "0"*(nd-v.size) + v
134
+ i = 0
135
+ code = ""
136
+ mask = 0
137
+ v.reverse.each_byte do |b|
138
+ d = DIGITS.index(b.chr)
139
+ code << @code_digits[mask = ((d+i)%RADIX ^ mask),1]
140
+ i += 1
141
+ end
142
+ code << check_digit(code) if check_digit?
143
+ code
144
+ end
145
+
146
+ # Inverse encoding: compute the integer id for a Id-Code
147
+ def code_to_id(code)
148
+ raise InvalidCode, "Codes must be strings" unless code.kind_of?(String)
149
+ code = code.strip.upcase # tolerate case differences & surrounding whitespace
150
+ raise InvalidCode, "Invalid code: #{code}" unless code =~ /\A[#{@code_digits}]+\Z/
151
+ # raise InvalidCode, "Invalid code length: #{code.size} for #{code} (must be #{code_length})" unless code.size==code_length
152
+ if check_digit?
153
+ cd = code[-1,1]
154
+ code = code[0...-1]
155
+ raise InvalidCode, "Invalid code: #{code+cd}" if cd!=check_digit(code)
156
+ end
157
+ nd = code.size
158
+ sx = nd-num_digits
159
+ raise InvalidCode, "Invalid code length: #{code.size} for #{code}" unless sx>=0 && (sx%block_digits)==0
160
+ i = 0
161
+ v = ""
162
+ mask = 0
163
+ code.each_byte do |b|
164
+ next_mask = @code_digits.index(b.chr)
165
+ d = ((next_mask ^ mask)-i)%RADIX
166
+ mask = next_mask
167
+ d = DIGITS[d,1]
168
+ v = d + v
169
+ i += 1
170
+ end
171
+ v.to_i(RADIX)
172
+ end
173
+
174
+ # Check code: returns true (valid) or false (invalid)
175
+ def valid_code?(code)
176
+ is_valid = true
177
+ begin
178
+ code_to_id(code)
179
+ rescue InvalidCode
180
+ is_valid = false
181
+ end
182
+ is_valid
183
+ end
184
+
185
+ private
186
+
187
+ # Check digits are computed using the Luhn Mod N Algorithm:
188
+ # http://en.wikipedia.org/wiki/Luhn_mod_N_algorithm
189
+ def check_digit(code)
190
+ factor = 2
191
+ sum = 0
192
+ code.each_byte do |b|
193
+ addend = factor * @code_digits.index(b.chr)
194
+ factor = (factor==2) ? 1 : 2
195
+ addend = (addend / RADIX) + (addend % RADIX)
196
+ sum += addend
197
+ end
198
+ remainder = sum % RADIX
199
+ @code_digits[(RADIX - remainder) % RADIX, 1]
200
+ end
201
+
202
+
203
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'id_coder'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,152 @@
1
+ require 'helper'
2
+
3
+ class TestIdCoder < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @id_coder = IdCoder[
7
+ :num_digits => 6,
8
+ :block_digits => 2,
9
+ :check_digit => true
10
+ ]
11
+ end
12
+
13
+ def test_bijectivity
14
+ # sanity check
15
+ assert@id_coder.check_digit?
16
+ assert_equal 6,@id_coder.num_digits
17
+ assert_equal 2,@id_coder.block_digits
18
+ assert_equal 7,@id_coder.code_length
19
+ assert_equal 32, IdCoder::RADIX
20
+ assert_equal 32**6,@id_coder.num_valid_codes
21
+
22
+ # Test numbers within the basic range (num_digits)
23
+ test_numbers = (0..100).to_a + (99999900..100000020).to_a + [232211,9898774,1002,343332,1023,1024,1025]
24
+ test_numbers.each do |number|
25
+ code =@id_coder.id_to_code(number)
26
+ assert_equal 7, code.size # test also code length here
27
+ assert_equal number,@id_coder.code_to_id(code),"#{number} is converted to a code and back"
28
+ end
29
+
30
+ # Test larger numbers
31
+ test_numbers = (1_999_999_990..2_000_000_010).to_a + (1_999_999_999_990..2_000_000_000_010).to_a
32
+ test_numbers.each do |number|
33
+ code =@id_coder.id_to_code(number)
34
+ assert code.size > 7
35
+ assert(
36
+ (code.size-(@id_coder.check_digit? ? 1 : 0)-@id_coder.num_digits)%@id_coder.block_digits == 0
37
+ )
38
+ assert_equal number,@id_coder.code_to_id(code),"#{number} is converted to a code and back"
39
+ end
40
+
41
+ end
42
+
43
+ def test_invalid_numbers
44
+ # sanity check
45
+ assert@id_coder.check_digit?
46
+ assert_equal 6,@id_coder.num_digits
47
+ assert_equal 2,@id_coder.block_digits
48
+ assert_equal 7,@id_coder.code_length
49
+ assert_equal 32, IdCoder::RADIX
50
+ assert_equal 32**6,@id_coder.num_valid_codes
51
+ # => ~1000000000 codes
52
+
53
+ assert_raise(IdCoder::InvalidNumber){@id_coder.id_to_code("1") }
54
+ assert_raise(IdCoder::InvalidNumber){@id_coder.id_to_code(-1) }
55
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(2000000000) }
56
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(0) }
57
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(1) }
58
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(100) }
59
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(1000000000) }
60
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(2000000000) }
61
+ assert_nothing_raised(IdCoder::InvalidNumber){@id_coder.id_to_code(100000000000000000000) }
62
+ end
63
+
64
+ def test_invalid_codes
65
+ @id_coder = IdCoder[:num_digits=>4, :block_digits=>3, :check_digit=>false]
66
+ # sanity check
67
+ assert !@id_coder.check_digit?
68
+ assert_equal 4,@id_coder.num_digits
69
+ assert_equal 3,@id_coder.block_digits
70
+ assert_equal 4,@id_coder.code_length
71
+ assert_equal 32, IdCoder::RADIX
72
+ assert_equal 32**4,@id_coder.num_valid_codes
73
+
74
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(1023) }
75
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(234) }
76
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(2345) }
77
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id('2345') }
78
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('345') }
79
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('34567') }
80
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('3415') }
81
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('34I5') }
82
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2A04') }
83
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2AO4') }
84
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2A-3') }
85
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2A 3') }
86
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2A)3') }
87
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('345678') }
88
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id('3456789') }
89
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('3456789A') }
90
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('3456789AB') }
91
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id('3456789ABC') }
92
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('3456789ABCD') }
93
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id('2A45') }
94
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id(' 2A43 ') }
95
+ assert_nothing_raised(IdCoder::InvalidCode){@id_coder.code_to_id('2a43') }
96
+ end
97
+
98
+ def test_check_digits
99
+ # sanity check
100
+ assert@id_coder.check_digit?
101
+ assert_equal 6,@id_coder.num_digits
102
+ assert_equal 2,@id_coder.block_digits
103
+ assert_equal 7,@id_coder.code_length
104
+ assert_equal 32, IdCoder::RADIX
105
+ assert_equal 32**6,@id_coder.num_valid_codes
106
+
107
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(1023) }
108
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(234) }
109
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(2345938) }
110
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('2345938') }
111
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('345432') }
112
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id('3454321') }
113
+ valid_code =@id_coder.id_to_code(234331)
114
+ assert_equal 7, valid_code.size
115
+ digits = %w{2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z}
116
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(valid_code[0...-1])}
117
+ # Check that changing the check digit makes the code invalid
118
+ digits.each do |digit|
119
+ next if digit == valid_code[-1,1]
120
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(valid_code[0...-1]+digit)}
121
+ end
122
+ # Check that any single-digit change makes the code invalid
123
+ (0..5).each do |i|
124
+ digits.each do |digit|
125
+ next if digit == valid_code[i,1]
126
+ invalid_code = valid_code[0,i] + digit + valid_code[i+1..-1]
127
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(invalid_code)}
128
+ end
129
+ end
130
+ # Check that adjacent digit swapping makes the code invalid
131
+ # (there are some exceptions though, see http://en.wikipedia.org/wiki/Luhn_mod_N_algorithm)
132
+ # TODO: sistematic check avoiding exceptions
133
+ invalid_code = valid_code[0,2] + valid_code[3,1] + valid_code[2,1] + valid_code[4..-1]
134
+ assert_raise(IdCoder::InvalidCode){@id_coder.code_to_id(invalid_code)}
135
+ end
136
+
137
+ def test_internal_sanity
138
+ # Check the coded digits used: must be exactly IdCoder::RADIX unique uppercase characters
139
+ chars = []
140
+ IdCoder::CODE_DIGITS.each_byte{|b| chars << b.chr}
141
+ assert_equal IdCoder::RADIX, chars.uniq.size
142
+ assert_equal IdCoder::CODE_DIGITS.upcase, IdCoder::CODE_DIGITS
143
+
144
+ # Check the internally-used radix-32 digits to be consistent with Integer#to_s
145
+ assert_equal IdCoder::RADIX, IdCoder::DIGITS.size
146
+ (0...IdCoder::RADIX).each do |i|
147
+ assert_equal i.to_s(IdCoder::RADIX), IdCoder::DIGITS[i,1]
148
+ end
149
+ end
150
+
151
+
152
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: id_coder
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Javier Goizueta
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: modalsupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: modalsettings
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: shoulda
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rdoc
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '3.12'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '3.12'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1'
94
+ - !ruby/object:Gem::Dependency
95
+ name: jeweler
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 1.8.3
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 1.8.3
110
+ description: Generates relatively short codes to represent id numbers externally
111
+ email: jgoizueta@gmail.com
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files:
115
+ - LICENSE.txt
116
+ - README.rdoc
117
+ files:
118
+ - .document
119
+ - Gemfile
120
+ - Gemfile.lock
121
+ - LICENSE.txt
122
+ - README.rdoc
123
+ - Rakefile
124
+ - VERSION
125
+ - lib/id_coder.rb
126
+ - test/helper.rb
127
+ - test/test_id_coder.rb
128
+ homepage: http://github.com/jgoizueta/id_coder
129
+ licenses:
130
+ - MIT
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ segments:
142
+ - 0
143
+ hash: -1112580131298559240
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 1.8.21
153
+ signing_key:
154
+ specification_version: 3
155
+ summary: Alphanumeric code generator
156
+ test_files: []