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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile CHANGED
@@ -1,16 +1,4 @@
1
1
  source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
- gem "anvl"
6
- gem "json"
7
- gem "backports"
8
2
 
9
- # Add dependencies to develop your gem here.
10
- # Include everything needed to run rake, tests, features, etc.
11
- group :development do
12
- gem "shoulda", ">= 0"
13
- gem "bundler", "~> 1.0.0"
14
- gem "jeweler", "~> 1.5.1"
15
- gem "rcov", ">= 0"
16
- end
3
+ # Specify your gem's dependencies in noid.gemspec
4
+ gemspec
data/Rakefile CHANGED
@@ -1,53 +1,8 @@
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 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "noid"
16
- gem.homepage = "http://github.com/cbeer/noid"
17
- gem.license = "MIT"
18
- gem.summary = %Q{Nice Opaque Identifier}
19
- gem.description = %Q{}
20
- gem.email = "chris@cbeer.info"
21
- gem.authors = ["Chris Beer"]
22
- # Include your dependencies below. Runtime dependencies are required when using your gem,
23
- # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
- # gem.add_development_dependency 'rspec', '> 1.2.3'
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
28
-
29
- require 'rake/testtask'
30
- Rake::TestTask.new(:test) do |test|
31
- test.libs << 'lib' << 'test'
32
- test.pattern = 'test/**/test_*.rb'
33
- test.verbose = true
34
- end
35
-
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/test_*.rb'
40
- test.verbose = true
41
- end
42
-
43
- task :default => :test
1
+ require 'bundler/gem_tasks'
44
2
 
45
- require 'rake/rdoctask'
46
- Rake::RDocTask.new do |rdoc|
47
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
3
+ require 'rspec/core/rake_task'
48
4
 
49
- rdoc.rdoc_dir = 'rdoc'
50
- rdoc.title = "noid #{version}"
51
- rdoc.rdoc_files.include('README*')
52
- rdoc.rdoc_files.include('lib/**/*.rb')
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
7
+ t.pattern = 'spec/**/*_spec.rb'
53
8
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
data/lib/noid.rb CHANGED
@@ -1,13 +1,8 @@
1
- require 'noid/base'
2
- require 'noid/minter'
3
- require 'noid/persistence'
4
- require 'noid/persistence/base'
5
- require 'noid/persistence/json'
6
- require 'noid/identifier'
7
- require 'noid/identifier/singleton'
8
- require 'noid/identifier/anvl'
9
- require 'noid/active_record'
10
- require 'noid/active_record/provider'
11
- module Noid
1
+ require "noid/version"
2
+ require "noid/minter"
3
+ require "noid/template"
12
4
 
5
+ module Noid
6
+ XDIGIT = ['0','1','2','3','4','5','6','7','8','9','b','c','d','f','g','h','j','k','m','n','p','q','r','s','t','v','w','x','z']
7
+ MAX_COUNTERS = 293
13
8
  end
data/lib/noid/minter.rb CHANGED
@@ -1,5 +1,117 @@
1
+ require 'backports'
2
+ require 'backports'
3
+
1
4
  module Noid
2
5
  class Minter
