hydra-works 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +17 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +14 -0
  6. data/CONTRIBUTING.md +115 -0
  7. data/Gemfile +14 -0
  8. data/LICENSE +16 -0
  9. data/README.md +80 -0
  10. data/Rakefile +23 -0
  11. data/hydra-works.gemspec +33 -0
  12. data/lib/hydra/works.rb +81 -0
  13. data/lib/hydra/works/models/collection.rb +5 -0
  14. data/lib/hydra/works/models/concerns/aggregates_collections.rb +16 -0
  15. data/lib/hydra/works/models/concerns/aggregates_generic_files.rb +20 -0
  16. data/lib/hydra/works/models/concerns/aggregates_generic_works.rb +20 -0
  17. data/lib/hydra/works/models/concerns/collection_behavior.rb +28 -0
  18. data/lib/hydra/works/models/concerns/generic_file/contained_files.rb +22 -0
  19. data/lib/hydra/works/models/concerns/generic_file/derivatives.rb +32 -0
  20. data/lib/hydra/works/models/concerns/generic_file/mime_types.rb +69 -0
  21. data/lib/hydra/works/models/concerns/generic_file_behavior.rb +25 -0
  22. data/lib/hydra/works/models/concerns/generic_work_behavior.rb +30 -0
  23. data/lib/hydra/works/models/generic_file.rb +17 -0
  24. data/lib/hydra/works/models/generic_work.rb +9 -0
  25. data/lib/hydra/works/processor.rb +9 -0
  26. data/lib/hydra/works/services/collection/add_collection.rb +19 -0
  27. data/lib/hydra/works/services/collection/add_generic_work.rb +19 -0
  28. data/lib/hydra/works/services/collection/add_related_object.rb +19 -0
  29. data/lib/hydra/works/services/collection/get_collections.rb +17 -0
  30. data/lib/hydra/works/services/collection/get_generic_works.rb +17 -0
  31. data/lib/hydra/works/services/collection/get_related_objects.rb +17 -0
  32. data/lib/hydra/works/services/collection/remove_collection.rb +19 -0
  33. data/lib/hydra/works/services/collection/remove_generic_work.rb +20 -0
  34. data/lib/hydra/works/services/collection/remove_related_object.rb +19 -0
  35. data/lib/hydra/works/services/generic_file/add_file.rb +55 -0
  36. data/lib/hydra/works/services/generic_file/add_generic_file.rb +19 -0
  37. data/lib/hydra/works/services/generic_file/add_original_file.rb +11 -0
  38. data/lib/hydra/works/services/generic_file/add_related_object.rb +19 -0
  39. data/lib/hydra/works/services/generic_file/add_versioned_original_file.rb +10 -0
  40. data/lib/hydra/works/services/generic_file/generate/thumbnail.rb +19 -0
  41. data/lib/hydra/works/services/generic_file/get_generic_files.rb +17 -0
  42. data/lib/hydra/works/services/generic_file/get_related_objects.rb +17 -0
  43. data/lib/hydra/works/services/generic_file/remove_generic_file.rb +20 -0
  44. data/lib/hydra/works/services/generic_file/remove_related_object.rb +19 -0
  45. data/lib/hydra/works/services/generic_file/upload_file.rb +32 -0
  46. data/lib/hydra/works/services/generic_work/add_generic_file.rb +19 -0
  47. data/lib/hydra/works/services/generic_work/add_generic_work.rb +19 -0
  48. data/lib/hydra/works/services/generic_work/add_related_object.rb +19 -0
  49. data/lib/hydra/works/services/generic_work/get_generic_files.rb +17 -0
  50. data/lib/hydra/works/services/generic_work/get_generic_works.rb +17 -0
  51. data/lib/hydra/works/services/generic_work/get_related_objects.rb +17 -0
  52. data/lib/hydra/works/services/generic_work/move_generic_file.rb +19 -0
  53. data/lib/hydra/works/services/generic_work/remove_generic_file.rb +20 -0
  54. data/lib/hydra/works/services/generic_work/remove_generic_work.rb +20 -0
  55. data/lib/hydra/works/services/generic_work/remove_related_object.rb +19 -0
  56. data/lib/hydra/works/version.rb +5 -0
  57. data/lib/hydra/works/vocab/works_terms.rb +12 -0
  58. data/spec/fixtures/sample-file.pdf +0 -0
  59. data/spec/fixtures/updated-file.txt +1 -0
  60. data/spec/hydra/works/models/collection_spec.rb +41 -0
  61. data/spec/hydra/works/models/concerns/file/contained_files_spec.rb +113 -0
  62. data/spec/hydra/works/models/concerns/generic_file_behavior_spec.rb +12 -0
  63. data/spec/hydra/works/models/generic_file_spec.rb +45 -0
  64. data/spec/hydra/works/models/generic_work_spec.rb +50 -0
  65. data/spec/hydra/works/services/collection/add_collection_spec.rb +166 -0
  66. data/spec/hydra/works/services/collection/add_generic_work_spec.rb +155 -0
  67. data/spec/hydra/works/services/collection/add_related_object_spec.rb +149 -0
  68. data/spec/hydra/works/services/collection/get_collections_spec.rb +35 -0
  69. data/spec/hydra/works/services/collection/get_generic_works_spec.rb +35 -0
  70. data/spec/hydra/works/services/collection/get_related_objects_spec.rb +49 -0
  71. data/spec/hydra/works/services/collection/remove_collection_spec.rb +133 -0
  72. data/spec/hydra/works/services/collection/remove_generic_work_spec.rb +133 -0
  73. data/spec/hydra/works/services/collection/remove_related_object_spec.rb +128 -0
  74. data/spec/hydra/works/services/generic_file/add_file_spec.rb +28 -0
  75. data/spec/hydra/works/services/generic_file/add_generic_file_spec.rb +174 -0
  76. data/spec/hydra/works/services/generic_file/add_related_object_spec.rb +150 -0
  77. data/spec/hydra/works/services/generic_file/generate/thumbnail_spec.rb +21 -0
  78. data/spec/hydra/works/services/generic_file/get_generic_files_spec.rb +19 -0
  79. data/spec/hydra/works/services/generic_file/get_related_objects_spec.rb +45 -0
  80. data/spec/hydra/works/services/generic_file/remove_generic_file_spec.rb +124 -0
  81. data/spec/hydra/works/services/generic_file/remove_related_object_spec.rb +123 -0
  82. data/spec/hydra/works/services/generic_file/upload_file_spec.rb +82 -0
  83. data/spec/hydra/works/services/generic_work/add_generic_file_spec.rb +156 -0
  84. data/spec/hydra/works/services/generic_work/add_generic_work_spec.rb +157 -0
  85. data/spec/hydra/works/services/generic_work/add_related_object_spec.rb +148 -0
  86. data/spec/hydra/works/services/generic_work/get_generic_files_spec.rb +35 -0
  87. data/spec/hydra/works/services/generic_work/get_generic_works_spec.rb +35 -0
  88. data/spec/hydra/works/services/generic_work/get_related_objects_spec.rb +46 -0
  89. data/spec/hydra/works/services/generic_work/move_generic_file_spec.rb +21 -0
  90. data/spec/hydra/works/services/generic_work/remove_generic_file_spec.rb +132 -0
  91. data/spec/hydra/works/services/generic_work/remove_generic_work_spec.rb +133 -0
  92. data/spec/hydra/works/services/generic_work/remove_related_object_spec.rb +128 -0
  93. data/spec/hydra/works_spec.rb +149 -0
  94. data/spec/spec_helper.rb +40 -0
  95. data/use-cases/conference_event_use_case.md +16 -0
  96. data/use-cases/lafayette_college_geospatial_use_case.md +80 -0
  97. data/use-cases/northwestern_adminset_use-case.md +19 -0
  98. data/use-cases/northwestern_displayset_use_case.md +23 -0
  99. data/use-cases/northwestern_playlist_use_case.md +21 -0
  100. data/use-cases/princeton_book_use_case.md +117 -0
  101. data/use-cases/scholarsphere_use_case.md +32 -0
  102. data/use-cases/stanford_data_model_use_case.md +86 -0
  103. data/use-cases/ucin_linked_resource_use_case.md +21 -0
  104. metadata +338 -0
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hydra::Works do
4
+
5
+ let(:works_coll) { Hydra::Works::Collection.create }
6
+ let(:works_gwork) { Hydra::Works::GenericWork::Base.create }
7
+ let(:works_gfile) { Hydra::Works::GenericFile::Base.create }
8
+
9
+ let(:pcdm_coll) { Hydra::PCDM::Collection.create }
10
+ let(:pcdm_obj) { Hydra::PCDM::Object.create }
11
+ let(:pcdm_file) { Hydra::PCDM::File.new }
12
+
13
+ describe 'Validations' do
14
+
15
+ describe "#collection?" do
16
+ it "should return true for a works collection" do
17
+ expect( Hydra::Works.collection? works_coll ).to be true
18
+ end
19
+
20
+ it "should return false for a works generic work" do
21
+ expect( Hydra::Works.collection? works_gwork ).to be false
22
+ end
23
+
24
+ it "should return false for a works generic file" do
25
+ expect( Hydra::Works.collection? works_gfile ).to be false
26
+ end
27
+
28
+ it "should return false for a pcdm collection" do
29
+ expect( Hydra::Works.collection? pcdm_coll ).to be false
30
+ end
31
+
32
+ it "should return false for a pcdm object" do
33
+ expect( Hydra::Works.collection? pcdm_obj ).to be false
34
+ end
35
+
36
+ it "should return false for a pcdm file" do
37
+ expect( Hydra::Works.collection? pcdm_file ).to be false
38
+ end
39
+ end
40
+
41
+ describe "#generic_work?" do
42
+ it "should return false for a works collection" do
43
+ expect( Hydra::Works.generic_work? works_coll ).to be false
44
+ end
45
+
46
+ it "should return true for a works generic work" do
47
+ expect( Hydra::Works.generic_work? works_gwork ).to be true
48
+ end
49
+
50
+ it "should return false for a works generic file" do
51
+ expect( Hydra::Works.generic_work? works_gfile ).to be false
52
+ end
53
+
54
+ it "should return false for a pcdm collection" do
55
+ expect( Hydra::Works.generic_work? pcdm_coll ).to be false
56
+ end
57
+
58
+ it "should return false for a pcdm object" do
59
+ expect( Hydra::Works.generic_work? pcdm_obj ).to be false
60
+ end
61
+
62
+ it "should return false for a pcdm file" do
63
+ expect( Hydra::Works.generic_work? pcdm_file ).to be false
64
+ end
65
+ end
66
+
67
+ describe "#generic_file?" do
68
+ it "should return false for a works collection" do
69
+ expect( Hydra::Works.generic_file? works_coll ).to be false
70
+ end
71
+
72
+ it "should return false for a works generic work" do
73
+ expect( Hydra::Works.generic_file? works_gwork ).to be false
74
+ end
75
+
76
+ it "should return true for a works generic file" do
77
+ expect( Hydra::Works.generic_file? works_gfile ).to be true
78
+ end
79
+
80
+ it "should return false for a pcdm collection" do
81
+ expect( Hydra::Works.generic_file? pcdm_coll ).to be false
82
+ end
83
+
84
+ it "should return false for a pcdm object" do
85
+ expect( Hydra::Works.generic_file? pcdm_obj ).to be false
86
+ end
87
+
88
+ it "should return false for a pcdm file" do
89
+ expect( Hydra::Works.generic_file? pcdm_file ).to be false
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "Hydra::PCDM" do
95
+ describe "#collection?" do
96
+ it "should return true for a works collection" do
97
+ expect( Hydra::PCDM.collection? works_coll ).to be true
98
+ end
99
+
100
+ it "should return false for a works generic work" do
101
+ expect( Hydra::PCDM.collection? works_gwork ).to be false
102
+ end
103
+
104
+ it "should return false for a works generic file" do
105
+ expect( Hydra::PCDM.collection? works_gfile ).to be false
106
+ end
107
+
108
+ it "should return true for a pcdm collection" do
109
+ expect( Hydra::PCDM.collection? pcdm_coll ).to be true
110
+ end
111
+
112
+ it "should return false for a pcdm object" do
113
+ expect( Hydra::PCDM.collection? pcdm_obj ).to be false
114
+ end
115
+
116
+ it "should return false for a pcdm file" do
117
+ expect( Hydra::PCDM.collection? pcdm_file ).to be false
118
+ end
119
+ end
120
+
121
+ describe "#object?" do
122
+ it "should return false for a works collection" do
123
+ expect( Hydra::PCDM.object? works_coll ).to be false
124
+ end
125
+
126
+ it "should return true for a works generic work" do
127
+ expect( Hydra::PCDM.object? works_gwork ).to be true
128
+ end
129
+
130
+ it "should return true for a works generic file" do
131
+ expect( Hydra::PCDM.object? works_gfile ).to be true
132
+ end
133
+
134
+ it "should return false for a pcdm collection" do
135
+ expect( Hydra::PCDM.object? pcdm_coll ).to be false
136
+ end
137
+
138
+ it "should return true for a pcdm object" do
139
+ expect( Hydra::PCDM.object? pcdm_obj ).to be true
140
+ end
141
+
142
+ it "should return false for a pcdm file" do
143
+ expect( Hydra::PCDM.object? pcdm_file ).to be false
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,40 @@
1
+ ENV['environment'] ||= 'test'
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
5
+ require 'bundler/setup'
6
+ Bundler.setup
7
+
8
+ require 'hydra/works'
9
+ require 'pry' unless ENV['CI']
10
+ require 'active_fedora'
11
+ require 'active_fedora/cleaner'
12
+
13
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
14
+
15
+ # require 'http_logger'
16
+ # HttpLogger.logger = Logger.new(STDOUT)
17
+ # HttpLogger.ignore = [/localhost:8983\/solr/]
18
+ # HttpLogger.colorize = false
19
+ # HttpLogger.log_headers = true
20
+
21
+ RSpec.configure do |config|
22
+ config.color = true
23
+ config.tty = true
24
+
25
+ # Uncomment the following line to get errors and backtrace for deprecation warnings
26
+ # config.raise_errors_for_deprecations!
27
+
28
+ # Use the specified formatter
29
+ config.formatter = :progress
30
+
31
+ config.before :each do |example|
32
+ unless example.metadata[:no_clean]
33
+ ActiveFedora::Cleaner.clean!
34
+ end
35
+ end
36
+ end
37
+
38
+ def fixture_path
39
+ File.expand_path("../fixtures", __FILE__)
40
+ end
@@ -0,0 +1,16 @@
1
+ #### Sponsors
2
+ UC San Diego Library (Metadata Services): @MetadataDeluxe @Juliane666 @remerjohnson
3
+
4
+ #### Goal and Reason
5
+ Given an event (a conference), with many sub-events with many creative works created by many entities about related but different topics:
6
+
7
+ As a user:
8
+ * I want to see a hierarchical list of all sub-events that can sorted by date, title, or creator while maintaining the order of any sub-components (for example, parts 1-3 of a single music performance are kept together and in order).
9
+ * I want to see a timeline of events with dates and times, so that there is greater context for the event.
10
+ * I want to see descriptive metadata for the entire event (the conference).
11
+ * I want to see descriptive metadata for each sub-event (for example, a musical demonstration as part of a presentation).
12
+ * I want to see technical metadata for each file (let's say an .mp3).
13
+ * I want to see components by descriptive characteristics, so that I could for example access all the performances of electronic percussion music.
14
+
15
+
16
+ ![screenshot from 2014-10-17 14 09 41](https://cloud.githubusercontent.com/assets/5183580/4686135/0d27e954-5642-11e4-9519-2236a6e967d7.png)
@@ -0,0 +1,80 @@
1
+ # Lafayette College Libraries Geospatial Data Set Use Case
2
+
3
+ Sponsor: @jrgriffiniii
4
+
5
+ ```
6
+ Given an Esri Shapefile containing many Features
7
+ As a user
8
+ I want to view all point Features in the Shapefile on a raster base layer
9
+ And I want to view all polygon Features in the Shapefile on a raster base layer
10
+ And I want to discover all Features for the related Shapefile
11
+ And I want to discover all Features using a box bounded by geospatial coordinates
12
+ And I want to discover the Shapefile using MODS element values
13
+ And I want to discover the Shapefile using a box bounded by geospatial coordinates
14
+ ```
15
+
16
+ ```
17
+ Given an Esri Shapefile containing many Features
18
+ As a curator
19
+ Or as an archivist
20
+ I want to create MODS element values for Esri Shapefiles
21
+ And I want to edit MODS element values for Esri Shapefiles
22
+ And I want to delete MODS element values for Esri Shapefiles
23
+ ```
24
+
25
+ ```
26
+ Given an Esri Shapefile containing many Features
27
+ And given a TIFF image
28
+ As a curator
29
+ Or as an archivist
30
+ I want to reference a TIFF image from a Feature
31
+ And I want to view a thumbnail for the referenced TIFF image when I click on the Feature
32
+ ```
33
+
34
+ ```
35
+ Given a GeoTIFF referencing many geospatial coordinates
36
+ As a user
37
+ I want to view the GeoTIFF image on a raster base layer
38
+ And I want to discover the GeoTIFF using a box bounded by geospatial coordinates
39
+ And I want to discover the GeoTIFF using MODS element values
40
+ ```
41
+
42
+ ```
43
+ Given a GeoTIFF referencing many geospatial coordinates
44
+ As a curator
45
+ Or as an archivist
46
+ I want to create MODS element values for Esri Shapefiles
47
+ And I want to edit MODS element values for Esri Shapefiles
48
+ And I want to delete MODS element values for Esri Shapefiles
49
+ ```
50
+
51
+ ```
52
+ Given an Esri Shapefile containing many Features
53
+ As a user
54
+ I want to view all point Features in the Shapefile and the GeoTIFF image on a raster base layer
55
+ And I want to view all polygon Features in the Shapefile and the GeoTIFF image on a raster base layer
56
+ ```
57
+
58
+ ## Esri Shapefile
59
+
60
+ Characteristics:
61
+
62
+ * Descriptive MD
63
+ * We've been working with the MODS
64
+ * Rights MD
65
+ * Geospatial MD
66
+ * Ideally, this should be managed within either FGDC XML Documents or in compliance with ISO 19139
67
+ * Keyhole Markup Language (KML) Document
68
+ * GeoJSON Objects
69
+ * Preferably, these would be deprecated in favor of [TopoJSON Objects](https://github.com/mbostock/topojson/wiki)
70
+
71
+ ## GeoTIFF Image
72
+
73
+ Characteristics:
74
+
75
+ * Descriptive MD
76
+ * We've been working with the MODS
77
+ * Rights MD
78
+ * Technical MD
79
+ * Structured using a METS-PREMIS profile and extracted using the FITS
80
+ * Perhaps gdalinfo could also be integrated for additional metadata?
@@ -0,0 +1,19 @@
1
+ Northwestern AdminSet Use Case
2
+ Sponsor: @julesies
3
+
4
+ Given an administrative grouping of items
5
+ As an administrative unit that is ultimately responsible for managing. The set itself helps to manage the items within it.
6
+ I want to maintain the following relationships of an AdminSet.
7
+ Can not contain other sets of any kind
8
+ Only staff with permission to create or manage an admin set can do so
9
+ All items must be in an AdminSet (there could be a default collection)
10
+ Items can only be in one AdminSet
11
+ Admin sets contain a set of default values (permissions, metadata, etc) that can be applied to new objects in the set
12
+ Any changes to default settings should not automatically change all items in a collection but prompt the user with options
13
+ Can be faceted for discovery (but it would be nice if that was optional)
14
+ Order does not matter
15
+ So that an Administrative Set's primary use is to manage distinct collections of digital objects over time
16
+
17
+ Here are some example object we need to represent, and their characteristics, from least to most complex.
18
+
19
+ AdminSet
@@ -0,0 +1,23 @@
1
+ Northwestern DisplaySets Use Case
2
+ Sponsor: @julesies
3
+
4
+ Given a Display Set is an intellectual grouping of items that a curator (or person who has the rights to) creates
5
+ As an aid in the discovery and presentation of collections of materials.
6
+ The display set is distinct from User Collections because it's primary purpose is the visual display of Display Sets. The Display Set is distinct from an Admin Set because the Display Set itself does not affect items within it.
7
+ I want to maintain the folllowing relationships of a DisplaySet.
8
+ Supports hierarchical display of collections in facets
9
+ Items in a repository may be in more than one Display Set
10
+ Items in a repository do not have to be in a Display Set
11
+ Display Sets can contain other Display Sets
12
+ So that a curator makes a library collection of Maps of Africa, some of which are contained in different collections.
13
+ The Biology Department has a collection of departmental masters theses and wants viewers to navigate the collections via facets like this:
14
+ Biology Department
15
+ Master's Theses
16
+ 1972
17
+ 1973
18
+ 1974
19
+
20
+ Here are some example object we need to represent, and their characteristics, from least to most complex.
21
+
22
+ DisplaySet
23
+ User Collection
@@ -0,0 +1,21 @@
1
+ Northwestern Playlist Use Case
2
+ Sponsor: @julesies
3
+
4
+ Given a User Collection with an intellectual grouping of items
5
+ As a primary list used by individual users to create groups of items or favorites.
6
+ I want to maintain the following relationships of a Nested User Collection.
7
+ A bookmark-like approach to grouping items
8
+ A User Collection can be shared with others in some way or kept private
9
+ Items within User Collections are not governed by the collection in any way
10
+ Items can belong to more than one User Collection
11
+ Items in a repository do not have to belong to any User Collection
12
+ Items can appear in the same User Collection more than once
13
+ Ordered items
14
+ So that a Researcher who creates a group of intellectually related items for a research purpose. Example:
15
+ Professor who creates a group of items for a particular course or presentation. Examples: Art History professor creates an group of images for a lecture. A history professor creates a playlist of audio and video for an entire course.
16
+ Audio and Video playlists.
17
+
18
+ Here are some example object we need to represent, and their characteristics, from least to most complex.
19
+
20
+ Playlist
21
+ User Collection
@@ -0,0 +1,117 @@
1
+ # Princeton Book Use Case
2
+
3
+ Sponsor: @jpstroop
4
+
5
+ ```
6
+ Given a book with many pages, and many images of each page
7
+ As a repository comprised of digitized books and manuscripts
8
+ I want to maintain the relationships between images of a page and technical,
9
+ descriptive, and provenance metadata about each image
10
+ And I want to maintain sorting, label, and other metadata, as well as files
11
+ that represent the whole object in one place
12
+ So that I can have multiple images of a page tied to one instance of a model
13
+ without relying on naming conventions (e.g. jp2_md5_checksum)
14
+ ```
15
+
16
+ Here are some example object we need to represent, and their characteristics, from least to most complex.
17
+
18
+ ## A Photograph or Poster
19
+
20
+ Characteristics:
21
+
22
+ * Descriptive MD
23
+ * Rights MD (rights could theoretically apply at any level but that's not in my use case)
24
+ * Provenance MD
25
+ * A PDF
26
+ * Technical metadata about the PDF
27
+ * Has one or two images (of front and back):
28
+ * A label for each surface
29
+ * A sort integer for each surface
30
+ * A TIFF of each surface
31
+ * Technical MD about the TIFF
32
+ * A JPEG2000 of each surface
33
+ * Technical MD about the JP2
34
+ * OCR of each page potentially in one or more flavors
35
+ * Technical MD about the OCR
36
+
37
+ ## A Book, Manuscript, or Ephemera
38
+
39
+ Characteristics:
40
+
41
+ * Descriptive MD
42
+ * Rights MD (rights could theoretically apply at any level but that's not in my use case)
43
+ * Structural MD
44
+ * Provenance MD
45
+ * A PDF
46
+ * Technical metadata about the PDF
47
+ * Has many pages:
48
+ * A label for each page
49
+ * A sort integer for each page
50
+ * A TIFF of each page
51
+ * Technical MD about the TIFF
52
+ * A JPEG2000 of each page
53
+ * Technical MD about the JP2
54
+ * OCR of each page potentially in one or more flavors
55
+ * Technical MD about the OCR
56
+
57
+ ## A Book Set or (or Multi-part Manuscripts)
58
+
59
+ Characteristics:
60
+
61
+ Can have one or more physical volumes; below assumes multi.
62
+
63
+ * Descriptive MD about the set
64
+ * Rights MD about the set
65
+ * For each member/volume:
66
+ * Descriptive MD
67
+ * Rights MD
68
+ * Structural MD
69
+ * Provenance MD
70
+ * A PDF
71
+ * Technical metadata about the PDF
72
+ * Has many pages:
73
+ * A label for each page
74
+ * A sort integer for each page
75
+ * A TIFF of each page
76
+ * Technical MD about the TIFF
77
+ * A JPEG2000 of each page
78
+ * Technical MD about the JP2
79
+ * OCR of each page potentially in one or more flavors
80
+ * Technical MD about the OCR
81
+
82
+ ## Photo Albums
83
+
84
+ Characteristics:
85
+
86
+ Can have one or more physical volumes. Below assumes this is the case.
87
+
88
+ * Descriptive MD about the set
89
+ * Rights MD about the set
90
+ * For each member/volume:
91
+ * Descriptive MD
92
+ * Rights MD
93
+ * Structural MD
94
+ * Provenance MD
95
+ * A PDF
96
+ * Technical metadata about the PDF
97
+ * Has many pages:
98
+ * A label for each page
99
+ * A sort integer for each page
100
+ * A TIFF of each page
101
+ * Technical MD about the TIFF
102
+ * A JPEG2000 of each page
103
+ * Technical MD about the JP2
104
+ * OCR of each page potentially in one or more flavors
105
+ * Technical MD about the OCR
106
+ * Has many detail images representing individual photos mounted on the page:
107
+ * A label for each page
108
+ * A sort integer for each page
109
+ * A TIFF of each page
110
+ * Technical MD about the TIFF
111
+ * A JPEG2000 of each page
112
+ * Technical MD about the JP2
113
+
114
+
115
+ ## Proposal
116
+
117
+ No doubt there are other ways, but I feel confident that [this approach](https://github.com/projecthydra-labs/hydra-works/issues/9#issuecomment-58511913) would solve all of the above use cases. Validations included in subclasses of Hydra::Work would serve to constrain recursion.