hydra-pcdm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +26 -0
  4. data/.travis.yml +14 -0
  5. data/CONTRIBUTING.md +115 -0
  6. data/Gemfile +13 -0
  7. data/LICENSE +12 -0
  8. data/README.md +87 -0
  9. data/Rakefile +20 -0
  10. data/config/jetty.yml +6 -0
  11. data/hydra-pcdm.gemspec +30 -0
  12. data/lib/hydra/pcdm/collection_indexer.rb +12 -0
  13. data/lib/hydra/pcdm/models/collection.rb +6 -0
  14. data/lib/hydra/pcdm/models/concerns/collection_behavior.rb +79 -0
  15. data/lib/hydra/pcdm/models/concerns/object_behavior.rb +104 -0
  16. data/lib/hydra/pcdm/models/file.rb +20 -0
  17. data/lib/hydra/pcdm/models/object.rb +6 -0
  18. data/lib/hydra/pcdm/object_indexer.rb +10 -0
  19. data/lib/hydra/pcdm/services/collection/add_collection.rb +20 -0
  20. data/lib/hydra/pcdm/services/collection/add_object.rb +19 -0
  21. data/lib/hydra/pcdm/services/collection/add_related_object.rb +21 -0
  22. data/lib/hydra/pcdm/services/collection/get_collections.rb +18 -0
  23. data/lib/hydra/pcdm/services/collection/get_objects.rb +18 -0
  24. data/lib/hydra/pcdm/services/collection/get_related_objects.rb +17 -0
  25. data/lib/hydra/pcdm/services/collection/remove_collection.rb +36 -0
  26. data/lib/hydra/pcdm/services/collection/remove_object.rb +43 -0
  27. data/lib/hydra/pcdm/services/collection/remove_related_object.rb +36 -0
  28. data/lib/hydra/pcdm/services/file/add_type.rb +20 -0
  29. data/lib/hydra/pcdm/services/file/get_mime_type.rb +11 -0
  30. data/lib/hydra/pcdm/services/object/add_object.rb +20 -0
  31. data/lib/hydra/pcdm/services/object/add_related_object.rb +21 -0
  32. data/lib/hydra/pcdm/services/object/get_objects.rb +18 -0
  33. data/lib/hydra/pcdm/services/object/get_related_objects.rb +17 -0
  34. data/lib/hydra/pcdm/services/object/remove_object.rb +43 -0
  35. data/lib/hydra/pcdm/services/object/remove_related_object.rb +36 -0
  36. data/lib/hydra/pcdm/version.rb +5 -0
  37. data/lib/hydra/pcdm/vocab/ebucore_terms.rb +33 -0
  38. data/lib/hydra/pcdm/vocab/pcdm_terms.rb +87 -0
  39. data/lib/hydra/pcdm/vocab/sweetjpl_terms.rb +10 -0
  40. data/lib/hydra/pcdm.rb +69 -0
  41. data/spec/hydra/pcdm/collection_indexer_spec.rb +26 -0
  42. data/spec/hydra/pcdm/models/collection_spec.rb +82 -0
  43. data/spec/hydra/pcdm/models/file_spec.rb +56 -0
  44. data/spec/hydra/pcdm/models/object_spec.rb +141 -0
  45. data/spec/hydra/pcdm/object_indexer_spec.rb +20 -0
  46. data/spec/hydra/pcdm/services/collection/add_collection_spec.rb +197 -0
  47. data/spec/hydra/pcdm/services/collection/add_object_spec.rb +132 -0
  48. data/spec/hydra/pcdm/services/collection/add_related_object_spec.rb +94 -0
  49. data/spec/hydra/pcdm/services/collection/get_collections_spec.rb +40 -0
  50. data/spec/hydra/pcdm/services/collection/get_objects_spec.rb +40 -0
  51. data/spec/hydra/pcdm/services/collection/get_related_objects_spec.rb +37 -0
  52. data/spec/hydra/pcdm/services/collection/remove_collection_spec.rb +143 -0
  53. data/spec/hydra/pcdm/services/collection/remove_object_spec.rb +180 -0
  54. data/spec/hydra/pcdm/services/collection/remove_related_object_spec.rb +146 -0
  55. data/spec/hydra/pcdm/services/file/add_type_spec.rb +19 -0
  56. data/spec/hydra/pcdm/services/file/get_mime_type_spec.rb +24 -0
  57. data/spec/hydra/pcdm/services/object/add_object_spec.rb +186 -0
  58. data/spec/hydra/pcdm/services/object/add_related_object_spec.rb +94 -0
  59. data/spec/hydra/pcdm/services/object/get_objects_spec.rb +33 -0
  60. data/spec/hydra/pcdm/services/object/get_related_objects_spec.rb +39 -0
  61. data/spec/hydra/pcdm/services/object/remove_object_spec.rb +158 -0
  62. data/spec/hydra/pcdm/services/object/remove_related_object_spec.rb +126 -0
  63. data/spec/hydra/pcdm_spec.rb +56 -0
  64. data/spec/spec_helper.rb +34 -0
  65. metadata +215 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9c4ca4330987a12626e2dd8a45e54d08e83b8c07
