Skip to content

Commit

Permalink
bring hydra works inline with pcdm
Browse files Browse the repository at this point in the history
* validate collections, generic_works, and generic_files (there are known failures)
* refactor file_behavior to generic_file_behavior
* refactor work_behavior to generic_work_behavior
* make setters/getters match pcdm approach
* add tests following the pcdm pattern
* add first take on README
* get active_fedora gem from stable branch
* add hardcoded RDFVocabulary -- need to switch to generated when ready
* remove TODOs and make new issues -- A few TODOs remain for known issues in progress.  They identify the location where work is actively being done.  They are all marked with issue numbers.
  • Loading branch information
elrayle committed May 13, 2015
1 parent d11976a commit f5980a8
Show file tree
Hide file tree
Showing 18 changed files with 1,179 additions and 274 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ source 'https://rubygems.org'
gemspec

gem 'activefedora-aggregation', github: 'projecthydra-labs/activefedora-aggregation'
gem 'active-fedora', github: 'projecthydra/active_fedora', branch: 'indirectly_contains'
gem 'active-fedora', github: 'projecthydra/active_fedora'
gem 'hydra-pcdm', github: 'projecthydra-labs/hydra-pcdm'
gem 'slop', '~> 3.6' # For byebug

Expand Down
95 changes: 89 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,93 @@
## What is this?
# Hydra::Works
[![Build Status](https://travis-ci.org/projecthydra-labs/hydra-works.svg?branch=master)](https://travis-ci.org/projecthydra-labs/hydra-works)
[![Coverage Status](https://coveralls.io/repos/projecthydra-labs/hydra-works/badge.svg?branch=master)](https://coveralls.io/r/projecthydra-labs/hydra-works?branch=master)

This is a project to establish a standard base data model for Hydra and perhaps other Fedora projects.
Hydra implementation of a works model based on the [Portland Common Data Model](https://github.com/projecthydra-labs/hydra-pcdm) (PCDM).

It is currently in _MAJOR_ flux and should not be used for code you care about.

It currently works for ActiveFedora 9 (Fedora 4).
## Installation

## Application Profile
https://docs.google.com/document/d/1o-Iq1oKN_W5NXXDQC81pxkhibOz_AhZlY7IShxPTR5M/edit
Add these lines to your application's Gemfile:

```ruby
gem 'active-fedora', github: 'projecthydra/active_fedora' # hydra-pcdm requires an unreleased version of ActiveFedora
gem 'hydra-pcdm', github: 'projecthydra-labs/hydra-pcdm'
gem 'hydra-works', github: 'projecthydra-labs/hydra-works'
```

Substitute another branch name for 'master' to test out a branch under development.
<!-- Temporarily comment out until gem is published.
gem 'hydra-pcdm'
-->

And then execute:
```
$ bundle
```
<!-- Temporarily comment out until gem is published.
Or install it yourself as:
$ gem install hydra-works
-->

## Access Controls
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

## Hydra Works Model

PCDM Reference: [Portland Common Data Model](https://wiki.duraspace.org/x/9IoOB)

![Hydra Works Model Definition](https://docs.google.com/presentation/d/1d43d5o2d0x6NyI1tjjuJN6BDI9F9XYxZ1_9_EoZbAyE/edit#slide=id.p8)


## Usage

Hydra-works provides three classes:
```
Hydra::Works::Collection - a collection aggregates collections and generic works
Hydra::Works::GenericWork - a generic work aggregates generic works and generic files
Hydra::Works::GenericFile - a generic file aggregates generic files and contains pcdm files
```

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.

Typically usage involves extending the behavior provided by this gem. In your application you can write something like this:

```ruby

class Collection < ActiveFedora::Base
include Hydra::PCDM::CollectionBehavior
include Hydra::Works::CollectionBehavior
end

class BookWork < ActiveFedora::Base
include Hydra::PCDM::ObjectBehavior
include Hydra::Works::GenericWorkBehavior
end

class BookFiles < ActiveFedora::Base
include Hydra::PCDM::ObjectBehavior
include Hydra::Works::GenericFileBehavior
end


c1 = Collection.create
bw1 = BookWork.create
bf1 = BookFiles.create

bf1.save
bw1.generic_files = [bf1]
bw1.save
c1.generic_works = [bw1]
# c1.members << b1 # This should work in the future
c1.save


# This section waiting on https://github.com/projecthydra-labs/hydra-pcdm/pull/52
# f1 = b1.files.build
# f1.conent = "The quick brown fox jumped over the lazy dog."
# b1.save
```

## How to contribute
If you'd like to contribute to this effort, please check out the [Contributing Guide](CONTRIBUTING.md)
35 changes: 32 additions & 3 deletions lib/hydra/works.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,44 @@
module Hydra
module Works

# vocabularies
autoload :RDFVocabularies, 'hydra/works/vocab/works_terms'

# models
autoload :Collection, 'hydra/works/models/collection'
autoload :GenericWork, 'hydra/works/models/generic_work'
autoload :GenericFile, 'hydra/works/models/generic_file'

#behaviors
autoload :CollectionBehavior, 'hydra/works/models/concerns/collection_behavior'
autoload :WorkBehavior, 'hydra/works/models/concerns/work_behavior'
autoload :FileBehavior, 'hydra/works/models/concerns/file_behavior'

autoload :GenericWorkBehavior, 'hydra/works/models/concerns/generic_work_behavior'
autoload :GenericFileBehavior, 'hydra/works/models/concerns/generic_file_behavior'


# model validations
def self.collection? collection
return false unless collection.respond_to? :type
# collection.type.include? RDFVocabularies::WorksTerms.Collection

# TODO check for works collection instead of pcdm collection (see issue #71)
Hydra::PCDM.collection? collection
end

def self.generic_work? generic_work
return false unless generic_work.respond_to? :type
# generic_work.type.include? RDFVocabularies::WorksTerms.GenericWork

# TODO check for works generic_work instead of pcdm object (see issue #71)
Hydra::PCDM.object? generic_work
end

def self.generic_file? generic_file
return false unless generic_file.respond_to? :type
# generic_file.type.include? RDFVocabularies::WorksTerms.GenericFile

# TODO check for works generic_work instead of pcdm object (see issue #71)
Hydra::PCDM.object? generic_file
end

end
end
59 changes: 27 additions & 32 deletions lib/hydra/works/models/concerns/collection_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,50 @@ module CollectionBehavior
extend ActiveSupport::Concern
include Hydra::PCDM::CollectionBehavior

# TODO: Is there a separate HydraWorks ontology or are works terms and properties defined in PCDM ontology?
# TODO: Extend rdf type to include HydraWorks.Collection
# TODO: Extend rdf type to include RDFVocabularies::WorksTerms.Collection (see issue #71)
# included do
# type RDFVocabularies::WorksTerms.Collection
# end

# behavior:
# NOTE: Hydra::PCDM::Collection can aggregate Hydra::Works::Collection because Hydra::Works::Collection inherits
# from Hydra::PCDM::Collection TODO: Need to test this.
# 1) Hydra::Works::Collection can NOT aggregate Hydra::PCDM::Collection unless it is also a Hydra::Works::Collection
# 2) Hydra::Works::Collection can aggregate Hydra::Works::Collection
# 3) Hydra::Works::Collection can aggregate Hydra::Works::GenericWork
# 1) Hydra::Works::Collection can aggregate Hydra::Works::Collection
# 2) Hydra::Works::Collection can aggregate Hydra::Works::GenericWork

# 3) Hydra::Works::Collection can NOT aggregate Hydra::PCDM::Collection unless it is also a Hydra::Works::Collection
# 4) Hydra::Works::Collection can NOT aggregate Hydra::Works::GenericFile
# 5) Hydra::Works::Collection can NOT aggregate non-PCDM object
# 6) Hydra::Works::Collection can NOT contain Hydra::PCDM::File
# 7) Hydra::Works::Collection can NOT contain Hydra::Works::File

# 8) Hydra::Works::Collection can have descriptive metadata
# 9) Hydra::Works::Collection can have access metadata
# TODO: add code to enforce behavior rules

# TODO Need allow both generic works and collections to
# def collections= collections
# raise ArgumentError, "each collection must be a Hydra::Works::Collection" unless
# collections.all? { |c| c.is_a? Hydra::Works::Collection }
# self.members = self.generic_works + collections
# end

# def collections
# TODO: Not sure how to handle coll1.collections << new_collection. (see issue #45)
# Want to override << on coll1.collections to check that new_work Hydra::Works.collection?
# TODO: Not sure how to handle coll1.generic_works << new_generic_work. (see issue #45)
# Want to override << on coll1.generic_works to check that new_work Hydra::Works.generic_work?

# # TODO Should this just inherit from PCDM or is it significant to check for Hydra::Works::Collection instead of
# # the inherited Hydra::PCDM::Collection

# # TODO: query fedora for collection id && hasMember && rdf_type == RDFVocabularies::HydraWorksTerms.Collection
# end

def generic_works= works
# check that object is an instance of Hydra::Works::GenericWork
raise ArgumentError, "each object must be a Hydra::Works::GenericWork" unless
works.all? { |o| o.is_a? Hydra::Works::GenericWork }
self.members = works
def collections= collections
raise ArgumentError, "each collection must be a hydra works collection" unless collections.all? { |c| Hydra::Works.collection? c }
raise ArgumentError, "a collection can't be an ancestor of itself" if collection_ancestor?(collections)
self.members = self.generic_works + collections
end

def generic_works
# TODO: query fedora for collection id && hasMember && rdf_type == RDFVocabularies::HydraWorksTerms.Object
self.members
def collections
members.to_a.select { |m| Hydra::Works.collection? m }
end

def generic_works= generic_works
raise ArgumentError, "each generic_work must be a hydra works generic work" unless generic_works.all? { |w| Hydra::Works.generic_work? w }
self.members = self.collections + generic_works
end

# TODO: RDF metadata can be added using property definitions. -- inherit from Hydra::PCDM::Collection???
# * How to distinguish between descriptive and access metadata?
# * Are there any default properties to set for Collection's descriptive metadata?
# * Are there any default properties to set for Collection's access metadata?
# * Is there a way to override default properties defined in this class?
def generic_works
members.to_a.select { |m| Hydra::Works.generic_work? m }
end

end
end
44 changes: 0 additions & 44 deletions lib/hydra/works/models/concerns/file_behavior.rb

This file was deleted.

38 changes: 38 additions & 0 deletions lib/hydra/works/models/concerns/generic_file_behavior.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Hydra::Works
module GenericFileBehavior
extend ActiveSupport::Concern
include Hydra::PCDM::ObjectBehavior

# TODO: Extend rdf type to include RDFVocabularies::HydraWorks.GenericFile (see issue #71)
# included do
# type RDFVocabularies::WorksTerms.GenericFile
# end

# behavior:
# 1) Hydra::Works::GenericFile can contain (pcdm:hasFile) Hydra::PCDM::File (inherits from Hydra::PCDM::Object)
# 2) Hydra::Works::GenericFile can contain (pcdm:hasRelatedFile) Hydra::PCDM::File (inherits from Hydra::PCDM::Object)
# 3) Hydra::Works::GenericFile can aggregate (pcdm:hasMember) Hydra::Works::GenericFile

# 4) Hydra::Works::GenericFile can NOT aggregate anything else

# 5) Hydra::Works::GenericFile can have descriptive metadata
# 6) Hydra::Works::GenericFile can have access metadata



# TODO: Not sure how to handle work1.generic_files << new_generic_file. (see issue #45)
# Want to override << on work1.generic_files to check that new_work Hydra::Works.generic_file?


def generic_files= generic_files
raise ArgumentError, "each generic_file must be a hydra works generic file" unless generic_files.all? { |w| Hydra::Works.generic_file? w }
raise ArgumentError, "a generic file can't be an ancestor of itself" if object_ancestor?(generic_files)
self.members = generic_files
end

def generic_files
members.to_a.select { |m| Hydra::Works.generic_file? m }
end

end
end
58 changes: 58 additions & 0 deletions lib/hydra/works/models/concerns/generic_work_behavior.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module Hydra::Works
module GenericWorkBehavior
extend ActiveSupport::Concern
include Hydra::PCDM::ObjectBehavior

# TODO: Extend rdf type to include RDFVocabularies::WorksTerms.GenericWork (see issue #71)
# included do
# type RDFVocabularies::WorksTerms.GenericWork
# end


# behavior:
# 1) Hydra::Works::GenericWork can aggregate Hydra::Works::GenericWork
# 2) Hydra::Works::GenericWork can aggregate Hydra::Works::GenericFile

# 3) Hydra::Works::GenericWork can NOT aggregate Hydra::PCDM::Collection
# 4) Hydra::Works::GenericWork can NOT aggregate Hydra::Works::Collection
# 5) Hydra::Works::GenericWork can NOT aggregate Works::Object unless it is also a Hydra::Works::GenericFile
# 6) Hydra::Works::GenericWork can NOT contain PCDM::File
# 7) Hydra::Works::GenericWork can NOT aggregate non-PCDM object

# 8) Hydra::Works::GenericWork can NOT contain Hydra::Works::File

# 9) Hydra::Works::GenericWork can have descriptive metadata
# 10) Hydra::Works::GenericWork can have access metadata


# TODO: Not sure how to handle work1.generic_works << new_generic_work. (see issue #45)
# Want to override << on work1.generic_works to check that new_work Hydra::Works.generic_work?
# TODO: Not sure how to handle work1.generic_files << new_generic_file. (see issue #45)
# Want to override << on work1.generic_files to check that new_work Hydra::Works.generic_file?


def generic_works= generic_works
raise ArgumentError, "each generic_work must be a hydra works generic work" unless generic_works.all? { |w| Hydra::Works.generic_work? w }
raise ArgumentError, "a generic work can't be an ancestor of itself" if object_ancestor?(generic_works)
self.members = self.generic_files + generic_works
end

def generic_works
members.to_a.select { |m| Hydra::Works.generic_work? m }
end

def generic_files= generic_files
raise ArgumentError, "each generic_file must be a hydra works generic file" unless generic_files.all? { |w| Hydra::Works.generic_file? w }
self.members = self.generic_works + generic_files
end

def generic_files
members.to_a.select { |m| Hydra::Works.generic_file? m }
end

def contains= files
raise NoMethodError, "works can not contain files"
end

end
end

0 comments on commit f5980a8

Please sign in to comment.