mods_display 0.10.1 → 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -1
  3. data/.rubocop_todo.yml +433 -35
  4. data/README.md +0 -95
  5. data/app/components/mods_display/field_component.html.erb +13 -0
  6. data/app/components/mods_display/field_component.rb +27 -0
  7. data/app/components/mods_display/list_field_component.html.erb +11 -0
  8. data/app/components/mods_display/list_field_component.rb +10 -0
  9. data/app/components/mods_display/record_component.html.erb +5 -0
  10. data/app/components/mods_display/record_component.rb +39 -0
  11. data/app/helpers/mods_display/record_helper.rb +106 -0
  12. data/app/models/mods_display/record.rb +26 -0
  13. data/config/locales/en.yml +1 -1
  14. data/config.ru +9 -0
  15. data/lib/mods_display/engine.rb +13 -0
  16. data/lib/mods_display/fields/access_condition.rb +4 -0
  17. data/lib/mods_display/fields/contents.rb +14 -15
  18. data/lib/mods_display/fields/field.rb +13 -149
  19. data/lib/mods_display/fields/genre.rb +4 -0
  20. data/lib/mods_display/fields/imprint.rb +52 -3
  21. data/lib/mods_display/fields/name.rb +11 -20
  22. data/lib/mods_display/fields/nested_related_item.rb +7 -18
  23. data/lib/mods_display/fields/note.rb +4 -0
  24. data/lib/mods_display/fields/related_item.rb +4 -0
  25. data/lib/mods_display/fields/sub_title.rb +3 -3
  26. data/lib/mods_display/fields/subject.rb +13 -39
  27. data/lib/mods_display/fields/title.rb +4 -0
  28. data/lib/mods_display/fields/values.rb +4 -4
  29. data/lib/mods_display/html.rb +54 -107
  30. data/lib/mods_display/version.rb +1 -1
  31. data/lib/mods_display.rb +2 -23
  32. data/mods_display.gemspec +15 -9
  33. metadata +45 -105
  34. data/.github/workflows/ruby.yml +0 -24
  35. data/.gitignore +0 -21
  36. data/lib/mods_display/configuration/access_condition.rb +0 -21
  37. data/lib/mods_display/configuration/base.rb +0 -34
  38. data/lib/mods_display/configuration/genre.rb +0 -9
  39. data/lib/mods_display/configuration/imprint.rb +0 -13
  40. data/lib/mods_display/configuration/name.rb +0 -9
  41. data/lib/mods_display/configuration/note.rb +0 -9
  42. data/lib/mods_display/configuration/related_item.rb +0 -9
  43. data/lib/mods_display/configuration/subject.rb +0 -13
  44. data/lib/mods_display/configuration/title.rb +0 -9
  45. data/lib/mods_display/configuration.rb +0 -93
  46. data/lib/mods_display/controller_extension.rb +0 -32
  47. data/lib/mods_display/helpers/record_helper.rb +0 -131
  48. data/lib/mods_display/model_extension.rb +0 -22
  49. data/lib/mods_display/railtie.rb +0 -10
  50. data/spec/configuration/access_condition_spec.rb +0 -10
  51. data/spec/configuration/base_spec.rb +0 -39
  52. data/spec/fake_app.rb +0 -18
  53. data/spec/fields/abstract_spec.rb +0 -39
  54. data/spec/fields/access_condition_spec.rb +0 -107
  55. data/spec/fields/audience_spec.rb +0 -24
  56. data/spec/fields/cartographics_spec.rb +0 -38
  57. data/spec/fields/collection_spec.rb +0 -77
  58. data/spec/fields/contact_spec.rb +0 -23
  59. data/spec/fields/contents_spec.rb +0 -39
  60. data/spec/fields/description_spec.rb +0 -55
  61. data/spec/fields/extent_spec.rb +0 -31
  62. data/spec/fields/form_spec.rb +0 -49
  63. data/spec/fields/genre_spec.rb +0 -34
  64. data/spec/fields/geo_spec.rb +0 -40
  65. data/spec/fields/identifier_spec.rb +0 -61
  66. data/spec/fields/imprint_spec.rb +0 -289
  67. data/spec/fields/language_spec.rb +0 -51
  68. data/spec/fields/location_spec.rb +0 -81
  69. data/spec/fields/name_spec.rb +0 -166
  70. data/spec/fields/nested_related_item_spec.rb +0 -89
  71. data/spec/fields/note_spec.rb +0 -72
  72. data/spec/fields/related_item_spec.rb +0 -72
  73. data/spec/fields/resource_type_spec.rb +0 -34
  74. data/spec/fields/sub_title_spec.rb +0 -20
  75. data/spec/fields/subject_spec.rb +0 -113
  76. data/spec/fields/title_spec.rb +0 -82
  77. data/spec/fixtures/access_condition_fixtures.rb +0 -58
  78. data/spec/fixtures/cartographics_fixtures.rb +0 -52
  79. data/spec/fixtures/imprint_fixtures.rb +0 -349
  80. data/spec/fixtures/name_fixtures.rb +0 -398
  81. data/spec/fixtures/nested_realted_items_fixtures.rb +0 -64
  82. data/spec/fixtures/related_item_fixtures.rb +0 -107
  83. data/spec/fixtures/subjects_fixtures.rb +0 -115
  84. data/spec/fixtures/title_fixtures.rb +0 -115
  85. data/spec/helpers/record_helper_spec.rb +0 -241
  86. data/spec/integration/configuration_spec.rb +0 -57
  87. data/spec/integration/html_spec.rb +0 -87
  88. data/spec/integration/installation_spec.rb +0 -26
  89. data/spec/spec_helper.rb +0 -46
  90. data/spec/test_fr.yml +0 -3
