active_fedora-noid 2.0.0.beta3 → 2.0.0.beta4
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/.travis.yml +2 -2
- data/Gemfile +12 -12
- data/README.md +38 -15
- data/active_fedora-noid.gemspec +3 -3
- data/app/models/minter_state.rb +0 -16
- data/db/migrate/20161021203429_rename_minter_state_random_to_rand.rb +5 -0
- data/lib/active_fedora/noid.rb +4 -4
- data/lib/active_fedora/noid/config.rb +6 -1
- data/lib/active_fedora/noid/minter.rb +3 -0
- data/lib/active_fedora/noid/minter/base.rb +32 -2
- data/lib/active_fedora/noid/minter/db.rb +25 -10
- data/lib/active_fedora/noid/minter/file.rb +60 -0
- data/lib/active_fedora/noid/service.rb +1 -1
- data/lib/active_fedora/noid/version.rb +1 -1
- data/lib/tasks/noid_tasks.rake +43 -17
- data/spec/models/minter_state_spec.rb +0 -18
- data/spec/support/shared_examples/minter.rb +55 -0
- data/spec/unit/config_spec.rb +65 -4
- data/spec/unit/db_minter_spec.rb +27 -40
- data/spec/unit/file_minter_spec.rb +58 -0
- data/spec/unit/noid_spec.rb +4 -0
- data/spec/unit/service_spec.rb +1 -1
- metadata +15 -11
- data/lib/active_fedora/noid/synchronized_minter.rb +0 -45
- data/spec/unit/synchronized_minter_spec.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 709c8e18225adbbd00041373fc45c436166ffa50
|
4
|
+
data.tar.gz: 4b4a569df3483bf994dc154ed986fc4bf700561c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ad9a677d42550c1fa40545ab19b5f872da006971a73cdbe9cf8788667316da5fee10541779f155d156ba772eca59f79d0a9c7db5262c07bb97e0f0320b506d1
|
7
|
+
data.tar.gz: db77507d045c565b2c7aa1ea351f4112405f0dcbaef0f47081f5589e6a56c2099cb1639dd6fda906ac621ec9a30a4229c3607db728a676674f01fa770159477d
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -6,13 +6,13 @@ gemspec
|
|
6
6
|
group :development, :test do
|
7
7
|
gem 'byebug' unless ENV['CI']
|
8
8
|
gem 'coveralls', require: false
|
9
|
-
gem 'byebug' unless ENV['CI']
|
10
9
|
end
|
10
|
+
|
11
11
|
# BEGIN ENGINE_CART BLOCK
|
12
|
-
# engine_cart: 0.
|
13
|
-
# engine_cart stanza: 0.
|
12
|
+
# engine_cart: 1.0.1
|
13
|
+
# engine_cart stanza: 0.10.0
|
14
14
|
# the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
|
15
|
-
file = File.expand_path(
|
15
|
+
file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', File.dirname(__FILE__)))
|
16
16
|
if File.exist?(file)
|
17
17
|
begin
|
18
18
|
eval_gemfile file
|
@@ -26,19 +26,19 @@ else
|
|
26
26
|
if ENV['RAILS_VERSION']
|
27
27
|
if ENV['RAILS_VERSION'] == 'edge'
|
28
28
|
gem 'rails', github: 'rails/rails'
|
29
|
-
ENV['ENGINE_CART_RAILS_OPTIONS']=
|
29
|
+
ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
|
30
30
|
else
|
31
31
|
gem 'rails', ENV['RAILS_VERSION']
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
gem '
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
gem 'sass-rails',
|
35
|
+
case ENV['RAILS_VERSION']
|
36
|
+
when /^4.2/
|
37
|
+
gem 'responders', '~> 2.0'
|
38
|
+
gem 'sass-rails', '>= 5.0'
|
39
|
+
gem 'coffee-rails', '~> 4.1.0'
|
40
|
+
when /^4.[01]/
|
41
|
+
gem 'sass-rails', '< 5.0'
|
42
42
|
end
|
43
43
|
end
|
44
44
|
# END ENGINE_CART BLOCK
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
[](http://badge.fury.io/rb/active_fedora-noid)
|
2
|
+
[](https://travis-ci.org/projecthydra-labs/active_fedora-noid)
|
3
|
+
[](https://coveralls.io/r/projecthydra-labs/active_fedora-noid)
|
4
|
+
[](https://codeclimate.com/github/projecthydra-labs/active_fedora-noid)
|
5
|
+
[](https://gemnasium.com/projecthydra-labs/active_fedora-noid)
|
2
6
|
[](./LICENSE)
|
3
7
|
[](./CONTRIBUTING.md)
|
4
8
|
[](http://rubydoc.info/gems/active_fedora-noid)
|
5
|
-
[](https://travis-ci.org/projecthydra-labs/active_fedora-noid)
|
6
|
-
[](https://gemnasium.com/projecthydra-labs/active_fedora-noid)
|
7
|
-
[](https://coveralls.io/r/projecthydra-labs/active_fedora-noid)
|
8
9
|
|
9
10
|
# ActiveFedora::Noid
|
10
11
|
|
@@ -96,18 +97,30 @@ This will make sure your objects have Noid-like identifiers (e.g. `bb22bb22b`) t
|
|
96
97
|
|
97
98
|
## Overriding default behavior
|
98
99
|
|
99
|
-
|
100
|
+
The default minter in ActiveFedora::Noid 2.x is the database-backed minter to better support multi-host production installations that expect a shared database but not necessarily a shared filesystem (e.g., between load-balanced Rails applications).
|
100
101
|
|
101
|
-
|
102
|
+
### Use file-based minter state (for replayability)
|
103
|
+
|
104
|
+
The file-based minter -- which was the default and only minter in 1.x -- creates a Noid and dumps it to a statefile in the /tmp directory. You can override the location or name of this statefile as follows in e.g. `config/initializers/active_fedora-noid.rb`:
|
102
105
|
|
103
106
|
```ruby
|
104
107
|
require 'active_fedora/noid'
|
105
108
|
|
106
109
|
ActiveFedora::Noid.configure do |config|
|
110
|
+
config.minter_class = ActiveFedora::Noid::Minter::File
|
107
111
|
config.statefile = '/var/foo/bar'
|
108
112
|
end
|
109
113
|
```
|
110
114
|
|
115
|
+
**NOTE**: If you switch to a new minter, it will not automatically start with the same state as the old minter. AF::Noid does include a couple of rake tasks for copying state from database-backed minters to file-backed ones and vice versa:
|
116
|
+
|
117
|
+
``` bash
|
118
|
+
# For migrating minter state from a file to a database
|
119
|
+
$ rake active_fedora:noid:migrate:file_to_database
|
120
|
+
# For migrating minter state from a database to a file
|
121
|
+
$ rake active_fedora:noid:migrate:database_to_file
|
122
|
+
```
|
123
|
+
|
111
124
|
### Identifier template
|
112
125
|
|
113
126
|
To override the default identifier pattern -- a nine-character string consisting of two alphanumeric digits, two numeric digits, two alphanumeric digits, two numeric digits, and a check digit -- put the following code in e.g. `config/initializers/active_fedora-noid.rb`:
|
@@ -124,28 +137,38 @@ For more information about the format of Noid patterns, see pages 8-10 of the [N
|
|
124
137
|
|
125
138
|
### Custom minters
|
126
139
|
|
127
|
-
If you don't want your minter's state to be persisted, you may also
|
140
|
+
If you don't want your minter's state to be persisted, you may also write and configure your own minter. First write up a minter class that looks like the following:
|
128
141
|
|
129
142
|
```ruby
|
130
|
-
class MyMinter
|
131
|
-
def
|
132
|
-
#
|
143
|
+
class MyMinter < ActiveFedora::Noid::Minter::Base
|
144
|
+
def valid?(identifier)
|
145
|
+
# return true/false if you care about ids conforming to templates
|
133
146
|
end
|
134
147
|
|
135
|
-
def
|
136
|
-
#
|
148
|
+
def read
|
149
|
+
# return current minter state
|
137
150
|
end
|
138
151
|
|
139
|
-
def
|
140
|
-
#
|
152
|
+
def write!(state)
|
153
|
+
# write a passed-in minter state
|
154
|
+
end
|
155
|
+
|
156
|
+
protected
|
157
|
+
|
158
|
+
def next_id
|
159
|
+
# return the next identifier from the minter
|
141
160
|
end
|
142
161
|
end
|
143
162
|
```
|
144
163
|
|
145
|
-
Then
|
164
|
+
Then add your new minter class to the ActiveFedora::Noid configuration (`config/initializers/active_fedora-noid.rb`):
|
146
165
|
|
147
166
|
```ruby
|
148
|
-
|
167
|
+
require 'active_fedora/noid'
|
168
|
+
|
169
|
+
ActiveFedora::Noid.configure do |config|
|
170
|
+
config.minter_class = MyMinter
|
171
|
+
end
|
149
172
|
```
|
150
173
|
|
151
174
|
And the service will delegate minting and validating to an instance of your customized minter class.
|
data/active_fedora-noid.gemspec
CHANGED
@@ -19,11 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_dependency 'active-fedora', '>= 9.7', '< 12'
|
21
21
|
spec.add_dependency 'noid', '~> 0.9'
|
22
|
-
spec.add_dependency 'rails', '>= 4.2.
|
22
|
+
spec.add_dependency 'rails', '>= 4.2.7.1', '< 6'
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
-
spec.add_development_dependency "rake", "~>
|
25
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3.2'
|
27
27
|
spec.add_development_dependency 'sqlite3'
|
28
|
-
spec.add_development_dependency 'engine_cart', '~> 0
|
28
|
+
spec.add_development_dependency 'engine_cart', '~> 1.0'
|
29
29
|
end
|
data/app/models/minter_state.rb
CHANGED
@@ -2,20 +2,4 @@ class MinterState < ActiveRecord::Base
|
|
2
2
|
validates :namespace, presence: true, uniqueness: true
|
3
3
|
validates :template, presence: true
|
4
4
|
validates :template, format: { with: Object.const_get('Noid::Template::VALID_PATTERN'), message: 'value fails regex' }
|
5
|
-
|
6
|
-
# @return [Hash] options for Noid::Minter.new
|
7
|
-
# * template [String] setting the identifier pattern
|
8
|
-
# * seq [Integer] reflecting minter position in sequence
|
9
|
-
# * counters [Array{Hash}] "buckets" each with :current and :max values
|
10
|
-
# * rand [Object] random number generator object
|
11
|
-
def noid_options
|
12
|
-
return nil unless template
|
13
|
-
opts = {
|
14
|
-
:template => template,
|
15
|
-
:seq => seq
|
16
|
-
}
|
17
|
-
opts[:counters] = JSON.parse(counters, :symbolize_names => true) if counters
|
18
|
-
opts[:rand] = Marshal.load(random) if random
|
19
|
-
opts
|
20
|
-
end
|
21
5
|
end
|
data/lib/active_fedora/noid.rb
CHANGED
@@ -2,9 +2,7 @@ require 'active_fedora/noid/version'
|
|
2
2
|
require 'active_fedora/noid/config'
|
3
3
|
require 'active_fedora/noid/engine'
|
4
4
|
require 'active_fedora/noid/service'
|
5
|
-
require 'active_fedora/noid/minter
|
6
|
-
require 'active_fedora/noid/minter/db'
|
7
|
-
require 'active_fedora/noid/synchronized_minter'
|
5
|
+
require 'active_fedora/noid/minter'
|
8
6
|
|
9
7
|
module ActiveFedora
|
10
8
|
module Noid
|
@@ -18,7 +16,9 @@ module ActiveFedora
|
|
18
16
|
end
|
19
17
|
|
20
18
|
def treeify(identifier)
|
21
|
-
|
19
|
+
head = identifier.split('/').first
|
20
|
+
head.gsub!(/#.*/, '')
|
21
|
+
(head.scan(/..?/).first(4) + [identifier]).join('/')
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
module Noid
|
3
3
|
class Config
|
4
|
-
attr_writer :template, :translate_uri_to_id, :translate_id_to_uri,
|
4
|
+
attr_writer :template, :translate_uri_to_id, :translate_id_to_uri,
|
5
|
+
:statefile, :namespace, :minter_class
|
5
6
|
|
6
7
|
def template
|
7
8
|
@template ||= '.reeddeeddk'
|
@@ -15,6 +16,10 @@ module ActiveFedora
|
|
15
16
|
@namespace ||= 'default'
|
16
17
|
end
|
17
18
|
|
19
|
+
def minter_class
|
20
|
+
@minter_class ||= Minter::Db
|
21
|
+
end
|
22
|
+
|
18
23
|
def translate_uri_to_id
|
19
24
|
lambda do |uri|
|
20
25
|
uri.to_s.sub(baseurl, '').split('/', baseparts).last
|
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'noid'
|
2
|
+
require 'active_fedora'
|
2
3
|
|
3
4
|
module ActiveFedora
|
4
5
|
module Noid
|
5
6
|
module Minter
|
6
7
|
class Base < ::Noid::Minter
|
8
|
+
##
|
9
|
+
# @param template [#to_s] a NOID template
|
10
|
+
#
|
11
|
+
# @see Noid::Template
|
7
12
|
def initialize(template = default_template)
|
8
|
-
super(:
|
13
|
+
super(template: template.to_s)
|
9
14
|
end
|
10
15
|
|
16
|
+
##
|
17
|
+
# Sychronously mint a new identifier. Guarantees the ID is not
|
18
|
+
# already reserved in ActiveFedora.
|
19
|
+
#
|
20
|
+
# @return [String] the minted identifier
|
11
21
|
def mint
|
12
22
|
Mutex.new.synchronize do
|
13
23
|
while true
|
@@ -17,14 +27,34 @@ module ActiveFedora
|
|
17
27
|
end
|
18
28
|
end
|
19
29
|
|
30
|
+
##
|
31
|
+
# @return [Hash] an object representing the current minter state
|
32
|
+
def read
|
33
|
+
raise NotImplementedError.new('Implement #read in child class')
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Updates the minter state to that of the `minter` parameter.
|
38
|
+
#
|
39
|
+
# @param minter [Minter::Base]
|
40
|
+
#
|
41
|
+
# @return [void]
|
42
|
+
def write!(_)
|
43
|
+
raise NotImplementedError.new('Implement #write! in child class')
|
44
|
+
end
|
45
|
+
|
20
46
|
protected
|
21
47
|
|
48
|
+
##
|
49
|
+
# @return [#to_s] the default template for this
|
22
50
|
def default_template
|
23
51
|
ActiveFedora::Noid.config.template
|
24
52
|
end
|
25
53
|
|
54
|
+
##
|
55
|
+
# @return [String] a new identifier.
|
26
56
|
def next_id
|
27
|
-
raise NotImplementedError.new('Implement next_id in child class')
|
57
|
+
raise NotImplementedError.new('Implement #next_id in child class')
|
28
58
|
end
|
29
59
|
end
|
30
60
|
end
|
@@ -4,6 +4,22 @@ module ActiveFedora
|
|
4
4
|
module Noid
|
5
5
|
module Minter
|
6
6
|
class Db < Base
|
7
|
+
|
8
|
+
def read
|
9
|
+
filtered_hash = instance.as_json.select { |key| ['template', 'counters', 'seq', 'rand', 'namespace'].include?(key) }
|
10
|
+
filtered_hash['counters'] = JSON.parse(filtered_hash['counters'], symbolize_names: true) if filtered_hash['counters']
|
11
|
+
filtered_hash.symbolize_keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def write!(minter)
|
15
|
+
# namespace and template are the same, now update the other attributes
|
16
|
+
instance.update_attributes!(
|
17
|
+
seq: minter.seq,
|
18
|
+
counters: JSON.generate(minter.counters),
|
19
|
+
rand: Marshal.dump(minter.instance_variable_get(:@rand))
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
7
23
|
protected
|
8
24
|
|
9
25
|
# Uses pessimistic lock to ensure the record fetched is the same one updated.
|
@@ -19,21 +35,20 @@ module ActiveFedora
|
|
19
35
|
def next_id
|
20
36
|
id = nil
|
21
37
|
MinterState.transaction do
|
22
|
-
state =
|
23
|
-
|
24
|
-
template: ActiveFedora::Noid.config.template,
|
25
|
-
).first!
|
26
|
-
minter = ::Noid::Minter.new(state.noid_options)
|
38
|
+
state = read
|
39
|
+
minter = ::Noid::Minter.new(state)
|
27
40
|
id = minter.mint
|
28
|
-
|
29
|
-
state.seq = minter.seq
|
30
|
-
state.counters = JSON.generate(minter.counters)
|
31
|
-
state.random = Marshal.dump(minter.instance_variable_get(:@rand))
|
32
|
-
state.save!
|
41
|
+
write!(minter)
|
33
42
|
end # transaction
|
34
43
|
id
|
35
44
|
end
|
36
45
|
|
46
|
+
def instance
|
47
|
+
MinterState.lock.find_by(
|
48
|
+
namespace: ActiveFedora::Noid.config.namespace,
|
49
|
+
template: ActiveFedora::Noid.config.template,
|
50
|
+
)
|
51
|
+
end
|
37
52
|
end # class Db
|
38
53
|
end
|
39
54
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'noid'
|
2
|
+
|
3
|
+
module ActiveFedora
|
4
|
+
module Noid
|
5
|
+
module Minter
|
6
|
+
class File < Base
|
7
|
+
attr_reader :statefile
|
8
|
+
|
9
|
+
def initialize(template = default_template, statefile = default_statefile)
|
10
|
+
@statefile = statefile
|
11
|
+
super(template)
|
12
|
+
end
|
13
|
+
|
14
|
+
def default_statefile
|
15
|
+
ActiveFedora::Noid.config.statefile
|
16
|
+
end
|
17
|
+
|
18
|
+
def read
|
19
|
+
with_file do |f|
|
20
|
+
state_for(f)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def write!(minter)
|
25
|
+
with_file do |f|
|
26
|
+
# Wipe prior contents so the new state can be written from the beginning of the file
|
27
|
+
f.truncate(0)
|
28
|
+
f.write(Marshal.dump(minter.dump))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def with_file
|
35
|
+
::File.open(statefile, 'a+b', 0644) do |f|
|
36
|
+
f.flock(::File::LOCK_EX)
|
37
|
+
# Files opened in append mode seek to end of file
|
38
|
+
f.rewind
|
39
|
+
yield f
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def state_for(io_object)
|
44
|
+
Marshal.load(io_object.read)
|
45
|
+
rescue TypeError, ArgumentError
|
46
|
+
{ template: template }
|
47
|
+
end
|
48
|
+
|
49
|
+
def next_id
|
50
|
+
state = read
|
51
|
+
state[:template] &&= state[:template].to_s
|
52
|
+
minter = ::Noid::Minter.new(state) # minter w/in the minter, lives only for an instant
|
53
|
+
id = minter.mint
|
54
|
+
write!(minter)
|
55
|
+
id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/tasks/noid_tasks.rake
CHANGED
@@ -4,25 +4,51 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
namespace :active_fedora do
|
6
6
|
namespace :noid do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
namespace :migrate do
|
8
|
+
desc 'Migrate minter state file from YAML to Marshal'
|
9
|
+
task :yaml_to_marshal do
|
10
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
11
|
+
raise "File not found: #{statefile}\nAborting" unless File.exist?(statefile)
|
12
|
+
puts "Migrating #{statefile} from YAML to Marshal serialization..."
|
13
|
+
File.open(statefile, 'a+b', 0644) do |f|
|
14
|
+
f.flock(File::LOCK_EX)
|
15
|
+
f.rewind
|
16
|
+
begin
|
17
|
+
yaml_state = YAML.load(f)
|
18
|
+
rescue Psych::SyntaxError
|
19
|
+
raise "File not valid YAML: #{statefile}\nAborting."
|
20
|
+
end
|
21
|
+
minter = Noid::Minter.new(yaml_state)
|
22
|
+
f.truncate(0)
|
23
|
+
new_state = Marshal.dump(minter.dump)
|
24
|
+
f.write(new_state)
|
19
25
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
26
|
+
puts "Done!"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Migrate minter state from file to database'
|
30
|
+
task file_to_database: :environment do
|
31
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
32
|
+
raise "File not found: #{statefile}\nAborting" unless File.exist?(statefile)
|
33
|
+
puts "Migrating #{statefile} to database..."
|
34
|
+
state = ActiveFedora::Noid::Minter::File.new.read
|
35
|
+
minter = Noid::Minter.new(state)
|
36
|
+
new_state = ActiveFedora::Noid::Minter::Db.new
|
37
|
+
new_state.write!(minter)
|
38
|
+
puts "Done!"
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Migrate minter state from database to file'
|
42
|
+
task database_to_file: :environment do
|
43
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
44
|
+
raise "File already exists (delete it first if it's not valuable): #{statefile}\nAborting" if File.exist?(statefile)
|
45
|
+
puts "Migrating minter state from database to #{statefile}..."
|
46
|
+
state = ActiveFedora::Noid::Minter::Db.new.read
|
47
|
+
minter = Noid::Minter.new(state)
|
48
|
+
new_state = ActiveFedora::Noid::Minter::File.new
|
49
|
+
new_state.write!(minter)
|
50
|
+
puts "Done!"
|
24
51
|
end
|
25
|
-
puts "Done!"
|
26
52
|
end
|
27
53
|
end
|
28
54
|
end
|
@@ -37,22 +37,4 @@ describe MinterState, type: :model do
|
|
37
37
|
expect(described_class.group(:namespace).count).to eq('default' => 1, 'foobar' => 1)
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
41
|
-
describe '#noid_options' do
|
42
|
-
it 'returns nil without template (new object not persisted)' do
|
43
|
-
expect(state.noid_options).to be_nil
|
44
|
-
end
|
45
|
-
it 'returns correct hash when populated' do
|
46
|
-
state.template = '.reeddddk'
|
47
|
-
state.seq = 1
|
48
|
-
expect(state.noid_options).to match a_hash_including(
|
49
|
-
:template => '.reeddddk',
|
50
|
-
:seq => 1
|
51
|
-
)
|
52
|
-
expect(first.noid_options).to match a_hash_including(
|
53
|
-
:template => '.reeddeeddk',
|
54
|
-
:seq => 0
|
55
|
-
)
|
56
|
-
end
|
57
|
-
end
|
58
40
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
shared_examples 'a minter' do
|
2
|
+
describe '#mint' do
|
3
|
+
subject { minter.mint }
|
4
|
+
let(:other) { described_class.new('.reedddk') }
|
5
|
+
|
6
|
+
it { is_expected.not_to be_empty }
|
7
|
+
|
8
|
+
it 'does not mint the same ID twice in a row' do
|
9
|
+
expect(subject).not_to eq described_class.new.mint
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'is valid' do
|
13
|
+
expect(minter.valid?(subject)).to be true
|
14
|
+
expect(described_class.new.valid?(subject)).to be true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is invalid under a different template' do
|
18
|
+
expect(described_class.new('.reedddk').valid?(subject)).to be false
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'is invalid under a different template' do
|
22
|
+
expect(other).not_to be_valid(minter.mint)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'conflicts' do
|
27
|
+
let(:existing_pid) { 'ef12ef12f' }
|
28
|
+
let(:unique_pid) { 'bb22bb22b' }
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
expect(subject).to receive(:next_id).and_return(existing_pid, unique_pid)
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the pid already exists in Fedora' do
|
35
|
+
before do
|
36
|
+
expect(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
|
37
|
+
end
|
38
|
+
it 'skips the existing pid' do
|
39
|
+
expect(subject.mint).to eq unique_pid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the pid already existed in Fedora and now is gone' do
|
44
|
+
let(:gone_pid) { existing_pid }
|
45
|
+
|
46
|
+
before do
|
47
|
+
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'skips the deleted pid' do
|
51
|
+
expect(subject.mint).to eq unique_pid
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/unit/config_spec.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
describe ActiveFedora::Noid::Config do
|
2
|
+
subject { described_class.new }
|
3
|
+
|
2
4
|
it { is_expected.to respond_to(:template) }
|
3
5
|
it { is_expected.to respond_to(:statefile) }
|
4
6
|
it { is_expected.to respond_to(:namespace) }
|
7
|
+
it { is_expected.to respond_to(:minter_class) }
|
5
8
|
it { is_expected.to respond_to(:translate_id_to_uri) }
|
6
9
|
it { is_expected.to respond_to(:translate_uri_to_id) }
|
7
10
|
|
@@ -23,6 +26,22 @@ describe ActiveFedora::Noid::Config do
|
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
describe '#minter_class' do
|
30
|
+
let(:default) { ActiveFedora::Noid::Minter::Db }
|
31
|
+
|
32
|
+
it 'has a default' do
|
33
|
+
expect(subject.minter_class).to eq default
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when overridden' do
|
37
|
+
before { subject.minter_class = different_minter }
|
38
|
+
let(:different_minter) { ActiveFedora::Noid::Minter::File }
|
39
|
+
it 'uses the different minter' do
|
40
|
+
expect(subject.minter_class).to eq different_minter
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
26
45
|
describe '#translate_uri_to_id' do
|
27
46
|
let(:config) { described_class.new }
|
28
47
|
let(:translator) { config.translate_uri_to_id }
|
@@ -38,10 +57,10 @@ describe ActiveFedora::Noid::Config do
|
|
38
57
|
|
39
58
|
context "with a hash code uri" do
|
40
59
|
let(:uri) { "http://localhost:8983/fedora/rest/test/hh/63/vz/22/hh63vz22q#g123" }
|
41
|
-
|
60
|
+
it { is_expected.to eq 'hh63vz22q#g123' }
|
42
61
|
end
|
43
62
|
|
44
|
-
|
63
|
+
context 'with a short custom template' do
|
45
64
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
|
46
65
|
let(:custom_template) { '.reeee' }
|
47
66
|
before { config.template = custom_template }
|
@@ -50,7 +69,7 @@ describe ActiveFedora::Noid::Config do
|
|
50
69
|
it { is_expected.to eq 'abcd/members' }
|
51
70
|
end
|
52
71
|
|
53
|
-
|
72
|
+
context 'with an even shorter custom template' do
|
54
73
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
|
55
74
|
let(:custom_template) { '.reee' }
|
56
75
|
before { config.template = custom_template }
|
@@ -59,7 +78,7 @@ describe ActiveFedora::Noid::Config do
|
|
59
78
|
it { is_expected.to eq 'abc/members' }
|
60
79
|
end
|
61
80
|
|
62
|
-
|
81
|
+
context 'with a long custom template' do
|
63
82
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
|
64
83
|
let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
|
65
84
|
before { config.template = custom_template }
|
@@ -67,6 +86,48 @@ describe ActiveFedora::Noid::Config do
|
|
67
86
|
|
68
87
|
it { is_expected.to eq 'abcdefghijklmnopqrstuvwxyz/members' }
|
69
88
|
end
|
89
|
+
end
|
70
90
|
|
91
|
+
describe '#translate_id_to_uri' do
|
92
|
+
let(:config) { described_class.new }
|
93
|
+
let(:translator) { config.translate_id_to_uri }
|
94
|
+
let(:id) { "hh63vz2/members" }
|
95
|
+
let(:ActiveFedora) { double(ActiveFedora) }
|
96
|
+
subject { translator.call(id) }
|
97
|
+
before do
|
98
|
+
allow(ActiveFedora).to receive_message_chain("fedora.host") { "http://localhost:8983" }
|
99
|
+
allow(ActiveFedora).to receive_message_chain("fedora.base_path") { "/fedora/rest/test" }
|
100
|
+
end
|
101
|
+
|
102
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2/members" }
|
103
|
+
|
104
|
+
context "with a hash code id" do
|
105
|
+
let(:id) { 'hh63vz2#g123' }
|
106
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2#g123" }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with a short custom template' do
|
110
|
+
let(:id) { "abcd/members" }
|
111
|
+
let(:custom_template) { '.reeee' }
|
112
|
+
before { config.template = custom_template }
|
113
|
+
subject { translator.call(id) }
|
114
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with an even shorter custom template' do
|
118
|
+
let(:id) { 'abc/members' }
|
119
|
+
let(:custom_template) { '.reee' }
|
120
|
+
before { config.template = custom_template }
|
121
|
+
subject { translator.call(id) }
|
122
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'with a long custom template' do
|
126
|
+
let(:id) { "abcdefghijklmnopqrstuvwxyz/members" }
|
127
|
+
let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
|
128
|
+
before { config.template = custom_template }
|
129
|
+
subject { translator.call(id) }
|
130
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
|
131
|
+
end
|
71
132
|
end
|
72
133
|
end
|
data/spec/unit/db_minter_spec.rb
CHANGED
@@ -2,7 +2,7 @@ include MinterStateHelper
|
|
2
2
|
|
3
3
|
describe ActiveFedora::Noid::Minter::Db do
|
4
4
|
before(:each) { reset_minter_state_table }
|
5
|
-
after(
|
5
|
+
after(:all) { reset_minter_state_table }
|
6
6
|
|
7
7
|
before :each do
|
8
8
|
# default novel mintings
|
@@ -10,19 +10,22 @@ describe ActiveFedora::Noid::Minter::Db do
|
|
10
10
|
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
11
11
|
end
|
12
12
|
|
13
|
-
let(:minter) { described_class.new }
|
14
13
|
let(:other) { described_class.new('.reedddk') }
|
15
14
|
|
15
|
+
it_behaves_like 'a minter' do
|
16
|
+
let(:minter) { described_class.new }
|
17
|
+
end
|
18
|
+
|
16
19
|
describe '#initialize' do
|
17
20
|
it 'raises on bad templates' do
|
18
21
|
expect{ described_class.new('reeddeeddk') }.to raise_error(Noid::TemplateError)
|
19
22
|
expect{ described_class.new('') }.to raise_error(Noid::TemplateError)
|
20
23
|
end
|
21
24
|
it 'returns object w/ default template' do
|
22
|
-
expect(
|
23
|
-
expect(
|
24
|
-
expect(
|
25
|
-
expect(
|
25
|
+
expect(subject).to be_instance_of described_class
|
26
|
+
expect(subject).to be_a Noid::Minter
|
27
|
+
expect(subject.template).to be_instance_of Noid::Template
|
28
|
+
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
26
29
|
end
|
27
30
|
it 'accepts valid template arg' do
|
28
31
|
expect(other).to be_instance_of described_class
|
@@ -32,45 +35,29 @@ describe ActiveFedora::Noid::Minter::Db do
|
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
|
-
describe '#
|
36
|
-
|
37
|
-
|
38
|
-
it 'does not mint the same ID twice in a row' do
|
39
|
-
expect(subject).not_to eq described_class.new.mint
|
38
|
+
describe '#read' do
|
39
|
+
it 'returns a hash' do
|
40
|
+
expect(subject.read).to be_a(Hash)
|
40
41
|
end
|
41
|
-
it '
|
42
|
-
expect(
|
43
|
-
expect(described_class.new.valid?(subject)).to be true
|
42
|
+
it 'has the expected namespace' do
|
43
|
+
expect(subject.read[:namespace]).to eq ActiveFedora::Noid.config.namespace
|
44
44
|
end
|
45
|
-
it '
|
46
|
-
expect(
|
45
|
+
it 'has the expected template' do
|
46
|
+
expect(subject.read[:template]).to eq ActiveFedora::Noid.config.template
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
let(:
|
52
|
-
let(:
|
53
|
-
before
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
it 'skips the existing pid' do
|
62
|
-
expect(minter.mint).to eq unique_pid
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'when the pid already existed in Fedora and now is gone' do
|
67
|
-
let(:gone_pid) { existing_pid }
|
68
|
-
before do
|
69
|
-
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
70
|
-
end
|
71
|
-
it 'skips the deleted pid' do
|
72
|
-
expect(minter.mint).to eq unique_pid
|
73
|
-
end
|
50
|
+
describe '#write!' do
|
51
|
+
let(:starting_state) { subject.read }
|
52
|
+
let(:minter) { Noid::Minter.new(starting_state) }
|
53
|
+
before { minter.mint }
|
54
|
+
it 'changes the state of the minter' do
|
55
|
+
expect { subject.write!(minter) }.to change { subject.read[:seq] }
|
56
|
+
.from(starting_state[:seq]).to(minter.seq)
|
57
|
+
.and change { subject.read[:counters] }
|
58
|
+
.from(starting_state[:counters]).to(minter.counters)
|
59
|
+
.and change { subject.read[:rand] }
|
60
|
+
.from(starting_state[:rand]).to(Marshal.dump(minter.instance_variable_get(:@rand)))
|
74
61
|
end
|
75
62
|
end
|
76
63
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe ActiveFedora::Noid::Minter::File do
|
2
|
+
before :each do
|
3
|
+
# default novel mintings
|
4
|
+
allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
|
5
|
+
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
it { is_expected.to respond_to(:mint) }
|
9
|
+
|
10
|
+
it 'has a default statefile' do
|
11
|
+
expect(subject.statefile).to eq ActiveFedora::Noid.config.statefile
|
12
|
+
end
|
13
|
+
it 'has a default template' do
|
14
|
+
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
15
|
+
end
|
16
|
+
|
17
|
+
it_behaves_like 'a minter' do
|
18
|
+
let(:minter) { described_class.new }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#initialize' do
|
22
|
+
let(:template) { '.rededk' }
|
23
|
+
let(:statefile) { '/tmp/foobar' }
|
24
|
+
|
25
|
+
subject { described_class.new(template, statefile) }
|
26
|
+
|
27
|
+
it 'respects the custom template' do
|
28
|
+
expect(subject.template.to_s).to eq template
|
29
|
+
end
|
30
|
+
it 'respects the custom statefile' do
|
31
|
+
expect(subject.statefile).to eq statefile
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#read' do
|
36
|
+
it 'returns a hash' do
|
37
|
+
expect(subject.read).to be_a(Hash)
|
38
|
+
end
|
39
|
+
it 'has the expected template' do
|
40
|
+
expect(subject.read[:template]).to eq ActiveFedora::Noid.config.template
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#write!' do
|
45
|
+
let(:starting_state) { subject.read }
|
46
|
+
let(:minter) { Noid::Minter.new(starting_state) }
|
47
|
+
before { minter.mint }
|
48
|
+
it 'changes the state of the minter' do
|
49
|
+
expect { subject.write!(minter) }.to change { subject.read[:seq] }
|
50
|
+
.from(starting_state[:seq]).to(minter.seq)
|
51
|
+
.and change { subject.read[:rand] }
|
52
|
+
.from(starting_state[:rand]).to(Marshal.dump(minter.instance_variable_get(:@rand)))
|
53
|
+
.and change { subject.read[:counters] }
|
54
|
+
.to(minter.counters)
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/unit/noid_spec.rb
CHANGED
@@ -13,5 +13,9 @@ describe ActiveFedora::Noid do
|
|
13
13
|
subject { ActiveFedora::Noid.treeify(id) }
|
14
14
|
let(:id) { 'abc123def45' }
|
15
15
|
it { is_expected.to eq 'ab/c1/23/de/abc123def45' }
|
16
|
+
context 'with a seven-digit identifier' do
|
17
|
+
let(:id) { 'abc123z' }
|
18
|
+
it { is_expected.to eq 'ab/c1/23/z/abc123z' }
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
data/spec/unit/service_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe ActiveFedora::Noid::Service do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
it 'has a default minter' do
|
8
|
-
expect(subject.minter).to be_instance_of ActiveFedora::Noid::
|
8
|
+
expect(subject.minter).to be_instance_of ActiveFedora::Noid::Minter::Db
|
9
9
|
end
|
10
10
|
|
11
11
|
context 'with a custom minter' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_fedora-noid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael J. Giarlo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active-fedora
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 4.2.
|
53
|
+
version: 4.2.7.1
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '6'
|
@@ -60,7 +60,7 @@ dependencies:
|
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 4.2.
|
63
|
+
version: 4.2.7.1
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '6'
|
@@ -84,14 +84,14 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
87
|
+
version: '11.0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
94
|
+
version: '11.0'
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: rspec
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +126,14 @@ dependencies:
|
|
126
126
|
requirements:
|
127
127
|
- - "~>"
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version: '0
|
129
|
+
version: '1.0'
|
130
130
|
type: :development
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version: '0
|
136
|
+
version: '1.0'
|
137
137
|
description: Noid identifier services for ActiveFedora-based applications.
|
138
138
|
email:
|
139
139
|
- leftwing@alumni.rutgers.edu
|
@@ -152,13 +152,15 @@ files:
|
|
152
152
|
- active_fedora-noid.gemspec
|
153
153
|
- app/models/minter_state.rb
|
154
154
|
- db/migrate/20160610010003_create_minter_states.rb
|
155
|
+
- db/migrate/20161021203429_rename_minter_state_random_to_rand.rb
|
155
156
|
- lib/active_fedora/noid.rb
|
156
157
|
- lib/active_fedora/noid/config.rb
|
157
158
|
- lib/active_fedora/noid/engine.rb
|
159
|
+
- lib/active_fedora/noid/minter.rb
|
158
160
|
- lib/active_fedora/noid/minter/base.rb
|
159
161
|
- lib/active_fedora/noid/minter/db.rb
|
162
|
+
- lib/active_fedora/noid/minter/file.rb
|
160
163
|
- lib/active_fedora/noid/service.rb
|
161
|
-
- lib/active_fedora/noid/synchronized_minter.rb
|
162
164
|
- lib/active_fedora/noid/version.rb
|
163
165
|
- lib/generators/active_fedora/noid/install_generator.rb
|
164
166
|
- lib/generators/active_fedora/noid/seed_generator.rb
|
@@ -166,12 +168,13 @@ files:
|
|
166
168
|
- spec/models/minter_state_spec.rb
|
167
169
|
- spec/spec_helper.rb
|
168
170
|
- spec/support/minterstate_table.rb
|
171
|
+
- spec/support/shared_examples/minter.rb
|
169
172
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
170
173
|
- spec/unit/config_spec.rb
|
171
174
|
- spec/unit/db_minter_spec.rb
|
175
|
+
- spec/unit/file_minter_spec.rb
|
172
176
|
- spec/unit/noid_spec.rb
|
173
177
|
- spec/unit/service_spec.rb
|
174
|
-
- spec/unit/synchronized_minter_spec.rb
|
175
178
|
homepage: https://github.com/projecthydra-labs/active_fedora-noid
|
176
179
|
licenses:
|
177
180
|
- Apache2
|
@@ -200,9 +203,10 @@ test_files:
|
|
200
203
|
- spec/models/minter_state_spec.rb
|
201
204
|
- spec/spec_helper.rb
|
202
205
|
- spec/support/minterstate_table.rb
|
206
|
+
- spec/support/shared_examples/minter.rb
|
203
207
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
204
208
|
- spec/unit/config_spec.rb
|
205
209
|
- spec/unit/db_minter_spec.rb
|
210
|
+
- spec/unit/file_minter_spec.rb
|
206
211
|
- spec/unit/noid_spec.rb
|
207
212
|
- spec/unit/service_spec.rb
|
208
|
-
- spec/unit/synchronized_minter_spec.rb
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'noid'
|
2
|
-
|
3
|
-
module ActiveFedora
|
4
|
-
module Noid
|
5
|
-
class SynchronizedMinter < Minter::Base
|
6
|
-
attr_reader :statefile
|
7
|
-
|
8
|
-
def initialize(template = default_template, statefile = default_statefile)
|
9
|
-
super(template)
|
10
|
-
@statefile = statefile
|
11
|
-
end
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def default_statefile
|
16
|
-
ActiveFedora::Noid.config.statefile
|
17
|
-
end
|
18
|
-
|
19
|
-
def state_for(io_object)
|
20
|
-
Marshal.load(io_object.read)
|
21
|
-
rescue TypeError, ArgumentError
|
22
|
-
{ template: template }
|
23
|
-
end
|
24
|
-
|
25
|
-
def next_id
|
26
|
-
id = nil
|
27
|
-
::File.open(statefile, 'a+b', 0644) do |f|
|
28
|
-
f.flock(::File::LOCK_EX)
|
29
|
-
# Files opened in append mode seek to end of file
|
30
|
-
f.rewind
|
31
|
-
state = state_for(f)
|
32
|
-
state[:template] &&= state[:template].to_s
|
33
|
-
minter = ::Noid::Minter.new(state) # minter w/in the minter, lives only for an instant
|
34
|
-
id = minter.mint
|
35
|
-
|
36
|
-
# Wipe prior contents so the new state can be written from the beginning of the file
|
37
|
-
f.truncate(0)
|
38
|
-
new_state = Marshal.dump(minter.dump)
|
39
|
-
f.write(new_state)
|
40
|
-
end
|
41
|
-
id
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
describe ActiveFedora::Noid::SynchronizedMinter do
|
2
|
-
before :each do
|
3
|
-
# default novel mintings
|
4
|
-
allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
|
5
|
-
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
6
|
-
end
|
7
|
-
|
8
|
-
let(:minter) { described_class.new }
|
9
|
-
|
10
|
-
it { is_expected.to respond_to(:mint) }
|
11
|
-
it 'has a default statefile' do
|
12
|
-
expect(subject.statefile).to eq ActiveFedora::Noid.config.statefile
|
13
|
-
end
|
14
|
-
it 'has a default template' do
|
15
|
-
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
16
|
-
end
|
17
|
-
|
18
|
-
describe '#initialize' do
|
19
|
-
let(:template) { '.rededk' }
|
20
|
-
let(:statefile) { '/tmp/foobar' }
|
21
|
-
|
22
|
-
subject { described_class.new(template, statefile) }
|
23
|
-
|
24
|
-
it 'respects the custom template' do
|
25
|
-
expect(subject.template.to_s).to eq template
|
26
|
-
end
|
27
|
-
it 'respects the custom statefile' do
|
28
|
-
expect(subject.statefile).to eq statefile
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '#mint' do
|
33
|
-
subject { minter.mint }
|
34
|
-
it { is_expected.not_to be_empty }
|
35
|
-
it 'does not mint the same ID twice in a row' do
|
36
|
-
expect(subject).not_to eq described_class.new.mint
|
37
|
-
end
|
38
|
-
it 'is valid' do
|
39
|
-
expect(minter.valid?(subject)).to be true
|
40
|
-
expect(described_class.new.valid?(subject)).to be true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'conflicts' do
|
45
|
-
let(:unique_pid) { 'bb22bb22b' }
|
46
|
-
let(:existing_pid) { 'ef12ef12f' }
|
47
|
-
before :each do
|
48
|
-
expect(minter).to receive(:next_id).and_return(existing_pid, unique_pid)
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'when the pid already exists in Fedora' do
|
52
|
-
before do
|
53
|
-
expect(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
|
54
|
-
end
|
55
|
-
it 'skips the existing pid' do
|
56
|
-
expect(minter.mint).to eq unique_pid
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'when the pid already existed in Fedora and now is gone' do
|
61
|
-
let(:gone_pid) { existing_pid }
|
62
|
-
before do
|
63
|
-
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
64
|
-
end
|
65
|
-
it 'skips the deleted pid' do
|
66
|
-
expect(minter.mint).to eq unique_pid
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|