uwdc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzZmZTU4NjE2MmIyNDdlYTdiYzI4NjlhNTc0NDNiYTAxYzYyZWZjMw==
5
+ data.tar.gz: !binary |-
6
+ ZGQyOTczOTcxZjlmZTIwNjhkZWFmMDc3YzEzMjE1MjExMmI5ZWI0OA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ODFkNzNlNjVmNThiMDNkNGM1OGMyZGEwMGY1YzM1NWY0NDg2ZDcyODRmNzBj
10
+ NDg4N2I1Zjg5MjA1NjU3OTc4ZWY1MjZkZDc2MjIzYjcyYmQ0ZjgxN2RjMWFl
11
+ NzAyNzFkYWVhNjFkOWZjMmRmZWUyNjUwNGE5YjNkNTA2YTRkMTM=
12
+ data.tar.gz: !binary |-
13
+ ODc5NTM2YzE1OTRmODgzYjJjOTU5MzQ1YmZiOWE5ZDk1Y2Y2YWE4M2UxNGVh
14
+ NWY3MzllYzA3N2QzNzVhZTExOGJiNzRhMWEzMzM4MjgwYzBkMTliZjhhNTVl
15
+ ZDMxNmRlYjM2YTcwNWJjNGExNWQ2ZDg5ZDEzNzUzYTcyZTYwMTM=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p392
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in uwdc.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/uwdc/(.+)\.rb$}) { |m| "spec/models/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Turnip features and steps
10
+ watch(%r{^spec/acceptance/(.+)\.feature$})
11
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
12
+ end
13
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Board of Regents - University of Wisconsin System
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ UWDC
2
+ ====
3
+
4
+ [![Build Status](https://travis-ci.org/ewlarson/uwdc.png)](https://travis-ci.org/ewlarson/uwdc)
5
+ [![Dependency Status](https://gemnasium.com/ewlarson/uwdc.png)](https://gemnasium.com/ewlarson/uwdc)
6
+ [![Code Climate](https://codeclimate.com/github/ewlarson/uwdc.png)](https://codeclimate.com/github/ewlarson/uwdc)
7
+
8
+ ## Synopsis
9
+
10
+ Gem for accessing University of Wisconsin Digital Collection items from our Fedora Commons repository.
11
+
12
+ ## Usage
13
+
14
+ ### METS
15
+ Obtain the METS metadata for a UWDC object.
16
+
17
+ ```ruby
18
+ require 'uwdc'
19
+ mets = UWDC::Mets.new('33QOBSVPJLWEM8S') # Ignoring
20
+ mets.mods
21
+ mets.mods.titles
22
+ ```
23
+
24
+ UWDC METS will contain:
25
+
26
+ * MODS
27
+ * Origin (PREMIS)
28
+ * RELS-EXT
29
+ * FileSec
30
+ * StructMap
31
+
32
+ ### MODS
33
+ Obtain the MODS metadata for a UWDC object.
34
+
35
+ ```ruby
36
+ mods = UWDC::Mods.new('33QOBSVPJLWEM8S')
37
+ mods.titles
38
+ ```
39
+ MODS top-level elements are boiled in Ruby to something more dot-syntax friendly.
40
+
41
+ <table>
42
+ <thead>
43
+ <tr>
44
+ <th>UWDC::Mods method</th>
45
+ <th>MODS Element</th>
46
+ <th>Example output</th>
47
+ </tr>
48
+ </thead>
49
+ <tbody>
50
+ <tr>
51
+ <td>mods.titles</td>
52
+ <td>titleInfo</td>
53
+ <td>["A life idyl", ...]</td>
54
+ </tr>
55
+ <tr>
56
+ <td>mods.names</td>
57
+ <td>name</td>
58
+ <td>[OpenStruct.new(:name, :role), ...]</td>
59
+ </tr>
60
+ <tr>
61
+ <td>mods.dates</td>
62
+ <td>originInfo</td>
63
+ <td>["1869"]</td>
64
+ </tr>
65
+ <tr>
66
+ <td>mods.forms</td>
67
+ <td>physicalDescription</td>
68
+ <td>["text"]</td>
69
+ </tr>
70
+ <tr>
71
+ <td>mods.abstracts</td>
72
+ <td>abstract</td>
73
+ <td>["Green leather with gold stamping...", ...]</td>
74
+ </tr>
75
+ <tr>
76
+ <td>mods.subjects</td>
77
+ <td>subject</td>
78
+ <td>["Bookbinding--Techniques--Gold stamping", ...]</td>
79
+ </tr>
80
+ <tr>
81
+ <td>mods.access_conditions</td>
82
+ <td>accessCondition</td>
83
+ <td>[OpenStruct.new(:rights, :reuse), ...]</td>
84
+ </tr>
85
+ <tr>
86
+ <td>mods.related_items</td>
87
+ <td>relatedItem</td>
88
+ <td>[OpenStruct.new(:label, :name), ...]</td>
89
+ </tr>
90
+ </tbody>
91
+ </table>
92
+
93
+ ```ruby
94
+ # Transform via to_* calls
95
+ # - supports JSON, Ruby and XML
96
+ mods.to_json
97
+ mods.to_ruby
98
+ mods.to_xml
99
+ ```
100
+
101
+ ## Changelog
102
+
103
+ Nothing to mention yet.
104
+
105
+ ## Contributors
106
+
107
+ Eric Larson
108
+
109
+ ## Copyright
110
+
111
+ UWDC © 2013 Board of Regents - University of Wisconsin System. UWDC is licensed under the MIT license. Please see the LICENSE for more information.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
data/lib/uwdc.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'uwdc/version'
2
+ require 'httpclient/include_client'
3
+ require 'httpclient'
4
+ require 'nokogiri'
5
+ require 'json'
6
+ require 'active_support/core_ext/hash'
7
+
8
+ # UWDC
9
+ module UWDC
10
+ XmlNotFound = Class.new(StandardError)
11
+ end
12
+
13
+ require 'uwdc/mets'
14
+ require 'uwdc/mods'
15
+ require 'uwdc/origin'
16
+ require 'uwdc/rels_ext'
17
+ require 'uwdc/file_sec'
18
+ require 'uwdc/struct_map'
19
+ require 'uwdc/display'
20
+ require 'uwdc/dublin_core'
21
+ require 'uwdc/xml'
@@ -0,0 +1,91 @@
1
+ module UWDC
2
+ # Return an object to drive the display of UWDC items
3
+ class Display
4
+
5
+ attr_accessor :mets, :title, :visual_representation
6
+
7
+ def initialize(id, xml=nil)
8
+ @mets = UWDC::Mets.new(id,xml)
9
+ end
10
+
11
+ def use
12
+ {
13
+ "title" => { :view => false, :partial => "text" },
14
+ "visualrepresentation" => { :view => false, :partial => "text" },
15
+ "icon" => { :view => true, :partial => "image" },
16
+ "thumb" => { :view => true, :partial => "image" },
17
+ "reference" => { :view => true, :partial => "image" },
18
+ "large" => { :view => true, :partial => "image" },
19
+ "audiostream" => { :view => true, :partial => "audio" }
20
+ }
21
+ end
22
+
23
+ def cmodels
24
+ {
25
+ "info:fedora/1711.dl:CModelAudio" => { :view => true, :partial => "audio" },
26
+ "info:fedora/1711.dl:CModelAudioStream" => { :view => true, :partial => "audio" },
27
+ "info:fedora/1711.dl:CModelCompositeObject" => { :view => true, :partial => "set" },
28
+ "info:fedora/1711.dl:CModelCollection" => { :view => true, :partial => "collection" },
29
+ "info:fedora/1711.dl:CModelCompositeObject" => { :view => false, :partial => nil },
30
+ "info:fedora/1711.dl:CModelCompositeSequenceObject" => { :view => true, :partial => "image-with-sequence" },
31
+ "info:fedora/1711.dl:CModelFirstClassObject" => { :view => false, :partial => nil },
32
+ "info:fedora/1711.dl:CModelImageWithDefaultRes" => { :view => true, :partial => "image" },
33
+ "info:fedora/1711.dl:CModelImageWithDetail" => { :view => true, :partial => "image-with-detail" },
34
+ "info:fedora/1711.dl:CModelImageWithSequence" => { :view => true, :partial => "image-with-sequence" },
35
+ "info:fedora/1711.dl:CModelImageWithXLarge" => { :view => true, :partial => "image-with-xlarge" },
36
+ "info:fedora/1711.dl:CModelImageWithZoom" => { :view => true, :partial => "image-with-zoom" },
37
+ "info:fedora/1711.dl:CModelSimpleDocument" => { :view => true, :partial => "download" },
38
+ "info:fedora/1711.dl:CModelUWDCObject" => { :view => false, :partial => nil }
39
+ }
40
+ end
41
+
42
+ def files
43
+ @mets.file_sec.files
44
+ end
45
+
46
+ def image_files(model)
47
+ files.select{|file| file.id.include?(model) && use[file.use][:partial] == "image"}
48
+ end
49
+
50
+ def images
51
+ viewable_models.inject({}) do |result, model|
52
+ result[model] = image_files(model)
53
+ result
54
+ end
55
+ end
56
+
57
+ def video
58
+ end
59
+
60
+ def audio
61
+ end
62
+
63
+ def mods
64
+ @mets.mods
65
+ end
66
+
67
+ alias :metadata :mods
68
+
69
+ private
70
+
71
+ def content_models
72
+ @mets.rels_ext.models
73
+ end
74
+
75
+ def viewable_model?(model)
76
+ model.last.detect{|name| cmodels[name][:view] == true}
77
+ end
78
+
79
+ def viewable_models
80
+ content_models.inject([]) do |result, model|
81
+ result << clean_id(model.first) if viewable_model?(model)
82
+ result
83
+ end
84
+ end
85
+
86
+ def clean_id(id)
87
+ clean = id.split("-")
88
+ "#{clean[0]}-#{clean[1]}"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,34 @@
1
+ module UWDC
2
+ # Return dublin core based metadata associated with METS files
3
+ class DublinCore < Mets
4
+ def nodes
5
+ @xml.nodes.xpath("//dmdSec//dc")
6
+ end
7
+
8
+ def titles
9
+ nodes.inject({}) do |result, children|
10
+ result[capture_id(children)] = capture_title(children)
11
+ result
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def capture_id(children)
18
+ fix_id(clean_nodes(children.xpath(".//identifier[1]"))[0])
19
+ end
20
+
21
+ def capture_title(children)
22
+ clean_nodes(children.xpath(".//title[1]"))[0]
23
+ end
24
+
25
+ # @FIXME: UWDC identifiers are all jacked up
26
+ # - mets[@OBJID] => 1711.dl:FJIOAPU6Z7UKR8E
27
+ # - dmdSec[@ID] => x1711-dl_FJIOAPU6Z7UKR8E
28
+ # - mods/identifier[@type='handle'] => 1711.dl/FJIOAPU6Z7UKR8E
29
+ # - mods/recordInfo/recordIdentifier => 1711.dl:FJIOAPU6Z7UKR8E.BIB0ˇ
30
+ def fix_id(id)
31
+ "x#{id.gsub('.','-').gsub(':','_')}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module UWDC
2
+ # Return the METS files
3
+ class FileSec < Mets
4
+ def nodes
5
+ @xml.nodes.xpath("//fileSec")
6
+ end
7
+
8
+ def files
9
+ nodes.xpath("//fileGrp/file").inject([]){|result, file| result << FileAsset.new(file)}
10
+ end
11
+ end
12
+ end
data/lib/uwdc/mets.rb ADDED
@@ -0,0 +1,195 @@
1
+ module UWDC
2
+ # Public: Methods to obtain UWDC METS metadata via an object identifier.
3
+ #
4
+ # Examples
5
+ #
6
+ # UWDC::Mets.new('ECJ6ZXEYWUE7B8W')
7
+ # # => object fetched from Fedora
8
+ #
9
+ # UWDC::Mets.new('ECJ6ZXEYWUE7B8W', File.read('../file.xml'))
10
+ # # => object constructed from XML file
11
+ class Mets
12
+ attr_accessor :id, :xml
13
+
14
+ # Public: Intialize a UWDC Mets object
15
+ #
16
+ # id - A UWDC identifier.
17
+ # xml - An optional XML file.
18
+ #
19
+ # Raises XmlNotFound if the xml file cannot be found or fetched.
20
+ def initialize(id, xml=nil)
21
+ @id = id
22
+ @xml ||= UWDC::XML.new(@id,xml)
23
+ raise(XmlNotFound) unless [nil,200].include?(@xml.status)
24
+ end
25
+
26
+ # Public: Access the XML nodes of the METS file
27
+ #
28
+ # Example
29
+ #
30
+ # @mets.nodes
31
+ # # => Nokogiri::XML::NodeSet
32
+ #
33
+ # Returns the Nokogiri::XML::NodeSet for the parsed METS file
34
+ def nodes
35
+ @xml.nodes
36
+ end
37
+
38
+ # Public: Convert the XML nodes to JSON
39
+ #
40
+ # Example
41
+ #
42
+ # @mets.to_json
43
+ # # => {'mets': ...}
44
+ #
45
+ # Returns the Nokogiri::XML::NodeSet as JSON
46
+ def to_json
47
+ Hash.from_xml(nodes.to_xml).to_json
48
+ end
49
+
50
+ # Public: Convert the XML nodes to Ruby
51
+ #
52
+ # Example
53
+ #
54
+ # @mets.to_ruby
55
+ # # => {'mets': ...}
56
+ #
57
+ # Returns the Nokogiri::XML::NodeSet as a Ruby Hash
58
+ def to_ruby
59
+ Hash.from_xml(nodes.to_xml)
60
+ end
61
+
62
+ # Public: Convert the XML nodes to XML
63
+ #
64
+ # Example
65
+ #
66
+ # @mets.to_xml
67
+ # # => "<mets>..."
68
+ #
69
+ # Returns the Nokogiri::XML::NodeSet as XML
70
+ def to_xml
71
+ nodes.to_xml
72
+ end
73
+
74
+ # Public: Access the MODS descriptive metadata XML nodes
75
+ #
76
+ # Example
77
+ #
78
+ # @mets.mods
79
+ # # => UWDC::Mods
80
+ #
81
+ # Returns a UWDC::Mods object
82
+ def mods
83
+ @mods = Mods.new(@id)
84
+ end
85
+
86
+ # Public: Access the StructMap structural map section XML nodes
87
+ #
88
+ # Example
89
+ #
90
+ # @mets.struct_map
91
+ # # => UWDC::StructMap
92
+ #
93
+ # Returns a UWDC::StructMap object
94
+ def struct_map(id=@id)
95
+ @struct_map = StructMap.new(id)
96
+ end
97
+
98
+ # Public: Access the RelsExt RDF relation XML nodes
99
+ #
100
+ # Example
101
+ #
102
+ # @mets.rels_ext
103
+ # # => UWDC::RelsExt
104
+ #
105
+ # Returns a UWDC::RelsExt object
106
+ def rels_ext(id=@id)
107
+ @rels_ext = RelsExt.new(id)
108
+ end
109
+
110
+ # Public: Access the FileSec file section XML nodes
111
+ #
112
+ # Example
113
+ #
114
+ # @mets.file_sec
115
+ # # => UWDC::FileSec
116
+ #
117
+ # Returns a UWDC::FileSec object
118
+ def file_sec(id=@id)
119
+ @file_sec = FileSec.new(id)
120
+ end
121
+
122
+ # Public: Access the DublinCore descriptive metadata XML nodes
123
+ #
124
+ # Example
125
+ #
126
+ # @mets.dublin_core
127
+ # # => UWDC::DublinCore
128
+ #
129
+ # Returns a UWDC::DublinCore object
130
+ def dublin_core(id=@id)
131
+ @dublin_core = DublinCore.new(id)
132
+ end
133
+
134
+ # Public: Access the Display class/methods for the METS file
135
+ #
136
+ # Example
137
+ #
138
+ # @mets.display
139
+ # # => UWDC::Display
140
+ #
141
+ # Returns a UWDC::Display object
142
+ def display(id=@id)
143
+ @display = Display.new(id)
144
+ end
145
+
146
+ private
147
+
148
+ # Internal: Strip the id of it's ClassName
149
+ def identifier(id)
150
+ id[0,id.rindex(/[\.-]/)]
151
+ end
152
+
153
+ # Internal: Remove empty node entries
154
+ def clean_nodes(node_array)
155
+ node_array.map{|node| node.text}.reject(&:empty?)
156
+ end
157
+
158
+ # Internal: Select the attribute in a node array
159
+ def pick_attribute(node_array, attribute)
160
+ node_array.map{|node| node.attribute(attribute).value}.reject(&:empty?)
161
+ end
162
+ end
163
+
164
+ # Public: One division from the StructMap
165
+ class Div
166
+ attr_accessor :id, :admid, :order
167
+
168
+ def initialize(node)
169
+ @node = node
170
+ @id = node["ID"]
171
+ @admid = node["ADMID"]
172
+ @order = node["ORDER"] ? node["ORDER"] : ""
173
+ end
174
+
175
+ def file_pointers
176
+ @node.children.map{|node| node["FILEID"] if node.name == "fptr"}.compact
177
+ end
178
+
179
+ def kids
180
+ @node.children.map{|div| Div.new(div) if div.name == "div"}.compact
181
+ end
182
+ end
183
+
184
+ # Public: One file asset from the FileSec
185
+ class FileAsset
186
+ attr_accessor :id, :mimetype, :use, :href, :title
187
+
188
+ def initialize(node)
189
+ @id = node["ID"]
190
+ @mimetype = node["MIMETYPE"]
191
+ @use = node["USE"]
192
+ @href = node.children.detect{|child| child.name == "FLocat"}.attr('href')
193
+ end
194
+ end
195
+ end