mods_display 0.7.0 → 0.10.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +24 -0
- data/lib/mods_display.rb +11 -0
- data/lib/mods_display/fields/access_condition.rb +3 -0
- data/lib/mods_display/fields/imprint.rb +16 -0
- data/lib/mods_display/fields/location.rb +1 -1
- data/lib/mods_display/fields/title.rb +39 -32
- data/lib/mods_display/helpers/record_helper.rb +131 -0
- data/lib/mods_display/html.rb +3 -1
- data/lib/mods_display/railtie.rb +10 -0
- data/lib/mods_display/version.rb +1 -1
- data/mods_display.gemspec +2 -0
- data/spec/fake_app.rb +18 -0
- data/spec/fields/access_condition_spec.rb +13 -2
- data/spec/fields/imprint_spec.rb +18 -0
- data/spec/fields/location_spec.rb +1 -1
- data/spec/fields/title_spec.rb +8 -0
- data/spec/fixtures/access_condition_fixtures.rb +8 -0
- data/spec/fixtures/imprint_fixtures.rb +11 -0
- data/spec/fixtures/title_fixtures.rb +14 -0
- data/spec/helpers/record_helper_spec.rb +241 -0
- data/spec/integration/html_spec.rb +5 -0
- data/spec/spec_helper.rb +6 -0
- metadata +41 -7
- data/.travis.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 586a8299be19e795bc90b434d9902084ca8fa10bb8cbe9690fc108471e1f5495
|
4
|
+
data.tar.gz: 00574a48dc3c3ba050529bf2d3fcd5e38df5de4c0e5ed4023ad07904dea29c99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9430fa89a1efb94a17ec8c83f5fc96e55f96221f962480ff6a71a9283548d385e1afabe1c8653215155a8d7804648075aae93d217ff2d25ec29357c5b2e64544
|
7
|
+
data.tar.gz: 0d7b2e673cae7f336e65824c528b78abd59e8b730430570faa98910cf715e875a707dde7787a48cbf158f15bc596b057181c443d253387136604b307036812ea
|
@@ -0,0 +1,24 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
tests:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby: [2.6, 2.7, 3.0]
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up Ruby
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
21
|
+
- name: Install dependencies
|
22
|
+
run: bundle install
|
23
|
+
- name: Run tests
|
24
|
+
run: bundle exec rake
|
data/lib/mods_display.rb
CHANGED
@@ -49,3 +49,14 @@ require 'i18n/backend/fallbacks'
|
|
49
49
|
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
50
50
|
I18n.load_path += Dir["#{File.expand_path('../..', __FILE__)}/config/locales/*.yml"]
|
51
51
|
I18n.backend.load_translations
|
52
|
+
|
53
|
+
# load Rails/Railtie
|
54
|
+
begin
|
55
|
+
require 'rails'
|
56
|
+
rescue LoadError
|
57
|
+
#do nothing
|
58
|
+
end
|
59
|
+
|
60
|
+
if defined? ::Rails::Railtie
|
61
|
+
require 'mods_display/railtie'
|
62
|
+
end
|
@@ -77,6 +77,9 @@ module ModsDisplay
|
|
77
77
|
|
78
78
|
def license_statement(element)
|
79
79
|
matches = element.text.match(/^(?<code>.*) (?<type>.*):(?<description>.*)$/)
|
80
|
+
|
81
|
+
return "<div>#{element.text}</div>" unless matches
|
82
|
+
|
80
83
|
code = matches[:code].downcase
|
81
84
|
type = matches[:type].downcase
|
82
85
|
description = license_description(code, type) || matches[:description]
|
@@ -68,6 +68,8 @@ module ModsDisplay
|
|
68
68
|
date_fields.map do |date_field|
|
69
69
|
if date_is_w3cdtf?(date_field)
|
70
70
|
process_w3cdtf_date(date_field)
|
71
|
+
elsif date_is_iso8601?(date_field)
|
72
|
+
process_iso8601_date(date_field)
|
71
73
|
else
|
72
74
|
date_field
|
73
75
|
end
|
@@ -158,6 +160,10 @@ module ModsDisplay
|
|
158
160
|
field_is_encoded?(date_field, 'w3cdtf')
|
159
161
|
end
|
160
162
|
|
163
|
+
def date_is_iso8601?(date_field)
|
164
|
+
field_is_encoded?(date_field, 'iso8601')
|
165
|
+
end
|
166
|
+
|
161
167
|
def process_w3cdtf_date(date_field)
|
162
168
|
date_field = date_field.clone
|
163
169
|
date_field.content = begin
|
@@ -174,6 +180,16 @@ module ModsDisplay
|
|
174
180
|
date_field
|
175
181
|
end
|
176
182
|
|
183
|
+
def process_iso8601_date(date_field)
|
184
|
+
date_field = date_field.clone
|
185
|
+
date_field.content = begin
|
186
|
+
Date.iso8601(date_field.text).strftime(@config.full_date_format)
|
187
|
+
rescue
|
188
|
+
date_field.content
|
189
|
+
end
|
190
|
+
date_field
|
191
|
+
end
|
192
|
+
|
177
193
|
def dedup_dates(date_fields)
|
178
194
|
date_text = date_fields.map { |d| normalize_date(d.text) }
|
179
195
|
if date_text != date_text.uniq
|
@@ -4,31 +4,10 @@ module ModsDisplay
|
|
4
4
|
return_values = []
|
5
5
|
if @values
|
6
6
|
@values.each do |value|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
)
|
12
|
-
else
|
13
|
-
nonSort = nil
|
14
|
-
title = nil
|
15
|
-
subTitle = nil
|
16
|
-
nonSort = value.nonSort.text.strip unless value.nonSort.text.strip.empty?
|
17
|
-
title = value.title.text.strip unless value.title.text.strip.empty?
|
18
|
-
subTitle = value.subTitle.text unless value.subTitle.text.strip.empty?
|
19
|
-
preSubTitle = [nonSort, title].compact.join(' ')
|
20
|
-
preSubTitle = nil if preSubTitle.strip.empty?
|
21
|
-
preParts = compact_and_join_with_delimiter([preSubTitle, subTitle], ' : ')
|
22
|
-
preParts = nil if preParts.strip.empty?
|
23
|
-
parts = value.children.select do |child|
|
24
|
-
%w(partName partNumber).include?(child.name)
|
25
|
-
end.map(&:text).compact.join(parts_delimiter(value))
|
26
|
-
parts = nil if parts.strip.empty?
|
27
|
-
return_values << ModsDisplay::Values.new(
|
28
|
-
label: displayLabel(value) || title_label(value),
|
29
|
-
values: [compact_and_join_with_delimiter([preParts, parts], '. ')]
|
30
|
-
)
|
31
|
-
end
|
7
|
+
return_values << ModsDisplay::Values.new(
|
8
|
+
label: displayLabel(value) || title_label(value),
|
9
|
+
values: [assemble_title(value)]
|
10
|
+
)
|
32
11
|
end
|
33
12
|
end
|
34
13
|
collapse_fields(return_values)
|
@@ -36,14 +15,42 @@ module ModsDisplay
|
|
36
15
|
|
37
16
|
private
|
38
17
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
18
|
+
def assemble_title(element)
|
19
|
+
return displayForm(element) if displayForm(element)
|
20
|
+
|
21
|
+
title = ''
|
22
|
+
previous_element = nil
|
23
|
+
|
24
|
+
element.children.select { |value| title_parts.include? value.name }.each do |value|
|
25
|
+
str = value.text.strip
|
26
|
+
next if str.empty?
|
27
|
+
|
28
|
+
delimiter = case
|
29
|
+
when title.empty?, title.end_with?(' ')
|
30
|
+
nil
|
31
|
+
when title.end_with?('.', ',', ':', ';')
|
32
|
+
' '
|
33
|
+
when value.name == 'subTitle'
|
34
|
+
' : '
|
35
|
+
when value.name == 'partName' && previous_element.name == 'partNumber'
|
36
|
+
', '
|
37
|
+
when value.name == 'partNumber', value.name == 'partName'
|
38
|
+
'. '
|
39
|
+
else
|
40
|
+
' '
|
41
|
+
end
|
42
|
+
|
43
|
+
title += delimiter if delimiter
|
44
|
+
title += str
|
45
|
+
|
46
|
+
previous_element = value
|
45
47
|
end
|
46
|
-
|
48
|
+
|
49
|
+
title
|
50
|
+
end
|
51
|
+
|
52
|
+
def title_parts
|
53
|
+
%w[nonSort title subTitle partName partNumber]
|
47
54
|
end
|
48
55
|
|
49
56
|
def title_label(element)
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModsDisplay
|
4
|
+
module Helpers
|
5
|
+
module RecordHelper
|
6
|
+
def display_content_field(field)
|
7
|
+
return unless field.respond_to?(:label, :values) && field.values.any?(&:present?)
|
8
|
+
|
9
|
+
display_content_label(field.label) + display_content_values(field.values)
|
10
|
+
end
|
11
|
+
|
12
|
+
def display_content_label(label)
|
13
|
+
content_tag :dt, label
|
14
|
+
end
|
15
|
+
|
16
|
+
def display_content_values(values)
|
17
|
+
values.map do |value|
|
18
|
+
content_tag :dd, value
|
19
|
+
end.join('').html_safe
|
20
|
+
end
|
21
|
+
|
22
|
+
def mods_display_label(label)
|
23
|
+
content_tag(:dt, label.delete(':')) + "\n".html_safe
|
24
|
+
end
|
25
|
+
|
26
|
+
def mods_display_content(values, delimiter = nil)
|
27
|
+
if delimiter
|
28
|
+
content_tag(:dd, values.map do |value|
|
29
|
+
link_urls_and_email(value) if value.present?
|
30
|
+
end.compact.join(delimiter).html_safe)
|
31
|
+
else
|
32
|
+
Array[values].flatten.map do |value|
|
33
|
+
content_tag(:dd, link_urls_and_email(value.to_s).html_safe) if value.present?
|
34
|
+
end.join.html_safe
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def mods_record_field(field, delimiter = nil)
|
39
|
+
return unless field.respond_to?(:label, :values) && field.values.any?(&:present?)
|
40
|
+
|
41
|
+
mods_display_label(field.label) + mods_display_content(field.values, delimiter)
|
42
|
+
end
|
43
|
+
|
44
|
+
def mods_name_field(field, &block)
|
45
|
+
return unless field.respond_to?(:label, :values) && field.values.any?(&:present?)
|
46
|
+
|
47
|
+
mods_display_label(field.label) + mods_display_name(field.values, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def mods_display_name(names, &block)
|
51
|
+
names.map do |name|
|
52
|
+
content_tag(:dd) do
|
53
|
+
block_given? ? yield(name.name) : name.name
|
54
|
+
end
|
55
|
+
end.join.html_safe
|
56
|
+
end
|
57
|
+
|
58
|
+
# We need this to remove the ending ":" from the role labels only in data from
|
59
|
+
# mods_display
|
60
|
+
def sanitize_mods_name_label(label)
|
61
|
+
label.sub(/:$/, '')
|
62
|
+
end
|
63
|
+
|
64
|
+
def mods_subject_field(subject, &block)
|
65
|
+
return unless subject.values.any?(&:present?)
|
66
|
+
|
67
|
+
fields = subject.values.map do |subject_line|
|
68
|
+
content_tag :dd, safe_join(link_mods_subjects(subject_line, &block), ' > ')
|
69
|
+
end
|
70
|
+
|
71
|
+
(mods_display_label(subject.label) + safe_join(fields))
|
72
|
+
end
|
73
|
+
|
74
|
+
def mods_genre_field(genre, &block)
|
75
|
+
return unless genre.values.any?(&:present?)
|
76
|
+
|
77
|
+
fields = genre.values.map do |genre_line|
|
78
|
+
content_tag :dd, link_mods_genres(genre_line, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
mods_display_label(genre.label) + safe_join(fields)
|
82
|
+
end
|
83
|
+
|
84
|
+
def link_mods_genres(genre, &block)
|
85
|
+
link_buffer = []
|
86
|
+
link_to_mods_subject(genre, link_buffer, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def link_mods_subjects(subjects, &block)
|
90
|
+
link_buffer = []
|
91
|
+
linked_subjects = []
|
92
|
+
subjects.each do |subject|
|
93
|
+
if subject.present?
|
94
|
+
linked_subjects << link_to_mods_subject(subject, link_buffer, &block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
linked_subjects
|
98
|
+
end
|
99
|
+
|
100
|
+
def link_to_mods_subject(subject, buffer, &block)
|
101
|
+
subject_text = subject.respond_to?(:name) ? subject.name : subject
|
102
|
+
link = block_given? ? yield(subject_text, buffer) : subject_text
|
103
|
+
buffer << subject_text.strip
|
104
|
+
link << " (#{subject.roles.join(', ')})" if subject.respond_to?(:roles) && subject.roles.present?
|
105
|
+
link
|
106
|
+
end
|
107
|
+
|
108
|
+
# rubocop:disable Layout/LineLength
|
109
|
+
def link_urls_and_email(val)
|
110
|
+
val = val.dup
|
111
|
+
# http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
112
|
+
url = %r{(?i)\b(?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\([^\s()<>]+|\([^\s()<>]+\)*\))+(?:\([^\s()<>]+|\([^\s()<>]+\)*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])}i
|
113
|
+
# http://www.regular-expressions.info/email.html
|
114
|
+
email = %r{[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b}i
|
115
|
+
matches = [val.scan(url), val.scan(email)].flatten.uniq
|
116
|
+
unless val =~ /<a/ # we'll assume that linking has alraedy occured and we don't want to double link
|
117
|
+
matches.each do |match|
|
118
|
+
if match =~ email
|
119
|
+
val.gsub!(match, "<a href='mailto:#{match}'>#{match}</a>")
|
120
|
+
else
|
121
|
+
val.gsub!(match, "<a href='#{match}'>#{match}</a>")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
val
|
126
|
+
end
|
127
|
+
# rubocop:enable Layout/LineLength
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/mods_display/html.rb
CHANGED
@@ -41,7 +41,9 @@ module ModsDisplay
|
|
41
41
|
if to_s.respond_to?(method_name)
|
42
42
|
to_html.send(method_name, *args, &block)
|
43
43
|
elsif method_name == :subTitle || mods_display_fields.include?(method_name)
|
44
|
-
mods_field(@xml, method_name)
|
44
|
+
field = mods_field(@xml, method_name)
|
45
|
+
return field if (args.dig(0, :raw))
|
46
|
+
field.fields
|
45
47
|
else
|
46
48
|
super
|
47
49
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModsDisplay
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
ActiveSupport.on_load :action_view do
|
6
|
+
require 'mods_display/helpers/record_helper'
|
7
|
+
::ActionView::Base.send :include, ModsDisplay::Helpers::RecordHelper
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/mods_display/version.rb
CHANGED
data/mods_display.gemspec
CHANGED
@@ -22,7 +22,9 @@ Gem::Specification.new do |gem|
|
|
22
22
|
|
23
23
|
gem.add_development_dependency 'rake'
|
24
24
|
gem.add_development_dependency 'rspec', '~> 3.0'
|
25
|
+
gem.add_development_dependency 'rspec-rails'
|
25
26
|
gem.add_development_dependency 'rubocop'
|
26
27
|
gem.add_development_dependency 'capybara'
|
27
28
|
gem.add_development_dependency 'byebug'
|
29
|
+
gem.add_development_dependency 'rails', '~> 6.0'
|
28
30
|
end
|
data/spec/fake_app.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'action_controller/railtie'
|
4
|
+
require 'action_view/railtie'
|
5
|
+
|
6
|
+
class ModsDisplayTestApp < Rails::Application
|
7
|
+
end
|
8
|
+
|
9
|
+
Rails.application.routes.draw do
|
10
|
+
resources 'searches', only: :index
|
11
|
+
end
|
12
|
+
|
13
|
+
class ApplicationController < ActionController::Base; end
|
14
|
+
class SearchesController < ApplicationController
|
15
|
+
def index; end
|
16
|
+
end
|
17
|
+
|
18
|
+
Object.const_set(:ApplicationHelper, Module.new)
|
@@ -25,6 +25,7 @@ describe ModsDisplay::AccessCondition do
|
|
25
25
|
@cc_license_note = Stanford::Mods::Record.new.from_str(cc_license_fixture, false).accessCondition
|
26
26
|
@odc_license_note = Stanford::Mods::Record.new.from_str(odc_license_fixture, false).accessCondition
|
27
27
|
@no_link_license_note = Stanford::Mods::Record.new.from_str(no_license_fixture, false).accessCondition
|
28
|
+
@garbage_license_fixture = Stanford::Mods::Record.new.from_str(garbage_license_fixture, false).accessCondition
|
28
29
|
end
|
29
30
|
describe 'labels' do
|
30
31
|
it 'should normalize types and assign proper labels' do
|
@@ -54,7 +55,7 @@ describe ModsDisplay::AccessCondition do
|
|
54
55
|
expect(fields.first.values.length).to eq(1)
|
55
56
|
expect(fields.first.values.first).to match(%r{^<div class='unknown-something'>.*</div>$})
|
56
57
|
end
|
57
|
-
it 'should
|
58
|
+
it 'should identify and link CreativeCommons licenses properly' do
|
58
59
|
fields = mods_display_access_condition(@cc_license_note).fields
|
59
60
|
expect(fields.length).to eq(1)
|
60
61
|
expect(fields.first.values.length).to eq(1)
|
@@ -63,7 +64,7 @@ describe ModsDisplay::AccessCondition do
|
|
63
64
|
'This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License'
|
64
65
|
)
|
65
66
|
end
|
66
|
-
it 'should
|
67
|
+
it 'should identify and link OpenDataCommons licenses properly' do
|
67
68
|
fields = mods_display_access_condition(@odc_license_note).fields
|
68
69
|
expect(fields.length).to eq(1)
|
69
70
|
expect(fields.first.values.length).to eq(1)
|
@@ -82,6 +83,16 @@ describe ModsDisplay::AccessCondition do
|
|
82
83
|
)
|
83
84
|
expect(fields.first.values.first).not_to include('<a.*>')
|
84
85
|
end
|
86
|
+
|
87
|
+
it 'returns the license text if it does not look like our expected format' do
|
88
|
+
fields = mods_display_access_condition(@garbage_license_fixture).fields
|
89
|
+
expect(fields.length).to eq(1)
|
90
|
+
expect(fields.first.values.length).to eq(1)
|
91
|
+
expect(fields.first.values.first).to include(
|
92
|
+
'Unknown garbage that does not look like a license'
|
93
|
+
)
|
94
|
+
expect(fields.first.values.first).not_to include('<a.*>')
|
95
|
+
end
|
85
96
|
end
|
86
97
|
end
|
87
98
|
describe 'to_html' do
|
data/spec/fields/imprint_spec.rb
CHANGED
@@ -43,6 +43,7 @@ describe ModsDisplay::Imprint do
|
|
43
43
|
@imprint_date_range = Stanford::Mods::Record.new.from_str(imprint_date_range, false).origin_info
|
44
44
|
@encoded_place = Stanford::Mods::Record.new.from_str(encoded_place, false).origin_info
|
45
45
|
@encoded_dates = Stanford::Mods::Record.new.from_str(encoded_dates, false).origin_info
|
46
|
+
@iso8601_encoded_dates = Stanford::Mods::Record.new.from_str(iso8601_encoded_dates, false).origin_info
|
46
47
|
@bad_dates = Stanford::Mods::Record.new.from_str(bad_dates, false).origin_info
|
47
48
|
@invalid_dates = Stanford::Mods::Record.new.from_str(invalid_dates, false).origin_info
|
48
49
|
@punctuation_imprint = Stanford::Mods::Record.new.from_str(punctuation_imprint_fixture, false).origin_info
|
@@ -209,6 +210,23 @@ describe ModsDisplay::Imprint do
|
|
209
210
|
end.values).to eq(['July (2013)'])
|
210
211
|
end
|
211
212
|
end
|
213
|
+
|
214
|
+
describe 'iso8601' do
|
215
|
+
it 'handles full dates properly' do
|
216
|
+
fields = mods_display_imprint(@iso8601_encoded_dates).fields
|
217
|
+
expect(fields.length).to eq(2)
|
218
|
+
expect(fields.find do |field|
|
219
|
+
field.label == 'Date created:'
|
220
|
+
end.values).to eq(['November 14, 2013'])
|
221
|
+
end
|
222
|
+
it "should not try to handle dates we can't parse" do
|
223
|
+
fields = mods_display_imprint(@iso8601_encoded_dates).fields
|
224
|
+
expect(fields.length).to eq(2)
|
225
|
+
expect(fields.find do |field|
|
226
|
+
field.label == 'Date modified:'
|
227
|
+
end.values).to eq(['Jul. 22, 2013'])
|
228
|
+
end
|
229
|
+
end
|
212
230
|
end
|
213
231
|
describe 'bad dates' do
|
214
232
|
it 'should ignore date values' do
|
data/spec/fields/title_spec.rb
CHANGED
@@ -15,6 +15,7 @@ describe ModsDisplay::Title do
|
|
15
15
|
@multi_label = Stanford::Mods::Record.new.from_str(multi_label_fixture, false).title_info
|
16
16
|
@alt_title = Stanford::Mods::Record.new.from_str(alt_title_fixture, false).title_info
|
17
17
|
@title_punctuation = Stanford::Mods::Record.new.from_str(title_puncutation_fixture, false).title_info
|
18
|
+
@ordered_title_fixture = Stanford::Mods::Record.new.from_str(ordered_title_fixture, false).title_info
|
18
19
|
end
|
19
20
|
describe 'labels' do
|
20
21
|
it 'should return a default label of Title if nothing else is available' do
|
@@ -70,5 +71,12 @@ describe ModsDisplay::Title do
|
|
70
71
|
expect(values.first).not_to include '..'
|
71
72
|
expect(values.first).to eq 'A title that ends in punctuation. 2015'
|
72
73
|
end
|
74
|
+
|
75
|
+
it 'combines the title parts in the order from the record' do
|
76
|
+
values = mods_display_title(@ordered_title_fixture).fields.first.values
|
77
|
+
expect(values.length).to eq 1
|
78
|
+
|
79
|
+
expect(values.first).to eq 'The medium term expenditure framework (MTEF) for ... and the annual estimates for ... 016, Ministry of Tourism : expenditure to be met out of moneys granted and drawn from the consolidated fund, central government budget'
|
80
|
+
end
|
73
81
|
end
|
74
82
|
end
|
@@ -280,6 +280,17 @@ module ImprintFixtures
|
|
280
280
|
MODS
|
281
281
|
end
|
282
282
|
|
283
|
+
def iso8601_encoded_dates
|
284
|
+
<<-MODS
|
285
|
+
<mods>
|
286
|
+
<originInfo>
|
287
|
+
<dateCreated encoding="iso8601">20131114161429</dateCreated>
|
288
|
+
<dateModified encoding="iso8601">Jul. 22, 2013</dateModified>
|
289
|
+
</originInfo>
|
290
|
+
</mods>
|
291
|
+
MODS
|
292
|
+
end
|
293
|
+
|
283
294
|
def bad_dates
|
284
295
|
<<-MODS
|
285
296
|
<mods>
|
@@ -98,4 +98,18 @@ module TitleFixtures
|
|
98
98
|
</mods>
|
99
99
|
XML
|
100
100
|
end
|
101
|
+
|
102
|
+
def ordered_title_fixture
|
103
|
+
<<-XML
|
104
|
+
<mods>
|
105
|
+
<titleInfo>
|
106
|
+
<nonSort>The</nonSort>
|
107
|
+
<title>medium term expenditure framework (MTEF) for ... and the annual estimates for ...</title>
|
108
|
+
<partNumber>016</partNumber>
|
109
|
+
<partName>Ministry of Tourism</partName>
|
110
|
+
<subTitle>expenditure to be met out of moneys granted and drawn from the consolidated fund, central government budget</subTitle>
|
111
|
+
</titleInfo>
|
112
|
+
</mods>
|
113
|
+
XML
|
114
|
+
end
|
101
115
|
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'byebug'
|
5
|
+
|
6
|
+
describe ModsDisplay::Helpers::RecordHelper, type: :helper do
|
7
|
+
let(:empty_field) { OpenStruct.new(label: 'test', values: ['']) }
|
8
|
+
|
9
|
+
describe 'display_content_field' do
|
10
|
+
let(:values) { ['guitar (1)', 'solo cowbell, trombone (2)'] }
|
11
|
+
let(:content) { OpenStruct.new(label: 'Instrumentation', values: values) }
|
12
|
+
|
13
|
+
it 'should return dt with label and dd with values' do
|
14
|
+
expect(helper.display_content_field(content)).to have_css('dt', text: 'Instrumentation')
|
15
|
+
expect(helper.display_content_field(content)).to have_css('dd', count: 2)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'display_content_label' do
|
20
|
+
it 'should return correct dt' do
|
21
|
+
expect(helper.display_content_label('test')).to have_css('dt', text: 'test')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'display_content_values' do
|
26
|
+
let(:values) { ['guitar (1)', 'solo cowbell, trombone (2)'] }
|
27
|
+
|
28
|
+
it 'should return dds of values' do
|
29
|
+
expect(helper.display_content_values(values)).to have_css('dd', count: 2)
|
30
|
+
expect(helper.display_content_values(values)).to have_css('dd', text: 'guitar (1)')
|
31
|
+
expect(helper.display_content_values(values)).to have_css('dd', text: 'solo cowbell, trombone (2)')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'mods_display_label' do
|
36
|
+
it 'should return correct label' do
|
37
|
+
expect(helper.mods_display_label('test:')).not_to have_content ':'
|
38
|
+
expect(helper.mods_display_label('test:')).to have_css('dt', text: 'test')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'mods_display_content' do
|
43
|
+
it 'should return correct content' do
|
44
|
+
expect(helper.mods_display_content('hello, there')).to have_css('dd', text: 'hello, there')
|
45
|
+
end
|
46
|
+
it 'should return multiple dd elements when a multi-element array is passed' do
|
47
|
+
expect(helper.mods_display_content(%w(hello there))).to have_css('dd', count: 2)
|
48
|
+
end
|
49
|
+
it 'should handle nil values correctly' do
|
50
|
+
expect(helper.mods_display_content(['something', nil])).to have_css('dd', count: 1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'mods_record_field' do
|
55
|
+
let(:mods_field) { OpenStruct.new(label: 'test', values: ['hello, there']) }
|
56
|
+
let(:url_field) { OpenStruct.new(label: 'test', values: ['https://library.stanford.edu']) }
|
57
|
+
let(:multi_values) { double(label: 'test', values: %w(123 321)) }
|
58
|
+
|
59
|
+
it 'should return correct content' do
|
60
|
+
expect(helper.mods_record_field(mods_field)).to have_css('dt', text: 'test')
|
61
|
+
expect(helper.mods_record_field(mods_field)).to have_css('dd', text: 'hello, there')
|
62
|
+
end
|
63
|
+
it 'should link fields with URLs' do
|
64
|
+
expect(mods_record_field(url_field)).to have_css("a[href='https://library.stanford.edu']", text: 'https://library.stanford.edu')
|
65
|
+
end
|
66
|
+
it 'should not print empty labels' do
|
67
|
+
expect(helper.mods_record_field(empty_field)).not_to be_present
|
68
|
+
end
|
69
|
+
it 'should join values with a <dd> by default' do
|
70
|
+
expect(helper.mods_record_field(multi_values)).to have_css('dd', count: 2)
|
71
|
+
end
|
72
|
+
it 'should join values with a supplied delimiter' do
|
73
|
+
expect(helper.mods_record_field(multi_values, 'DELIM')).to have_css('dd', count: 1)
|
74
|
+
expect(helper.mods_record_field(multi_values, 'DELIM')).to have_css('dd', text: '123DELIM321')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'names' do
|
79
|
+
let(:name_field) do
|
80
|
+
OpenStruct.new(
|
81
|
+
label: 'Contributor',
|
82
|
+
values: [
|
83
|
+
OpenStruct.new(name: 'Winefrey, Oprah', roles: %w(Host Producer)),
|
84
|
+
OpenStruct.new(name: 'Kittenz, Emergency')
|
85
|
+
]
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#mods_name_field' do
|
90
|
+
it 'should join the label and values' do
|
91
|
+
name = mods_name_field(name_field) do |name|
|
92
|
+
link_to(name, searches_path(q: "\"#{name}\"", search_field: 'search_author'))
|
93
|
+
end
|
94
|
+
expect(name).to match /<dt>Contributor<\/dt>/
|
95
|
+
expect(name).to match /<dd><a href.*<\/dd>/
|
96
|
+
end
|
97
|
+
it 'should not print empty labels' do
|
98
|
+
expect(mods_name_field(empty_field)).not_to be_present
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#mods_display_name' do
|
103
|
+
let(:name) do
|
104
|
+
mods_display_name(name_field.values) do |name|
|
105
|
+
link_to(name, searches_path(q: "\"#{name}\"", search_field: 'search_author'))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should link to the name' do
|
110
|
+
expect(name).to match /<a href=.*%22Winefrey%2C\+Oprah%22.*>Winefrey, Oprah<\/a>/
|
111
|
+
expect(name).to match /<a href=.*%22Kittenz%2C\+Emergency%22.*>Kittenz, Emergency<\/a>/
|
112
|
+
end
|
113
|
+
it 'should link to an author search' do
|
114
|
+
expect(name).to match /<a href.*search_field=search_author.*>/
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#sanitize_mods_name_label' do
|
119
|
+
it 'removes a ":" at the end of label if present' do
|
120
|
+
expect(sanitize_mods_name_label('Test String:')).to eq 'Test String'
|
121
|
+
expect(sanitize_mods_name_label('Test String')).to eq 'Test String'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'subjects' do
|
127
|
+
let(:subjects) { [OpenStruct.new(label: 'Subjects', values: [%w(Subject1a Subject1b), %w(Subject2a Subject2b Subject2c)])] }
|
128
|
+
let(:name_subjects) { [OpenStruct.new(label: 'Subjects', values: [OpenStruct.new(name: 'Person Name', roles: %w(Role1 Role2))])] }
|
129
|
+
let(:genres) { [OpenStruct.new(label: 'Genres', values: %w(Genre1 Genre2 Genre3))] }
|
130
|
+
|
131
|
+
describe '#mods_subject_field' do
|
132
|
+
let(:subject) do
|
133
|
+
mods_subject_field(subjects.first) do |subject_text|
|
134
|
+
link_to(
|
135
|
+
subject_text,
|
136
|
+
searches_path(
|
137
|
+
q: "\"#{[[], subject_text.strip].flatten.join(' ')}\"",
|
138
|
+
search_field: 'subject_terms'
|
139
|
+
)
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
it 'should join the subject fields in a dd' do
|
144
|
+
expect(subject).to match /<dd><a href=*.*\">Subject1a*.*Subject1b<\/a><\/dd><dd><a/
|
145
|
+
end
|
146
|
+
it "should join the individual subjects with a '>'" do
|
147
|
+
expect(subject).to match /Subject2b<\/a> > <a href/
|
148
|
+
end
|
149
|
+
it 'should not print empty labels' do
|
150
|
+
expect(mods_subject_field(empty_field)).not_to be_present
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#mods_genre_field' do
|
155
|
+
it 'should join the genre fields with a dd' do
|
156
|
+
expect(mods_genre_field(genres.first) do |text|
|
157
|
+
link_to(text, searches_path(q: text))
|
158
|
+
end).to match /<dd><a href=*.*>Genre1*.*<\/a><\/dd><dd><a*.*Genre2<\/a><\/dd>/
|
159
|
+
end
|
160
|
+
it 'should not print empty labels' do
|
161
|
+
expect(mods_genre_field(empty_field)).not_to be_present
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#link_mods_subjects' do
|
166
|
+
let(:linked_subjects) do
|
167
|
+
link_mods_subjects(subjects.first.values.last) do |subject_text, buffer|
|
168
|
+
link_to(
|
169
|
+
subject_text,
|
170
|
+
searches_path(
|
171
|
+
q: "\"#{[buffer, subject_text.strip].flatten.join(' ')}\"",
|
172
|
+
search_field: 'subject_terms'
|
173
|
+
)
|
174
|
+
)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should return all subjects' do
|
179
|
+
expect(linked_subjects.length).to eq 3
|
180
|
+
end
|
181
|
+
it 'should link to the subject hierarchically' do
|
182
|
+
expect(linked_subjects[0]).to match /^<a href=.*q=%22Subject2a%22.*>Subject2a<\/a>$/
|
183
|
+
expect(linked_subjects[1]).to match /^<a href=.*q=%22Subject2a\+Subject2b%22.*>Subject2b<\/a>$/
|
184
|
+
expect(linked_subjects[2]).to match /^<a href=.*q=%22Subject2a\+Subject2b\+Subject2c%22.*>Subject2c<\/a>$/
|
185
|
+
end
|
186
|
+
it 'should link to subject terms search field' do
|
187
|
+
linked_subjects.each do |subject|
|
188
|
+
expect(subject).to match /search_field=subject_terms/
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#link_mods_genres' do
|
194
|
+
let(:linked_genres) do
|
195
|
+
link_mods_genres(genres.first.values.last) do |text|
|
196
|
+
link_to(
|
197
|
+
text,
|
198
|
+
searches_path(
|
199
|
+
q: "\"#{[[], text.strip].flatten.join(' ')}\"",
|
200
|
+
search_field: 'subject_terms'
|
201
|
+
)
|
202
|
+
)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should return correct link' do
|
207
|
+
expect(linked_genres).to match /<a href=*.*Genre3*.*<\/a>/
|
208
|
+
end
|
209
|
+
it 'should link to subject terms search field' do
|
210
|
+
expect(linked_genres).to match /search_field=subject_terms/
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#link_to_mods_subject' do
|
215
|
+
it 'should handle subjects that behave like names' do
|
216
|
+
name_subject = link_to_mods_subject(name_subjects.first.values.first, []) do |subject_text|
|
217
|
+
link_to(
|
218
|
+
subject_text,
|
219
|
+
searches_path(
|
220
|
+
q: "\"#{[[], subject_text.strip].flatten.join(' ')}\"",
|
221
|
+
search_field: 'subject_terms'
|
222
|
+
)
|
223
|
+
)
|
224
|
+
end
|
225
|
+
expect(name_subject).to match /<a href=.*%22Person\+Name%22.*>Person Name<\/a> \(Role1, Role2\)/
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#link_urls_and_email' do
|
231
|
+
let(:url) { 'This is a field that contains an https://library.stanford.edu URL' }
|
232
|
+
let(:email) { 'This is a field that contains an email@email.com address' }
|
233
|
+
|
234
|
+
it 'should link URLs' do
|
235
|
+
expect(link_urls_and_email(url)).to eq "This is a field that contains an <a href='https://library.stanford.edu'>https://library.stanford.edu</a> URL"
|
236
|
+
end
|
237
|
+
it 'should link email addresses' do
|
238
|
+
expect(link_urls_and_email(email)).to eq "This is a field that contains an <a href='mailto:email@email.com'>email@email.com</a> address"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -79,4 +79,9 @@ describe 'HTML Output' do
|
|
79
79
|
expect { @abstract.not_a_real_field }.to raise_error NoMethodError
|
80
80
|
end
|
81
81
|
end
|
82
|
+
describe 'individual fields' do
|
83
|
+
it 'should return ModsDispaly::Class when raw is specified' do
|
84
|
+
expect(@abstract.abstract(raw: true)).to be_a ModsDisplay::Abstract
|
85
|
+
end
|
86
|
+
end
|
82
87
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
ENV['RAILS_ENV'] ||= 'test'
|
1
2
|
require 'mods_display'
|
2
3
|
require 'stanford-mods'
|
3
4
|
require 'capybara'
|
5
|
+
require 'rails'
|
6
|
+
require 'fake_app'
|
7
|
+
require 'rspec/rails'
|
8
|
+
require 'mods_display/helpers/record_helper'
|
4
9
|
|
5
10
|
Dir["#{File.expand_path('..', __FILE__)}/fixtures/*.rb"].each { |file| require file }
|
6
11
|
# Load i18n test file.
|
@@ -24,6 +29,7 @@ RSpec.configure do |config|
|
|
24
29
|
# the seed, which is printed after each run.
|
25
30
|
# --seed 1234
|
26
31
|
config.order = 'random'
|
32
|
+
config.include Rails.application.routes.url_helpers
|
27
33
|
end
|
28
34
|
class TestModel
|
29
35
|
attr_accessor :modsxml
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mods_display
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jessie Keck
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: stanford-mods
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rubocop
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rails
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '6.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '6.0'
|
111
139
|
description: MODS Display is a gem to centralize the display logic of MODS medadata.
|
112
140
|
email:
|
113
141
|
- jessie.keck@gmail.com
|
@@ -115,10 +143,10 @@ executables: []
|
|
115
143
|
extensions: []
|
116
144
|
extra_rdoc_files: []
|
117
145
|
files:
|
146
|
+
- ".github/workflows/ruby.yml"
|
118
147
|
- ".gitignore"
|
119
148
|
- ".rubocop.yml"
|
120
149
|
- ".rubocop_todo.yml"
|
121
|
-
- ".travis.yml"
|
122
150
|
- Gemfile
|
123
151
|
- LICENSE.txt
|
124
152
|
- README.md
|
@@ -163,14 +191,17 @@ files:
|
|
163
191
|
- lib/mods_display/fields/subject.rb
|
164
192
|
- lib/mods_display/fields/title.rb
|
165
193
|
- lib/mods_display/fields/values.rb
|
194
|
+
- lib/mods_display/helpers/record_helper.rb
|
166
195
|
- lib/mods_display/html.rb
|
167
196
|
- lib/mods_display/model_extension.rb
|
197
|
+
- lib/mods_display/railtie.rb
|
168
198
|
- lib/mods_display/related_item_concerns.rb
|
169
199
|
- lib/mods_display/relator_codes.rb
|
170
200
|
- lib/mods_display/version.rb
|
171
201
|
- mods_display.gemspec
|
172
202
|
- spec/configuration/access_condition_spec.rb
|
173
203
|
- spec/configuration/base_spec.rb
|
204
|
+
- spec/fake_app.rb
|
174
205
|
- spec/fields/abstract_spec.rb
|
175
206
|
- spec/fields/access_condition_spec.rb
|
176
207
|
- spec/fields/audience_spec.rb
|
@@ -203,6 +234,7 @@ files:
|
|
203
234
|
- spec/fixtures/related_item_fixtures.rb
|
204
235
|
- spec/fixtures/subjects_fixtures.rb
|
205
236
|
- spec/fixtures/title_fixtures.rb
|
237
|
+
- spec/helpers/record_helper_spec.rb
|
206
238
|
- spec/integration/configuration_spec.rb
|
207
239
|
- spec/integration/html_spec.rb
|
208
240
|
- spec/integration/installation_spec.rb
|
@@ -211,7 +243,7 @@ files:
|
|
211
243
|
homepage: https://github.com/sul-dlss/mods_display
|
212
244
|
licenses: []
|
213
245
|
metadata: {}
|
214
|
-
post_install_message:
|
246
|
+
post_install_message:
|
215
247
|
rdoc_options: []
|
216
248
|
require_paths:
|
217
249
|
- lib
|
@@ -226,8 +258,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
258
|
- !ruby/object:Gem::Version
|
227
259
|
version: '0'
|
228
260
|
requirements: []
|
229
|
-
rubygems_version: 3.
|
230
|
-
signing_key:
|
261
|
+
rubygems_version: 3.2.3
|
262
|
+
signing_key:
|
231
263
|
specification_version: 4
|
232
264
|
summary: The MODS Display gem allows implementers to configure a customized display
|
233
265
|
of MODS metadata. This display implements the specifications defined at Stanford
|
@@ -235,6 +267,7 @@ summary: The MODS Display gem allows implementers to configure a customized disp
|
|
235
267
|
test_files:
|
236
268
|
- spec/configuration/access_condition_spec.rb
|
237
269
|
- spec/configuration/base_spec.rb
|
270
|
+
- spec/fake_app.rb
|
238
271
|
- spec/fields/abstract_spec.rb
|
239
272
|
- spec/fields/access_condition_spec.rb
|
240
273
|
- spec/fields/audience_spec.rb
|
@@ -267,6 +300,7 @@ test_files:
|
|
267
300
|
- spec/fixtures/related_item_fixtures.rb
|
268
301
|
- spec/fixtures/subjects_fixtures.rb
|
269
302
|
- spec/fixtures/title_fixtures.rb
|
303
|
+
- spec/helpers/record_helper_spec.rb
|
270
304
|
- spec/integration/configuration_spec.rb
|
271
305
|
- spec/integration/html_spec.rb
|
272
306
|
- spec/integration/installation_spec.rb
|
data/.travis.yml
DELETED