active-triples 0.7.6 → 0.8.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -3
  3. data/AUTHORS +1 -1
  4. data/CHANGES.md +12 -17
  5. data/Gemfile +2 -0
  6. data/README.md +2 -2
  7. data/active-triples.gemspec +6 -5
  8. data/lib/active_triples.rb +56 -5
  9. data/lib/active_triples/configurable.rb +13 -17
  10. data/lib/active_triples/list.rb +22 -21
  11. data/lib/active_triples/persistable.rb +100 -0
  12. data/lib/active_triples/persistence_strategies/parent_strategy.rb +89 -0
  13. data/lib/active_triples/persistence_strategies/persistence_strategy.rb +77 -0
  14. data/lib/active_triples/persistence_strategies/repository_strategy.rb +78 -0
  15. data/lib/active_triples/properties.rb +2 -1
  16. data/lib/active_triples/rdf_source.rb +94 -159
  17. data/lib/active_triples/relation.rb +17 -45
  18. data/lib/active_triples/repositories.rb +23 -9
  19. data/lib/active_triples/version.rb +1 -1
  20. data/spec/active_triples/configurable_spec.rb +5 -9
  21. data/spec/active_triples/identifiable_spec.rb +1 -18
  22. data/spec/active_triples/list_spec.rb +0 -4
  23. data/spec/active_triples/persistable_spec.rb +93 -0
  24. data/spec/active_triples/persistence_strategies/parent_strategy_spec.rb +93 -0
  25. data/spec/active_triples/persistence_strategies/persistence_strategy_spec.rb +24 -0
  26. data/spec/active_triples/persistence_strategies/repository_strategy_spec.rb +120 -0
  27. data/spec/active_triples/rdf_source_spec.rb +217 -9
  28. data/spec/active_triples/relation_spec.rb +51 -4
  29. data/spec/active_triples/repositories_spec.rb +17 -7
  30. data/spec/active_triples/resource_spec.rb +6 -53
  31. data/spec/active_triples_spec.rb +50 -1
  32. data/spec/spec_helper.rb +5 -1
  33. data/spec/support/active_model_lint.rb +6 -3
  34. data/spec/support/dummies/basic_persistable.rb +13 -0
  35. data/spec/support/shared_examples/persistence_strategy.rb +36 -0
  36. metadata +32 -9
  37. data/spec/active_triples/validations_spec.rb +0 -33
@@ -42,7 +42,7 @@ module ActiveTriples
42
42
  .each_with_object([]) do |x, collector|
43
43
  converted_object = convert_object(x.object)
44
44
  collector << converted_object unless converted_object.nil?
45
- end
45
+ end
46
46
  end
47
47
 
48
48
  def set(values)
@@ -52,14 +52,16 @@ module ActiveTriples
52
52
  values.each do |val|
53
53
  set_value(val)
54
54
  end
55
- parent.persist! if parent.class.repository == :parent && parent.send(:repository)
55
+ parent.persist! if parent.persistence_strategy.is_a? ParentStrategy
56
56
  end
57
57
 
58
+ ##
59
+ # Deletes the values for this relation. This removes all triples matching
60
+ # the basic graph pattern [:rdf_subject :predicate ?object] from the parent
61
+ # Enumerable.
58
62
  def empty_property
59
63
  parent.query([rdf_subject, predicate, nil]).each_statement do |statement|
60
- if !uri_class(statement.object) || uri_class(statement.object) == class_for_property
61
- parent.delete(statement)
62
- end
64
+ parent.delete(statement)
63
65
  end
64
66
  end
65
67
 
@@ -133,8 +135,9 @@ module ActiveTriples
133
135
  return
134
136
  end
135
137
  val = val.to_uri if val.respond_to? :to_uri
136
- raise ValueError, val unless
137
- val.kind_of? RDF::Value or val.kind_of? RDF::Literal
138
+ raise "value must be an RDF URI, Node, Literal, or a valid datatype." \
139
+ " See RDF::Literal.\n\tYou provided #{val.inspect}" unless
140
+ val.kind_of? RDF::Term
138
141
  parent.insert [rdf_subject, predicate, val]
139
142
  end
140
143
 
@@ -144,9 +147,12 @@ module ActiveTriples
144
147
 
145
148
  def add_child_node(resource,object=nil)
146
149
  parent.insert [rdf_subject, predicate, resource.rdf_subject]
147
- resource.parent = parent unless resource.frozen?
150
+ unless resource.frozen?
151
+ resource.set_persistence_strategy(ParentStrategy)
152
+ resource.parent = parent
153
+ end
148
154
  self.node_cache[resource.rdf_subject] = (object ? object : resource)
149
- resource.persist! if resource.class.repository == :parent
155
+ resource.persist! if resource.persistence_strategy.is_a? ParentStrategy
150
156
  end
