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.
Files changed (60) hide show
  1. data/.gitignore +19 -0
  2. data/.travis.yml +5 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +26 -0
  5. data/README.md +136 -0
  6. data/Rakefile +5 -0
  7. data/lib/mods_display.rb +30 -0
  8. data/lib/mods_display/configuration.rb +73 -0
  9. data/lib/mods_display/configuration/base.rb +23 -0
  10. data/lib/mods_display/configuration/subject.rb +11 -0
  11. data/lib/mods_display/controller_extension.rb +32 -0
  12. data/lib/mods_display/fields/abstract.rb +32 -0
  13. data/lib/mods_display/fields/audience.rb +7 -0
  14. data/lib/mods_display/fields/cartographics.rb +21 -0
  15. data/lib/mods_display/fields/collection.rb +21 -0
  16. data/lib/mods_display/fields/contents.rb +7 -0
  17. data/lib/mods_display/fields/description.rb +30 -0
  18. data/lib/mods_display/fields/field.rb +89 -0
  19. data/lib/mods_display/fields/format.rb +34 -0
  20. data/lib/mods_display/fields/identifier.rb +60 -0
  21. data/lib/mods_display/fields/imprint.rb +68 -0
  22. data/lib/mods_display/fields/language.rb +33 -0
  23. data/lib/mods_display/fields/location.rb +25 -0
  24. data/lib/mods_display/fields/name.rb +97 -0
  25. data/lib/mods_display/fields/note.rb +49 -0
  26. data/lib/mods_display/fields/related_item.rb +24 -0
  27. data/lib/mods_display/fields/related_location.rb +14 -0
  28. data/lib/mods_display/fields/subject.rb +103 -0
  29. data/lib/mods_display/fields/title.rb +49 -0
  30. data/lib/mods_display/fields/values.rb +11 -0
  31. data/lib/mods_display/html.rb +87 -0
  32. data/lib/mods_display/model_extension.rb +20 -0
  33. data/lib/mods_display/version.rb +3 -0
  34. data/mods_display.gemspec +24 -0
  35. data/spec/configuration/base_spec.rb +29 -0
  36. data/spec/fields/abstract_spec.rb +21 -0
  37. data/spec/fields/audience_spec.rb +21 -0
  38. data/spec/fields/cartographics_spec.rb +39 -0
  39. data/spec/fields/collection_spec.rb +31 -0
  40. data/spec/fields/contents_spec.rb +21 -0
  41. data/spec/fields/description_spec.rb +37 -0
  42. data/spec/fields/format_spec.rb +35 -0
  43. data/spec/fields/identifier_spec.rb +49 -0
  44. data/spec/fields/imprint_spec.rb +78 -0
  45. data/spec/fields/language_spec.rb +55 -0
  46. data/spec/fields/location_spec.rb +25 -0
  47. data/spec/fields/name_spec.rb +88 -0
  48. data/spec/fields/note_spec.rb +53 -0
  49. data/spec/fields/related_item_spec.rb +37 -0
  50. data/spec/fields/related_location_spec.rb +31 -0
  51. data/spec/fields/subject_spec.rb +89 -0
  52. data/spec/fields/title_spec.rb +47 -0
  53. data/spec/fixtures/cartographics_fixtures.rb +52 -0
  54. data/spec/fixtures/imprint_fixtures.rb +89 -0
  55. data/spec/fixtures/name_fixtures.rb +3 -0
  56. data/spec/fixtures/subjects_fixtures.rb +70 -0
  57. data/spec/integration/configuration_spec.rb +37 -0
  58. data/spec/integration/installation_spec.rb +26 -0
  59. data/spec/spec_helper.rb +35 -0
  60. 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,11 @@
1
+ class ModsDisplay::Values
2
+ attr_accessor :label, :values
3
+ def initialize(values)
4
+ values.each do |key, value|
5
+ if [:label, :values].include?(key)
6
+ self.send("#{key}=".to_sym, value)
7
+ end
8
+ end
9
+ end
10
+
11
+ 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,3 @@
1
+ module ModsDisplay
2
+ VERSION = "0.0.1.beta1"
3
+ 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