3
- include Noid::Base
6
+ attr_reader :seed, :seq
7
+ attr_writer :counters
8
+
9
+ def initialize args = {}
10
+ @seq = 0
11
+ seed(args[:seed], args[:seq])
12
+ @template_string = args[:template]
13
+ @max_counters = args[:max_counters]
14
+ @counters = args[:counters]
15
+ end
16
+
17
+ ##
18
+ # Mint a new identifier
19
+ def mint
20
+ n = nil
21
+
22
+
23
+ case template.generator
24
+ when 's'
25
+ n = next_in_sequence
26
+ when 'z'
27
+ n = next_in_sequence
28
+ when 'r'
29
+ raise Exception if counters.size == 0
30
+ i = @rand.rand(counters.size)
31
+ next_in_sequence
32
+ n = counters[i][:value]
33
+ counters[i][:value] += 1
34
+ counters.delete_at(i) if counters[i][:value] == counters[i][:max]
35
+ end
36
+
37
+ template.mint(n)
38
+ end
39
+
40
+ ##
41
+ # Noid identifier template
42
+ #
43
+ # @return Noid::Template
44
+ def template
45
+ @template ||= Noid::Template.new(@template_string)
46
+ end
47
+
48
+ ##
49
+ # Is the identifier valid under the template string and checksum?
50
+ # @param [String] id
51
+ # @return bool
52
+ def valid? id
53
+ prefix = id[0..@prefix.length-1]
54
+ ch = id[@prefix.length..-1].split('')
55
+ check = ch.pop if @check
56
+ return false unless prefix == @prefix
57
+
58
+ return false unless @characters.length == ch.length
59
+ @characters.each_with_index do |c, i|
60
+ return false unless Noid::XDIGIT.include? ch[i]
61
+ return false if c == 'd' and ch[i] =~ /[^\d]/
62
+ end
63
+
64
+ return false unless check.nil? or check == checkdigit(id[0..-2])
65
+
66
+ true
67
+ end
68
+
69
+ ##
70
+ # Seed the random number generator with a seed and sequence offset
71
+ # @param [Integer] seed
72
+ # @param [Integer] seq
73
+ # @return [Random]
74
+ def seed seed = nil, seq = 0
75
+ @rand = Random.new(seed) if seed
76
+ @rand ||= Random.new
77
+ @seed = @rand.seed
78
+
79
+ seq.times { @rand.rand } if seq
80
+
81
+ @rand
82
+ end
83
+
84
+ def next_in_sequence
85
+ n = @seq
86
+ @seq += 1
87
+ n
88
+ end
89
+
90
+ ##
91
+ # Counters to use for quasi-random NOID sequences
92
+ def counters
93
+ return @counters if @counters
94
+ return [] unless template.generator == "r"
95
+
96
+ percounter = template.max / (@max_counters || Noid::MAX_COUNTERS) + 1
97
+ t = 0
98
+ @counters = []
99
+
100
+ while t < template.max
101
+ counter = {}
102
+ counter[:value] = t
103
+ counter[:max] = [t + percounter, template.max].min
104
+
105
+ t += percounter
106
+
107
+ @counters << counter
108
+ end
109
+
110
+ @counters
111
+ end
112
+
113
+ def dump
114
+ { :seq => @seq, :seed => @seed, :template => template.template, :counters => Marshal.load(Marshal.dump(counters)) }
115
+ end
4
116
  end
5
117
  end
@@ -0,0 +1,144 @@
1
+ module Noid
2
+ class Template
3
+ attr_reader :template
4
+
5
+ # @param [String] template A Template is a coded string of the form Prefix.Mask that governs how identifiers will be minted.
6
+ def initialize template
7
+ @template = template
8
+ end
9
+
10
+ def mint n
11
+ str = prefix
12
+ str += n2xdig(n)
13
+ str += checkdigit(str) if checkdigit?
14
+
15
+ str
16
+ end
17
+
18
+ def valid? str
19
+ return false unless str[0..prefix.length] == prefix
20
+
21
+ if generator == 'z'
22
+ str[prefix.length..-1].length > 2
23
+ else
24
+ str[prefix.length..-1].length == characters.length
25
+ end
26
+
27
+ characters.each_with_index do |c, i|
28
+ case c
29
+ when 'e'
30
+ return false unless Noid::XDIGIT.include? str[prefix.length + i]
31
+ when 'd'
32
+ return false unless str[prefix.length + i] =~ /\d/
33
+ end
34
+ end
35
+
36
+ return false unless checkdigit(str[0..-2]) == str.split('').last if checkdigit?
37
+
38
+ true
39
+ end
40
+
41
+ ##
42
+ # identifier prefix string
43
+ def prefix
44
+ @prefix ||= @template.split('.').first
45
+ end
46
+
47
+ ##
48
+ # identifier mask string
49
+ def mask
50
+ @mask ||= @template.split('.').last
51
+ end
52
+
53
+ ##
54
+ # generator type to use: r, s, z
55
+ def generator
56
+ @generator ||= mask[0..0]
57
+ end
58
+
59
+ ##
60
+ # sequence pattern: e (extended), d (digit)
61
+ def characters
62
+ @characters ||= begin
63
+ if checkdigit?
64
+ mask[1..-2]
65
+ else
66
+ mask[1..-1]
67
+ end
68
+ end
69
+ end
70
+
71
+ ##
72
+ # should generated identifiers have a checkdigit?
73
+ def checkdigit?
74
+ mask.split('').last == 'k'
75
+ end
76
+
77
+ ##
78
+ # calculate a checkdigit for the str
79
+ # @param [String] str
80
+ # @return [String] checkdigit
81
+ def checkdigit str
82
+ Noid::XDIGIT[str.split('').map { |x| Noid::XDIGIT.index(x).to_i }.each_with_index.map { |n, idx| n*(idx+1) }.inject { |sum, n| sum += n } % Noid::XDIGIT.length ]
83
+ end
84
+
85
+ ##
86
+ # minimum sequence value
87
+ def min
88
+ @min ||= 0
89
+ end
90
+
91
+ ##
92
+ # maximum sequence value for the template
93
+ def max
94
+ @max ||= begin
95
+ case generator
96
+ when 'z'
97
+ nil
98
+ else
99
+ characters.split('').map { |x| character_space(x) }.compact.inject(1) { |total, x| total *= x }
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ protected
106
+ ##
107
+ # total size of a given template character value
108
+ # @param [String] c
109
+ def character_space c
110
+ case c
111
+ when 'e'
112
+ Noid::XDIGIT.length
113
+ when 'd'
114
+ 10
115
+ end
116
+ end
117
+
118
+ ##
119
+ # convert a minter position to a noid string under this template
120
+ # @param [Integer] n
121
+ # @return [String]
122
+ def n2xdig n
123
+ xdig = characters.reverse.split('').map do |c|
124
+ value = n % character_space(c)
125
+ n = n / character_space(c)
126
+ Noid::XDIGIT[value]
127
+ end.compact.join('')
128
+
129
+ if generator == 'z'
130
+ c = characters.split('').last
131
+ while n > 0
132
+ value = n % character_space(c)
133
+ n = n / character_space(c)
134
+ xdig += Noid::XDIGIT[value]
135
+ end
136
+ end
137
+
138
+ raise Exception if n > 0
139
+
140
+ xdig.reverse
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,9 @@
1
+ module Noid
2
+ unless Noid.const_defined? :VERSION
3
+ def self.version
4
+ @version ||= File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION')).chomp
5
+ end
6
+
7
+ VERSION = self.version
8
+ end
9
+ end
data/noid.gemspec CHANGED
@@ -1,87 +1,25 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "noid/version"
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{noid}
8
- s.version = "0.4.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Chris Beer"]
12
- s.date = %q{2010-12-23}
6
+ s.name = "noid"
7
+ s.version = Noid::VERSION
8
+ s.authors = ["Chris Beer"]
9
+ s.email = ["chris@cbeer.info"]
10
+ s.homepage = "http://github.com/microservices/noid"
11
+ s.summary = %q{Nice Opaque Identifier}
13
12
  s.description = %q{}