4
+ data.tar.gz: 99e3953956fe7a5a45b6c14bbee233d14e32eb2a
5
+ SHA512:
6
+ metadata.gz: 5a0af66d3e277f5d2f05dbb2e96043742f1faeec169641cf64058c3a89dc7762bfd93ca7ed48055c621fa0cc3a463b8492d5dc3d0351a996e248a138c081ae66
7
+ data.tar.gz: 43f4e5f13d121da66b59c54a496b538d2cd8bbb74b4be5fa8bfb60944f793d485313e2aa1d0aec23e5bceb6dbd0a6f4ae09f7eaaff141f355ff913ff650d31bc
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,26 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .idea
24
+ .ruby-gemset
25
+ .ruby-version
26
+ jetty
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ bundler_args: --without debug
5
+ env:
6
+ global:
7
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
8
+ rvm:
9
+ - 2.1
10
+ - 2.2
11
+ - jruby-head
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: jruby-head
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,115 @@
1
+ # How to Contribute
2
+
3
+ We want your help to make Project Hydra great.
4
+ There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
5
+
6
+ ## Hydra Project Intellectual Property Licensing and Ownership
7
+
8
+ All code contributors must have an Individual Contributor License Agreement (iCLA) on file with the Hydra Project Steering Group.
9
+ If the contributor works for an institution, the institution must have a Corporate Contributor License Agreement (cCLA) on file.
10
+
11
+ https://wiki.duraspace.org/display/hydra/Hydra+Project+Intellectual+Property+Licensing+and+Ownership
12
+
13
+ You should also add yourself to the `CONTRIBUTORS.md` file in the root of the project.
14
+
15
+ ## Contribution Tasks
16
+
17
+ * Reporting Issues
18
+ * Making Changes
19
+ * Submitting Changes
20
+ * Merging Changes
21
+
22
+ ### Reporting Issues
23
+
24
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
25
+ * Submit a [Github issue](./issues) by:
26
+ * Clearly describing the issue
27
+ * Provide a descriptive summary
28
+ * Explain the expected behavior
29
+ * Explain the actual behavior
30
+ * Provide steps to reproduce the actual behavior
31
+
32
+ ### Making Changes
33
+
34
+ * Fork the repository on GitHub
35
+ * Create a topic branch from where you want to base your work.
36
+ * This is usually the master branch.
37
+ * To quickly create a topic branch based on master; `git branch fix/master/my_contribution master`
38
+ * Then checkout the new branch with `git checkout fix/master/my_contribution`.
39
+ * Please avoid working directly on the `master` branch.
40
+ * You may find the [hub suite of commands](https://github.com/defunkt/hub) helpful
41
+ * Make commits of logical units.
42
+ * Your commit should include a high level description of your work in HISTORY.textile
43
+ * Check for unnecessary whitespace with `git diff --check` before committing.
44
+ * Make sure your commit messages are [well formed](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
45
+ * If you created an issue, you can close it by including "Closes #issue" in your commit message. See [Github's blog post for more details](https://github.com/blog/1386-closing-issues-via-commit-messages)
46
+
47
+ ```
48
+ Present tense short summary (50 characters or less)
49
+
50
+ More detailed description, if necessary. It should be wrapped to 72
51
+ characters. Try to be as descriptive as you can, even if you think that
52
+ the commit content is obvious, it may not be obvious to others. You
53
+ should add such description also if it's already present in bug tracker,
54
+ it should not be necessary to visit a webpage to check the history.
55
+
56
+ Include Closes #<issue-number> when relavent.
57
+
58
+ Description can have multiple paragraphs and you can use code examples
59
+ inside, just indent it with 4 spaces:
60
+
61
+ class PostsController
62
+ def index
63
+ respond_with Post.limit(10)
64
+ end
65
+ end
66
+
67
+ You can also add bullet points:
68
+
69
+ - you can use dashes or asterisks
70
+
71
+ - also, try to indent next line of a point for readability, if it's too
72
+ long to fit in 72 characters
73
+ ```
74
+
75
+ * Make sure you have added the necessary tests for your changes.
76
+ * Run _all_ the tests to assure nothing else was accidentally broken.
77
+ * When you are ready to submit a pull request
78
+
79
+ ### Submitting Changes
80
+
81
+ * Read the article ["Using Pull Requests"](https://help.github.com/articles/using-pull-requests) on GitHub.
82
+ * Make sure your branch is up to date with its parent branch (i.e. master)
83
+ * `git checkout master`
84
+ * `git pull --rebase`
85
+ * `git checkout <your-branch>`
86
+ * `git rebase master`
87
+ * It is likely a good idea to run your tests again.
88
+ * If you've made more than one commit take a moment to consider whether squashing commits together would help improve their logical grouping.
89
+ * [Detailed Walkthrough of One Pull Request per Commit](http://ndlib.github.io/practices/one-commit-per-pull-request/)
90
+ * `git rebase --interactive HEAD~<number-of-commits>` ([See Github help](https://help.github.com/articles/interactive-rebase))
91
+ * To determine the number of commits on your branch: `git log master..<your-branch> --oneline | wc -l`
92
+ * Squashing your branch's changes into one commit is "good form" and helps the person merging your request to see everything that is going on.
93
+ * Push your changes to a topic branch in your fork of the repository.
94
+ * Submit a pull request from your fork to the project.
95
+
96
+ ### Merging Changes
97
+
98
+ * It is considered "poor from" to merge your own request.
99
+ * Please take the time to review the changes and get a sense of what is being changed. Things to consider:
100
+ * Does the commit message explain what is going on?
101
+ * Does the code changes have tests? _Not all changes need new tests, some changes are refactorings_
102
+ * Does the commit contain more than it should? Are two separate concerns being addressed in one commit?
103
+ * Did the Travis tests complete successfully?
104
+ * If you are uncertain, bring other contributors into the conversation by creating a comment that includes their @username.
105
+ * If you like the pull request, but want others to chime in, create a +1 comment and tag a user.
106
+
107
+ ## New Developers
108
+ A great way to get new developers involved and to learn the process is to have them go through the Hierarchy of Promises and create a pull request to improve it.
109
+
110
+ # Additional Resources
111
+
112
+ * [General GitHub documentation](http://help.github.com/)
113
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
114
+ * [Pro Git](http://git-scm.com/book) is both a free and excellent book about Git.
115
+ * [A Git Config for Contributing](http://ndlib.github.io/practices/my-typical-per-project-git-config/)
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activefedora-aggregation', github: 'projecthydra-labs/activefedora-aggregation'
4
+ gem 'active-fedora', github: 'projecthydra/active_fedora'
5
+
6
+
7
+ unless ENV['CI']
8
+ gem 'pry'
9
+ gem 'pry-byebug'
10
+ end
11
+
12
+ # Specify your gem's dependencies in hydra-pcdm.gemspec
13
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ ##########################################################################
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Hydra::PCDM
2
+ [![Build Status](https://travis-ci.org/projecthydra-labs/hydra-pcdm.svg?branch=master)](https://travis-ci.org/projecthydra-labs/hydra-pcdm)
3
+ [![Coverage Status](https://coveralls.io/repos/projecthydra-labs/hydra-pcdm/badge.svg?branch=master)](https://coveralls.io/r/projecthydra-labs/hydra-pcdm?branch=master)
4
+
5
+ Hydra implementation of Portland Common Data Models (PCDM)
6
+
7
+ ## Installation
8
+
9
+ Add these lines to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'active-fedora', github: 'projecthydra/active_fedora' # hydra-pcdm requires an unreleased version of ActiveFedora
13
+ gem 'hydra-pcdm', github: 'projecthydra-labs/hydra-pcdm'
14
+ ```
15
+
16
+ Substitute another branch name for 'master' to test out a branch under development.
17
+ <!-- Temporarily comment out until gem is published.
18
+ gem 'hydra-pcdm'
19
+ -->
20
+
21
+ And then execute:
22
+ ```
23
+ $ bundle
24
+ ```
25
+ <!-- Temporarily comment out until gem is published.
26
+ Or install it yourself as:
27
+
28
+ $ gem install hydra-pcdm
29
+ -->
30
+
31
+ ## Access Controls
32
+ We are using [Web ACL](http://www.w3.org/wiki/WebAccessControl) as implemented by [hydra-access](https://github.com/projecthydra/hydra-head/tree/master/hydra-access-controls) controls
33
+
34
+ ## PCDM Model
35
+
36
+ Reference: [Portland Common Data Model](https://wiki.duraspace.org/x/9IoOB)
37
+
38
+
39
+ ### Model Definition
40
+
41
+ ![PCDM Model Definition](https://wiki.duraspace.org/download/attachments/68061940/coll-object-file.png?version=1&modificationDate=1425932362178&api=v2)
42
+
43
+
44
+ ### Example
45
+
46
+ To test the model and provide clarity we have included a sample mode that exercises the interfaces provided by the gem.
47
+ The sample model may change over time to reflect the state of the gam and what it supports.
48
+
49
+ ![Sandwich Objet Model](https://docs.google.com/drawings/d/1wI4H3AH9pdIPllKIMO356c1cFHUN57azDlgIqMVODSw/pub?w=1369&h=727)
50
+
51
+ ## Usage
52
+
53
+ Hydra-pcdm provides three classes:
54
+ ```
55
+ Hydra::PCDM::Object
56
+ Hydra::PCDM::Collection
57
+ Hydra::PCDM::File
58
+ ```
59
+
60
+ A `Hydra::PCDM::File` is a NonRDFSource &emdash; a bitstream. You can use this to store content. A PCDM::File is contained by a PCDM::Object. A `File` has some attached technical metadata, but no descriptive metadata. A `Hydra::PCDM::Object` contains files and other objects and may have descriptive metadata. A `Hydra::PCDM::Collection` can contain other `Collection`s or `Object`s but not `File`s. A `Collection` also may have descriptive metadata.
61
+
62
+ Typically usage involves extending the behavior provided by this gem. In your application you can write something like this:
63
+
64
+ ```ruby
65
+
66
+ class Book < ActiveFedora::Base
67
+ include Hydra::PCDM::ObjectBehavior
68
+ end
69
+
70
+ class Collection < ActiveFedora::Base
71
+ include Hydra::PCDM::CollectionBehavior
72
+ end
73
+
74
+ c1 = Collection.create
75
+ b1 = Book.create
76
+
77
+ c1.members = [b1]
78
+ # c1.members << b1 # This should work in the future
79
+ c1.save
80
+
81
+ f1 = b1.files.build
82
+ f1.content = "The quick brown fox jumped over the lazy dog."
83
+ b1.save
84
+ ```
85
+
86
+ ## How to contribute
87
+ If you'd like to contribute to this effort, please check out the [Contributing Guide](CONTRIBUTING.md)
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'jettywrapper'
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ Jettywrapper.hydra_jetty_version = "master"
8
+
9
+ desc 'Spin up hydra-jetty and run specs'
10
+ task ci: ['jetty:clean'] do
11
+ puts 'running continuous integration'
12
+ jetty_params = Jettywrapper.load_config
13
+ jetty_params[:startup_wait]= 90
14
+ error = Jettywrapper.wrap(jetty_params) do
15
+ Rake::Task['spec'].invoke
16
+ end
17
+ raise "test failures: #{error}" if error
18
+ end
19
+
20
+ task default: :ci
data/config/jetty.yml ADDED
@@ -0,0 +1,6 @@
1
+ default:
2
+ startup_wait: 90
3
+ jetty_port: 8983
4
+ java_opts:
5
+ - "-Xmx256m"
6
+ - "-XX:MaxPermSize=128m"
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hydra/pcdm/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hydra-pcdm"
8
+ spec.version = Hydra::PCDM::VERSION
9
+ spec.authors = ["E. Lynette Rayle"]
10
+ spec.email = ["elr37@cornell.edu"]
11
+ spec.summary = %q{Portland Common Data Model (PCDM)}
12
+ spec.description = %q{Portland Common Data Model (PCDM)}
13
+ spec.homepage = "https://github.com/projecthydra-labs/hydra-pcdm"
14
+ spec.license = "APACHE2"
15
+ spec.required_ruby_version = '>= 1.9.3'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'activefedora-aggregation', '~> 0.2.0'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
25
+ spec.add_development_dependency 'jettywrapper', '>= 2.0.0'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'coveralls'
28
+ spec.add_development_dependency 'rspec'
29
+
30
+ end
@@ -0,0 +1,12 @@
1
+ module Hydra::PCDM
2
+ class CollectionIndexer < ObjectIndexer
3
+
4
+ def generate_solr_document
5
+ super.tap do |solr_doc|
6
+ solr_doc["members_ssim"] = object.member_ids
7
+ solr_doc["child_collections_ssim"] = object.child_collections.map { |o| o.id }
8
+ end
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module Hydra::PCDM
2
+ class Collection < ActiveFedora::Base
3
+ include Hydra::PCDM::CollectionBehavior
4
+ end
5
+ end
6
+
@@ -0,0 +1,79 @@
1
+ require 'active_fedora/aggregation'
2
+
3
+ module Hydra::PCDM
4
+ module CollectionBehavior
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ type RDFVocabularies::PCDMTerms.Collection
9
+
10
+ aggregates :members, predicate: RDFVocabularies::PCDMTerms.hasMember,
11
+ class_name: "ActiveFedora::Base"
12
+
13
+ indirectly_contains :related_objects, has_member_relation: RDF::Vocab::ORE.aggregates,
14
+ inserted_content_relation: RDF::Vocab::ORE.proxyFor, class_name: "ActiveFedora::Base",
15
+ through: 'ActiveFedora::Aggregation::Proxy', foreign_key: :target
16
+ end
17
+
18
+ module ClassMethods
19
+ def indexer
20
+ Hydra::PCDM::CollectionIndexer
21
+ end
22
+ end
23
+
24
+ # behavior:
25
+ # 1) Hydra::PCDM::Collection can aggregate (pcdm:hasMember) Hydra::PCDM::Collection (no infinite loop, e.g., A -> B -> C -> A)
26
+ # 2) Hydra::PCDM::Collection can aggregate (pcdm:hasMember) Hydra::PCDM::Object
27
+ # 3) Hydra::PCDM::Collection can aggregate (ore:aggregates) Hydra::PCDM::Object (Object related to the Collection)
28
+
29
+ # 4) Hydra::PCDM::Collection can NOT aggregate non-PCDM object
30
+ # 5) Hydra::PCDM::Collection can NOT contain (pcdm:hasFile) Hydra::PCDM::File
31
+
32
+ # 6) Hydra::PCDM::Collection can have descriptive metadata
33
+ # 7) Hydra::PCDM::Collection can have access metadata
34
+
35
+ def child_collections= collections
36
+ raise ArgumentError, "each collection must be a pcdm collection" unless collections.all? { |c| Hydra::PCDM.collection? c }
37
+ raise ArgumentError, "a collection can't be an ancestor of itself" if collection_ancestor?(collections)
38
+ self.members = objects + collections
39
+ end
40
+
41
+ def child_collections
42
+ members.to_a.select { |m| Hydra::PCDM.collection? m }
43
+ end
44
+
45
+ def objects= objects
46
+ raise ArgumentError, "each object must be a pcdm object" unless objects.all? { |o| Hydra::PCDM.object? o }
47
+ self.members = child_collections + objects
48
+ end
49
+
50
+ def objects
51
+ members.to_a.select { |m| Hydra::PCDM.object? m }
52
+ end
53
+
54
+ def collection_ancestor? collections
55
+ collections.each do |check|
56
+ return true if check.id == self.id
57
+ return true if ancestor?(check)
58
+ end
59
+ false
60
+ end
61
+
62
+ def ancestor? collection
63
+ return true if collection.id == self.id
64
+ return false if collection.child_collections.empty?
65
+ current_collections = collection.child_collections
66
+ next_batch = []
67
+ while !current_collections.empty? do
68
+ current_collections.each do |c|
69
+ return true if c.id == self.id
70
+ next_batch += c.child_collections
71
+ end
72
+ current_collections = next_batch
73
+ end
74
+ false
75
+ end
76
+
77
+ end
78
+ end
79
+
@@ -0,0 +1,104 @@
1
+ require 'active_fedora/aggregation'
2
+
3
+ module Hydra::PCDM
4
+
5
+ # behavior:
6
+ # 1) Hydra::PCDM::Object can aggregate (pcdm:hasMember) Hydra::PCDM::Object
7
+ # 2) Hydra::PCDM::Object can aggregate (ore:aggregates) Hydra::PCDM::Object (Object related to the Object)
8
+ # 3) Hydra::PCDM::Object can contain (pcdm:hasFile) Hydra::PCDM::File
9
+ # 4) Hydra::PCDM::Object can contain (pcdm:hasRelatedFile) Hydra::PCDM::File
10
+ # 5) Hydra::PCDM::Object can NOT aggregate Hydra::PCDM::Collection
11
+ # 6) Hydra::PCDM::Object can NOT aggregate non-PCDM object
12
+ # 7) Hydra::PCDM::Object can have descriptive metadata
13
+ # 8) Hydra::PCDM::Object can have access metadata
14
+ module ObjectBehavior
15
+ extend ActiveSupport::Concern
16
+
17
+ included do
18
+ type RDFVocabularies::PCDMTerms.Object
19
+
20
+ aggregates :members, predicate: RDFVocabularies::PCDMTerms.hasMember,
21
+ class_name: "ActiveFedora::Base"
22
+
23
+ indirectly_contains :related_objects, has_member_relation: RDF::Vocab::ORE.aggregates,
24
+ inserted_content_relation: RDF::Vocab::ORE.proxyFor, class_name: "ActiveFedora::Base",
25
+ through: 'ActiveFedora::Aggregation::Proxy', foreign_key: :target
26
+
27
+ directly_contains :files, has_member_relation: RDFVocabularies::PCDMTerms.hasFile,
28
+ class_name: "Hydra::PCDM::File"
29
+
30
+ end
31
+
32
+ module ClassMethods
33
+ def indexer
34
+ Hydra::PCDM::ObjectIndexer
35
+ end
36
+ end
37
+
38
+ def objects= objects
39
+ raise ArgumentError, "each object must be a pcdm object" unless objects.all? { |o| Hydra::PCDM.object? o }
40
+ raise ArgumentError, "an object can't be an ancestor of itself" if object_ancestor?(objects)
41
+ self.members = objects
42
+ end
43
+
44
+ def objects
45
+ members.to_a.select { |m| Hydra::PCDM.object? m }
46
+ end
47
+
48
+ def object_ancestor? objects
49
+ objects.each do |check|
50
+ return true if check.id == self.id
51
+ return true if ancestor?(check)
52
+ end
53
+ false
54
+ end
55
+
56
+ def ancestor? object
57
+ return true if object.id == self.id
58
+ return false if object.objects.empty?
59
+ current_objects = object.objects
60
+ next_batch = []
61
+ while !current_objects.empty? do
62
+ current_objects.each do |c|
63
+ return true if c.id == self.id
64
+ next_batch += c.objects
65
+ end
66
+ current_objects = next_batch
67
+ end
68
+ false
69
+ end
70
+
71
+ def contains= files
72
+ # check that file is an instance of Hydra::PCDM::File
73
+ raise ArgumentError, "each file must be a pcdm file" unless
74
+ files.all? { |f| Hydra::PCDM.file? f }
75
+ super(files)
76
+ end
77
+
78
+ # Returns directly contained files that have the requested RDF Type
79
+ # @param [RDF::URI] uri for the desired Type
80
+ # @example
81
+ # filter_files_by_type(::RDF::URI("http://pcdm.org/ExtractedText"))
82
+ def filter_files_by_type uri
83
+ self.files.reject do |file|
84
+ file.metadata_node.query(predicate: RDF.type, object: uri).map(&:object).empty?
85
+ end
86
+ end
87
+
88
+ # Finds or Initializes directly contained file with the requested RDF Type
89
+ # @param [RDF::URI] uri for the desired Type
90
+ # @example
91
+ # file_of_type(::RDF::URI("http://pcdm.org/ExtractedText"))
92
+ def file_of_type uri
93
+ matching_files = filter_files_by_type(uri)
94
+ if matching_files.empty?
95
+ file = self.files.build
96
+ Hydra::PCDM::AddTypeToFile.call(file, uri)
97
+ else
98
+ return matching_files.first
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+
@@ -0,0 +1,20 @@
1
+ module Hydra::PCDM
2
+ class File < ActiveFedora::File
3
+ include ActiveFedora::WithMetadata
4
+
5
+ metadata do
6
+ configure type: RDFVocabularies::PCDMTerms.File
7
+ property :label, predicate: ::RDF::RDFS.label
8
+
9
+ property :file_name, predicate: EBUCoreVocabularies::EBUCoreTerms.filename
10
+ property :file_size, predicate: EBUCoreVocabularies::EBUCoreTerms.fileSize
11
+ property :date_created, predicate: EBUCoreVocabularies::EBUCoreTerms.dateCreated
12
+ property :has_mime_type, predicate: EBUCoreVocabularies::EBUCoreTerms.hasMimeType
13
+ property :date_modified, predicate: EBUCoreVocabularies::EBUCoreTerms.dateModified
14
+ property :byte_order, predicate: SweetjplVocabularies::SweetjplTerms.byteOrder
15
+
16
+ # This is a server-managed predicate which means Fedora does not let us change it.
17
+ property :file_hash, predicate: RDF::Vocab::PREMIS.hasMessageDigest
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module Hydra::PCDM
2
+ class Object < ActiveFedora::Base
3
+ include Hydra::PCDM::ObjectBehavior
4
+ end
5
+ end
6
+
@@ -0,0 +1,10 @@
1
+ module Hydra::PCDM
2
+ class ObjectIndexer < ActiveFedora::IndexingService
3
+ def generate_solr_document
4
+ super.tap do |solr_doc|
5
+ solr_doc["objects_ssim"] = object.objects.map { |o| o.id }
6
+ end
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Hydra::PCDM
2
+ class AddCollectionToCollection
3
+
4
+ ##
5
+ # Add a collection to a collection.
6
+ #
7
+ # @param [Hydra::PCDM::Collection] :parent_collection to which to add collection
8
+ # @param [Hydra::PCDM::Collection] :child_collection being added
9
+ #
10
+ # @return [Hydra::PCDM::Collection] the updated pcdm collection
11
+
12
+ def self.call( parent_collection, child_collection )
13
+ raise ArgumentError, "parent_collection must be a pcdm collection" unless Hydra::PCDM.collection? parent_collection
14
+ raise ArgumentError, "child_collection must be a pcdm collection" unless Hydra::PCDM.collection? child_collection
15
+ raise ArgumentError, "a collection can't be an ancestor of itself" if parent_collection.ancestor? child_collection
16
+ parent_collection.members << child_collection
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Hydra::PCDM
2
+ class AddObjectToCollection
3
+
4
+ ##
5
+ # Add an object to a collection.
6
+ #
7
+ # @param [Hydra::PCDM::Collection] :parent_collection to which to add object
8
+ # @param [Hydra::PCDM::Object] :child_object being added
9
+ #
10
+ # @return [Hydra::PCDM::Collection] the updated pcdm collection
11
+
12
+ def self.call( parent_collection, child_object )
13
+ raise ArgumentError, "parent_collection must be a pcdm collection" unless Hydra::PCDM.collection? parent_collection
14
+ raise ArgumentError, "child_object must be a pcdm object" unless Hydra::PCDM.object? child_object
15
+ parent_collection.members << child_object
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module Hydra::PCDM
2
+ class AddRelatedObjectToCollection
3
+
4
+ ##
5
+ # Add a related object to a collection.
6
+ #
7
+ # @param [Hydra::PCDM::Collection] :parent_collection to which to add the related object
8
+ # @param [Hydra::PCDM::Object] :child_related_object being added
9
+ #
10
+ # @return [Hydra::PCDM::Collection] the updated pcdm collection
11
+
12
+ def self.call( parent_collection, child_related_object )
13
+ raise ArgumentError, 'parent_collection must be a pcdm object' unless Hydra::PCDM.collection? parent_collection
14
+ raise ArgumentError, 'child_related_object must be a pcdm object' unless Hydra::PCDM.object? child_related_object
15
+
16
+ # parent_collection.related_objects = parent_collection.related_objects.to_a + child_related_object
17
+ parent_collection.related_objects << child_related_object
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Hydra::PCDM
2
+ class GetCollectionsFromCollection
3
+
4
+ ##
5
+ # Get member collections from a collection in order.
6
+ #
7
+ # @param [Hydra::PCDM::Collection] :parent_collection in which the child collections are members
8
+ #
9
+ # @return [Array<Hydra::PCDM::Collection>] all member collections
10
+
11
+ def self.call( parent_collection )
12
+ raise ArgumentError, "parent_collection must be a pcdm collection" unless Hydra::PCDM.collection? parent_collection
13
+
14
+ parent_collection.child_collections
15
+ end
16
+
17
+ end
18
+ end