activefedora-aggregation 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +2 -33
- data/Rakefile +1 -1
- data/activefedora-aggregation.gemspec +1 -0
- data/bin/jetty_wait +6 -0
- data/circle.yml +11 -0
- data/lib/active_fedora/aggregation/aggregation_extension.rb +26 -0
- data/lib/active_fedora/aggregation/appends_to_aggregation.rb +31 -0
- data/lib/active_fedora/aggregation/association.rb +58 -33
- data/lib/active_fedora/aggregation/base_extension.rb +53 -14
- data/lib/active_fedora/aggregation/builder.rb +8 -20
- data/lib/active_fedora/aggregation/decorating_repository.rb +29 -0
- data/lib/active_fedora/aggregation/decorator_list.rb +15 -0
- data/lib/active_fedora/aggregation/decorator_with_arguments.rb +15 -0
- data/lib/active_fedora/aggregation/link_inserter.rb +56 -0
- data/lib/active_fedora/aggregation/null_proxy.rb +23 -0
- data/lib/active_fedora/aggregation/ordered_proxy.rb +57 -0
- data/lib/active_fedora/aggregation/ordered_reader.rb +23 -0
- data/lib/active_fedora/aggregation/persist_links.rb +9 -0
- data/lib/active_fedora/aggregation/proxy.rb +1 -2
- data/lib/active_fedora/aggregation/proxy_owner.rb +24 -0
- data/lib/active_fedora/aggregation/proxy_repository.rb +38 -0
- data/lib/active_fedora/aggregation/reflection.rb +18 -1
- data/lib/active_fedora/aggregation/version.rb +1 -1
- data/lib/active_fedora/aggregation.rb +14 -3
- data/lib/active_fedora/filter/association.rb +70 -0
- data/lib/active_fedora/filter/builder.rb +14 -0
- data/lib/active_fedora/filter/reflection.rb +21 -0
- data/lib/active_fedora/filter.rb +11 -0
- metadata +35 -6
- data/lib/active_fedora/aggregation/proxy_container.rb +0 -111
- data/lib/active_fedora/aggregation/through_association.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6accff4705ce11b36750f93b831e532f7276e1c
|
4
|
+
data.tar.gz: f603f7707698d4ca8b239da7f3f8dd489cdb0a58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76293d09bec958fb7a1a645806d2736d62d184cd0a27d38a12cd380db2f2cca49b9ba9e0eb9d1d9432e383738afd70580f14b83a00dc826b1755309cfb00598a
|
7
|
+
data.tar.gz: 045f5653e592fc45e9ae62b3da06ef2d4d9cbeb70fabd2f0aa5fe27aa3e1f8a2a6e6e835b2ac79dd3f59e43d73a14b044adde6dc06690b0e485059478c9f922b
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Gem Version](https://badge.fury.io/rb/activefedora-aggregation.svg)](http://badge.fury.io/rb/activefedora-aggregation) [![Build Status](https://
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/activefedora-aggregation.svg)](http://badge.fury.io/rb/activefedora-aggregation) [![Build Status](https://circleci.com/gh/projecthydra-labs/activefedora-aggregation.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/projecthydra-labs/activefedora-aggregation)
|
2
2
|
# ActiveFedora::Aggregation
|
3
3
|
|
4
4
|
Aggregations for ActiveFedora.
|
@@ -21,35 +21,4 @@ image.save
|
|
21
21
|
|
22
22
|
```
|
23
23
|
|
24
|
-
Now the
|
25
|
-
|
26
|
-
Here's what the graph looks like:
|
27
|
-
|
28
|
-
```ttl
|
29
|
-
<http://127.0.0.1:8983/fedora/rest/dev/my_image> a <http://www.w3.org/ns/ldp#RDFSource>,
|
30
|
-
<http://www.w3.org/ns/ldp#Container>;
|
31
|
-
<http://www.w3.org/ns/ldp#contains> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files>;
|
32
|
-
<info:fedora/fedora-system:def/model#hasModel> "Image" .
|
33
|
-
|
34
|
-
<http://127.0.0.1:8983/fedora/rest/dev/my_image/files> a <http://www.w3.org/ns/ldp#RDFSource>,
|
35
|
-
<http://www.w3.org/ns/ldp#Container>;
|
36
|
-
<http://www.iana.org/assignments/relation/first> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files/5a5af870-594b-4966-93f6-0348402583f0>;
|
37
|
-
<http://www.iana.org/assignments/relation/last> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files/9cc70b3d-c9d7-4cfc-b504-adbcb0bdfb3d>;
|
38
|
-
<http://www.w3.org/ns/ldp#contains> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files/5a5af870-594b-4966-93f6-0348402583f0>,
|
39
|
-
<http://127.0.0.1:8983/fedora/rest/dev/my_image/files/9cc70b3d-c9d7-4cfc-b504-adbcb0bdfb3d>;
|
40
|
-
<info:fedora/fedora-system:def/model#hasModel> "ActiveFedora::Aggregation::ProxyContainer" .
|
41
|
-
|
42
|
-
<http://127.0.0.1:8983/fedora/rest/dev/my_image/files/5a5af870-594b-4966-93f6-0348402583f0> a <http://www.w3.org/ns/ldp#RDFSource>,
|
43
|
-
<http://www.w3.org/ns/ldp#Container>;
|
44
|
-
<http://www.iana.org/assignments/relation/next> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files/9cc70b3d-c9d7-4cfc-b504-adbcb0bdfb3d>;
|
45
|
-
<http://www.openarchives.org/ore/terms/proxyFor> <http://127.0.0.1:8983/fedora/rest/dev/file2>;
|
46
|
-
<http://www.openarchives.org/ore/terms/proxyIn> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files>;
|
47
|
-
<info:fedora/fedora-system:def/model#hasModel> "ActiveFedora::Aggregation::Proxy" .
|
48
|
-
|
49
|
-
<http://127.0.0.1:8983/fedora/rest/dev/my_image/files/9cc70b3d-c9d7-4cfc-b504-adbcb0bdfb3d> a <http://www.w3.org/ns/ldp#RDFSource>,
|
50
|
-
<http://www.w3.org/ns/ldp#Container>;
|
51
|
-
<http://www.iana.org/assignments/relation/prev> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files/5a5af870-594b-4966-93f6-0348402583f0>;
|
52
|
-
<http://www.openarchives.org/ore/terms/proxyFor> <http://127.0.0.1:8983/fedora/rest/dev/file1>;
|
53
|
-
<http://www.openarchives.org/ore/terms/proxyIn> <http://127.0.0.1:8983/fedora/rest/dev/my_image/files>;
|
54
|
-
<info:fedora/fedora-system:def/model#hasModel> "ActiveFedora::Aggregation::Proxy" .
|
55
|
-
```
|
24
|
+
Now the `generic\_files` method returns an ordered list of GenericFile objects.
|
data/Rakefile
CHANGED
data/bin/jetty_wait
ADDED
data/circle.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
machine:
|
2
|
+
ruby:
|
3
|
+
version: 2.2.0
|
4
|
+
dependencies:
|
5
|
+
pre:
|
6
|
+
- gem install bundler
|
7
|
+
post:
|
8
|
+
- bundle exec rake jetty:clean
|
9
|
+
- cd jetty && java -Djetty.port=8983 -Dsolr.solr.home=/home/ubuntu/activefedora-aggregation/jetty/solr -XX:MaxPermSize=128m -Xmx256m -jar start.jar:
|
10
|
+
background: true
|
11
|
+
- bin/jetty_wait
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# This module is mixed into classes that declare 'aggregates ...'
|
2
|
+
#
|
3
|
+
module ActiveFedora::Aggregation
|
4
|
+
module AggregationExtension
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include PersistLinks
|
7
|
+
|
8
|
+
included do
|
9
|
+
after_destroy :remove_aggregation_proxies_from_solr
|
10
|
+
|
11
|
+
# Doesn't use after_save because we need this callback to come after the autosave callback
|
12
|
+
after_create :persist_aggregation_links
|
13
|
+
after_update :persist_aggregation_links
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# The proxies, being nested under the object, are automatically destroyed
|
19
|
+
# this cleans up their records from solr.
|
20
|
+
def remove_aggregation_proxies_from_solr
|
21
|
+
query = ActiveFedora::SolrQueryBuilder.construct_query_for_rel(proxyIn: id, has_model: Proxy.to_class_uri)
|
22
|
+
ActiveFedora::SolrService.instance.conn.delete_by_query(query, params: {'softCommit' => true})
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
class AppendsToAggregation < SimpleDelegator
|
3
|
+
attr_reader :parent_node
|
4
|
+
# @param [#next, #prev] proxy The proxy to add behavior to.
|
5
|
+
# @param [#head, #tail] parent_node The aggregation to append proxies to.
|
6
|
+
def initialize(proxy, parent_node)
|
7
|
+
@parent_node = parent_node
|
8
|
+
super(proxy)
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_a?(klass)
|
12
|
+
__getobj__.is_a?(klass)
|
13
|
+
end
|
14
|
+
|
15
|
+
def save(*args)
|
16
|
+
insert_link do
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def insert_link
|
24
|
+
result = yield
|
25
|
+
if result
|
26
|
+
LinkInserter.new(parent_node, self).call
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,59 +1,84 @@
|
|
1
1
|
module ActiveFedora::Aggregation
|
2
|
-
class Association
|
2
|
+
class Association < ::ActiveFedora::Associations::IndirectlyContainsAssociation
|
3
|
+
delegate :first, to: :ordered_reader
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
# @opts options [String] class_name name of the class in the association
|
7
|
-
def initialize(parent, reflection)
|
8
|
-
@parent = parent
|
9
|
-
@reflection = reflection
|
5
|
+
def ordered_reader
|
6
|
+
OrderedReader.new(owner).to_a
|
10
7
|
end
|
11
8
|
|
12
|
-
def
|
13
|
-
@
|
9
|
+
def proxy_class
|
10
|
+
@proxy_class ||= ProxyRepository.new(owner, super)
|
14
11
|
end
|
15
12
|
|
16
|
-
def
|
17
|
-
|
13
|
+
def options
|
14
|
+
@all_options ||= default_options.merge(super)
|
18
15
|
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
|
18
|
+
def ids_reader
|
19
|
+
if loaded?
|
20
|
+
load_target.map do |record|
|
21
|
+
record.id
|
22
|
+
end
|
23
|
+
else
|
24
|
+
proxies = load_proxies_from_solr(fl: 'id, next_ssim, proxyFor_ssim')
|
25
|
+
create_linked_list(@owner.head_id, proxies)
|
23
26
|
end
|
24
|
-
save #causes the (head/tail) pointers on the aggregation to be persisted
|
25
27
|
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
# Write a query to find the proxies
|
32
|
+
def construct_proxy_query
|
33
|
+
@proxy_query ||= begin
|
34
|
+
clauses = { 'proxyIn' => @owner.id }
|
35
|
+
clauses[:has_model] = ActiveFedora::Aggregation::Proxy.to_class_uri
|
36
|
+
ActiveFedora::SolrQueryBuilder.construct_query_for_rel(clauses)
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
|
-
|
32
|
-
|
40
|
+
# Finds the proxies
|
41
|
+
# @param opts [Hash] Options that will be passed through to ActiveFedora::SolrService.query.
|
42
|
+
def load_proxies_from_solr(opts = Hash.new)
|
43
|
+
finder_query = construct_proxy_query
|
44
|
+
rows = 1000
|
45
|
+
ActiveFedora::SolrService.query(finder_query, { rows: rows }.merge(opts))
|
33
46
|
end
|
34
47
|
|
35
|
-
|
36
|
-
|
48
|
+
# @param [String, NilClass] first_id
|
49
|
+
# @param [Array<Hash>] remainder
|
50
|
+
# @param [Array] list
|
51
|
+
def create_linked_list(first_id, remainder, list=[])
|
52
|
+
return list if remainder.empty?
|
53
|
+
|
54
|
+
index = remainder.find_index { |n| n.fetch('id') == first_id }
|
55
|
+
first = remainder.delete_at(index)
|
56
|
+
next_id = first['next_ssim'].try(:first)
|
57
|
+
create_linked_list(next_id, remainder, list + [first.fetch('proxyFor_ssim').first])
|
37
58
|
end
|
38
59
|
|
39
|
-
def
|
40
|
-
|
60
|
+
def default_options
|
61
|
+
{ through: default_proxy_class, foreign_key: :target, has_member_relation: reflection.predicate, inserted_content_relation: content_relation }
|
41
62
|
end
|
42
63
|
|
43
|
-
def
|
44
|
-
|
45
|
-
ProxyContainer.find_or_initialize(klass.uri_to_id(uri)).tap do |container|
|
46
|
-
container.parent = @parent
|
47
|
-
end
|
48
|
-
end
|
64
|
+
def content_relation
|
65
|
+
default_proxy_class.constantize.reflect_on_association(:target).predicate
|
49
66
|
end
|
50
67
|
|
51
|
-
def
|
52
|
-
|
68
|
+
def default_proxy_class
|
69
|
+
'ActiveFedora::Aggregation::Proxy'
|
53
70
|
end
|
54
71
|
|
55
|
-
def
|
56
|
-
|
72
|
+
def raise_on_type_mismatch(record)
|
73
|
+
super
|
74
|
+
if type_validator
|
75
|
+
type_validator.validate!(self,record)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def type_validator
|
80
|
+
options[:type_validator]
|
57
81
|
end
|
82
|
+
|
58
83
|
end
|
59
84
|
end
|
@@ -1,23 +1,62 @@
|
|
1
1
|
module ActiveFedora::Aggregation
|
2
2
|
module BaseExtension
|
3
|
+
extend ActiveSupport::Concern
|
3
4
|
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
# Queries the RDF graph to find all records that include this object in their aggregations
|
6
|
+
# Since any class may be the target of an aggregation, this must be on every class extending
|
7
|
+
# from ActiveFedora::Base
|
8
|
+
# @return [Array] records that include this object in their aggregations
|
9
|
+
def aggregated_by
|
10
|
+
# In theory you should be able to find the aggregation predicate (ie ore:aggregates)
|
11
|
+
# but Fedora does not return that predicate due to this bug in FCREPO:
|
12
|
+
# https://jira.duraspace.org/browse/FCREPO-1497
|
13
|
+
# so we have to look up the proxies asserting RDF::Vocab::ORE.proxyFor
|
14
|
+
# and return their containers.
|
15
|
+
proxy_class.where(proxyFor_ssim: id).map(&:container)
|
12
16
|
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def proxy_class
|
21
|
+
ActiveFedora::Aggregation::Proxy
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
##
|
26
|
+
# Create an aggregation association on the class
|
27
|
+
# @example
|
28
|
+
# class Image < ActiveFedora::Base
|
29
|
+
# aggregates :generic_files
|
30
|
+
# end
|
31
|
+
def aggregates(name, options={})
|
32
|
+
Builder.build(self, name, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Create an association filter on the class
|
37
|
+
# @example
|
38
|
+
# class Image < ActiveFedora::Base
|
39
|
+
# aggregates :generic_files
|
40
|
+
# filters_association :generic_files, as: :large_files, condition: :big_file?
|
41
|
+
# end
|
42
|
+
def filters_association(extending_from, options={})
|
43
|
+
name = options.delete(:as)
|
44
|
+
ActiveFedora::Filter::Builder.build(self, name, options.merge(extending_from: extending_from))
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_reflection(macro, name, options, active_fedora)
|
48
|
+
case macro
|
49
|
+
when :aggregation
|
50
|
+
Reflection.new(macro, name, options, active_fedora).tap do |reflection|
|
51
|
+
add_reflection name, reflection
|
52
|
+
end
|
53
|
+
when :filter
|
54
|
+
ActiveFedora::Filter::Reflection.new(macro, name, options, active_fedora).tap do |reflection|
|
55
|
+
add_reflection name, reflection
|
56
|
+
end
|
57
|
+
else
|
58
|
+
super
|
18
59
|
end
|
19
|
-
else
|
20
|
-
super
|
21
60
|
end
|
22
61
|
end
|
23
62
|
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
module ActiveFedora::Aggregation
|
2
2
|
class Builder < ActiveFedora::Associations::Builder::CollectionAssociation
|
3
|
+
include ActiveFedora::AutosaveAssociation::AssociationBuilderExtension
|
3
4
|
self.macro = :aggregation
|
5
|
+
self.valid_options += [
|
6
|
+
:type_validator
|
7
|
+
]
|
4
8
|
|
5
9
|
def build
|
6
10
|
reflection = super
|
7
|
-
configure_dependency
|
8
|
-
model.has_and_belongs_to_many :proxies, predicate: ::RDF::Vocab::ORE.aggregates, class_name: 'ActiveFedora::Aggregation::Proxy', inverse_of: :containers
|
9
11
|
model.belongs_to :head, predicate: ::RDF::Vocab::IANA['first'], class_name: 'ActiveFedora::Aggregation::Proxy'
|
10
12
|
model.belongs_to :tail, predicate: ::RDF::Vocab::IANA.last, class_name: 'ActiveFedora::Aggregation::Proxy'
|
11
13
|
|
14
|
+
model.include AggregationExtension
|
12
15
|
reflection
|
13
16
|
end
|
14
17
|
|
@@ -17,6 +20,9 @@ module ActiveFedora::Aggregation
|
|
17
20
|
mixin.redefine_method("#{name.to_s.singularize}_ids") do
|
18
21
|
association(name).ids_reader
|
19
22
|
end
|
23
|
+
mixin.redefine_method("ordered_#{name.to_s.pluralize}") do
|
24
|
+
association(name).ordered_reader
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
def self.define_writers(mixin, name)
|
@@ -26,23 +32,5 @@ module ActiveFedora::Aggregation
|
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
|
-
private
|
30
|
-
|
31
|
-
def configure_dependency
|
32
|
-
define_save_dependency_method
|
33
|
-
model.after_save dependency_method_name
|
34
|
-
end
|
35
|
-
|
36
|
-
def define_save_dependency_method
|
37
|
-
name = self.name
|
38
|
-
model.send(:define_method, dependency_method_name) do
|
39
|
-
send(name).save
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def dependency_method_name
|
44
|
-
"aggregator_dependent_for_#{name}"
|
45
|
-
end
|
46
|
-
|
47
35
|
end
|
48
36
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
##
|
3
|
+
# Decorates the results of a repository with the given decorator.
|
4
|
+
class DecoratingRepository < SimpleDelegator
|
5
|
+
attr_reader :decorator
|
6
|
+
# @param [#new] decorator A decorator.
|
7
|
+
# @param [#find, #new] base_repository A repository to decorate.
|
8
|
+
def initialize(decorator, base_repository)
|
9
|
+
@decorator = decorator
|
10
|
+
super(base_repository)
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(id)
|
14
|
+
decorate(super(id))
|
15
|
+
end
|
16
|
+
|
17
|
+
def new(*args)
|
18
|
+
result = decorate(super(*args))
|
19
|
+
yield result if block_given?
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def decorate(obj)
|
26
|
+
decorator.new(obj)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
# A composite object to allow for a list of decorators to be treated like one.
|
3
|
+
class DecoratorList
|
4
|
+
attr_reader :decorators
|
5
|
+
def initialize(*decorators)
|
6
|
+
@decorators = decorators
|
7
|
+
end
|
8
|
+
|
9
|
+
def new(undecorated_object)
|
10
|
+
decorators.inject(undecorated_object) do |obj, decorator|
|
11
|
+
decorator.new(obj)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
# This is an Adapter to allow a Decorator to respond to the interface #new()
|
3
|
+
# but still require other arguments to instantiate.
|
4
|
+
class DecoratorWithArguments
|
5
|
+
attr_reader :decorator, :args
|
6
|
+
def initialize(decorator, *args)
|
7
|
+
@decorator = decorator
|
8
|
+
@args = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def new(obj)
|
12
|
+
decorator.new(obj, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
class LinkInserter
|
3
|
+
attr_reader :root, :proxy
|
4
|
+
# @param [ProxyOwner] root the node representing the aggregation
|
5
|
+
# @param [Proxy] proxy the proxy to add to the aggregation
|
6
|
+
def initialize(root, proxy)
|
7
|
+
@root = root
|
8
|
+
@proxy = proxy
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
if root.head
|
13
|
+
append
|
14
|
+
else
|
15
|
+
set
|
16
|
+
end
|
17
|
+
proxy.container = root
|
18
|
+
persist_nodes!
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def append
|
24
|
+
Appender.new(root, proxy).call
|
25
|
+
end
|
26
|
+
|
27
|
+
def set
|
28
|
+
root.head = proxy
|
29
|
+
root.tail = proxy
|
30
|
+
end
|
31
|
+
|
32
|
+
def persist_nodes!
|
33
|
+
[proxy, proxy.prev].uniq.compact.each(&:save!)
|
34
|
+
end
|
35
|
+
|
36
|
+
class Appender
|
37
|
+
attr_reader :root, :proxy
|
38
|
+
def initialize(root, proxy)
|
39
|
+
@root = root
|
40
|
+
@proxy = proxy
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
last_proxy.next = proxy
|
45
|
+
proxy.prev = last_proxy
|
46
|
+
root.tail = proxy
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def last_proxy
|
52
|
+
@last_proxy ||= root.tail
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
# A null proxy to simplify logic.
|
3
|
+
class NullProxy
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
attr_writer :prev, :next
|
7
|
+
def prev
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def next
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def reload
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def changed?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
# A proxy which knows how to delete itself from an aggregation.
|
3
|
+
class OrderedProxy < SimpleDelegator
|
4
|
+
attr_reader :parent_node
|
5
|
+
# @param [#next, #prev, #delete] proxy The proxy to add behavior to.
|
6
|
+
# @param [#delete_proxy!] parent_node The aggregation to delete proxies
|
7
|
+
# from.
|
8
|
+
def initialize(proxy, parent_node)
|
9
|
+
@parent_node = parent_node
|
10
|
+
super(proxy)
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_a?(klass)
|
14
|
+
__getobj__.is_a?(klass)
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(*args)
|
18
|
+
link_node_if_true do
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def link_node_if_true
|
26
|
+
# Have to precache these or AF tries to access this node?
|
27
|
+
next_or_null
|
28
|
+
prev_or_null
|
29
|
+
yield.tap do |result|
|
30
|
+
if result
|
31
|
+
# Have to reload proxies because otherwise you persist them with bad
|
32
|
+
# referencing triples.
|
33
|
+
[next_or_null, prev_or_null, parent_node].each(&:reload)
|
34
|
+
prev_or_null.next = self.next
|
35
|
+
next_or_null.prev = prev
|
36
|
+
changed_nodes.each(&:save!)
|
37
|
+
parent_node.delete_proxy!(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def next_or_null
|
43
|
+
self.next || NullProxy.instance
|
44
|
+
end
|
45
|
+
|
46
|
+
def prev_or_null
|
47
|
+
self.prev || NullProxy.instance
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def changed_nodes
|
53
|
+
[self.prev, self.next].uniq.compact.select(&:changed?)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
class OrderedReader
|
3
|
+
include Enumerable
|
4
|
+
attr_reader :root
|
5
|
+
def initialize(root)
|
6
|
+
@root = root
|
7
|
+
end
|
8
|
+
|
9
|
+
def each
|
10
|
+
proxy = first_head
|
11
|
+
while proxy
|
12
|
+
yield proxy.target
|
13
|
+
proxy = proxy.next
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def first_head
|
20
|
+
root.head
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
module PersistLinks
|
3
|
+
# If the head or tail pointer was updated (in an autosave callback), then persist them
|
4
|
+
def persist_aggregation_links
|
5
|
+
return true unless @new_record_before_save
|
6
|
+
save if changes.key?("head_id") or changes.key?("tail_id")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ActiveFedora::Aggregation
|
2
2
|
class Proxy < ActiveFedora::Base
|
3
|
-
|
4
|
-
has_and_belongs_to_many :containers, predicate: ::RDF::Vocab::ORE.proxyIn, class_name: 'ActiveFedora::Base'
|
3
|
+
belongs_to :container, predicate: ::RDF::Vocab::ORE.proxyIn, class_name: 'ActiveFedora::Base'
|
5
4
|
belongs_to :target, predicate: ::RDF::Vocab::ORE.proxyFor, class_name: 'ActiveFedora::Base'
|
6
5
|
belongs_to :next, predicate: ::RDF::Vocab::IANA.next, class_name: 'ActiveFedora::Aggregation::Proxy'
|
7
6
|
belongs_to :prev, predicate: ::RDF::Vocab::IANA.prev, class_name: 'ActiveFedora::Aggregation::Proxy'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
##
|
3
|
+
# Decorates a proxy owner such that it knows how to delete a proxy from its
|
4
|
+
# ordered list.
|
5
|
+
class ProxyOwner < SimpleDelegator
|
6
|
+
def is_a?(klass)
|
7
|
+
__getobj__.is_a?(klass)
|
8
|
+
end
|
9
|
+
|
10
|
+
# @param [#next, #prev] proxy A Proxy link to delete.
|
11
|
+
def delete_proxy!(proxy)
|
12
|
+
if proxy == head || head.nil? # Head is nil if proxy is now deleted.
|
13
|
+
self.head = proxy.next
|
14
|
+
end
|
15
|
+
if proxy == tail || tail.nil? # Head is nil if proxy is now deleted.
|
16
|
+
self.tail = proxy.prev
|
17
|
+
end
|
18
|
+
[head, tail].uniq.compact.each(&:reload)
|
19
|
+
if changed?
|
20
|
+
save!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ActiveFedora::Aggregation
|
2
|
+
##
|
3
|
+
# Repository for Proxies. This repository is responsible for decorating a
|
4
|
+
# proxy such that it's useful for aggregation and is an attempt at
|
5
|
+
# centralizing hard-coded dependencies without a dependency injection
|
6
|
+
# container.
|
7
|
+
class ProxyRepository < SimpleDelegator
|
8
|
+
attr_reader :owner, :base_proxy_factory
|
9
|
+
# @param [ActiveFedora::Base] owner The node which proxy will assert order
|
10
|
+
# on.
|
11
|
+
# @param [#find, #new] base_proxy_factory The base factory which returns proxies
|
12
|
+
# that will be decorated.
|
13
|
+
# @return [#find, #new] A repository which can return proxies useful for
|
14
|
+
# aggregation.
|
15
|
+
def initialize(owner, base_proxy_factory)
|
16
|
+
@owner = owner
|
17
|
+
@base_proxy_factory = base_proxy_factory
|
18
|
+
super(repository)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def repository
|
24
|
+
DecoratingRepository.new(proxy_decorator, base_proxy_factory)
|
25
|
+
end
|
26
|
+
|
27
|
+
def proxy_decorator
|
28
|
+
DecoratorList.new(
|
29
|
+
DecoratorWithArguments.new(OrderedProxy, proxy_owner),
|
30
|
+
DecoratorWithArguments.new(AppendsToAggregation, proxy_owner)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def proxy_owner
|
35
|
+
@proxy_owner ||= ProxyOwner.new(owner)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,7 +1,24 @@
|
|
1
1
|
module ActiveFedora::Aggregation
|
2
2
|
class Reflection < ActiveFedora::Reflection::AssociationReflection
|
3
3
|
def association_class
|
4
|
-
|
4
|
+
Association
|
5
|
+
end
|
6
|
+
|
7
|
+
def klass
|
8
|
+
@klass ||= begin
|
9
|
+
klass = class_name.constantize
|
10
|
+
klass.respond_to?(:uri_to_id) ? klass : ActiveFedora::Base
|
11
|
+
rescue NameError => e
|
12
|
+
# If the NameError is a result of the class having a
|
13
|
+
# NameError (e.g. NoMethodError) within it then raise the error.
|
14
|
+
raise e if Object.const_defined? class_name
|
15
|
+
# Otherwise the NameError was a result of not being able to find the class
|
16
|
+
ActiveFedora::Base
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def predicate
|
21
|
+
@options[:predicate] || ::RDF::Vocab::ORE.aggregates
|
5
22
|
end
|
6
23
|
|
7
24
|
def collection?
|
@@ -2,20 +2,31 @@ require 'active_fedora/aggregation/version'
|
|
2
2
|
require 'active_support'
|
3
3
|
require 'active-fedora'
|
4
4
|
require 'rdf/vocab'
|
5
|
+
require 'active_fedora/filter'
|
5
6
|
|
6
7
|
module ActiveFedora
|
7
8
|
module Aggregation
|
8
9
|
extend ActiveSupport::Autoload
|
9
10
|
eager_autoload do
|
10
|
-
autoload :ProxyContainer
|
11
11
|
autoload :Association
|
12
|
+
autoload :AggregationExtension
|
12
13
|
autoload :Proxy
|
13
14
|
autoload :Builder
|
14
|
-
autoload :ThroughAssociation
|
15
15
|
autoload :Reflection
|
16
16
|
autoload :BaseExtension
|
17
|
+
autoload :LinkInserter
|
18
|
+
autoload :OrderedReader
|
19
|
+
autoload :PersistLinks
|
20
|
+
autoload :OrderedProxy
|
21
|
+
autoload :AppendsToAggregation
|
22
|
+
autoload :ProxyOwner
|
23
|
+
autoload :NullProxy
|
24
|
+
autoload :DecoratingRepository
|
25
|
+
autoload :DecoratorWithArguments
|
26
|
+
autoload :DecoratorList
|
27
|
+
autoload :ProxyRepository
|
17
28
|
end
|
18
29
|
|
19
|
-
ActiveFedora::Base.
|
30
|
+
ActiveFedora::Base.include BaseExtension
|
20
31
|
end
|
21
32
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveFedora::Filter
|
2
|
+
class Association < ::ActiveFedora::Associations::CollectionAssociation
|
3
|
+
# @param [Array] records a list of records to replace the current association with
|
4
|
+
# @raise [ArgumentError] if one of the records doesn't match the prescribed condition
|
5
|
+
def writer(records)
|
6
|
+
records.each { |r| validate_assertion!(r) }
|
7
|
+
existing_matching_records.each do |r|
|
8
|
+
extending_from.delete(r)
|
9
|
+
end
|
10
|
+
extending_from.concat(records)
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete(records)
|
14
|
+
extending_from.delete(records)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Array] records a list of records to append to the current association
|
18
|
+
# @raise [ArgumentError] if one of the records doesn't match the prescribed condition
|
19
|
+
def concat(records)
|
20
|
+
records.flatten.each { |r| validate_assertion!(r) }
|
21
|
+
extending_from.concat(records)
|
22
|
+
end
|
23
|
+
|
24
|
+
def ids_reader
|
25
|
+
load_target
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# target should never be cached as part of this objects state, because
|
32
|
+
# extending_from.target could change and we want to reflect those changes
|
33
|
+
def target
|
34
|
+
find_target
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_target?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_target
|
42
|
+
existing_matching_records
|
43
|
+
end
|
44
|
+
|
45
|
+
# We can't create an association scope on here until we can figure a way to
|
46
|
+
# index/query the condition in Solr
|
47
|
+
def association_scope
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def existing_matching_records
|
52
|
+
extending_from.reader.to_a.select do |r|
|
53
|
+
validate_assertion(r)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def extending_from
|
58
|
+
owner.association(options.fetch(:extending_from))
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_assertion(record)
|
62
|
+
record.send(options.fetch(:condition))
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_assertion!(record)
|
66
|
+
raise ArgumentError, "#{record.class} with ID: #{record.id} was expected to #{options.fetch(:condition)}, but it was false" unless validate_assertion(record)
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ActiveFedora::Filter
|
2
|
+
class Builder < ActiveFedora::Associations::Builder::CollectionAssociation
|
3
|
+
self.macro = :filter
|
4
|
+
self.valid_options = [:extending_from, :condition]
|
5
|
+
|
6
|
+
def self.define_readers(mixin, name)
|
7
|
+
super
|
8
|
+
mixin.redefine_method("#{name.to_s.singularize}_ids") do
|
9
|
+
association(name).ids_reader
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveFedora::Filter
|
2
|
+
class Reflection < ActiveFedora::Reflection::AssociationReflection
|
3
|
+
def association_class
|
4
|
+
Association
|
5
|
+
end
|
6
|
+
|
7
|
+
# delegates to extending_from
|
8
|
+
def klass
|
9
|
+
extending_from.klass
|
10
|
+
end
|
11
|
+
|
12
|
+
def extending_from
|
13
|
+
@extending_from ||= active_fedora.reflect_on_association(options.fetch(:extending_from))
|
14
|
+
end
|
15
|
+
|
16
|
+
def collection?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefedora-aggregation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
description:
|
112
126
|
email:
|
113
127
|
- justin@curationexperts.com
|
@@ -125,16 +139,32 @@ files:
|
|
125
139
|
- Rakefile
|
126
140
|
- activefedora-aggregation.gemspec
|
127
141
|
- bin/console
|
142
|
+
- bin/jetty_wait
|
128
143
|
- bin/setup
|
144
|
+
- circle.yml
|
129
145
|
- lib/active_fedora/aggregation.rb
|
146
|
+
- lib/active_fedora/aggregation/aggregation_extension.rb
|
147
|
+
- lib/active_fedora/aggregation/appends_to_aggregation.rb
|
130
148
|
- lib/active_fedora/aggregation/association.rb
|
131
149
|
- lib/active_fedora/aggregation/base_extension.rb
|
132
150
|
- lib/active_fedora/aggregation/builder.rb
|
151
|
+
- lib/active_fedora/aggregation/decorating_repository.rb
|
152
|
+
- lib/active_fedora/aggregation/decorator_list.rb
|
153
|
+
- lib/active_fedora/aggregation/decorator_with_arguments.rb
|
154
|
+
- lib/active_fedora/aggregation/link_inserter.rb
|
155
|
+
- lib/active_fedora/aggregation/null_proxy.rb
|
156
|
+
- lib/active_fedora/aggregation/ordered_proxy.rb
|
157
|
+
- lib/active_fedora/aggregation/ordered_reader.rb
|
158
|
+
- lib/active_fedora/aggregation/persist_links.rb
|
133
159
|
- lib/active_fedora/aggregation/proxy.rb
|
134
|
-
- lib/active_fedora/aggregation/
|
160
|
+
- lib/active_fedora/aggregation/proxy_owner.rb
|
161
|
+
- lib/active_fedora/aggregation/proxy_repository.rb
|
135
162
|
- lib/active_fedora/aggregation/reflection.rb
|
136
|
-
- lib/active_fedora/aggregation/through_association.rb
|
137
163
|
- lib/active_fedora/aggregation/version.rb
|
164
|
+
- lib/active_fedora/filter.rb
|
165
|
+
- lib/active_fedora/filter/association.rb
|
166
|
+
- lib/active_fedora/filter/builder.rb
|
167
|
+
- lib/active_fedora/filter/reflection.rb
|
138
168
|
homepage: http://github.org/curationexperts/activefedora-aggregation
|
139
169
|
licenses:
|
140
170
|
- APACHE2
|
@@ -155,9 +185,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
185
|
version: '0'
|
156
186
|
requirements: []
|
157
187
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.4.
|
188
|
+
rubygems_version: 2.4.5
|
159
189
|
signing_key:
|
160
190
|
specification_version: 4
|
161
191
|
summary: Aggregations for active-fedora
|
162
192
|
test_files: []
|
163
|
-
has_rdoc:
|
@@ -1,111 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class ProxyContainer < ActiveFedora::Base
|
3
|
-
type ::RDF::Vocab::LDP.IndirectContainer
|
4
|
-
|
5
|
-
attr_writer :parent
|
6
|
-
|
7
|
-
property :membership_resource, predicate: ::RDF::Vocab::LDP.membershipResource
|
8
|
-
property :member_relation, predicate: ::RDF::Vocab::LDP.hasMemberRelation
|
9
|
-
property :inserted_content_relation, predicate: ::RDF::Vocab::LDP.insertedContentRelation
|
10
|
-
|
11
|
-
after_initialize :default_relations
|
12
|
-
|
13
|
-
def parent
|
14
|
-
@parent || raise("Parent hasn't been set on #{self.class}")
|
15
|
-
end
|
16
|
-
|
17
|
-
def default_relations
|
18
|
-
self.member_relation = [::RDF::URI.new("http://pcdm.org/hasMember")] # TODO wrong predicate!
|
19
|
-
self.inserted_content_relation = [::RDF::Vocab::ORE.proxyFor]
|
20
|
-
end
|
21
|
-
|
22
|
-
def first
|
23
|
-
parent.head.target
|
24
|
-
end
|
25
|
-
|
26
|
-
# This can be a very expensive operation. avoid if possible
|
27
|
-
def to_a
|
28
|
-
@target ||= list_of_proxies.map(&:target)
|
29
|
-
end
|
30
|
-
|
31
|
-
def target= (collection)
|
32
|
-
link_target(build_proxies(collection))
|
33
|
-
end
|
34
|
-
|
35
|
-
def target_ids=(object_ids)
|
36
|
-
link_target(build_proxies_with_ids(object_ids))
|
37
|
-
end
|
38
|
-
|
39
|
-
# Set the links on the nodes in the list
|
40
|
-
def link_target(new_proxies)
|
41
|
-
new_proxies.each_with_index do |proxy, idx|
|
42
|
-
proxy.next_id = new_proxies[idx+1].id unless new_proxies.length - 1 <= idx
|
43
|
-
proxy.prev_id = new_proxies[idx-1].id unless idx == 0
|
44
|
-
end
|
45
|
-
|
46
|
-
parent.head = new_proxies.first
|
47
|
-
parent.tail = new_proxies.last
|
48
|
-
parent.proxies = new_proxies
|
49
|
-
end
|
50
|
-
|
51
|
-
# TODO clear out the old proxies (or reuse them)
|
52
|
-
def build_proxies(objects)
|
53
|
-
# need to create the proxies before we can add the links otherwise the linked to resource won't exist
|
54
|
-
objects.map do |object|
|
55
|
-
Proxy.create(id: mint_proxy_id, target: object)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# TODO clear out the old proxies (or reuse them)
|
60
|
-
def build_proxies_with_ids(object_ids)
|
61
|
-
# need to create the proxies before we can add the links otherwise the linked to resource won't exist
|
62
|
-
object_ids.map do |file_id|
|
63
|
-
Proxy.create(id: mint_proxy_id, target_id: file_id)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def target_ids
|
68
|
-
list_of_proxies.map(&:target_id)
|
69
|
-
end
|
70
|
-
|
71
|
-
# @param obj [ActiveFedora::Base]
|
72
|
-
def << (obj)
|
73
|
-
node = if persisted?
|
74
|
-
parent.proxies.create(id: mint_proxy_id, target: obj, prev: parent.tail)
|
75
|
-
else
|
76
|
-
parent.proxies.build(id: mint_proxy_id, target: obj, prev: parent.tail)
|
77
|
-
end
|
78
|
-
# set the old tail, if present, to have this new proxy as its next
|
79
|
-
parent.tail.update(next: node) if parent.tail
|
80
|
-
# update the tail to point at the new node
|
81
|
-
parent.tail = node
|
82
|
-
# if this is the first node, set it to be the head
|
83
|
-
parent.head = node unless parent.head
|
84
|
-
reset_target!
|
85
|
-
end
|
86
|
-
|
87
|
-
def mint_proxy_id
|
88
|
-
"#{id}/#{SecureRandom.uuid}"
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.find_or_initialize(id)
|
92
|
-
find(id)
|
93
|
-
rescue ActiveFedora::ObjectNotFoundError
|
94
|
-
new(id)
|
95
|
-
end
|
96
|
-
|
97
|
-
def reset_target!
|
98
|
-
@proxy_list = nil
|
99
|
-
@target = nil
|
100
|
-
end
|
101
|
-
|
102
|
-
# return the proxies in order
|
103
|
-
def list_of_proxies
|
104
|
-
@proxy_list ||= if parent.head
|
105
|
-
parent.head.as_list
|
106
|
-
else
|
107
|
-
[]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class ThroughAssociation
|
3
|
-
def initialize(owner, reflection)
|
4
|
-
@owner, @reflection = owner, reflection
|
5
|
-
end
|
6
|
-
|
7
|
-
# has_one :aggregation
|
8
|
-
# has_many :generic_files, through: :aggregation
|
9
|
-
def reader
|
10
|
-
@file_association ||= Association.new(@owner, @reflection)
|
11
|
-
end
|
12
|
-
|
13
|
-
def writer(vals)
|
14
|
-
reader.target = vals
|
15
|
-
end
|
16
|
-
|
17
|
-
def ids_writer(vals)
|
18
|
-
reader.target_ids = vals
|
19
|
-
end
|
20
|
-
|
21
|
-
def ids_reader
|
22
|
-
reader.target_ids
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|