151
157
 
152
158
  def predicate
@@ -163,6 +169,8 @@ module ActiveTriples
163
169
  # Converts an object to the appropriate class.
164
170
  def convert_object(value)
165
171
  case value
172
+ when RDFSource
173
+ value
166
174
  when RDF::Literal
167
175
  return_literals? ? value : value.object
168
176
  when RDF::Resource
@@ -235,41 +243,5 @@ module ActiveTriples
235
243
  parent.rdf_subject
236
244
  end
237
245
  end
238
-
239
- public
240
-
241
- ##
242
- # An error class for unallowable values in relations.
243
- class ValueError < ArgumentError
244
- # @!attribute [r] value
245
- attr_reader :value
246
-
247
- ##
248
- # @param value [Object]
249
- def initialize(value)
250
- @value = value
251
- end
252
-
253
- ##
254
- # @return [String]
255
- def message
256
- 'value must be an RDF URI, Node, Literal, or a valid datatype. '\
257
- "See RDF::Literal.\n\tYou provided #{value.inspect}"
258
- end
259
- end
260
- end
261
-
262
- class Term < Relation
263
- def self.inherited(*)
264
- warn 'ActiveTriples::Term is deprecated! ' \
265
- 'Use ActiveTriples::Relation instead.'
266
- super
267
- end
268
-
269
- def initialize(*)
270
- warn 'ActiveTriples::Term is deprecated! ' \
271
- 'Use ActiveTriples::Relation instead.'
272
- super
273
- end
274
246
  end
275
247
  end
@@ -7,7 +7,9 @@ module ActiveTriples
7
7
  # RDF::Repository implementation to be used for persistence of
8
8
  # resources that will be shared between ActiveFedora::Base objects.
9
9
  #
10
- # ActiveTriples::Repositories.add_repository :blah, RDF::Repository.new
10
+ # @example registering a repository
11
+ #
12
+ # ActiveTriples::Repositories.add_repository :defaulst, RDF::Repository.new
11
13
  #
12
14
  # Multiple repositories can be registered to keep different kinds of
13
15
  # resources seperate. This is configurable on subclasses of Resource
@@ -17,23 +19,32 @@ module ActiveTriples
17
19
  module Repositories
18
20
 
19
21
  ##
20
- # @param name [Symbol]
21
- # @param repo [RDF::Repository]
22
+ # Register a repository to be configured by name
23
+ #
24
+ # @param name [Symbol]
25
+ # @param repo [RDF::Repository]
22
26
  #
23
- # @return [RDF::Repository]
24
- # @raise [ArgumentError] if a non-repository is passed
27
+ # @return [RDF::Repository] gives the original repository on success
28
+ #
29
+ # @raise [RuntimeError] raised if the repository is not an `RDF::Repository`
25
30
  def add_repository(name, repo)
26
- raise ArgumentError, "Repositories must be an RDF::Repository" unless
27
- repo.kind_of? RDF::Repository
31
+ raise "Repositories must be an RDF::Repository" unless repo.kind_of? RDF::Repository
28
32
  repositories[name] = repo
29
33
  end
30
34
  module_function :add_repository
31
35
 
36
+ ##
37
+ # Delete existing name, repository pairs from the registry hash
38
+ #
39
+ # @return [Hash<Symbol, Repository>] the now empty repository registry hash
32
40
  def clear_repositories!
33
41
  @repositories = {}
34
42
  end
35
43
  module_function :clear_repositories!
36
44
 
45
+ ##
46
+ # @return [Hash<Symbol, Repository>] a hash of currrently registered names
47
+ # and repositories
37
48
  def repositories
38
49
  @repositories ||= {}
39
50
  end
@@ -42,9 +53,13 @@ module ActiveTriples
42
53
  ##
43
54
  # Check for the specified rdf_subject in the specified repository
44
55
  # defaulting to search all registered repositories.
56
+ #
45
57
  # @param [String] rdf_subject
46
58
  # @param [Symbol] repository name
47
- def has_subject?(rdf_subject,repo_name=nil)
59
+ #
60
+ # @return [Boolean] true if the repository contains at least one statement
61
+ # with the given subject term
62
+ def has_subject?(rdf_subject, repo_name=nil)
48
63
  search_repositories = [repositories[repo_name]] if repo_name
49
64
  search_repositories ||= repositories.values
50
65
  found = false
@@ -55,6 +70,5 @@ module ActiveTriples
55
70
  found
56
71
  end
57
72
  module_function :has_subject?
58
-
59
73
  end
60
74
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveTriples
2
- VERSION = '0.7.6'.freeze
2
+ VERSION = "0.8.0".freeze
3
3
  end
