noid 0.4.0 → 0.5.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.
- data/.gitignore +4 -0
- data/Gemfile +2 -14
- data/Rakefile +5 -50
- data/VERSION +1 -1
- data/lib/noid.rb +6 -11
- data/lib/noid/minter.rb +113 -1
- data/lib/noid/template.rb +144 -0
- data/lib/noid/version.rb +9 -0
- data/noid.gemspec +18 -80
- data/spec/lib/minter_spec.rb +153 -0
- data/spec/spec_helper.rb +7 -0
- metadata +65 -153
- data/.document +0 -5
- data/doc/active_record_sample.rb +0 -6
- data/lib/noid/active_record.rb +0 -5
- data/lib/noid/active_record/provider.rb +0 -36
- data/lib/noid/base.rb +0 -154
- data/lib/noid/identifier.rb +0 -24
- data/lib/noid/identifier/anvl.rb +0 -32
- data/lib/noid/identifier/singleton.rb +0 -14
- data/lib/noid/persistence.rb +0 -4
- data/lib/noid/persistence/base.rb +0 -11
- data/lib/noid/persistence/json.rb +0 -38
- data/test/helper.rb +0 -18
- data/test/test_binding.rb +0 -42
- data/test/test_noid.rb +0 -134
- data/test/test_persistence.rb +0 -47
data/lib/noid/base.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
require 'backports'
|
2
|
-
|
3
|
-
module Noid
|
4
|
-
module Base
|
5
|
-
XDIGIT = ['0','1','2','3','4','5','6','7','8','9','b','c','d','f','g','h','j','k','l','n','p','q','r','s','t','v','w','x','z']
|
6
|
-
MAX_COUNTERS = 293
|
7
|
-
|
8
|
-
def initialize args = {}
|
9
|
-
@max = nil
|
10
|
-
@min = nil
|
11
|
-
@config = { :identifier => {} }.merge args
|
12
|
-
super() if respond_to?('super')
|
13
|
-
setup_mask args
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
def mint
|
18
|
-
str = @prefix
|
19
|
-
n = @s
|
20
|
-
@s += 1
|
21
|
-
|
22
|
-
case @type
|
23
|
-
when 's'
|
24
|
-
when 'z'
|
25
|
-
when 'r'
|
26
|
-
raise Exception if @counters.size == 0
|
27
|
-
i = @rand.rand(@counters.size)
|
28
|
-
n = @counters[i][:value]
|
29
|
-
@counters[i][:value] += 1
|
30
|
-
@counters.delete_at(i) if @counters[i][:value] == @counters[i][:max]
|
31
|
-
end
|
32
|
-
str += n2xdig(n)
|
33
|
-
|
34
|
-
str += checkdigit(str) if @check
|
35
|
-
|
36
|
-
identifier.new str
|
37
|
-
end
|
38
|
-
|
39
|
-
def valid? id
|
40
|
-
prefix = id[0..@prefix.length-1]
|
41
|
-
ch = id[@prefix.length..-1].split('')
|
42
|
-
check = ch.pop if @check
|
43
|
-
return false unless prefix == @prefix
|
44
|
-
|
45
|
-
return false unless @characters.length == ch.length
|
46
|
-
@characters.each_with_index do |c, i|
|
47
|
-
return false unless XDIGIT.include? ch[i]
|
48
|
-
return false if c == 'd' and ch[i] =~ /[^\d]/
|
49
|
-
end
|
50
|
-
|
51
|
-
return false unless check.nil? or check == checkdigit(id[0..-2])
|
52
|
-
|
53
|
-
true
|
54
|
-
end
|
55
|
-
|
56
|
-
protected
|
57
|
-
def identifier
|
58
|
-
@config[:identifier][:class] || String
|
59
|
-
end
|
60
|
-
|
61
|
-
def checkdigit str
|
62
|
-
i = 1
|
63
|
-
XDIGIT[str.split('').map { |x| XDIGIT.index(x).to_i }.inject { |sum, n| i+=1; sum += (n * i) } % XDIGIT.length]
|
64
|
-
end
|
65
|
-
|
66
|
-
def min
|
67
|
-
return @min if @min
|
68
|
-
@min = 0
|
69
|
-
end
|
70
|
-
|
71
|
-
def max
|
72
|
-
return @max if @max
|
73
|
-
return @max = nil if @type == 'z'
|
74
|
-
@max = @characters.inject(1) do |sum, n|
|
75
|
-
i = case n
|
76
|
-
when 'e'
|
77
|
-
XDIGIT.length
|
78
|
-
when 'd'
|
79
|
-
10
|
80
|
-
else
|
81
|
-
1
|
82
|
-
end
|
83
|
-
sum *= i
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def n2xdig n
|
88
|
-
xdig = @characters.reverse.map do |c|
|
89
|
-
div = case c
|
90
|
-
when 'e' then XDIGIT.length
|
91
|
-
when 'd' then 10
|
92
|
-
end
|
93
|
-
next if div.nil?
|
94
|
-
|
95
|
-
value = n % div
|
96
|
-
n = n / div
|
97
|
-
XDIGIT[value]
|
98
|
-
end.compact.join ''
|
99
|
-
|
100
|
-
if @type == 'z'
|
101
|
-
while n > 0
|
102
|
-
c = @characters.last
|
103
|
-
div = case c
|
104
|
-
when 'e' then XDIGIT.length
|
105
|
-
when 'd' then 10
|
106
|
-
end
|
107
|
-
next if div.nil?
|
108
|
-
|
109
|
-
value = n % div
|
110
|
-
n = n / div
|
111
|
-
xdig += XDIGIT[value]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
raise Exception if n > 0
|
116
|
-
|
117
|
-
xdig.reverse
|
118
|
-
end
|
119
|
-
|
120
|
-
def setup_mask args
|
121
|
-
@template = args[:template]
|
122
|
-
@prefix, @mask = @template.split('.')
|
123
|
-
|
124
|
-
@prefix = "#{args[:namespace]}/#{@prefix}" if args[:namespace]
|
125
|
-
|
126
|
-
@type, @characters = @mask.split '', 2
|
127
|
-
@characters = @characters.split ''
|
128
|
-
@check = @characters.pop and true if @characters.last == 'k'
|
129
|
-
@s = args[:s] || 0
|
130
|
-
case @type
|
131
|
-
when 's'
|
132
|
-
when 'z'
|
133
|
-
when 'r'
|
134
|
-
@rand = Random.new(args[:seed]) if args[:seed]
|
135
|
-
@rand ||= Random.new
|
136
|
-
@seed = @rand.seed
|
137
|
-
|
138
|
-
if args[:s]
|
139
|
-
args[:s].times { @rand.rand }
|
140
|
-
end
|
141
|
-
|
142
|
-
percounter = max / (args[:max_counters] || MAX_COUNTERS) + 1
|
143
|
-
t = 0
|
144
|
-
@counters = args[:counters]
|
145
|
-
@counters ||= Array.new(max/percounter) do |i|
|
146
|
-
{ :value => case i
|
147
|
-
when 0 then 0
|
148
|
-
else t += percounter
|
149
|
-
end, :max => t + percounter }
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
data/lib/noid/identifier.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Noid::Identifier
|
2
|
-
class Base
|
3
|
-
def initialize id
|
4
|
-
@id = id
|
5
|
-
@metadata = {}
|
6
|
-
end
|
7
|
-
|
8
|
-
def id
|
9
|
-
@id
|
10
|
-
end
|
11
|
-
|
12
|
-
def [] key
|
13
|
-
@metadata[key]
|
14
|
-
end
|
15
|
-
|
16
|
-
def []= key, value
|
17
|
-
@metadata[key] = value
|
18
|
-
end
|
19
|
-
|
20
|
-
def push hash
|
21
|
-
@metadata.merge! hash
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/noid/identifier/anvl.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module Noid::Identifier
|
2
|
-
class Anvl < Base
|
3
|
-
def initialize id
|
4
|
-
@id = id
|
5
|
-
@metadata = ::ANVL::Document.new
|
6
|
-
end
|
7
|
-
|
8
|
-
def []= key, value
|
9
|
-
super
|
10
|
-
save
|
11
|
-
end
|
12
|
-
|
13
|
-
def push hash
|
14
|
-
@metadata << hash
|
15
|
-
save
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def file
|
20
|
-
@id
|
21
|
-
end
|
22
|
-
|
23
|
-
def save
|
24
|
-
File.open(file, 'w') do |f|
|
25
|
-
f.write @metadata.to_s
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
data/lib/noid/persistence.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
module Noid::Persistence
|
3
|
-
class JSON < Base
|
4
|
-
FILENAME = 'NOID.js'
|
5
|
-
def initialize args = {}
|
6
|
-
@file = args[:filename] || FILENAME
|
7
|
-
@json = args[:json] || File.read(@file) rescue nil
|
8
|
-
data = load_json if @json
|
9
|
-
data ||= {}
|
10
|
-
super data.merge(args)
|
11
|
-
save
|
12
|
-
end
|
13
|
-
|
14
|
-
protected
|
15
|
-
def load_json
|
16
|
-
data = ::JSON.parse(@json) rescue nil
|
17
|
-
data ||= {}
|
18
|
-
data = data.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} unless data.empty?
|
19
|
-
data[:counters] = data[:counters].map { |x| x.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} } if data[:counters]
|
20
|
-
data[:identifier] = { :class => Kernel.const_get(data[:identifier]['class']) } if data[:identifier]
|
21
|
-
data
|
22
|
-
end
|
23
|
-
|
24
|
-
def save
|
25
|
-
str = self.to_json
|
26
|
-
File.open(@file, 'w') do |f|
|
27
|
-
f.write(str)
|
28
|
-
end unless @file == '/dev/null'
|
29
|
-
|
30
|
-
str
|
31
|
-
end
|
32
|
-
|
33
|
-
def to_json
|
34
|
-
str = { :template => @template, :identifier => { :class => identifier.name }, :s => @s, :counters => @counters, :seed => @seed }.to_json
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
data/test/helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
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 'noid'
|
16
|
-
|
17
|
-
class Test::Unit::TestCase
|
18
|
-
end
|
data/test/test_binding.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'anvl'
|
3
|
-
require 'tmpdir'
|
4
|
-
|
5
|
-
class TestNoidBinding < Test::Unit::TestCase
|
6
|
-
context "Noid" do
|
7
|
-
should "accept identifier_class for NOID bindings" do
|
8
|
-
Dir.mktmpdir do |d|
|
9
|
-
Dir.chdir d
|
10
|
-
n = Noid::Minter.new :template => 'r.rek', :identifier => { :class => Noid::Identifier::Base }
|
11
|
-
id = n.mint
|
12
|
-
assert_equal(Noid::Identifier::Base, id.class)
|
13
|
-
id['abc'] = 123
|
14
|
-
assert_equal(123, id['abc'])
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
should "use singleton instance to persist NOID bindings" do
|
19
|
-
Dir.mktmpdir do |d|
|
20
|
-
Dir.chdir d
|
21
|
-
n = Noid::Minter.new :template => 'r.rek', :identifier => { :class => Noid::Identifier::Singleton }
|
22
|
-
id = n.mint
|
23
|
-
id['abc'] = 123
|
24
|
-
assert_equal(123, id['abc'])
|
25
|
-
|
26
|
-
id2 = Noid::Identifier::Singleton.new id.id
|
27
|
-
assert_equal(123, id2['abc'])
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
should "user anvl instance to persist NOID binding info" do
|
32
|
-
Dir.mktmpdir do |d|
|
33
|
-
Dir.chdir d
|
34
|
-
n = Noid::Minter.new :template => 'r.rek', :identifier => { :class => Noid::Identifier::Anvl }
|
35
|
-
id = n.mint
|
36
|
-
id['abc'] = "123"
|
37
|
-
assert_equal(Noid::Identifier::Anvl, id.class)
|
38
|
-
assert_equal("123", id['abc'])
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/test/test_noid.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestNoid < Test::Unit::TestCase
|
4
|
-
context "Noid" do
|
5
|
-
should "generate checkdigits correctly" do
|
6
|
-
n = Noid::Minter.new :template => 's.zd'
|
7
|
-
assert_equal('q', n.send(:checkdigit, '13030/xf93gt2'))
|
8
|
-
end
|
9
|
-
|
10
|
-
should "generate max sequence for type 'r'" do
|
11
|
-
n = Noid::Minter.new :template => 's.rd'
|
12
|
-
assert_equal(0, n.send(:min))
|
13
|
-
assert_equal(10, n.send(:max))
|
14
|
-
|
15
|
-
n = Noid::Minter.new :template => 's.rdd'
|
16
|
-
assert_equal(0, n.send(:min))
|
17
|
-
assert_equal(100, n.send(:max))
|
18
|
-
end
|
19
|
-
|
20
|
-
should "generate quasi-random counters for type 'r'" do
|
21
|
-
n = Noid::Minter.new :template => 's.rd'
|
22
|
-
assert_equal((0..9).map { |x| {:value => x, :max => (x + 1)} }, n.instance_variable_get('@counters'))
|
23
|
-
|
24
|
-
n = Noid::Minter.new :template => 's.rdde'
|
25
|
-
s = n.instance_variable_get('@counters')
|
26
|
-
assert_contains(s, {:value => 2890, :max => 2900})
|
27
|
-
end
|
28
|
-
|
29
|
-
should "generate random sequence for type 'r'" do
|
30
|
-
n = Noid::Minter.new :template => 's.rd'
|
31
|
-
a = 10.times.map { |i| n.mint }
|
32
|
-
|
33
|
-
10.times do |i|
|
34
|
-
assert_contains(a, "s#{i}")
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
should "generate numeric sequence for type 's'" do
|
40
|
-
n = Noid::Minter.new :template => 's.sd'
|
41
|
-
10.times do |i|
|
42
|
-
assert_equal("s#{i}", n.mint)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
should "generate extended sequence for type 's'" do
|
47
|
-
n = Noid::Minter.new :template => 's.se'
|
48
|
-
10.times do |i|
|
49
|
-
assert_equal("s#{i}", n.mint)
|
50
|
-
end
|
51
|
-
assert_equal("sb", n.mint)
|
52
|
-
10.times { n.mint }
|
53
|
-
assert_equal("sq", n.mint)
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
should "raise an exception when overflowing sequence" do
|
58
|
-
n = Noid::Minter.new :template => 's.sd'
|
59
|
-
10.times do |i|
|
60
|
-
assert_equal("s#{i}", n.mint)
|
61
|
-
end
|
62
|
-
|
63
|
-
assert_raise Exception do
|
64
|
-
n.mint
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
should "generate sequence for type 's' with checkdigit" do
|
69
|
-
n = Noid::Minter.new :template => 's.sdk'
|
70
|
-
assert_equal('s0s', n.mint)
|
71
|
-
assert_equal('s1v', n.mint)
|
72
|
-
assert_equal('s2x', n.mint)
|
73
|
-
end
|
74
|
-
|
75
|
-
should "generate sequence for type 'z' with checkdigit" do
|
76
|
-
n = Noid::Minter.new :template => 'z.zdk'
|
77
|
-
assert_equal('z0z', n.mint)
|
78
|
-
assert_equal('z11', n.mint)
|
79
|
-
assert_equal('z23', n.mint)
|
80
|
-
end
|
81
|
-
should "generate sequence for type 'z', adding new digits as needed" do
|
82
|
-
n = Noid::Minter.new :template => 'z.zdk'
|
83
|
-
assert_equal('z0z', n.mint)
|
84
|
-
assert_equal('z11', n.mint)
|
85
|
-
assert_equal('z23', n.mint)
|
86
|
-
10.times { n.mint }
|
87
|
-
assert_equal('z13b', n.mint)
|
88
|
-
end
|
89
|
-
|
90
|
-
should "generate sequence for type 'z', adding new xdigits as needed" do
|
91
|
-
n = Noid::Minter.new :template => 'z.zdek'
|
92
|
-
assert_equal('z00z', n.mint)
|
93
|
-
assert_equal('z012', n.mint)
|
94
|
-
assert_equal('z025', n.mint)
|
95
|
-
10.times {
|
96
|
-
assert_match(/^z[0-9]/, n.mint)
|
97
|
-
}
|
98
|
-
assert_equal('z0f9', n.mint)
|
99
|
-
100.times {
|
100
|
-
assert_match(/^z[0-9]/, n.mint)
|
101
|
-
}
|
102
|
-
assert_equal('z3xz', n.mint)
|
103
|
-
1000.times {
|
104
|
-
assert_match(/^z[0-9]/, n.mint)
|
105
|
-
}
|
106
|
-
assert_equal('z38fs', n.mint)
|
107
|
-
end
|
108
|
-
|
109
|
-
should "validate 'r' digit sequences" do
|
110
|
-
n = Noid::Minter.new :template => 'r.rd'
|
111
|
-
|
112
|
-
assert_equal(true, n.valid?('r1') )
|
113
|
-
assert_equal(true, n.valid?('r9') )
|
114
|
-
assert_equal(false, n.valid?('r11') )
|
115
|
-
assert_equal(false, n.valid?('ro'))
|
116
|
-
assert_equal(false, n.valid?('rb'))
|
117
|
-
end
|
118
|
-
|
119
|
-
should "validate 'r' xdigit sequences" do
|
120
|
-
n = Noid::Minter.new :template => 'r.re'
|
121
|
-
|
122
|
-
assert_equal(true, n.valid?('r1') )
|
123
|
-
assert_equal(true, n.valid?('r9') )
|
124
|
-
assert_equal(false, n.valid?('ro'))
|
125
|
-
assert_equal(true, n.valid?('rb'))
|
126
|
-
end
|
127
|
-
should "validate 'r' xdigit + checkdigit sequences" do
|
128
|
-
n = Noid::Minter.new :template => 'r.rek'
|
129
|
-
|
130
|
-
assert_equal(true, n.valid?('r2w') )
|
131
|
-
assert_equal(false, n.valid?('r2b') )
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|