14
- s.email = %q{chris@cbeer.info}
15
- s.extra_rdoc_files = [
16
- "LICENSE.txt",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- "Gemfile",
22
- "LICENSE.txt",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "doc/active_record_sample.rb",
27
- "lib/noid.rb",
28
- "lib/noid/active_record.rb",
29
- "lib/noid/active_record/provider.rb",
30
- "lib/noid/base.rb",
31
- "lib/noid/identifier.rb",
32
- "lib/noid/identifier/anvl.rb",
33
- "lib/noid/identifier/singleton.rb",
34
- "lib/noid/minter.rb",
35
- "lib/noid/persistence.rb",
36
- "lib/noid/persistence/base.rb",
37
- "lib/noid/persistence/json.rb",
38
- "noid.gemspec",
39
- "test/helper.rb",
40
- "test/test_binding.rb",
41
- "test/test_noid.rb",
42
- "test/test_persistence.rb"
43
- ]
44
- s.homepage = %q{http://github.com/cbeer/noid}
45
- s.licenses = ["MIT"]
46
- s.require_paths = ["lib"]
47
- s.rubygems_version = %q{1.3.7}
48
- s.summary = %q{Nice Opaque Identifier}
49
- s.test_files = [
50
- "test/helper.rb",
51
- "test/test_binding.rb",
52
- "test/test_noid.rb",
53
- "test/test_persistence.rb"
54
- ]
55
13
 
56
- if s.respond_to? :specification_version then
57
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58
- s.specification_version = 3
14
+ s.rubyforge_project = "noid"
59
15
 
60
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
- s.add_runtime_dependency(%q<anvl>, [">= 0"])
62
- s.add_runtime_dependency(%q<json>, [">= 0"])
63
- s.add_runtime_dependency(%q<backports>, [">= 0"])
64
- s.add_development_dependency(%q<shoulda>, [">= 0"])
65
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
66
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
67
- s.add_development_dependency(%q<rcov>, [">= 0"])
68
- else
69
- s.add_dependency(%q<anvl>, [">= 0"])
70
- s.add_dependency(%q<json>, [">= 0"])
71
- s.add_dependency(%q<backports>, [">= 0"])
72
- s.add_dependency(%q<shoulda>, [">= 0"])
73
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
75
- s.add_dependency(%q<rcov>, [">= 0"])
76
- end
77
- else
78
- s.add_dependency(%q<anvl>, [">= 0"])
79
- s.add_dependency(%q<json>, [">= 0"])
80
- s.add_dependency(%q<backports>, [">= 0"])
81
- s.add_dependency(%q<shoulda>, [">= 0"])
82
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
83
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
84
- s.add_dependency(%q<rcov>, [">= 0"])
85
- end
86
- end
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
87
20
 
21
+ s.add_dependency "backports"
22
+ s.add_development_dependency "bundler", "~> 1.0.0"
23
+ s.add_development_dependency "rspec", ">= 2.0"
24
+ s.add_development_dependency "rcov", ">= 0"
25
+ end