mods_display 0.7.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b98625a861414ce3c06cd365c9850454a50ccd83719124820a49f4fcb7ff107d
4
- data.tar.gz: e0c7ded47f3f3f38b821294f4bb9252e0fd7ffdb3fae837dc4da340bc225ab44
3
+ metadata.gz: 586a8299be19e795bc90b434d9902084ca8fa10bb8cbe9690fc108471e1f5495
4
+ data.tar.gz: 00574a48dc3c3ba050529bf2d3fcd5e38df5de4c0e5ed4023ad07904dea29c99
5
5
  SHA512:
6
- metadata.gz: efd399144bc193f4db0bfd4b3185346dce1e8cc523fad133af38f61a19d2f41b42e8d05a4fad6ea77dab744eeba2b7727b2dfe911f34c49844ca94fd433320fa
7
- data.tar.gz: 121a7fa3ba9a0af4887fbc5fac992c95be7c19b888cb632fede718bb2796b1ceb783ce98f16e06de415e149b344584f6c4046dfa2f25c1bcc01823ade826ee46
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
@@ -24,7 +24,7 @@ module ModsDisplay
24
24
  private
25
25
 
26
26
  def location_field_keys
27
- [:physicalLocation, :url, :shelfLocation, :holdingSimple, :holdingExternal]
27
+ [:physicalLocation, :url, :shelfLocator, :holdingSimple, :holdingExternal]
28
28
  end
29
29
 
30
30
  def location_label(element)
@@ -4,31 +4,10 @@ module ModsDisplay
4
4
  return_values = []
5
5
  if @values
6
6
  @values.each do |value|
7
- if displayForm(value)
8
- return_values << ModsDisplay::Values.new(
9
- label: displayLabel(value) || title_label(value),
10
- values: [displayForm(value)]
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 parts_delimiter(element)
40
- children = element.children.to_a
41
- # index will retun nil which is not comparable so we call 100
42
- # if the element isn't present (thus meaning it's at the end of the list)
43
- if (children.index { |c| c.name == 'partNumber' } || 100) < (children.index { |c| c.name == 'partName' } || 100)
44
- return ', '
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
@@ -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).fields
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
@@ -1,3 +1,3 @@
1
1
  module ModsDisplay
2
- VERSION = '0.7.0'
2
+ VERSION = '0.10.0'
3
3
  end
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 itentify and link CreativeCommons licenses properly' do
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 itentify and link OpenDataCommons licenses properly' do
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
@@ -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
@@ -5,7 +5,7 @@ describe ModsDisplay::Location do
5
5
  <<-XML
6
6
  <mods>
7
7
  <location>
8
- <shelfLocation>On Shelf A</shelfLocation>
8
+ <shelfLocator>On Shelf A</shelfLocator>
9
9
  </location>
10
10
  </mods>
11
11
  XML
@@ -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
@@ -47,4 +47,12 @@ module AccessConditionFixtures
47
47
  </mods>
48
48
  XML
49
49
  end
50
+
51
+ def garbage_license_fixture
52
+ <<-XML
53
+ <mods>
54
+ <accessCondition type='license'>Unknown garbage that does not look like a license</accessCondition>
55
+ </mods>
56
+ XML
57
+ end
50
58
  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> &gt; <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.7.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: 2019-08-12 00:00:00.000000000 Z
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.0.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
@@ -1,4 +0,0 @@
1
- notifications:
2
- email: false
3
- rvm:
4
- - 2.5.3