mods_display 0.0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +26 -0
- data/README.md +136 -0
- data/Rakefile +5 -0
- data/lib/mods_display.rb +30 -0
- data/lib/mods_display/configuration.rb +73 -0
- data/lib/mods_display/configuration/base.rb +23 -0
- data/lib/mods_display/configuration/subject.rb +11 -0
- data/lib/mods_display/controller_extension.rb +32 -0
- data/lib/mods_display/fields/abstract.rb +32 -0
- data/lib/mods_display/fields/audience.rb +7 -0
- data/lib/mods_display/fields/cartographics.rb +21 -0
- data/lib/mods_display/fields/collection.rb +21 -0
- data/lib/mods_display/fields/contents.rb +7 -0
- data/lib/mods_display/fields/description.rb +30 -0
- data/lib/mods_display/fields/field.rb +89 -0
- data/lib/mods_display/fields/format.rb +34 -0
- data/lib/mods_display/fields/identifier.rb +60 -0
- data/lib/mods_display/fields/imprint.rb +68 -0
- data/lib/mods_display/fields/language.rb +33 -0
- data/lib/mods_display/fields/location.rb +25 -0
- data/lib/mods_display/fields/name.rb +97 -0
- data/lib/mods_display/fields/note.rb +49 -0
- data/lib/mods_display/fields/related_item.rb +24 -0
- data/lib/mods_display/fields/related_location.rb +14 -0
- data/lib/mods_display/fields/subject.rb +103 -0
- data/lib/mods_display/fields/title.rb +49 -0
- data/lib/mods_display/fields/values.rb +11 -0
- data/lib/mods_display/html.rb +87 -0
- data/lib/mods_display/model_extension.rb +20 -0
- data/lib/mods_display/version.rb +3 -0
- data/mods_display.gemspec +24 -0
- data/spec/configuration/base_spec.rb +29 -0
- data/spec/fields/abstract_spec.rb +21 -0
- data/spec/fields/audience_spec.rb +21 -0
- data/spec/fields/cartographics_spec.rb +39 -0
- data/spec/fields/collection_spec.rb +31 -0
- data/spec/fields/contents_spec.rb +21 -0
- data/spec/fields/description_spec.rb +37 -0
- data/spec/fields/format_spec.rb +35 -0
- data/spec/fields/identifier_spec.rb +49 -0
- data/spec/fields/imprint_spec.rb +78 -0
- data/spec/fields/language_spec.rb +55 -0
- data/spec/fields/location_spec.rb +25 -0
- data/spec/fields/name_spec.rb +88 -0
- data/spec/fields/note_spec.rb +53 -0
- data/spec/fields/related_item_spec.rb +37 -0
- data/spec/fields/related_location_spec.rb +31 -0
- data/spec/fields/subject_spec.rb +89 -0
- data/spec/fields/title_spec.rb +47 -0
- data/spec/fixtures/cartographics_fixtures.rb +52 -0
- data/spec/fixtures/imprint_fixtures.rb +89 -0
- data/spec/fixtures/name_fixtures.rb +3 -0
- data/spec/fixtures/subjects_fixtures.rb +70 -0
- data/spec/integration/configuration_spec.rb +37 -0
- data/spec/integration/installation_spec.rb +26 -0
- data/spec/spec_helper.rb +35 -0
- metadata +182 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
class ModsDisplay::Note < ModsDisplay::Field
|
2
|
+
|
3
|
+
def fields
|
4
|
+
return_values = []
|
5
|
+
current_label = nil
|
6
|
+
prev_label = nil
|
7
|
+
buffer = []
|
8
|
+
@value.each_with_index do |val, index|
|
9
|
+
current_label = (displayLabel(val) || note_label(val))
|
10
|
+
if @value.length == 1
|
11
|
+
return_values << ModsDisplay::Values.new(:label => current_label, :values => [val.text])
|
12
|
+
elsif index == (@value.length-1)
|
13
|
+
# need to deal w/ when we have a last element but we have separate labels in the buffer.
|
14
|
+
if current_label != prev_label
|
15
|
+
return_values << ModsDisplay::Values.new(:label => prev_label, :values => buffer.flatten)
|
16
|
+
return_values << ModsDisplay::Values.new(:label => current_label, :values => [val.text])
|
17
|
+
else
|
18
|
+
buffer << val.text
|
19
|
+
return_values << ModsDisplay::Values.new(:label => current_label, :values => buffer.flatten)
|
20
|
+
end
|
21
|
+
elsif prev_label and (current_label != prev_label)
|
22
|
+
return_values << ModsDisplay::Values.new(:label => prev_label, :values => buffer.flatten)
|
23
|
+
buffer = []
|
24
|
+
end
|
25
|
+
buffer << val.text
|
26
|
+
prev_label = current_label
|
27
|
+
end
|
28
|
+
return_values
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def note_label(element)
|
35
|
+
if element.attributes["type"].respond_to?(:value)
|
36
|
+
return note_labels[element.attributes["type"].value] || element.attributes["type"].value
|
37
|
+
end
|
38
|
+
"Note"
|
39
|
+
end
|
40
|
+
|
41
|
+
def note_labels
|
42
|
+
{"statement of responsibility" => "Statement of Responsibility",
|
43
|
+
"date/sequential designation" => "Date/Sequential Designation",
|
44
|
+
"references" => "References",
|
45
|
+
"bibliography" => "Bibliography",
|
46
|
+
"preferred citation" => "Preferred citation"}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class ModsDisplay::RelatedItem < ModsDisplay::Field
|
2
|
+
|
3
|
+
def fields
|
4
|
+
return_values = []
|
5
|
+
@value.each do |val|
|
6
|
+
unless (val.typeOfResource.length > 0 and
|
7
|
+
val.typeOfResource.attributes.length > 0 and
|
8
|
+
val.typeOfResource.attributes.first.has_key?("collection") and
|
9
|
+
val.typeOfResource.attributes.first["collection"].value == "yes")
|
10
|
+
if val.titleInfo.length > 0
|
11
|
+
title = val.titleInfo.text.strip
|
12
|
+
return_text = title
|
13
|
+
location = nil
|
14
|
+
location = val.location.url.text if (val.location.length > 0 and
|
15
|
+
val.location.url.length > 0)
|
16
|
+
return_text = "<a href='#{location}'>#{title}</a>" if location
|
17
|
+
return_values << ModsDisplay::Values.new(:label => displayLabel(val) || "Related Item", :values => [return_text])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return_values
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ModsDisplay::RelatedLocation < ModsDisplay::Field
|
2
|
+
|
3
|
+
|
4
|
+
def fields
|
5
|
+
return_values = []
|
6
|
+
@value.each do |val|
|
7
|
+
if val.location.length > 0
|
8
|
+
return_values << ModsDisplay::Values.new(:label => displayLabel(val) || "Location", :values => [val.location.text.strip])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
return_values
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class ModsDisplay::Subject < ModsDisplay::Field
|
2
|
+
|
3
|
+
def fields
|
4
|
+
return_values = []
|
5
|
+
@value.each do |val|
|
6
|
+
return_text = []
|
7
|
+
selected_subjects(val).each do |child|
|
8
|
+
if self.respond_to?(:"process_#{child.name}")
|
9
|
+
return_text << self.send(:"process_#{child.name}", child)
|
10
|
+
else
|
11
|
+
if child.text.include?("--")
|
12
|
+
return_text << child.text.split("--").map{|t| t.strip }
|
13
|
+
else
|
14
|
+
return_text << child.text
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
unless return_text.empty?
|
19
|
+
return_values << return_text.flatten
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return [] if return_values.empty?
|
23
|
+
[ModsDisplay::Values.new(:label => "Subject", :values => return_values)]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Would really like to clean this up, but it works and is tested for now.
|
27
|
+
def to_html
|
28
|
+
return nil if fields.empty?
|
29
|
+
output = ""
|
30
|
+
fields.each do |field|
|
31
|
+
output << "<dt#{label_class} title='#{field.label}'>#{field.label}:</dt>"
|
32
|
+
output << "<dd#{value_class}>"
|
33
|
+
subs = []
|
34
|
+
field.values.each do |subjects|
|
35
|
+
buffer = []
|
36
|
+
sub_parts = []
|
37
|
+
subjects.each do |val|
|
38
|
+
if val.is_a?(ModsDisplay::Name::Person)
|
39
|
+
buffer << val.name
|
40
|
+
else
|
41
|
+
buffer << val
|
42
|
+
end
|
43
|
+
if @config.link and @config.hierarchical_link
|
44
|
+
if val.is_a?(ModsDisplay::Name::Person)
|
45
|
+
txt = link_to_value(val.name, buffer.join(' '))
|
46
|
+
txt << " (#{val.role})" if val.role
|
47
|
+
sub_parts << txt
|
48
|
+
else
|
49
|
+
sub_parts << link_to_value(val, buffer.join(' '))
|
50
|
+
end
|
51
|
+
elsif @config.link
|
52
|
+
if val.is_a?(ModsDisplay::Name::Person)
|
53
|
+
txt = link_to_value(val.name)
|
54
|
+
txt << " (#{val.role})" if val.role
|
55
|
+
sub_parts << txt
|
56
|
+
else
|
57
|
+
sub_parts << link_to_value(val.to_s)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
sub_parts << val.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
subs << sub_parts.join(@config.delimiter)
|
64
|
+
end
|
65
|
+
output << subs.join("<br/>")
|
66
|
+
output << "</dd>"
|
67
|
+
end
|
68
|
+
output
|
69
|
+
end
|
70
|
+
|
71
|
+
def process_hierarchicalGeographic(element)
|
72
|
+
values_from_subjects(element)
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_name(element)
|
76
|
+
ModsDisplay::Name.new([element], @config, @klass).fields.first.values.first
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def values_from_subjects(element)
|
82
|
+
return_values = []
|
83
|
+
selected_subjects(element).each do |child|
|
84
|
+
if child.text.include?("--")
|
85
|
+
return_values << child.text.split("--").map{|t| t.strip }
|
86
|
+
else
|
87
|
+
return_values << child.text.strip
|
88
|
+
end
|
89
|
+
end
|
90
|
+
return_values
|
91
|
+
end
|
92
|
+
|
93
|
+
def selected_subjects(element=@value)
|
94
|
+
element.children.select do |child|
|
95
|
+
!omit_elements.include?(child.name.to_sym)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def omit_elements
|
100
|
+
[:cartographics, :geographicCode, :text]
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class ModsDisplay::Title < ModsDisplay::Field
|
2
|
+
|
3
|
+
|
4
|
+
def fields
|
5
|
+
return_values = []
|
6
|
+
@value.each do |val|
|
7
|
+
if displayForm(val)
|
8
|
+
return_values << ModsDisplay::Values.new(:label => displayLabel(val) || title_label(val), :values => [displayForm(val).text])
|
9
|
+
else
|
10
|
+
nonSort = nil
|
11
|
+
title = nil
|
12
|
+
subTitle = nil
|
13
|
+
nonSort = val.nonSort.text.strip unless val.nonSort.text.strip.empty?
|
14
|
+
title = val.title.text.strip unless val.title.text.strip.empty?
|
15
|
+
subTitle = val.subTitle.text unless val.subTitle.text.strip.empty?
|
16
|
+
preSubTitle = [nonSort, title].compact.join(" ")
|
17
|
+
preSubTitle = nil if preSubTitle.strip.empty?
|
18
|
+
preParts = [preSubTitle, subTitle].compact.join(" : ")
|
19
|
+
preParts = nil if preParts.strip.empty?
|
20
|
+
parts = val.children.select do |child|
|
21
|
+
["partName", "partNumber"].include?(child.name)
|
22
|
+
end.map do |child|
|
23
|
+
child.text
|
24
|
+
end.compact.join(", ")
|
25
|
+
parts = nil if parts.strip.empty?
|
26
|
+
return_values << ModsDisplay::Values.new(:label => displayLabel(val) || title_label(val), :values => [[preParts, parts].compact.join(". ")])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return_values
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def title_label(element)
|
35
|
+
if (element.attributes["type"].respond_to?(:value) and
|
36
|
+
title_labels.has_key?(element.attributes["type"].value))
|
37
|
+
return title_labels[element.attributes["type"].value]
|
38
|
+
end
|
39
|
+
"Title"
|
40
|
+
end
|
41
|
+
|
42
|
+
def title_labels
|
43
|
+
{"abbreviated" => "Abbreviated Title",
|
44
|
+
"translated" => "Translated Title",
|
45
|
+
"alternative" => "Alternative Title",
|
46
|
+
"uniform" => "Uniform Title"}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class ModsDisplay::HTML
|
2
|
+
attr_reader :title, :body
|
3
|
+
def initialize(config, xml, klass)
|
4
|
+
@config = config
|
5
|
+
@xml = xml
|
6
|
+
@klass = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def title
|
10
|
+
unless mods_field(@xml, :title).fields.empty?
|
11
|
+
return mods_field(@xml, :title).fields.first.values
|
12
|
+
end
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
16
|
+
# Need to figure out how to get the 1st title out of the list.
|
17
|
+
# Maybe have a separate class that will omit the first tite natively
|
18
|
+
# and replace the first key in the the fields list with that.
|
19
|
+
def body
|
20
|
+
output = "<dl>"
|
21
|
+
mods_display_fields.each do |field_key|
|
22
|
+
unless mods_field(@xml, field_key).to_html.nil?
|
23
|
+
output << mods_field(@xml, field_key).to_html
|
24
|
+
end
|
25
|
+
end
|
26
|
+
output << "</dl>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_html
|
30
|
+
output = "<dl>"
|
31
|
+
mods_display_fields.each do |field_key|
|
32
|
+
unless mods_field(@xml, field_key).to_html.nil?
|
33
|
+
output << mods_field(@xml, field_key).to_html
|
34
|
+
end
|
35
|
+
end
|
36
|
+
output << "</dl>"
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(method_name, *args, &block)
|
40
|
+
if self.to_s.respond_to?(method_name)
|
41
|
+
self.to_html.send(method_name, *args, &block)
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def mods_field(xml, field_key)
|
50
|
+
if xml.respond_to?(mods_display_field_mapping[field_key])
|
51
|
+
field = xml.send(mods_display_field_mapping[field_key])
|
52
|
+
ModsDisplay.const_get("#{field_key.slice(0,1).upcase}#{field_key.slice(1..-1)}").new(field, field_config(field_key), @klass)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def field_config(field_key)
|
57
|
+
begin
|
58
|
+
@config.send(field_key)
|
59
|
+
rescue
|
60
|
+
ModsDisplay::Configuration::Base.new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def mods_display_fields
|
65
|
+
[:title, :name, :format, :imprint, :language, :description, :cartographics, :abstract, :contents, :audience, :note, :collection, :relatedLocation, :relatedItem, :subject, :identifier, :location]
|
66
|
+
end
|
67
|
+
|
68
|
+
def mods_display_field_mapping
|
69
|
+
{:title => :title_info,
|
70
|
+
:name => :plain_name,
|
71
|
+
:format => :typeOfResource,
|
72
|
+
:imprint => :origin_info,
|
73
|
+
:language => :language,
|
74
|
+
:description => :physical_description,
|
75
|
+
:cartographics => :subject,
|
76
|
+
:abstract => :abstract,
|
77
|
+
:contents => :tableOfContents,
|
78
|
+
:audience => :targetAudience,
|
79
|
+
:note => :note,
|
80
|
+
:collection => :related_item,
|
81
|
+
:relatedLocation => :related_item,
|
82
|
+
:relatedItem => :related_item,
|
83
|
+
:subject => :subject,
|
84
|
+
:identifier => :identifier,
|
85
|
+
:location => :location}
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ModsDisplay::ModelExtension
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.class_eval do
|
6
|
+
def mods_display_xml
|
7
|
+
xml = self.class.mods_xml_source.call(self)
|
8
|
+
return if xml.nil?
|
9
|
+
mods = Stanford::Mods::Record.new
|
10
|
+
mods.from_str(xml, false)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def mods_xml_source &xml
|
17
|
+
@mods_xml_source ||= xml
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mods_display/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "mods_display"
|
8
|
+
gem.version = ModsDisplay::VERSION
|
9
|
+
gem.authors = ["Jessie Keck"]
|
10
|
+
gem.email = ["jessie.keck@gmail.com"]
|
11
|
+
gem.description = %q{MODS Display is a gem to centralize the display logic of MODS medadata.}
|
12
|
+
gem.summary = %q{The MODS Display gem allows implementers to configure a customized display of MODS metadata. This display implements the specifications defined at Stanford for how to display MODS.}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(spec)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'stanford-mods'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rake'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ModsDisplay::Configuration::Base do
|
4
|
+
it "should set config options w/ a block" do
|
5
|
+
config = ModsDisplay::Configuration::Base.new do
|
6
|
+
label_class "testing_label_class"
|
7
|
+
value_class "testing_value_class"
|
8
|
+
end
|
9
|
+
config.label_class.should == "testing_label_class"
|
10
|
+
config.value_class.should == "testing_value_class"
|
11
|
+
end
|
12
|
+
describe "link" do
|
13
|
+
it "should return an array with a method name and params" do
|
14
|
+
ModsDisplay::Configuration::Base.new do
|
15
|
+
link :my_url_generating_method, q: '"%value%"'
|
16
|
+
end.link.should == [:my_url_generating_method, {:q => '"%value%"'}]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
describe "delmiter" do
|
20
|
+
it "should override the default delimiter" do
|
21
|
+
ModsDisplay::Configuration::Base.new do
|
22
|
+
delimiter "<br/>"
|
23
|
+
end.delimiter.should == "<br/>"
|
24
|
+
end
|
25
|
+
it "should default to ', '" do
|
26
|
+
ModsDisplay::Configuration::Base.new.delimiter.should == ", "
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
def mods_display_abstract(mods_record)
|
4
|
+
ModsDisplay::Abstract.new(mods_record, ModsDisplay::Configuration::Base.new, mock("controller"))
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ModsDisplay::Abstract do
|
8
|
+
before(:all) do
|
9
|
+
@link = Stanford::Mods::Record.new.from_str("<mods><abstract>A link to the library (http://library.stanford.edu) should appear here</abstract></mods>", false).abstract
|
10
|
+
@email = Stanford::Mods::Record.new.from_str("<mods><abstract>A link to an email address jdoe@example.com should appear here</abstract></mods>", false).abstract
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "links" do
|
14
|
+
it "should turn URLs into links" do
|
15
|
+
mods_display_abstract(@link).fields.first.values.first.should match(/\(<a href='http:\/\/library.stanford.edu'>http:\/\/library.stanford.edu<\/a>\)/)
|
16
|
+
end
|
17
|
+
it "should turn email addresses into mailto links" do
|
18
|
+
mods_display_abstract(@email).fields.first.values.first.should match(/<a href='mailto:jdoe@example.com'>jdoe@example.com<\/a>/)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|