pennmarc 1.0.22 → 1.0.24
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/lib/pennmarc/helpers/creator.rb +84 -21
- data/lib/pennmarc/helpers/date.rb +11 -9
- data/lib/pennmarc/mappings/locations.yml +6 -0
- data/lib/pennmarc/version.rb +1 -1
- data/spec/lib/pennmarc/helpers/creator_spec.rb +33 -0
- data/spec/lib/pennmarc/helpers/date_spec.rb +18 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59881d630f244bc6d8b76665df84f4b22297de2d51c44f5272df4226f4e27e75
|
4
|
+
data.tar.gz: 8d4e78c359dea40f482adc5b4deaa3fbb75bbe15a4fce5955ad48de054ce82c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a3a43ff1cecadf978a8c50d59b382c2592925116cacd757f368ea0a698e9b370a94e74fd98e1a6a06a3b837ab0dbdce2efece991aaf3da4b53c74396a73ee2e
|
7
|
+
data.tar.gz: 7f5468f9891c9fe15003160fb4d5a6c04cd8291ead5e803f0652368376e1fd67381195a7bdffd7ea9a7aa996c071b75240405dd956c46d879753f6811eca1b0a
|
@@ -21,6 +21,12 @@ module PennMARC
|
|
21
21
|
|
22
22
|
CONTRIBUTOR_TAGS = %w[700 710].freeze
|
23
23
|
|
24
|
+
FACET_SOURCE_MAP = {
|
25
|
+
100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
|
26
|
+
700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
|
27
|
+
800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
|
28
|
+
}.freeze
|
29
|
+
|
24
30
|
# Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from
|
25
31
|
# {https://www.oclc.org/bibformats/en/1xx/100.html 100 Main Entry--Personal Name} and
|
26
32
|
# {https://www.oclc.org/bibformats/en/1xx/110.html 110 Main Entry--Corporate Name}. Maps any relator codes found
|
@@ -51,19 +57,33 @@ module PennMARC
|
|
51
57
|
end
|
52
58
|
|
53
59
|
# Retrieve creator values for display from fields {https://www.loc.gov/marc/bibliographic/bd100.html 100}
|
54
|
-
# and {https://www.loc.gov/marc/bibliographic/bd110.html 110} and their linked alternates.
|
55
|
-
#
|
60
|
+
# and {https://www.loc.gov/marc/bibliographic/bd110.html 110} and their linked alternates. First, joins subfields
|
61
|
+
# other than $0, $1, $4, $6, $8, $e, and w. Then, appends any encoded relators found in $4.
|
62
|
+
# If there are no valid encoded relators, uses the value found in $e.
|
56
63
|
# @param [MARC::Record] record
|
57
64
|
# @return [Array<String>] array of author/creator values for display
|
58
65
|
def show(record, relator_map: Mappers.relator)
|
59
66
|
fields = record.fields(TAGS)
|
60
67
|
fields += record.fields('880').select { |field| subfield_value?(field, '6', /^(#{TAGS.join('|')})/) }
|
61
68
|
fields.filter_map { |field|
|
62
|
-
|
63
|
-
append_relator(field: field, joined_subfields: creator, relator_term_sf: 'e', relator_map: relator_map)
|
69
|
+
parse_show_value(field, relator_map: relator_map)
|
64
70
|
}.uniq
|
65
71
|
end
|
66
72
|
|
73
|
+
# Hash with main creator show values as the fields and the corresponding facet as the values.
|
74
|
+
# Does not include linked 880s.
|
75
|
+
# @param [MARC::Record] record
|
76
|
+
# @param [Hash] relator_map
|
77
|
+
# @return [Hash]
|
78
|
+
def show_facet_map(record, relator_map: Mappers.relator)
|
79
|
+
creators = record.fields(TAGS).filter_map do |field|
|
80
|
+
show = parse_show_value(field, relator_map: relator_map)
|
81
|
+
facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
|
82
|
+
{ show: show, facet: facet }
|
83
|
+
end
|
84
|
+
creators.to_h { |h| [h[:show], h[:facet]] }
|
85
|
+
end
|
86
|
+
|
67
87
|
# All author/creator values for display (like #show, but multivalued?) - no 880 linkage
|
68
88
|
# Performs additional normalization of author names
|
69
89
|
# @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
|
@@ -94,14 +114,9 @@ module PennMARC
|
|
94
114
|
# @param [MARC::Record] record
|
95
115
|
# @return [Array<String>] array of author/creator values for faceting
|
96
116
|
def facet(record)
|
97
|
-
|
98
|
-
100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
|
99
|
-
700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
|
100
|
-
800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
|
101
|
-
}
|
102
|
-
source_map.flat_map { |field_num, subfields|
|
117
|
+
FACET_SOURCE_MAP.flat_map { |field_num, subfields|
|
103
118
|
record.fields(field_num.to_s).map do |field|
|
104
|
-
|
119
|
+
parse_facet_value(field, subfields.chars)
|
105
120
|
end
|
106
121
|
}.uniq
|
107
122
|
end
|
@@ -117,7 +132,11 @@ module PennMARC
|
|
117
132
|
}.uniq
|
118
133
|
end
|
119
134
|
|
120
|
-
# Conference detailed display, intended for record show page.
|
135
|
+
# Conference detailed display, intended for record show page. Retrieve conference values for record display from
|
136
|
+
# {https://www.loc.gov/marc/bibliographic/bd111.html 111}, {https://www.loc.gov/marc/bibliographic/bd711.html 711}
|
137
|
+
# , and their linked 880s. If there is no $i, we join subfield $i we join subfield values other than
|
138
|
+
# $0, $4, $5, $6, $8, $e, $j, and $w. to create the conference value. We then join the conference subunit value
|
139
|
+
# using subfields $e and $w. We append any relators, preferring those defined in $4 and using $j as a fallback.
|
121
140
|
# @note ported from get_conference_values
|
122
141
|
# @todo what is ǂi for?
|
123
142
|
# @param [MARC::Record] record
|
@@ -126,15 +145,7 @@ module PennMARC
|
|
126
145
|
conferences = record.fields(%w[111 711]).filter_map do |field|
|
127
146
|
next unless field.indicator2.in? ['', ' ']
|
128
147
|
|
129
|
-
|
130
|
-
join_subfields field, &subfield_not_in?(%w[0 4 5 6 8 e j w])
|
131
|
-
else
|
132
|
-
''
|
133
|
-
end
|
134
|
-
sub_unit = join_subfields(field, &subfield_in?(%w[e w]))
|
135
|
-
conf = [conf, sub_unit].compact_blank.join(' ')
|
136
|
-
|
137
|
-
append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
|
148
|
+
parse_conference_detail_show_value(field, relator_map: relator_map)
|
138
149
|
end
|
139
150
|
conferences += record.fields('880').filter_map do |field|
|
140
151
|
next unless subfield_value? field, '6', /^(111|711)/
|
@@ -150,6 +161,24 @@ module PennMARC
|
|
150
161
|
conferences.uniq
|
151
162
|
end
|
152
163
|
|
164
|
+
# Return hash of detailed conference values mapped to their corresponding facets from fields
|
165
|
+
# {https://www.loc.gov/marc/bibliographic/bd111.html 111} and
|
166
|
+
# {https://www.loc.gov/marc/bibliographic/bd711.html 711}. Does not include linked 880s.
|
167
|
+
# @param [MARC::Record] record
|
168
|
+
# @param [Hash] relator_map
|
169
|
+
# @return [Hash]
|
170
|
+
def conference_detail_show_facet_map(record, relator_map: Mappers.relator)
|
171
|
+
conferences = record.fields(%w[111 711]).filter_map do |field|
|
172
|
+
next unless field.indicator2.in? ['', ' ']
|
173
|
+
|
174
|
+
show = parse_conference_detail_show_value(field, relator_map: relator_map)
|
175
|
+
facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
|
176
|
+
{ show: show, facet: facet }
|
177
|
+
end
|
178
|
+
|
179
|
+
conferences.to_h { |conf| [conf[:show], conf[:facet]] }
|
180
|
+
end
|
181
|
+
|
153
182
|
# Conference name values for searching
|
154
183
|
# @param [MARC::Record] record
|
155
184
|
# @return [Array<String>]
|
@@ -264,6 +293,40 @@ module PennMARC
|
|
264
293
|
before_comma = substring_before(name, ', ')
|
265
294
|
"#{after_comma} #{before_comma}".squish
|
266
295
|
end
|
296
|
+
|
297
|
+
# Parse creator facet value from given creator field and desired subfields
|
298
|
+
# @param [MARC::Field] field
|
299
|
+
# @param [Array<String>] subfields
|
300
|
+
# @return [String]
|
301
|
+
def parse_facet_value(field, subfields)
|
302
|
+
trim_punctuation(join_subfields(field, &subfield_in?(subfields)))
|
303
|
+
end
|
304
|
+
|
305
|
+
# Parse creator show value from given main creator fields (100/110).
|
306
|
+
# @param [MARC::Field] field
|
307
|
+
# @param [Hash] relator_map
|
308
|
+
# @return [String]
|
309
|
+
def parse_show_value(field, relator_map: Mappers.relator)
|
310
|
+
creator = join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
|
311
|
+
append_relator(field: field, joined_subfields: creator, relator_term_sf: 'e', relator_map: relator_map)
|
312
|
+
end
|
313
|
+
|
314
|
+
# Parse detailed conference show value from given conference field (111/711). If there is no $i, we join subfield
|
315
|
+
# values other than $0, $4, $5, $6, $8, $e, $j, and $w to create conference value. We join subfields $e and $w to
|
316
|
+
# determine the subunit value. We append any relators, preferring those defined in $4 and using $j as a fallback.
|
317
|
+
# @param [MARC::Field] field
|
318
|
+
# @return [String]
|
319
|
+
def parse_conference_detail_show_value(field, relator_map: Mappers.relator)
|
320
|
+
conf = if subfield_undefined? field, 'i'
|
321
|
+
join_subfields field, &subfield_not_in?(%w[0 4 5 6 8 e j w])
|
322
|
+
else
|
323
|
+
''
|
324
|
+
end
|
325
|
+
sub_unit = join_subfields(field, &subfield_in?(%w[e w]))
|
326
|
+
conf = [conf, sub_unit].compact_blank.join(' ')
|
327
|
+
|
328
|
+
append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
|
329
|
+
end
|
267
330
|
end
|
268
331
|
end
|
269
332
|
end
|
@@ -8,14 +8,14 @@ module PennMARC
|
|
8
8
|
# Publication date is a four-digit year found in position 7-10 and may contain 'u' characters to represent
|
9
9
|
# partially known dates. We replace any occurrences of 'u' with '0' before converting to DateTime object.
|
10
10
|
# @param [MARC::Record] record
|
11
|
-
# @return [
|
11
|
+
# @return [Time, nil] The publication date, or nil if date found in record is invalid
|
12
12
|
def publication(record)
|
13
13
|
record.fields('008').filter_map { |field|
|
14
14
|
four_digit_year = sanitize_partially_known_date(field.value[7, 4], '0')
|
15
15
|
|
16
16
|
next if four_digit_year.blank?
|
17
17
|
|
18
|
-
|
18
|
+
Time.new(four_digit_year.to_i)
|
19
19
|
}.first
|
20
20
|
end
|
21
21
|
|
@@ -23,7 +23,7 @@ module PennMARC
|
|
23
23
|
# {PennMARC::Enriched} maps enriched marc fields and subfields created during Alma publishing. The enriched
|
24
24
|
# metadata provided by the Alma API does not include the date created value, so we can't work with that here.
|
25
25
|
# @param [MARC::Record] record
|
26
|
-
# @return [
|
26
|
+
# @return [Time, nil] The date added, or nil if date found in record is invalid
|
27
27
|
def added(record)
|
28
28
|
record.fields(Enriched::Pub::ITEM_TAG).flat_map { |field|
|
29
29
|
subfield_values(field, Enriched::Pub::ITEM_DATE_CREATED).filter_map do |date_added|
|
@@ -34,9 +34,10 @@ module PennMARC
|
|
34
34
|
|
35
35
|
format = date_added.size == 10 ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S'
|
36
36
|
|
37
|
-
|
37
|
+
Time.strptime(date_added, format)
|
38
38
|
rescue StandardError => e
|
39
|
-
puts
|
39
|
+
puts 'Error parsing date in date added subfield. ' \
|
40
|
+
"mmsid: #{Identifier.mmsid(record)}, value: #{date_added}, error: #{e}"
|
40
41
|
nil
|
41
42
|
end
|
42
43
|
}.max
|
@@ -46,7 +47,7 @@ module PennMARC
|
|
46
47
|
# Date last updated is a sixteen character String recorded in
|
47
48
|
# {https://www.iso.org/iso-8601-date-and-time-format.html ISO 8601} format.
|
48
49
|
# @param [MARC::Record] record
|
49
|
-
# @return [
|
50
|
+
# @return [Time, nil] The date last updated, or nil if date found in record is invalid
|
50
51
|
def last_updated(record)
|
51
52
|
record.fields('005').filter_map { |field|
|
52
53
|
begin
|
@@ -56,9 +57,10 @@ module PennMARC
|
|
56
57
|
|
57
58
|
next if date_time_string.start_with?('0000')
|
58
59
|
|
59
|
-
|
60
|
-
rescue
|
61
|
-
puts
|
60
|
+
Time.strptime(date_time_string, '%Y%m%d%H%M%S.%N')
|
61
|
+
rescue StandardError => e
|
62
|
+
puts 'Error parsing last updated date. ' \
|
63
|
+
"mmsid: #{Identifier.mmsid(record)}, value: #{date_time_string}, error: #{e}"
|
62
64
|
nil
|
63
65
|
end
|
64
66
|
}.first
|
@@ -547,6 +547,12 @@ dent:
|
|
547
547
|
- Health Sciences Libraries
|
548
548
|
- Levy Dental Medicine Library
|
549
549
|
display: Levy Dental Medicine Library - Stacks
|
550
|
+
dentpcare:
|
551
|
+
specific_location: Levy Dental Medicine Library - PCare
|
552
|
+
library:
|
553
|
+
- Health Sciences Libraries
|
554
|
+
- Levy Dental Medicine Library
|
555
|
+
display: Levy Dental Medicine Library - PCare
|
550
556
|
dentrare:
|
551
557
|
specific_location: Levy Dental Medicine Library - Rare Books
|
552
558
|
library:
|
data/lib/pennmarc/version.rb
CHANGED
@@ -95,6 +95,23 @@ describe 'PennMARC::Creator' do
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
+
describe '.show_facet_map' do
|
99
|
+
let(:record) do
|
100
|
+
marc_record fields: [
|
101
|
+
marc_field(tag: '100', subfields: { a: 'Surname, Name', '0': 'http://cool.uri/12345', d: '1900-2000',
|
102
|
+
e: 'author.', '4': 'http://cool.uri/vocabulary/relators/aut' }),
|
103
|
+
marc_field(tag: '110', subfields: { a: 'Group of People', b: 'Annual Meeting', '4': 'aut' }),
|
104
|
+
marc_field(tag: '880', subfields: { a: 'Ignore', '6': '100' })
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns expected hash' do
|
109
|
+
values = helper.show_facet_map(record, relator_map: mapping)
|
110
|
+
expect(values).to eq({ 'Surname, Name 1900-2000, author.' => 'Surname, Name 1900-2000',
|
111
|
+
'Group of People Annual Meeting, Author.' => 'Group of People Annual Meeting' })
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
98
115
|
describe '.show_aux' do
|
99
116
|
let(:record) { marc_record fields: fields }
|
100
117
|
|
@@ -257,6 +274,22 @@ describe 'PennMARC::Creator' do
|
|
257
274
|
end
|
258
275
|
end
|
259
276
|
|
277
|
+
describe '.conference_detail_show_facet_map' do
|
278
|
+
let(:record) do
|
279
|
+
marc_record fields: [
|
280
|
+
marc_field(tag: '111', subfields: { a: 'Council of Trent', d: '(1545-1563 :', c: 'Trento, Italy)' }),
|
281
|
+
marc_field(tag: '711', subfields: { a: 'Code4Lib', n: '(18th :', d: '2024 :', c: 'Ann Arbor, MI)' }),
|
282
|
+
marc_field(tag: '880', subfields: { a: 'Alt Ignore', '6': '111' })
|
283
|
+
]
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'returns the expected hash' do
|
287
|
+
value = helper.conference_detail_show_facet_map(record)
|
288
|
+
expect(value).to eq({ 'Council of Trent (1545-1563 : Trento, Italy)' => 'Council of Trent Trento, Italy)',
|
289
|
+
'Code4Lib (18th : 2024 : Ann Arbor, MI)' => 'Code4Lib (18th : Ann Arbor, MI)' })
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
260
293
|
describe '.conference_search' do
|
261
294
|
let(:record) do
|
262
295
|
marc_record fields: [
|
@@ -10,7 +10,7 @@ describe 'PennMARC::Date' do
|
|
10
10
|
let(:fields) { [marc_control_field(tag: '008', value: '130827s2010 nyu o 000 1 eng d')] }
|
11
11
|
|
12
12
|
it 'returns publication date' do
|
13
|
-
expect(helper.publication(record)).to eq(
|
13
|
+
expect(helper.publication(record)).to eq(Time.new(2010))
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns a year value' do
|
@@ -33,7 +33,7 @@ describe 'PennMARC::Date' do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'returns only the expected date_added value' do
|
36
|
-
expect(helper.added(record)).to eq
|
36
|
+
expect(helper.added(record)).to eq Time.strptime('2023-10-19', '%Y-%m-%d')
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'does not output any warning to STDOUT' do
|
@@ -47,7 +47,7 @@ describe 'PennMARC::Date' do
|
|
47
47
|
let(:fields) { [marc_field(tag: 'itm', subfields: { q: '2023-06-28' })] }
|
48
48
|
|
49
49
|
it 'returns expected value' do
|
50
|
-
expect(helper.added(record)).to eq(
|
50
|
+
expect(helper.added(record)).to eq(Time.strptime('2023-06-28', '%Y-%m-%d'))
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'returns a year value' do
|
@@ -59,7 +59,7 @@ describe 'PennMARC::Date' do
|
|
59
59
|
let(:fields) { [marc_field(tag: 'itm', subfields: { q: '2023-06-29 11:04:30:10' })] }
|
60
60
|
|
61
61
|
it 'returns expected value' do
|
62
|
-
expect(helper.added(record)).to eq(
|
62
|
+
expect(helper.added(record)).to eq(Time.strptime('2023-06-29 11:04:30:10', '%Y-%m-%d %H:%M:%S'))
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'returns a year value' do
|
@@ -74,12 +74,15 @@ describe 'PennMARC::Date' do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'returns most recent date' do
|
77
|
-
expect(helper.added(record)).to eq(
|
77
|
+
expect(helper.added(record)).to eq(Time.strptime('2023-06-29', '%Y-%m-%d'))
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
context 'with invalid date' do
|
82
|
-
let(:fields)
|
82
|
+
let(:fields) do
|
83
|
+
[marc_control_field(tag: '001', value: 'mmsid'),
|
84
|
+
marc_field(tag: 'itm', subfields: { q: 'invalid date' })]
|
85
|
+
end
|
83
86
|
|
84
87
|
it 'returns nil' do
|
85
88
|
expect(helper.added(record)).to be_nil
|
@@ -88,7 +91,8 @@ describe 'PennMARC::Date' do
|
|
88
91
|
it 'outputs error message' do
|
89
92
|
expect {
|
90
93
|
helper.added(record)
|
91
|
-
}.to output(
|
94
|
+
}.to output('Error parsing date in date added subfield. mmsid: mmsid, value: invalid date, ' \
|
95
|
+
"error: invalid date or strptime format - `invalid date' `%Y-%m-%d %H:%M:%S'\n").to_stdout
|
92
96
|
end
|
93
97
|
end
|
94
98
|
end
|
@@ -97,7 +101,7 @@ describe 'PennMARC::Date' do
|
|
97
101
|
let(:fields) { [marc_field(tag: '005', subfields: { q: '20230213163851.1' })] }
|
98
102
|
|
99
103
|
it 'returns date last updated' do
|
100
|
-
expect(helper.last_updated(record)).to eq(
|
104
|
+
expect(helper.last_updated(record)).to eq(Time.strptime('20230213163851.1', '%Y%m%d%H%M%S.%N'))
|
101
105
|
end
|
102
106
|
|
103
107
|
it 'returns year value' do
|
@@ -105,7 +109,10 @@ describe 'PennMARC::Date' do
|
|
105
109
|
end
|
106
110
|
|
107
111
|
context 'with invalid date' do
|
108
|
-
let(:fields)
|
112
|
+
let(:fields) do
|
113
|
+
[marc_control_field(tag: '001', value: 'mmsid'),
|
114
|
+
marc_field(tag: '005', subfields: { q: 'invalid date' })]
|
115
|
+
end
|
109
116
|
|
110
117
|
it 'returns nil' do
|
111
118
|
expect(helper.last_updated(record)).to be_nil
|
@@ -114,7 +121,8 @@ describe 'PennMARC::Date' do
|
|
114
121
|
it 'outputs error message' do
|
115
122
|
expect {
|
116
123
|
helper.last_updated(record)
|
117
|
-
}.to output(
|
124
|
+
}.to output('Error parsing last updated date. mmsid: mmsid, value: invalid date, ' \
|
125
|
+
"error: invalid date or strptime format - `invalid date' `%Y%m%d%H%M%S.%N'\n").to_stdout
|
118
126
|
end
|
119
127
|
end
|
120
128
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pennmarc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Kanning
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|