active_fedora-noid 1.1.3 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb21b73450d652c999b6957aec06a64a6b93a424
4
- data.tar.gz: 92a908f1457731a303eaa3bede38fd139ba0a820
3
+ metadata.gz: b411ca036a7be29f78737f471e4299ae3e9dbe84
4
+ data.tar.gz: 11688eabbb0b224605aa9b236843cc30534c30f9
5
5
  SHA512:
6
- metadata.gz: 1a41ca01378cfab9bfeb598ebfbba2b685759058281897c6bc730b8d92cd7dc5e047676de949d05d802141cc46c448eaf052cef625154ed2a0695601e6cc88ea
7
- data.tar.gz: b844067ca1dd94891953605151997e594b0c57f4194148ed47a6ddcd9f1481b678e8bf672b73282e99a4ee4cec4e4f3dc559c9bf6f5faba7dae6daf57a39c7a8
6
+ metadata.gz: d683d23ff54c91077c0b2e3b334a5b38f894483326cda8e346fd0188efc8d81d231d0b41974ea786005edfba158a77b87ec2a76fc97b85162afab6d108d2f3f7
7
+ data.tar.gz: ab60c0951d64d425038a579f50a4727a7526e0a9b8c77b936e432b456d8c69aa3b3813feec49d0729aa3c1a5d52f91d13e7a2d121e6c8501523ec398ed7656fb
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  *.rbc
2
2
  capybara-*.html
3
- .rspec
4
3
  /log
5
4
  /tmp
