mods_display 0.0.1.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|