@@ -1,10 +1,12 @@
1
1
  require "spec_helper"
2
+
2
3
  describe ActiveTriples::Configurable do
3
4
  before do
4
5
  class DummyConfigurable
5
6
  extend ActiveTriples::Configurable
6
7
  end
7
8
  end
9
+
8
10
  after do
9
11
  Object.send(:remove_const, "DummyConfigurable")
10
12
  end
@@ -12,10 +14,12 @@ describe ActiveTriples::Configurable do
12
14
  it "should be okay if not configured" do
13
15
  expect(DummyConfigurable.type).to eq nil
14
16
  end
17
+
15
18
  it "should be okay if configured to nil" do
16
19
  DummyConfigurable.configure :type => nil
17
20
  expect(DummyConfigurable.type).to eq []
18
21
  end
22
+
19
23
  describe '#configure' do
20
24
  before do
21
25
  DummyConfigurable.configure base_uri: "http://example.org/base", type: RDF::RDFS.Class, rdf_label: RDF::DC.title
@@ -37,18 +41,10 @@ describe ActiveTriples::Configurable do
37
41
  it 'should set a type' do
38
42
  expect(DummyConfigurable.type).to eq [RDF::RDFS.Class]
39
43
  end
44
+
40
45
  it "should be able to set multiple types" do
41
46
  DummyConfigurable.configure type: RDF::RDFS.Container
42
47
  expect(DummyConfigurable.type).to eq [RDF::RDFS.Class, RDF::RDFS.Container]
43
48
  end
44
49
  end
45
-
46
- describe '#rdf_type' do
47
- it "should set the type the old way" do
48
- expect(DummyConfigurable).to receive(:configure).with(type: RDF::RDFS.Class).and_call_original
49
- expect(Deprecation).to receive(:warn)
50
- DummyConfigurable.rdf_type(RDF::RDFS.Class)
51
- expect(DummyConfigurable.type).to eq [RDF::RDFS.Class]
52
- end
53
- end
54
50
  end
@@ -3,24 +3,7 @@ require 'active_model'
3
3
 
4
4
  describe ActiveTriples::Identifiable do
5
5
  before do
6
- class ActiveExample
7
- include ActiveTriples::Identifiable
8
-
9
- def self.property(*args)
10
- prop = args.first
11
-
12
- define_method prop.to_s do
13
- resource.get_values(prop)
14
- end
15
-
16
- define_method "#{prop.to_s}=" do |*args|
17
- resource.set_value(prop, *args)
18
- end
19
-
20
- resource_class.property(*args)
21
- end
22
-
23
- end
6
+ class ActiveExample; include ActiveTriples::Identifiable; end
24
7
  end
25
8
 
26
9
  after do
@@ -3,7 +3,6 @@ require 'nokogiri'
3
3
  require 'linkeddata'
4
4
 
5
5
  describe ActiveTriples::List do
6
-
7
6
  subject { ActiveTriples::List.new }
8
7
 
9
8
  context 'when empty' do
@@ -258,9 +257,6 @@ END
258
257
 
259
258
  it "should be a valid list" do
260
259
  list << "Val"
261
- # TODO this is a workaround for https://github.com/projecthydra/active_fedora/issues/444
262
- # remove the following line when #444 is closed.
263
- list.resource.persist!
264
260
  expect(RDF::List.new(list.rdf_subject, subject)).to be_valid
265
261
  end
266
262
  end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveTriples::Persistable do