6
5
  /db/*.sqlite3
@@ -10,6 +9,7 @@ capybara-*.html
10
9
  **.orig
11
10
  rerun.txt
12
11
  pickle-email-*.html
12
+ .byebug_history
13
13
 
14
14
  # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
15
15
  config/initializers/secret_token.rb
@@ -32,3 +32,5 @@ pkg
32
32
  /vendor/assets/bower_components
33
33
  *.bowerrc
34
34
  bower.json
35
+
36
+ .internal_test_app
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml CHANGED
@@ -3,12 +3,12 @@ cache: bundler
3
3
  sudo: false
4
4
  rvm:
5
5
  - 2.3.1
6
+ - 2.2
7
+ - 2.1
6
8
  env:
7
9
  global:
8
10
  - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
9
- matrix:
10
- - "RAILS_VERSION=4.2.7.1"
11
- - "RAILS_VERSION=5.0.0.1"
11
+ - "RAILS_VERSION=4.2.6"
12
12
  notifications:
13
13
  irc:
14
14
  channels:
data/Gemfile CHANGED
@@ -6,4 +6,39 @@ 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
+ end
11
+ # BEGIN ENGINE_CART BLOCK
12
+ # engine_cart: 0.8.2
13
+ # engine_cart stanza: 0.8.0
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("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path(".internal_test_app", File.dirname(__FILE__)))
16
+ if File.exist?(file)
17
+ begin
18
+ eval_gemfile file
19
+ rescue Bundler::GemfileError => e
20
+ Bundler.ui.warn '[EngineCart] Skipping Rails application dependencies:'
21
+ Bundler.ui.warn e.message
22
+ end
23
+ else
24
+ Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
25
+
26
+ if ENV['RAILS_VERSION']
27
+ if ENV['RAILS_VERSION'] == 'edge'
28
+ gem 'rails', github: 'rails/rails'
29
+ ENV['ENGINE_CART_RAILS_OPTIONS']= "--edge --skip-turbolinks"
30
+ else
31
+ gem 'rails', ENV['RAILS_VERSION']
32
+ end
33
+ end
34
+
35
+ if ENV['RAILS_VERSION'].nil? || ENV['RAILS_VERSION'] =~ /^4.2/
36
+ gem 'responders', "~> 2.0"
37
+ gem 'sass-rails', ">= 5.0"
38
+ elsif ENV['RAILS_VERSION'] =~ /^5.0/ || ENV['RAILS_VERSION'] == 'edge'
39
+ # nop
40
+ else
41
+ gem 'sass-rails', "< 5.0"
42
+ end
9
43
  end
44
+ # END ENGINE_CART BLOCK
data/Rakefile CHANGED
@@ -1,7 +1,12 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rspec/core/rake_task'
3
+ require 'engine_cart/rake_task'
3
4
 
4
- task default: :spec
5
+ task default: :ci
5
6
  RSpec::Core::RakeTask.new
6
7
 
7
- import './lib/tasks/noid_tasks.rake'
8
+ Dir.glob('lib/tasks/*.rake').each { |r| import r }
9
+
10
+ desc 'Continuous Integration (generate test app and run tests)'
11
+ task ci: ['engine_cart:generate', 'spec'] do
12
+ end
@@ -18,16 +18,19 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_dependency 'active-fedora', '>= 9.7', '< 11'
21
- spec.add_dependency 'noid', '~> 0.7'
21
+ spec.add_dependency 'noid', '~> 0.9'
22
+ spec.add_dependency 'rails', '~> 4.2.6'
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.7"
24
25
  spec.add_development_dependency "rake", "~> 10.0"
25
26
  spec.add_development_dependency 'rspec', '~> 3.2'
27
+ spec.add_development_dependency 'sqlite3'
28
+ spec.add_development_dependency 'engine_cart', '~> 0.8'
26
29
 
27
30
  spec.post_install_message = <<-END
28
31
  NOTE: ActiveFedora::Noid 1.0.0 included a change that breaks existing minter
29
32
  statefiles. Run the `active_fedora:noid:migrate_statefile` rake task to migrate
30
- your statefile. (If you're using a custom statefile, not /tmp/minter-state,, set
33
+ your statefile. (If you're using a custom statefile, not /tmp/minter-state, set
31
34
  an environment variable called AFNOID_STATEFILE with its path.)
32
35
  END
33
36
 
@@ -0,0 +1,21 @@
1
+ class MinterState < ActiveRecord::Base
2
+ validates :namespace, presence: true, uniqueness: true
3
+ validates :template, presence: true
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
+ end
@@ -0,0 +1,14 @@
1
+ class CreateMinterStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :minter_states do |t|
4
+ t.string :namespace, null: false, default: 'default'
5
+ t.string :template, null: false
6
+ t.text :counters
7
+ t.bigint :seq, default: 0
8
+ t.binary :random
9
+ t.timestamps null: false
10
+ end
11
+ # Use both model and DB-level constraints for consistency while scaling horizontally
12
+ add_index :minter_states, :namespace, unique: true
13
+ end
14
+ end
@@ -1,7 +1,7 @@
1
1
  module ActiveFedora
2
2
  module Noid
3
3
  class Config
4
- attr_writer :template, :translate_uri_to_id, :translate_id_to_uri, :statefile
4
+ attr_writer :template, :translate_uri_to_id, :translate_id_to_uri, :statefile, :namespace
5
5
 
6
6
  def template
7
7
  @template ||= '.reeddeeddk'
@@ -11,6 +11,10 @@ module ActiveFedora
11
11
  @statefile ||= '/tmp/minter-state'
12
12
  end
13
13
 
14
+ def namespace
15
+ @namespace ||= 'default'
16
+ end
17
+
14
18
  def translate_uri_to_id
15
19
  lambda do |uri|
16
20
  uri.to_s.sub(baseurl, '').split('/', baseparts).last
@@ -0,0 +1,8 @@
1
+ require 'rails'
2
+
3
+ module ActiveFedora
4
+ module Noid
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,32 @@
1
+ require 'noid'
2
+
3
+ module ActiveFedora
4
+ module Noid
5
+ module Minter
6
+ class Base < ::Noid::Minter
7
+ def initialize(template = default_template)
8
+ super(:template => template.to_s)
9
+ end
10
+
11
+ def mint
12
+ Mutex.new.synchronize do
13
+ while true
14
+ pid = next_id
15
+ return pid unless ActiveFedora::Base.exists?(pid) || ActiveFedora::Base.gone?(pid)
16
+ end
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def default_template
23
+ ActiveFedora::Noid.config.template
24
+ end
25
+
26
+ def next_id
27
+ raise NotImplementedError.new('Implement next_id in child class')
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ require 'noid'
2
+
3
+ module ActiveFedora
4
+ module Noid
5
+ module Minter
6
+ class Db < Base
7
+ protected
8
+
9
+ # Uses pessimistic lock to ensure the record fetched is the same one updated.
10
+ # Should be fast enough to avoid terrible deadlock.
11
+ # Must lock because of multi-connection context! (transaction is per connection -- not enough)
12
+ # The DB table will only ever have at most one row per namespace.
13
+ # The 'default' namespace row is inserted by `rails generate active_fedora:noid:seed`.
14
+ # If you want another namespace, edit your config initialzer to something like:
15
+ # ActiveFedora::Noid.config.namespace = 'druid'
16
+ # ActiveFedora::Noid.config.template = '.reeedek'
17
+ # and in your app run:
18
+ # bundle exec rails generate active_fedora:noid:seed
19
+ def next_id
20
+ id = nil
21
+ MinterState.transaction do
22
+ state = MinterState.lock.where(
23
+ namespace: ActiveFedora::Noid.config.namespace,
24
+ template: ActiveFedora::Noid.config.template,
25
+ ).first!
26
+ minter = ::Noid::Minter.new(state.noid_options)
27
+ id = minter.mint
28
+ # namespace and template are the same, now update the other attributes
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!
33
+ end # transaction
34
+ id
35
+ end
36
+
37
+ end # class Db
38
+ end
39
+ end
40
+ end
@@ -20,7 +20,7 @@ module ActiveFedora
20
20
  protected
21
21
 
22
22
  def default_minter
23
- @minter ||= ActiveFedora::Noid::SynchronizedMinter.new
23
+ ActiveFedora::Noid::SynchronizedMinter.new
24
24
  end
25
25
  end
26
26
  end
@@ -1,35 +1,19 @@
1
1
  require 'noid'
2
+
2
3
  module ActiveFedora
3
4
  module Noid
4
- class SynchronizedMinter
5
- attr_reader :template, :statefile
5
+ class SynchronizedMinter < Minter::Base
6
+ attr_reader :statefile
6
7
 
7
8
  def initialize(template = default_template, statefile = default_statefile)
8
- @template = template
9
+ super(template)
9
10
  @statefile = statefile
10
11
  end
11
12
 
12
- def mint
13
- Mutex.new.synchronize do
14
- while true
15
- pid = next_id
16
- return pid unless ActiveFedora::Base.exists?(pid) || ActiveFedora::Base.gone?(pid)
17
- end
18
- end
19
- end
20
-
21
- def valid?(identifier)
22
- ::Noid::Minter.new(template: template).valid?(identifier)
23
- end
24
-
25
13
  protected
26
14
 
27
- def default_template
28
- @template ||= ActiveFedora::Noid.config.template
29
- end
30
-
31
15
  def default_statefile
32
- @statefile ||= ActiveFedora::Noid.config.statefile
16
+ ActiveFedora::Noid.config.statefile
33
17
  end
34
18
 
35
19
  def state_for(io_object)
@@ -39,14 +23,14 @@ module ActiveFedora
39
23
  end
40
24
 
41
25
  def next_id
42
- id = ''
26
+ id = nil
43
27
  ::File.open(statefile, 'a+b', 0644) do |f|
44
28
  f.flock(::File::LOCK_EX)
45
29
  # Files opened in append mode seek to end of file
46
30
  f.rewind
47
31
  state = state_for(f)
48
- minter = ::Noid::Minter.new(state)
49
-
32
+ state[:template] &&= state[:template].to_s
33
+ minter = ::Noid::Minter.new(state) # minter w/in the minter, lives only for an instant
50
34
  id = minter.mint
51
35
 
52
36
  # Wipe prior contents so the new state can be written from the beginning of the file
@@ -1,5 +1,5 @@
1
1
  module ActiveFedora
2
2
  module Noid
3
- VERSION = '1.1.3'.freeze
3
+ VERSION = '2.0.0.beta1'.freeze
4
4
  end
5
5
  end
@@ -1,6 +1,9 @@
1
1
  require 'active_fedora/noid/version'
2
2
  require 'active_fedora/noid/config'
3
+ require 'active_fedora/noid/engine'
3
4
  require 'active_fedora/noid/service'
5
+ require 'active_fedora/noid/minter/base'
6
+ require 'active_fedora/noid/minter/db'
4
7
  require 'active_fedora/noid/synchronized_minter'
5
8
 
6
9
  module ActiveFedora
@@ -15,10 +18,7 @@ module ActiveFedora
15
18
  end
16
19
 
17
20
  def treeify(identifier)
18
- raise ArgumentError, 'Identifier must be a string of size > 0 in order to be treeified' if identifier.blank?
19
- head = identifier.split('/').first
20
- head.gsub!(/#.*/, '')
21
- (head.scan(/..?/).first(4) + [identifier]).join('/')
21
+ (identifier.scan(/..?/).first(4) + [identifier]).join('/')
22
22
  end