@@ -1,24 +0,0 @@
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/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .rvmrc
4
- .ruby-version
5
- .ruby-gemset
6
- .bundle
7
- .config
8
- .yardoc
9
- .rvmrc
10
- Gemfile.lock
11
- InstalledFiles
12
- _yardoc
13
- coverage
14
- doc/
15
- lib/bundler/man
16
- pkg
17
- rdoc
18
- spec/reports
19
- test/tmp
20
- test/version_tmp
21
- tmp
@@ -1,21 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class AccessCondition < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
-
8
- def ignore?
9
- @ignore.nil? ? true : @ignore
10
- end
11
-
12
- def display!
13
- @ignore = false
14
- end
15
-
16
- def cc_license_version(cc_license_version = '3.0')
17
- @cc_license_version ||= cc_license_version
18
- end
19
- end
20
- end
21
- end
@@ -1,34 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Base
4
- def initialize(&config)
5
- instance_eval(&config) if block_given?
6
- end
7
-
8
- def label_class(label_class = '')
9
- @label_class ||= label_class
10
- end
11
-
12
- def value_class(value_class = '')
13
- @value_class ||= value_class
14
- end
15
-
16
- def delimiter(delimiter = ', ')
17
- @delimiter ||= delimiter
18
- end
19
-
20
- def link(method_name = '', args = {})
21
- return @link if method_name == ''
22
- @link ||= [method_name, args]
23
- end
24
-
25
- def ignore!
26
- @ignore = true
27
- end
28
-
29
- def ignore?
30
- @ignore || false
31
- end
32
- end
33
- end
34
- end
@@ -1,9 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Genre < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
- end
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Imprint < Base
4
- def full_date_format(full_date_format = '%B %d, %Y')
5
- @full_date_format ||= full_date_format
6
- end
7
-
8
- def short_date_format(short_date_format = '%B %Y')
9
- @short_date_format ||= short_date_format
10
- end
11
- end
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Name < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Note < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class RelatedItem < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
- end
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Subject < Base
4
- def hierarchical_link(hierarchical_link = false)
5
- @hierarchical_link ||= hierarchical_link
6
- end
7
-
8
- def delimiter(delimiter = ' &gt; ')
9
- @delimiter ||= delimiter
10
- end
11
- end
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- module ModsDisplay
2
- class Configuration
3
- class Title < Base
4
- def delimiter(delimiter = '<br/>')
5
- @delimiter ||= delimiter
6
- end
7
- end
8
- end
9
- end
@@ -1,93 +0,0 @@
1
- # We can probably do something smarter here using const_get to assign
2
- # special coniguration classes then fall back on the base config class
3
- module ModsDisplay
4
- class Configuration
5
- def initialize(&config)
6
- instance_eval(&config)
7
- end
8
-
9
- def title(&title)
10
- @title ||= ModsDisplay::Configuration::Title.new(&title || proc {})
11
- end
12
-
13
- def sub_title(&sub_title)
14
- @sub_title ||= ModsDisplay::Configuration::Title.new(&sub_title || proc {})
15
- end
16
-
17
- def name(&name)
18
- @name ||= ModsDisplay::Configuration::Name.new(&name || proc {})
19
- end
20
-
21
- def resource_type(&resource_type)
22
- @type_of_resource ||= ModsDisplay::Configuration::Base.new(&resource_type || proc {})
23
- end
24
-
25
- def genre(&genre)
26
- @genre ||= ModsDisplay::Configuration::Genre.new(&genre || proc {})
27
- end
28
-
29
- def imprint(&imprint)
30
- @imprint ||= ModsDisplay::Configuration::Imprint.new(&imprint || proc {})
31
- end
32
-
33
- def language(&language)
34
- @language ||= ModsDisplay::Configuration::Base.new(&language || proc {})
35
- end
36
-
37
- def description(&description)
38
- @description ||= ModsDisplay::Configuration::Base.new(&description || proc {})
39
- end
40
-
41
- def cartographics(&cartographics)
42
- @cartographics ||= ModsDisplay::Configuration::Base.new(&cartographics || proc {})
43
- end
44
-
45
- def abstract(&abstract)
46
- @abstract ||= ModsDisplay::Configuration::Base.new(&abstract || proc {})
47
- end
48
-
49
- def contents(&contents)
50
- @contents ||= ModsDisplay::Configuration::Base.new(&contents || proc {})
51
- end
52
-
53
- def audience(&audience)
54
- @audience ||= ModsDisplay::Configuration::Base.new(&audience || proc {})
55
- end
56
-
57
- def note(&note)
58
- @note ||= ModsDisplay::Configuration::Note.new(&note || proc {})
59
- end
60
-
61
- def contact(&contact)
62
- @contact ||= ModsDisplay::Configuration::Base.new(&contact || proc {})
63
- end
64
-
65
- def collection(&collection)
66
- @collection ||= ModsDisplay::Configuration::Base.new(&collection || proc {})
67
- end
68
-
69
- def related_item(&related_item)
70
- @related_item ||= ModsDisplay::Configuration::RelatedItem.new(&related_item || proc {})
71
- end
72
-
73
- def nested_related_item(&nested_related_item)
74
- @nested_related_item ||= ModsDisplay::Configuration::Base.new(&nested_related_item || proc {})
75
- end
76
-
77
- def subject(&subject)
78
- @subject ||= ModsDisplay::Configuration::Subject.new(&subject || proc {})
79
- end
80
-
81
- def identifier(&identifier)
82
- @identifier ||= ModsDisplay::Configuration::Base.new(&identifier || proc {})
83
- end
84
-
85
- def location(&location)
86
- @location ||= ModsDisplay::Configuration::Base.new(&location || proc {})
87
- end
88
-
89
- def access_condition(&access_condition)
90
- @access_condition ||= ModsDisplay::Configuration::AccessCondition.new(&access_condition || proc {})
91
- end
92
- end
93
- end
@@ -1,32 +0,0 @@
1
- module ModsDisplay
2
- module ControllerExtension
3
- def self.included(base)
4
- base.extend ClassMethods
5
- base.class_eval do
6
- def mods_display_config
7
- @mods_display_config || self.class.mods_display_config
8
- end
9
- if base.respond_to?(:helper_method)
10
- helper_method :mods_display_config, :render_mods_display
11
- end
12
- end
13
- end
14
-
15
- def render_mods_display(model)
16
- return '' if model.mods_display_xml.nil?
17
- ModsDisplay::HTML.new(mods_display_config, model.mods_display_xml, self)
18
- end
19
-
20
- private
21
-
22
- module ClassMethods
23
- def configure_mods_display(&config)
24
- @mods_display_config = ModsDisplay::Configuration.new(&config)
25
- end
26
-
27
- def mods_display_config
28
- @mods_display_config || ModsDisplay::Configuration.new {}
29
- end
30
- end
31
- end
32
- end
@@ -1,131 +0,0 @@
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
@@ -1,22 +0,0 @@
1
- module ModsDisplay
2
- module ModelExtension
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
- mods
12
- end
13
- end
14
- end
15
-
16
- module ClassMethods
17
- def mods_xml_source(&xml)
18
- @mods_xml_source ||= xml
19
- end
20
- end
21
- end
22
- end
@@ -1,10 +0,0 @@
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,10 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ModsDisplay::Configuration::AccessCondition do
4
- it 'should default ignore? to true' do
5
- expect(ModsDisplay::Configuration::AccessCondition.new.ignore?).to be true
6
- end
7
- it 'should set ignore? to false when the display! configuration is set' do
8
- expect(ModsDisplay::Configuration::AccessCondition.new { display! }.ignore?).to be false
9
- end
10
- end
@@ -1,39 +0,0 @@
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
- expect(config.label_class).to eq('testing_label_class')
10
- expect(config.value_class).to eq('testing_value_class')
11
- end
12
- describe 'link' do
13
- it 'should return an array with a method name and params' do
14
- expect(ModsDisplay::Configuration::Base.new do
15
- link :my_url_generating_method, q: '"%value%"'
16
- end.link).to eq([:my_url_generating_method, { q: '"%value%"' }])
17
- end
18
- end
19
- describe 'delmiter' do
20
- it 'should override the default delimiter' do
21
- expect(ModsDisplay::Configuration::Base.new do
22
- delimiter '<br/>'
23
- end.delimiter).to eq('<br/>')
24
- end
25
- it "should default to ', '" do
26
- expect(ModsDisplay::Configuration::Base.new.delimiter).to eq(', ')
27
- end
28
- end
29
- describe 'ignore' do
30
- it 'should be set to true if the #ignore! method is called' do
31
- expect(ModsDisplay::Configuration::Base.new do
32
- ignore!
33
- end.ignore?).to be true
34
- end
35
- it 'should be false by default' do
36
- expect(ModsDisplay::Configuration::Base.new.ignore?).to be false
37
- end
38
- end
39
- end
data/spec/fake_app.rb DELETED
@@ -1,18 +0,0 @@
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)
@@ -1,39 +0,0 @@
1
- require 'spec_helper'
2
-
3
- def mods_display_abstract(mods_record)
4
- ModsDisplay::Abstract.new(mods_record, ModsDisplay::Configuration::Base.new, double('controller'))
5
- end
6
-
7
- describe ModsDisplay::Abstract do
8
- before(:all) do
9
- @link = Stanford::Mods::Record.new.from_str(
10
- '<mods><abstract>A link to the library (http://library.stanford.edu) should appear here</abstract></mods>', false
11
- ).abstract
12
- @email = Stanford::Mods::Record.new.from_str(
13
- '<mods><abstract>A link to an email address jdoe@example.com should appear here</abstract></mods>', false
14
- ).abstract
15
- end
16
-
17
- describe 'labels' do
18
- it "should get a default 'Abstract' label" do
19
- fields = mods_display_abstract(@link).fields
20
- expect(fields.length).to eq(1)
21
- expect(fields.first.label).to eq('Abstract:')
22
- end
23
- end
24
-
25
- describe 'links' do
26
- it 'should turn URLs into links' do
27
- expect(mods_display_abstract(@link).to_html).to match(/A link to the library \(<a href/)
28
- expect(mods_display_abstract(@link).to_html).to match(
29
- %r{\(<a href='http://library.stanford.edu'>http://library.stanford.edu</a>\)}
30
- )
31
- expect(mods_display_abstract(@link).to_html).to match(%r{</a>\) should appear here})
32
- end
33
- it 'should turn email addresses into mailto links' do
34
- expect(mods_display_abstract(@email).to_html).to match(
35
- %r{A link to an email address <a href='mailto:jdoe@example.com'>jdoe@example.com</a> should appear here}
36
- )
37
- end
38
- end
39
- end