4
+ subject { klass.new }
5
+
6
+ let(:klass) { Class.new { include ActiveTriples::Persistable } }
7
+
8
+ let(:statement) { RDF::Statement(RDF::Node.new, RDF::DC.title, 'Moomin') }
9
+
10
+ it 'raises an error with no #graph implementation' do
11
+ expect { subject << statement }.to raise_error(NameError, /graph/)
12
+ end
13
+
14
+ describe 'method delegation' do
15
+ context 'with a strategy' do
16
+ let(:strategy_class) do
17
+ object_double(ActiveTriples::ParentStrategy).as_stubbed_const
18
+ end
19
+
20
+ let(:strategy) { instance_double('PersistenceStrategy') }
21
+
22
+ before do
23
+ allow(strategy_class).to receive(:new).and_return(strategy)
24
+ subject.set_persistence_strategy(strategy_class)
25
+ end
26
+
27
+ describe '#persist!' do
28
+ before { allow(subject).to receive(:run_callbacks).and_yield }
29
+
30
+ it 'sends message to strategy' do
31
+ expect(strategy).to receive(:persist!)
32
+ subject.persist!
33
+ end
34
+ end
35
+
36
+ describe '#destroy' do
37
+ it 'sends message to strategy' do
38
+ expect(strategy).to receive(:destroy)
39
+ subject.destroy
40
+ end
41
+ end
42
+
43
+ describe '#persisted?' do
44
+ it 'sends message to strategy' do
45
+ expect(strategy).to receive(:persisted?)
46
+ subject.persisted?
47
+ end
48
+ end
49
+
50
+ describe '#reload' do
51
+ it 'sends message to strategy' do
52
+ expect(strategy).to receive(:reload)
53
+ subject.reload
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#persistence_strategy' do
60
+ it 'defaults to RepositoryStrategy' do
61
+ expect(subject.persistence_strategy)
62
+ .to be_a ActiveTriples::RepositoryStrategy
63
+ end
64
+ end
65
+
66
+ describe '#set_persistence_strategy' do
67
+ let(:strategy_class) { double('strategy class') }
68
+ let(:strategy) { double('persistence strategy') }
69
+
70
+ before do
71
+ allow(strategy_class).to receive(:new).and_return(strategy)
72
+ end
73
+
74
+ it 'sets new persistence strategy as an instance of the given class' do
75
+ expect { subject.set_persistence_strategy(strategy_class) }
76
+ .to change { subject.persistence_strategy }
77
+ .from(an_instance_of(ActiveTriples::RepositoryStrategy))
78
+ .to(strategy)
79
+ end
80
+ end
81
+
82
+ context 'with graph implementation' do
83
+ before do
84
+ graph = RDF::Graph.new
85
+ allow(subject).to receive(:graph).and_return(graph)
86
+ end
87
+
88
+ it 'mirrors writes to graph' do
89
+ subject << statement
90
+ expect(subject.graph).to contain_exactly statement
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveTriples::ParentStrategy do
4
+ subject { described_class.new(rdf_source) }
5
+ let(:rdf_source) { BasicPersistable.new }
6
+
7
+ shared_context 'with a parent' do
8
+ before do
9
+ subject.parent = parent
10
+ end
11
+
12
+ let(:parent) { BasicPersistable.new }
13
+ end
14
+
15
+ context 'with a parent' do
16
+ include_context 'with a parent'
17
+ it_behaves_like 'a persistence strategy'
18
+ end
19
+
20
+ describe '#final_parent' do
21
+ it 'raises an error with no parent' do
22
+ expect { subject.final_parent }.to raise_error described_class::NilParentError
23
+ end
24
+
25
+ context 'with single parent' do
26
+ include_context 'with a parent'
27
+
28
+ it 'gives parent' do
29
+ expect(subject.final_parent).to eq subject.parent
30
+ end
31
+ end
32
+
33
+ context 'with parent chain' do
34
+ include_context 'with a parent'
35
+ let(:last) { double('last') }
36
+
37
+ it 'gives last parent terminating when no futher parents given' do
38
+ allow(parent).to receive(:parent).and_return(last)
39
+ expect(subject.final_parent).to eq last
40
+ end
41
+
42
+ it 'gives last parent terminating parent is nil' do
43
+ allow(parent).to receive(:parent).and_return(last)
44
+ allow(last).to receive(:parentt).and_return(nil)
45
+ expect(subject.final_parent).to eq last
46
+ end
47
+
48
+ it 'gives last parent terminating parent is same as current' do
49
+ allow(parent).to receive(:parent).and_return(last)
50
+ allow(last).to receive(:parentt).and_return(last)
51
+ expect(subject.final_parent).to eq last
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#parent' do
57
+ it { is_expected.to have_attributes(:parent => nil) }
58
+
59
+ it 'requires its parent to be RDF::Mutable' do
60
+ expect { subject.parent = Object.new }
61
+ .to raise_error described_class::UnmutableParentError
62
+ end
63
+
64
+ it 'requires its parent to be #mutable?' do
65
+ immutable = double
66
+ allow(immutable).to receive(:mutable?).and_return(false)
67
+ expect { subject.parent = immutable }
68
+ .to raise_error described_class::UnmutableParentError
69
+ end
70
+
71
+ context 'with a parent' do
72
+ include_context 'with a parent'
73
+ it { is_expected.to have_attributes(:parent => parent) }
74
+ end
75
+ end
76
+
77
+ describe '#persist!' do
78
+ it 'raises an error with no parent' do
79
+ expect { subject.persist! }.to raise_error described_class::NilParentError
80
+ end
81
+
82
+ context 'with parent' do
83
+ include_context 'with a parent'
84
+
85
+ it 'writes to #final_parent graph' do
86
+ rdf_source << RDF::Statement.new(RDF::Node.new, RDF::DC.title, 'moomin')
87
+ subject.persist!
88
+ expect(subject.final_parent.statements)
89
+ .to contain_exactly *rdf_source.statements
90
+ end
91
+ end
92
+ end
93
+ end