23
23
  end
24
24
  end
@@ -0,0 +1,24 @@
1
+ module ActiveFedora
2
+ module Noid
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ desc <<-END_OF_DESC
7
+ Copies DB migrations
8
+ END_OF_DESC
9
+
10
+ def banner
11
+ say_status('info', 'Installing ActiveFedora::Noid', :blue)
12
+ end
13
+
14
+ def migrations
15
+ rake 'active_fedora_noid_engine:install:migrations'
16
+ rake 'db:migrate'
17
+ end
18
+
19
+ def seed
20
+ generate 'active_fedora:noid:seed'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveFedora
2
+ module Noid
3
+ class SeedGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ argument :namespace, :type => :string, :default => ActiveFedora::Noid.config.namespace
6
+ argument :template, :type => :string, :default => ActiveFedora::Noid.config.template
7
+
8
+ desc <<-END_OF_DESC
9
+ Seeds DB from ActiveFedora::Noid.config (or command-line overrides)
10
+ END_OF_DESC
11
+
12
+ def banner
13
+ say_status('info', "Initializing database table for namespace:template of '#{namespace}:#{template}'", :blue)
14
+ end
15
+
16
+ def checks
17
+ say_status('warn', "Be sure to use an initializer to do 'ActiveFedora::Noid.config.namespace = #{namespace}'", :red) if namespace != ActiveFedora::Noid.config.namespace
18
+ say_status('warn', "Be sure to use an initializer to do 'ActiveFedora::Noid.config.template = #{template}'", :red) if template != ActiveFedora::Noid.config.template
19
+ end
20
+
21
+ def seed_row
22
+ MinterState.create!(
23
+ namespace: namespace,
24
+ template: template
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,58 @@
1
+ include MinterStateHelper
2
+
3
+ describe MinterState, type: :model do
4
+ before(:each) { reset_minter_state_table }
5
+ after( :all ) { reset_minter_state_table }
6
+
7
+ let(:state) { described_class.new }
8
+ let(:first) { described_class.first }
9
+
10
+ it 'db is seeded with first row' do
11
+ expect{ first }.not_to raise_error
12
+ expect(first.namespace).to eq 'default'
13
+ expect(first.template).to eq '.reeddeeddk'
14
+ expect(first.seq).to eq 0
15
+ expect(described_class.group(:namespace).count).to eq('default' => 1)
16
+ end
17
+ describe 'validation' do
18
+ it 'blocks invalid template' do
19
+ expect{ state.save! }.to raise_error(ActiveRecord::RecordInvalid) # empty
20
+ state.template = 'bad_template'
21
+ expect{ state.save! }.to raise_error(ActiveRecord::RecordInvalid)
22
+ state.template = 'reeddddk' # close, but missing '.'
23
+ expect{ state.save! }.to raise_error(ActiveRecord::RecordInvalid)
24
+ end
25
+ it 'allows valid template (edit)' do
26
+ first.template = '.reeddddk'
27
+ expect{ first.save! }.not_to raise_error # OK!
28
+ end
29
+ it 'blocks new record in same namespace' do
30
+ state.template = '.reeddddk'
31
+ expect{ state.save! }.to raise_error(ActiveRecord::RecordInvalid)
32
+ end
33
+ it 'allows new record in distinct namespace' do
34
+ state.template = '.reeddddk'
35
+ state.namespace = 'foobar'
36
+ expect{ state.save! }.not_to raise_error # OK!
37
+ expect(described_class.group(:namespace).count).to eq('default' => 1, 'foobar' => 1)
38
+ end
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
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,81 +1,22 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
1
3
  require 'coveralls'
2
4
  Coveralls.wear!
5
+ require 'engine_cart'
6
+ EngineCart.load_application!
3
7
 
4
8
  require 'active_fedora'
5
- require 'byebug' unless ENV['CI']
6
9
  require 'active_fedora/noid'
10
+ require 'byebug' unless ENV['CI']
11
+
12
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
7
13
 
8
14
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
15
  RSpec.configure do |config|
10
- # rspec-expectations config goes here. You can use an alternate
11
- # assertion/expectation library such as wrong or the stdlib/minitest
12
- # assertions if you prefer.
13
16
  config.expect_with :rspec do |expectations|
14
- # This option will default to `true` in RSpec 4. It makes the `description`
15
- # and `failure_message` of custom matchers include text for helper methods
16
- # defined using `chain`, e.g.:
17
- # be_bigger_than(2).and_smaller_than(4).description
18
- # # => "be bigger than 2 and smaller than 4"
19
- # ...rather than:
20
- # # => "be bigger than 2"
21
17
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
22
18
  end
23
-
24
- # rspec-mocks config goes here. You can use an alternate test double
25
- # library (such as bogus or mocha) by changing the `mock_with` option here.
26
19
  config.mock_with :rspec do |mocks|
27
- # Prevents you from mocking or stubbing a method that does not exist on
28
- # a real object. This is generally recommended, and will default to
29
- # `true` in RSpec 4.
30
20
  mocks.verify_partial_doubles = true
31
21
  end
32
-
33
- # The settings below are suggested to provide a good initial experience
34
- # with RSpec, but feel free to customize to your heart's content.
35
- =begin
36
- # These two settings work together to allow you to limit a spec run
37
- # to individual examples or groups you care about by tagging them with
38
- # `:focus` metadata. When nothing is tagged with `:focus`, all examples
39
- # get run.
40
- config.filter_run :focus
41
- config.run_all_when_everything_filtered = true
42
-
43
- # Limits the available syntax to the non-monkey patched syntax that is
44
- # recommended. For more details, see:
45
- # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
46
- # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
47
- # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
48
- config.disable_monkey_patching!
49
-
50
- # This setting enables warnings. It's recommended, but in some cases may
51
- # be too noisy due to issues in dependencies.
52
- config.warnings = true
53
-
54
- # Many RSpec users commonly either run the entire suite or an individual
55
- # file, and it's useful to allow more verbose output when running an
56
- # individual spec file.
57
- if config.files_to_run.one?
58
- # Use the documentation formatter for detailed output,
59
- # unless a formatter has already been configured
60
- # (e.g. via a command-line flag).
61
- config.default_formatter = 'doc'
62
- end
63
-
64
- # Print the 10 slowest examples and example groups at the
65
- # end of the spec run, to help surface which specs are running
66
- # particularly slow.
67
- config.profile_examples = 10
68
-
69
- # Run specs in random order to surface order dependencies. If you find an
70
- # order dependency and want to debug it, you can fix the order by providing
71
- # the seed, which is printed after each run.
72
- # --seed 1234
73
- config.order = :random
74
-
75
- # Seed global randomization in this process using the `--seed` CLI option.
76
- # Setting this allows you to use `--seed` to deterministically reproduce
77
- # test failures related to randomization by passing the same `--seed` value
78
- # as the one that triggered the failure.
79
- Kernel.srand config.seed
80
- =end
81
22
  end
@@ -0,0 +1,11 @@
1
+ module MinterStateHelper
2
+ # Simple truncation is not enough, since we also need seed data
3
+ def reset_minter_state_table
4
+ MinterState.destroy_all
5
+ MinterState.create!(
6
+ namespace: 'default',
7
+ template: '.reeddeeddk',
8
+ seq: 0
9
+ )
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ class TestAppGenerator < Rails::Generators::Base
4
+ source_root "./spec/test_app_templates"
5
+
6
+ # if you need to generate any additional configuration
7
+ # into the test app, this generator will be run immediately
8
+ # after setting up the application
9
+
10
+ def install_engine
11
+ generate 'active_fedora:noid:install'
12
+ end
13
+ end
@@ -1,8 +1,7 @@
1
- require 'spec_helper'
2
-
3
1
  describe ActiveFedora::Noid::Config do
4
2
  it { is_expected.to respond_to(:template) }
5
3
  it { is_expected.to respond_to(:statefile) }
4
+ it { is_expected.to respond_to(:namespace) }
6
5
  it { is_expected.to respond_to(:translate_id_to_uri) }
7
6
  it { is_expected.to respond_to(:translate_uri_to_id) }
8
7
 
@@ -39,77 +38,35 @@ describe ActiveFedora::Noid::Config do
39
38
 
40
39
  context "with a hash code uri" do
41
40
  let(:uri) { "http://localhost:8983/fedora/rest/test/hh/63/vz/22/hh63vz22q#g123" }
42
- it { is_expected.to eq 'hh63vz22q#g123' }
41
+ it { is_expected.to eq 'hh63vz22q#g123' }
43
42
  end
44
43
 
45
- context 'with a short custom template' do
44
+ describe 'with a short custom template' do
46
45
  let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
47
46
  let(:custom_template) { '.reeee' }
48
47
  before { config.template = custom_template }
49
48
  subject { translator.call(uri) }
50
-
49
+
51
50
  it { is_expected.to eq 'abcd/members' }
52
51
  end
53
52
 
54
- context 'with an even shorter custom template' do
53
+ describe 'with an even shorter custom template' do
55
54
  let(:uri) { "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
56
55
  let(:custom_template) { '.reee' }
57
56
  before { config.template = custom_template }
58
57
  subject { translator.call(uri) }
59
-
58
+
60
59
  it { is_expected.to eq 'abc/members' }
61
60
  end
62
61
 
63
- context 'with a long custom template' do
62
+ describe 'with a long custom template' do
64
63
  let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
65
64
  let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
66
65
  before { config.template = custom_template }
67
66
  subject { translator.call(uri) }
68
-
69
- it { is_expected.to eq 'abcdefghijklmnopqrstuvwxyz/members' }
70
- end
71
- end
72
-
73
- describe '#translate_id_to_uri' do
74
- let(:config) { described_class.new }
75
- let(:translator) { config.translate_id_to_uri }
76
- let(:id) { "hh63vz2/members" }
77
- let(:ActiveFedora) { double(ActiveFedora) }
78
- subject { translator.call(id) }
79
- before do
80
- allow(ActiveFedora).to receive_message_chain("fedora.host") { "http://localhost:8983" }
81
- allow(ActiveFedora).to receive_message_chain("fedora.base_path") { "/fedora/rest/test" }
82
- end
83
67
 
84
- it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2/members" }
85
-
86
- context "with a hash code id" do
87
- let(:id) { 'hh63vz2#g123' }
88
- it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2#g123" }
89
- end
90
-
91
- context 'with a short custom template' do
92
- let(:id) { "abcd/members" }
93
- let(:custom_template) { '.reeee' }
94
- before { config.template = custom_template }
95
- subject { translator.call(id) }
96
- it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
97
- end
98
-
99
- context 'with an even shorter custom template' do
100
- let(:id) { 'abc/members' }
101
- let(:custom_template) { '.reee' }
102
- before { config.template = custom_template }
103
- subject { translator.call(id) }
104
- it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
68
+ it { is_expected.to eq 'abcdefghijklmnopqrstuvwxyz/members' }
105
69
  end
106
70
 
107
- context 'with a long custom template' do
108
- let(:id) { "abcdefghijklmnopqrstuvwxyz/members" }
109
- let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
110
- before { config.template = custom_template }
111
- subject { translator.call(id) }
112
- it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
113
- end
114
71
  end
115
72
  end
@@ -0,0 +1,76 @@
1
+ include MinterStateHelper
2
+
3
+ describe ActiveFedora::Noid::Minter::Db do
4
+ before(:each) { reset_minter_state_table }
5
+ after( :all ) { reset_minter_state_table }
6
+
7
+ before :each do
8
+ # default novel mintings
9
+ allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
10
+ allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
11
+ end
12
+
13
+ let(:minter) { described_class.new }
14
+ let(:other) { described_class.new('.reedddk') }
15
+
16
+ describe '#initialize' do
17
+ it 'raises on bad templates' do
18
+ expect{ described_class.new('reeddeeddk') }.to raise_error(Noid::TemplateError)
19
+ expect{ described_class.new('') }.to raise_error(Noid::TemplateError)
20
+ end
21
+ it 'returns object w/ default template' do
22
+ expect(minter).to be_instance_of described_class
23
+ expect(minter).to be_a Noid::Minter
24
+ expect(minter.template).to be_instance_of Noid::Template
25
+ expect(minter.template.to_s).to eq ActiveFedora::Noid.config.template
26
+ end
27
+ it 'accepts valid template arg' do
28
+ expect(other).to be_instance_of described_class
29
+ expect(other).to be_a Noid::Minter
30
+ expect(other.template).to be_instance_of Noid::Template
31
+ expect(other.template.to_s).to eq '.reedddk'
32
+ end
33
+ end
34
+
35
+ describe '#mint' do
36
+ subject { minter.mint }
37
+ it { is_expected.not_to be_empty }
38
+ it 'does not mint the same ID twice in a row' do
39
+ expect(subject).not_to eq described_class.new.mint
40
+ end
41
+ it 'is valid' do
42
+ expect(minter.valid?(subject)).to be true
43
+ expect(described_class.new.valid?(subject)).to be true
44
+ end
45
+ it 'is invalid under a different template' do
46
+ expect(described_class.new('.reedddk').valid?(subject)).to be false
47
+ end
48
+ end
49
+
50
+ context 'conflicts' do
51
+ let(:existing_pid) { 'ef12ef12f' }
52
+ let(:unique_pid) { 'bb22bb22b' }
53
+ before :each do
54
+ expect(minter).to receive(:next_id).and_return(existing_pid, unique_pid)
55
+ end
56
+
57
+ context 'when the pid already exists in Fedora' do
58
+ before do
59
+ expect(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
60
+ end
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
74
+ end
75
+ end
76
+ end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe ActiveFedora::Noid do
4
2
  describe '#configure' do
5
3
  it { is_expected.to respond_to(:configure) }
@@ -15,21 +13,5 @@ describe ActiveFedora::Noid do
15
13
  subject { ActiveFedora::Noid.treeify(id) }
16
14
  let(:id) { 'abc123def45' }
17
15
  it { is_expected.to eq 'ab/c1/23/de/abc123def45' }
18
- context 'with a seven-digit identifier' do
19
- let(:id) { 'abc123z' }
20
- it { is_expected.to eq 'ab/c1/23/z/abc123z' }
21
- end
22
- context 'with an empty string' do
23
- let(:id) { '' }
24
- it 'raises ArgumentError' do
25
- expect { subject }.to raise_error(ArgumentError)
26
- end
27
- end
28
- context 'with a nil' do
29
- let(:id) { nil }
30
- it 'raises ArgumentError' do
31
- expect { subject }.to raise_error(ArgumentError)
32
- end
33
- end
34
16
  end
35
17
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe ActiveFedora::Noid::Service do
4
2
  describe 'public API' do
5
3
  it { is_expected.to respond_to(:valid?) }
@@ -1,80 +1,70 @@
1
- require 'spec_helper'
2
- require 'active_fedora'
3
-
4
1
  describe ActiveFedora::Noid::SynchronizedMinter do
5
- it { is_expected.to respond_to(:mint) }
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
6
7
 
8
+ let(:minter) { described_class.new }
9
+
10
+ it { is_expected.to respond_to(:mint) }
7
11
  it 'has a default statefile' do
8
12
  expect(subject.statefile).to eq ActiveFedora::Noid.config.statefile
9
13
  end
10
-
11
14
  it 'has a default template' do
12
- expect(subject.template).to eq ActiveFedora::Noid.config.template
15
+ expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
13
16
  end
14
17
 
15
18
  describe '#initialize' do
16
19
  let(:template) { '.rededk' }
17
20
  let(:statefile) { '/tmp/foobar' }
18
21
 
19
- subject { ActiveFedora::Noid::SynchronizedMinter.new(template, statefile) }
22
+ subject { described_class.new(template, statefile) }
20
23
 
21
24
  it 'respects the custom template' do
22
- expect(subject.template).to eq template
25
+ expect(subject.template.to_s).to eq template
23
26
  end
24
-
25
27
  it 'respects the custom statefile' do
26
28
  expect(subject.statefile).to eq statefile
27
29
  end
28
30
  end
29
31
 
30
32
  describe '#mint' do
31
- before do
32
- allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
33
- allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
34
- end
35
-
36
- subject { ActiveFedora::Noid::Service.new.mint }
37
-
33
+ subject { minter.mint }
38
34
  it { is_expected.not_to be_empty }
39
-
40
35
  it 'does not mint the same ID twice in a row' do
41
- expect(subject).not_to eq ActiveFedora::Noid::Service.new.mint
36
+ expect(subject).not_to eq described_class.new.mint
42
37
  end
43
-
44
38
  it 'is valid' do
45
- expect(ActiveFedora::Noid::Service.new.valid?(subject)).to be true
39
+ expect(minter.valid?(subject)).to be true
40
+ expect(described_class.new.valid?(subject)).to be true
46
41
  end
47
42
  end
48
43
 
49
- context "when the pid already exists in Fedora" do
50
- let(:existing_pid) { 'ef12ef12f' }
44
+ context 'conflicts' do
51
45
  let(:unique_pid) { 'bb22bb22b' }
52
-
53
- before do
54
- allow_any_instance_of(ActiveFedora::Noid::SynchronizedMinter).to receive(:next_id).and_return(existing_pid, unique_pid)
55
- allow(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
56
- allow(ActiveFedora::Base).to receive(:exists?).with(unique_pid).and_return(false)
57
- allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
58
- end
59
-
60
- it 'skips the existing pid' do
61
- expect(subject.mint).to eq unique_pid
46
+ let(:existing_pid) { 'ef12ef12f' }
47
+ before :each do
48
+ expect(minter).to receive(:next_id).and_return(existing_pid, unique_pid)
62
49
  end
63
- end
64
-
65
- context "when the pid already existed in Fedora and now is gone" do
66
- let(:gone_pid) { 'ef12ef12f' }
67
- let(:unique_pid) { 'bb22bb22b' }
68
50
 
69
- before do
70
- allow_any_instance_of(ActiveFedora::Noid::SynchronizedMinter).to receive(:next_id).and_return(gone_pid, unique_pid)
71
- allow(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
72
- allow(ActiveFedora::Base).to receive(:gone?).with(unique_pid).and_return(false)
73
- allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
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
74
58
  end
75
59
 
76
- it 'skips the deleted pid' do
77
- expect(subject.mint).to eq unique_pid
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
78
68
  end
79
69
  end
80
70
  end
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: 1.1.3
4
+ version: 2.0.0.beta1
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-10-26 00:00:00.000000000 Z
11
+ date: 2016-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active-fedora
@@ -36,14 +36,28 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.7'
39
+ version: '0.9'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.7'
46
+ version: '0.9'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 4.2.6
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 4.2.6
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: bundler
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +100,34 @@ dependencies:
86
100
  - - "~>"
87
101
  - !ruby/object:Gem::Version
88
102
  version: '3.2'
103
+ - !ruby/object:Gem::Dependency
104
+ name: sqlite3
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: engine_cart
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.8'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.8'
89
131
  description: Noid identifier services for ActiveFedora-based applications.
90
132
  email:
91
133
  - leftwing@alumni.rutgers.edu
@@ -94,6 +136,7 @@ extensions: []
94
136
  extra_rdoc_files: []
95
137
  files:
96
138
  - ".gitignore"
139
+ - ".rspec"
97
140
  - ".travis.yml"
98
141
  - CONTRIBUTING.md
99
142
  - Gemfile
@@ -101,14 +144,25 @@ files:
101
144
  - README.md
102
145
  - Rakefile
103
146
  - active_fedora-noid.gemspec
147
+ - app/models/minter_state.rb
148
+ - db/migrate/20160610010003_create_minter_states.rb
104
149
  - lib/active_fedora/noid.rb
105
150
  - lib/active_fedora/noid/config.rb
151
+ - lib/active_fedora/noid/engine.rb
152
+ - lib/active_fedora/noid/minter/base.rb
153
+ - lib/active_fedora/noid/minter/db.rb
106
154
  - lib/active_fedora/noid/service.rb
107
155
  - lib/active_fedora/noid/synchronized_minter.rb
108
156
  - lib/active_fedora/noid/version.rb
157
+ - lib/generators/active_fedora/noid/install_generator.rb
158
+ - lib/generators/active_fedora/noid/seed_generator.rb
109
159
  - lib/tasks/noid_tasks.rake
160
+ - spec/models/minter_state_spec.rb
110
161
  - spec/spec_helper.rb
162
+ - spec/support/minterstate_table.rb
163
+ - spec/test_app_templates/lib/generators/test_app_generator.rb
111
164
  - spec/unit/config_spec.rb
165
+ - spec/unit/db_minter_spec.rb
112
166
  - spec/unit/noid_spec.rb
113
167
  - spec/unit/service_spec.rb
114
168
  - spec/unit/synchronized_minter_spec.rb
@@ -119,7 +173,7 @@ metadata: {}
119
173
  post_install_message: |
120
174
  NOTE: ActiveFedora::Noid 1.0.0 included a change that breaks existing minter
121
175
  statefiles. Run the `active_fedora:noid:migrate_statefile` rake task to migrate
122
- your statefile. (If you're using a custom statefile, not /tmp/minter-state,, set
176
+ your statefile. (If you're using a custom statefile, not /tmp/minter-state, set
123
177
  an environment variable called AFNOID_STATEFILE with its path.)
124
178
  rdoc_options: []
125
179
  require_paths:
@@ -131,18 +185,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
185
  version: '0'
132
186
  required_rubygems_version: !ruby/object:Gem::Requirement
133
187
  requirements:
134
- - - ">="
188
+ - - ">"
135
189
  - !ruby/object:Gem::Version
136
- version: '0'
190
+ version: 1.3.1
137
191
  requirements: []
138
192
  rubyforge_project:
139
- rubygems_version: 2.5.1
193
+ rubygems_version: 2.4.6
140
194
  signing_key:
141
195
  specification_version: 4
142
196
  summary: Noid identifier services for ActiveFedora-based applications
143
197
  test_files:
198
+ - spec/models/minter_state_spec.rb
144
199
  - spec/spec_helper.rb
200
+ - spec/support/minterstate_table.rb
201
+ - spec/test_app_templates/lib/generators/test_app_generator.rb
145
202
  - spec/unit/config_spec.rb
203
+ - spec/unit/db_minter_spec.rb
146
204
  - spec/unit/noid_spec.rb
147
205
  - spec/unit/service_spec.rb
148
206
  - spec/unit/synchronized_minter_spec.rb