ebsco-eds 0.0.1.pre
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 +7 -0
- data/.env.test +12 -0
- data/.gitignore +20 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ebsco-eds.gemspec +47 -0
- data/lib/ebsco/eds.rb +27 -0
- data/lib/ebsco/eds/error.rb +47 -0
- data/lib/ebsco/eds/http_exception.rb +49 -0
- data/lib/ebsco/eds/info.rb +193 -0
- data/lib/ebsco/eds/jsonable.rb +28 -0
- data/lib/ebsco/eds/options.rb +339 -0
- data/lib/ebsco/eds/record.rb +700 -0
- data/lib/ebsco/eds/results.rb +375 -0
- data/lib/ebsco/eds/session.rb +624 -0
- data/lib/ebsco/eds/settings.yml +35 -0
- data/lib/ebsco/eds/version.rb +5 -0
- metadata +248 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module JSONable
|
4
|
+
module ClassMethods
|
5
|
+
attr_accessor :attributes
|
6
|
+
|
7
|
+
def attr_accessor(*attrs)
|
8
|
+
self.attributes = Array attrs
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json
|
18
|
+
serialized = Hash.new
|
19
|
+
self.class.attributes.each do |attribute|
|
20
|
+
serialized[attribute] = self.public_send attribute
|
21
|
+
end
|
22
|
+
serialized
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_json(*a)
|
26
|
+
as_json.to_json(*a)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,339 @@
|
|
1
|
+
require 'ebsco/eds/jsonable'
|
2
|
+
|
3
|
+
module EBSCO
|
4
|
+
|
5
|
+
module EDS
|
6
|
+
|
7
|
+
class Options
|
8
|
+
include JSONable
|
9
|
+
attr_accessor :SearchCriteria, :RetrievalCriteria, :Actions
|
10
|
+
def initialize(options = {}, info)
|
11
|
+
|
12
|
+
@SearchCriteria = EBSCO::EDS::SearchCriteria.new(options, info)
|
13
|
+
|
14
|
+
@RetrievalCriteria = EBSCO::EDS::RetrievalCriteria.new(options, info)
|
15
|
+
|
16
|
+
@Actions = []
|
17
|
+
|
18
|
+
options.each do |key, value|
|
19
|
+
|
20
|
+
case key
|
21
|
+
|
22
|
+
when :actions
|
23
|
+
add_actions(options[:actions], info)
|
24
|
+
|
25
|
+
# solr facet translation
|
26
|
+
# "f"=>{"format"=>["eBooks"]}
|
27
|
+
when 'f'
|
28
|
+
if value.has_key?('format')
|
29
|
+
format_list = value['format']
|
30
|
+
format_list.each do |item|
|
31
|
+
@Actions.push "addfacetfilter(SourceType:#{item})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
if value.has_key?('language_facet')
|
35
|
+
lang_list = value['language_facet']
|
36
|
+
lang_list.each do |item|
|
37
|
+
@Actions.push "addfacetfilter(Language:#{item})"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
if value.has_key?('subject_topic_facet')
|
41
|
+
subj_list = value['subject_topic_facet']
|
42
|
+
subj_list.each do |item|
|
43
|
+
@Actions.push "addfacetfilter(SubjectEDS:#{item})"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
puts 'ACTIONS: ' + @Actions.inspect
|
48
|
+
|
49
|
+
else
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_actions(actions, info)
|
57
|
+
if actions.kind_of?(Array) && actions.count > 0
|
58
|
+
actions.each do |item|
|
59
|
+
#if is_valid_action(item, info)
|
60
|
+
@Actions.push item
|
61
|
+
#end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
#if is_valid_action(actions, info)
|
65
|
+
@Actions = [actions]
|
66
|
+
#else
|
67
|
+
#end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# def is_valid_action(action, info)
|
72
|
+
# # actions in info that require an enumerated value (e.g., addlimiter(LA99:Bulgarian))
|
73
|
+
# _available_actions = info.available_actions
|
74
|
+
# _defined_action = _available_actions.include? action
|
75
|
+
# # actions not enumerated in info (e.g., GoToPage(3))
|
76
|
+
# _available_standard_actions = ['GoToPage']
|
77
|
+
# _standard_action = _available_standard_actions.any? { |std| action.include? std }
|
78
|
+
# # actions in info that require a user supplied value (e.g., addlimiter(TI:value))
|
79
|
+
# _available_value_actions = %w{PG4 CS1 FM FT FR RV DT1 SO}
|
80
|
+
# _value_action = _available_value_actions.any? { |type| action.include? type }
|
81
|
+
#
|
82
|
+
# if _value_action || _defined_action || _standard_action
|
83
|
+
# true
|
84
|
+
# else
|
85
|
+
# false
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
class SearchCriteria
|
92
|
+
include JSONable
|
93
|
+
attr_accessor :Queries, :SearchMode, :IncludeFacets, :FacetFilters, :Limiters, :Sort, :PublicationId,
|
94
|
+
:RelatedContent, :AutoSuggest, :Expanders
|
95
|
+
|
96
|
+
def initialize(options = {}, info)
|
97
|
+
|
98
|
+
# defaults
|
99
|
+
@SearchMode = info.default_search_mode
|
100
|
+
@IncludeFacets = 'y'
|
101
|
+
@Sort = 'relevance'
|
102
|
+
@AutoSuggest = info.default_auto_suggest
|
103
|
+
_has_query = false
|
104
|
+
|
105
|
+
@Expanders = info.default_expander_ids
|
106
|
+
_my_expanders = []
|
107
|
+
_available_expander_ids = info.available_expander_ids
|
108
|
+
|
109
|
+
@Limiter = nil
|
110
|
+
_my_limiters = []
|
111
|
+
|
112
|
+
@RelatedContent = info.default_related_content_types
|
113
|
+
_my_related_content = []
|
114
|
+
_available_related_content_types = info.available_related_content_types
|
115
|
+
|
116
|
+
options.each do |key, value|
|
117
|
+
|
118
|
+
case key
|
119
|
+
|
120
|
+
# ====================================================================================
|
121
|
+
# query
|
122
|
+
# ====================================================================================
|
123
|
+
when :query, 'q'
|
124
|
+
|
125
|
+
# add blacklight search_fields
|
126
|
+
_field_code = ''
|
127
|
+
if options.has_key? 'search_field'
|
128
|
+
_field = options['search_field']
|
129
|
+
case _field
|
130
|
+
when 'author'
|
131
|
+
_field_code = 'AU'
|
132
|
+
when 'subject'
|
133
|
+
_field_code = 'SU'
|
134
|
+
when 'title'
|
135
|
+
_field_code = 'TI'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
if not _field_code == ''
|
140
|
+
@Queries = [{:FieldCode => _field_code, :Term => value}]
|
141
|
+
else
|
142
|
+
@Queries = [{:Term => value}]
|
143
|
+
end
|
144
|
+
_has_query = true
|
145
|
+
|
146
|
+
# ====================================================================================
|
147
|
+
# mode
|
148
|
+
# ====================================================================================
|
149
|
+
when :mode
|
150
|
+
if info.available_search_mode_types.include? value.downcase
|
151
|
+
@SearchMode = value.downcase
|
152
|
+
else
|
153
|
+
@SearchMode = info.default_search_mode
|
154
|
+
end
|
155
|
+
|
156
|
+
# ====================================================================================
|
157
|
+
# facets
|
158
|
+
# ====================================================================================
|
159
|
+
when :include_facets
|
160
|
+
@IncludeFacets = value ? 'y' : 'n'
|
161
|
+
|
162
|
+
when :facet_filters
|
163
|
+
@FacetFilters = value
|
164
|
+
|
165
|
+
# ====================================================================================
|
166
|
+
# sort
|
167
|
+
# ====================================================================================
|
168
|
+
when :sort, 'sort'
|
169
|
+
if info.available_sorts(value.downcase).empty?
|
170
|
+
if value.downcase == 'newest' || value.downcase == 'pub_date_sort desc'
|
171
|
+
@Sort = 'date'
|
172
|
+
elsif value.downcase == 'oldest' || value.downcase == 'pub_date_sort asc'
|
173
|
+
@Sort = 'date2'
|
174
|
+
elsif value.downcase == 'score desc'
|
175
|
+
@Sort = 'relevance'
|
176
|
+
else
|
177
|
+
@Sort = 'relevance'
|
178
|
+
end
|
179
|
+
else
|
180
|
+
@Sort = value.downcase
|
181
|
+
end
|
182
|
+
|
183
|
+
# ====================================================================================
|
184
|
+
# publication id
|
185
|
+
# ====================================================================================
|
186
|
+
when :publication_id
|
187
|
+
@PublicationId = value
|
188
|
+
|
189
|
+
when :auto_suggest
|
190
|
+
@AutoSuggest = value ? 'y' : 'n'
|
191
|
+
|
192
|
+
# ====================================================================================
|
193
|
+
# expanders
|
194
|
+
# ====================================================================================
|
195
|
+
when :expanders
|
196
|
+
value.each do |item|
|
197
|
+
if _available_expander_ids.include? item.downcase
|
198
|
+
_my_expanders.push(item)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
if _my_expanders.empty?
|
202
|
+
_my_expanders = info.default_expander_ids
|
203
|
+
end
|
204
|
+
@Expanders = _my_expanders
|
205
|
+
|
206
|
+
# ====================================================================================
|
207
|
+
# limiters
|
208
|
+
# ====================================================================================
|
209
|
+
when :limiters
|
210
|
+
value.each do |item|
|
211
|
+
_key = item.split(':',2).first.upcase
|
212
|
+
_values = item.split(':',2).last
|
213
|
+
# is limiter id available?
|
214
|
+
if info.available_limiter_ids.include? _key
|
215
|
+
_limiter = info.available_limiters(_key)
|
216
|
+
# if multi-value, add the values if they're available
|
217
|
+
if _limiter['Type'] == 'multiselectvalue'
|
218
|
+
_available_values = info.available_limiter_values(_key)
|
219
|
+
_multi_values = []
|
220
|
+
_values.split(',').each do |val|
|
221
|
+
# todo: make case insensitive?
|
222
|
+
if _available_values.include? val
|
223
|
+
_multi_values.push(val)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if _multi_values.empty?
|
227
|
+
# do nothing, none of the values are available
|
228
|
+
else
|
229
|
+
_my_limiters.push({:Id => _key, :Values => _multi_values})
|
230
|
+
end
|
231
|
+
# single value, just pass it on
|
232
|
+
else
|
233
|
+
_my_limiters.push({:Id => _key, :Values => [_values]})
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
@Limiters = _my_limiters
|
238
|
+
|
239
|
+
# ====================================================================================
|
240
|
+
# related content
|
241
|
+
# ====================================================================================
|
242
|
+
when :related_content
|
243
|
+
value.each do |item|
|
244
|
+
if _available_related_content_types.include? item.downcase
|
245
|
+
_available_related_content_types.push(item)
|
246
|
+
else
|
247
|
+
# silently ignore
|
248
|
+
end
|
249
|
+
end
|
250
|
+
if _my_related_content.empty?
|
251
|
+
_my_related_content = info.default_related_content_types
|
252
|
+
end
|
253
|
+
@RelatedContent = _my_related_content
|
254
|
+
|
255
|
+
# ====================================================================================
|
256
|
+
# unsupported parameters, ignore
|
257
|
+
# ====================================================================================
|
258
|
+
else
|
259
|
+
# ignore
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
class RetrievalCriteria
|
270
|
+
include JSONable
|
271
|
+
attr_accessor :View, :ResultsPerPage, :PageNumber, :Highlight
|
272
|
+
def initialize(options = {}, info)
|
273
|
+
|
274
|
+
# defaults
|
275
|
+
@View = info.default_result_list_view
|
276
|
+
@ResultsPerPage = info.default_results_per_page
|
277
|
+
@PageNumber = 1
|
278
|
+
|
279
|
+
options.each do |key, value|
|
280
|
+
|
281
|
+
case key
|
282
|
+
|
283
|
+
# ====================================================================================
|
284
|
+
# view
|
285
|
+
# ====================================================================================
|
286
|
+
when :view
|
287
|
+
if info.available_result_list_views.include? value.downcase
|
288
|
+
@View = value.downcase
|
289
|
+
else
|
290
|
+
@View = info.default_result_list_view
|
291
|
+
end
|
292
|
+
|
293
|
+
# ====================================================================================
|
294
|
+
# results per page
|
295
|
+
# ====================================================================================
|
296
|
+
when :results_per_page, 'rows', 'per_page'
|
297
|
+
if value.to_i > info.max_results_per_page
|
298
|
+
@ResultsPerPage = info.max_results_per_page
|
299
|
+
else
|
300
|
+
@ResultsPerPage = value.to_i
|
301
|
+
end
|
302
|
+
|
303
|
+
# ====================================================================================
|
304
|
+
# page number
|
305
|
+
# ====================================================================================
|
306
|
+
when :page_number, 'page'
|
307
|
+
@PageNumber = value.to_i
|
308
|
+
# puts 'NEW PAGE: ' + @PageNumber.inspect
|
309
|
+
# solr starts at page 0
|
310
|
+
when 'start'
|
311
|
+
@PageNumber = value.to_i + 1
|
312
|
+
|
313
|
+
# ====================================================================================
|
314
|
+
# highlight
|
315
|
+
# ====================================================================================
|
316
|
+
when :highlight
|
317
|
+
@Highlight = value ? 'y' : 'n'
|
318
|
+
# solr/blacklight version
|
319
|
+
when 'hl'
|
320
|
+
if value == 'on'
|
321
|
+
@Highlight = 'y'
|
322
|
+
else
|
323
|
+
@Highlight = 'n'
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
else
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
end
|
339
|
+
end
|
@@ -0,0 +1,700 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
require 'bibtex'
|
4
|
+
|
5
|
+
module EBSCO
|
6
|
+
|
7
|
+
module EDS
|
8
|
+
|
9
|
+
# A single search result
|
10
|
+
class Record
|
11
|
+
|
12
|
+
# Raw record as returned by the \EDS API via search or retrieve
|
13
|
+
attr_reader :record
|
14
|
+
|
15
|
+
# Lookup table of databases that have their labels suppressed in the response.
|
16
|
+
DBS = YAML::load_file(File.join(__dir__, 'settings.yml'))['databases']
|
17
|
+
|
18
|
+
# Creates a search or retrieval result record
|
19
|
+
def initialize(results_record)
|
20
|
+
|
21
|
+
if results_record.key? 'Record'
|
22
|
+
@record = results_record['Record'] # single record returned by retrieve api
|
23
|
+
else
|
24
|
+
@record = results_record # set of records returned by search api
|
25
|
+
end
|
26
|
+
|
27
|
+
@items = @record.fetch('Items', {})
|
28
|
+
|
29
|
+
@bib_entity = @record.fetch('RecordInfo', {})
|
30
|
+
.fetch('BibRecord', {})
|
31
|
+
.fetch('BibEntity', {})
|
32
|
+
|
33
|
+
@bib_relationships = @record.fetch('RecordInfo', {})
|
34
|
+
.fetch('BibRecord', {})
|
35
|
+
.fetch('BibRelationships', {})
|
36
|
+
|
37
|
+
@bib_part = @record.fetch('RecordInfo', {})
|
38
|
+
.fetch('BibRecord', {})
|
39
|
+
.fetch('BibRelationships', {})
|
40
|
+
.fetch('IsPartOfRelationships', {})[0]
|
41
|
+
|
42
|
+
@bibtex = BibTeX::Entry.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# \Options hash containing accession number and database ID. This can be passed to the retrieve method.
|
46
|
+
def retrieve_options
|
47
|
+
options = {}
|
48
|
+
options['an'] = self.accession_number
|
49
|
+
options['dbid'] = self.database_id
|
50
|
+
options
|
51
|
+
end
|
52
|
+
|
53
|
+
# The accession number.
|
54
|
+
def accession_number
|
55
|
+
header_an
|
56
|
+
end
|
57
|
+
|
58
|
+
# The database ID.
|
59
|
+
def database_id
|
60
|
+
header_db_id
|
61
|
+
end
|
62
|
+
|
63
|
+
# The database name or label.
|
64
|
+
def database_name
|
65
|
+
header_db_label
|
66
|
+
end
|
67
|
+
|
68
|
+
# The access level.
|
69
|
+
def access_level
|
70
|
+
header_access_level
|
71
|
+
end
|
72
|
+
|
73
|
+
# The search relevancy score.
|
74
|
+
def relevancy_score
|
75
|
+
header_score
|
76
|
+
end
|
77
|
+
|
78
|
+
# The title.
|
79
|
+
def title
|
80
|
+
get_item_data_by_name('Title') || bib_title
|
81
|
+
end
|
82
|
+
|
83
|
+
# The source title (e.g., Journal)
|
84
|
+
def source_title
|
85
|
+
bib_source_title || get_item_data_by_name('TitleSource')
|
86
|
+
end
|
87
|
+
|
88
|
+
# Other alternative titles.
|
89
|
+
def other_titles
|
90
|
+
get_item_data_by_name('TitleAlt')
|
91
|
+
end
|
92
|
+
|
93
|
+
# The abstract
|
94
|
+
def abstract
|
95
|
+
get_item_data_by_name('Abstract')
|
96
|
+
end
|
97
|
+
|
98
|
+
# The list of authors
|
99
|
+
def authors
|
100
|
+
bib_authors || get_item_data_by_name('Author')
|
101
|
+
end
|
102
|
+
|
103
|
+
# The author affiliations
|
104
|
+
def author_affiliations
|
105
|
+
get_item_data_by_name('AffiliationAuthor')
|
106
|
+
end
|
107
|
+
|
108
|
+
# The list of subject terms.
|
109
|
+
def subjects
|
110
|
+
bib_subjects || get_item_data_by_name('Subject')
|
111
|
+
end
|
112
|
+
|
113
|
+
# The list of geographic subjects
|
114
|
+
def subjects_geographic
|
115
|
+
get_item_data_by_name('SubjectGeographic')
|
116
|
+
end
|
117
|
+
|
118
|
+
# The list of person subjects
|
119
|
+
def subjects_person
|
120
|
+
get_item_data_by_name('SubjectPerson')
|
121
|
+
end
|
122
|
+
|
123
|
+
# Author supplied keywords
|
124
|
+
def author_supplied_keywords
|
125
|
+
get_item_data_by_label('Author-Supplied Keywords')
|
126
|
+
end
|
127
|
+
|
128
|
+
# Notes
|
129
|
+
def notes
|
130
|
+
get_item_data_by_name('Note')
|
131
|
+
end
|
132
|
+
|
133
|
+
# Languages
|
134
|
+
def languages
|
135
|
+
get_item_data_by_name('Language') || bib_languages
|
136
|
+
end
|
137
|
+
|
138
|
+
# Total number of pages.
|
139
|
+
def page_count
|
140
|
+
bib_page_count
|
141
|
+
end
|
142
|
+
|
143
|
+
# Starting page number.
|
144
|
+
def page_start
|
145
|
+
bib_page_start
|
146
|
+
end
|
147
|
+
|
148
|
+
# Physical description.
|
149
|
+
def physical_description
|
150
|
+
get_item_data_by_name('PhysDesc')
|
151
|
+
end
|
152
|
+
|
153
|
+
# Publication type.
|
154
|
+
def publication_type
|
155
|
+
header_publication_type || get_item_data_by_name('TypePub')
|
156
|
+
end
|
157
|
+
|
158
|
+
# Publication type ID.
|
159
|
+
def publication_type_id
|
160
|
+
header_publication_type_id
|
161
|
+
end
|
162
|
+
|
163
|
+
# Publication date.
|
164
|
+
def publication_date
|
165
|
+
bib_publication_date || get_item_data_by_name('DatePub')
|
166
|
+
end
|
167
|
+
|
168
|
+
# Publication year.
|
169
|
+
def publication_year
|
170
|
+
bib_publication_year || get_item_data_by_name('DatePub')
|
171
|
+
end
|
172
|
+
|
173
|
+
# Publisher information.
|
174
|
+
def publisher_info
|
175
|
+
get_item_data_by_label('Publication Information')
|
176
|
+
end
|
177
|
+
|
178
|
+
# Document type.
|
179
|
+
def document_type
|
180
|
+
get_item_data_by_name('TypeDocument')
|
181
|
+
end
|
182
|
+
|
183
|
+
# DOI identifier.
|
184
|
+
def doi
|
185
|
+
get_item_data_by_name('DOI') || bib_doi
|
186
|
+
end
|
187
|
+
|
188
|
+
# OCLC identifier.
|
189
|
+
def oclc
|
190
|
+
get_item_data_by_label('OCLC')
|
191
|
+
end
|
192
|
+
|
193
|
+
# Prind ISSN
|
194
|
+
def issn_print
|
195
|
+
get_item_data_by_name('ISSN') || bib_issn_print
|
196
|
+
end
|
197
|
+
|
198
|
+
# List of ISSNs
|
199
|
+
def issns
|
200
|
+
bib_issns
|
201
|
+
end
|
202
|
+
|
203
|
+
# List of ISBNs
|
204
|
+
def isbns
|
205
|
+
bib_isbns | item_related_isbns
|
206
|
+
end
|
207
|
+
|
208
|
+
# Print ISBN
|
209
|
+
def isbn_print
|
210
|
+
bib_isbn_print
|
211
|
+
end
|
212
|
+
|
213
|
+
# Electronic ISBN
|
214
|
+
def isbn_electronic
|
215
|
+
bib_isbn_electronic
|
216
|
+
end
|
217
|
+
|
218
|
+
# Series information.
|
219
|
+
def series
|
220
|
+
get_item_data_by_name('SeriesInfo')
|
221
|
+
end
|
222
|
+
|
223
|
+
# Volume
|
224
|
+
def volume
|
225
|
+
bib_volume
|
226
|
+
end
|
227
|
+
|
228
|
+
# Issue
|
229
|
+
def issue
|
230
|
+
bib_issue
|
231
|
+
end
|
232
|
+
|
233
|
+
# Cover images
|
234
|
+
def covers
|
235
|
+
images
|
236
|
+
end
|
237
|
+
|
238
|
+
# Cover image - thumbnail size link
|
239
|
+
def cover_thumb_url
|
240
|
+
images('thumb').first[:src]
|
241
|
+
end
|
242
|
+
|
243
|
+
# Cover image - medium size link
|
244
|
+
def cover_medium_url
|
245
|
+
images('medium').first[:src]
|
246
|
+
end
|
247
|
+
|
248
|
+
# Word count for fulltext.
|
249
|
+
def fulltext_word_count
|
250
|
+
get_item_data_by_name('FullTextWordCount').to_i
|
251
|
+
end
|
252
|
+
|
253
|
+
# --
|
254
|
+
# ====================================================================================
|
255
|
+
# GENERAL: ResultId, PLink, ImageInfo, CustomLinks, FullText
|
256
|
+
# ====================================================================================
|
257
|
+
# ++
|
258
|
+
|
259
|
+
# Result ID.
|
260
|
+
def result_id
|
261
|
+
@record['ResultId']
|
262
|
+
end
|
263
|
+
|
264
|
+
# EBSCO's persistent link.
|
265
|
+
def plink
|
266
|
+
@record['PLink']
|
267
|
+
end
|
268
|
+
|
269
|
+
# Fulltext.
|
270
|
+
def html_fulltext
|
271
|
+
if @record.fetch('FullText',{}).fetch('Text',{}).fetch('Availability',0) == '1'
|
272
|
+
@record.fetch('FullText',{}).fetch('Text',{})['Value']
|
273
|
+
else
|
274
|
+
nil
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# List of cover images.
|
279
|
+
def images (size_requested = 'all')
|
280
|
+
returned_images = []
|
281
|
+
images = @record.fetch('ImageInfo', {})
|
282
|
+
if images.count > 0
|
283
|
+
images.each do |image|
|
284
|
+
if size_requested == image['Size'] || size_requested == 'all'
|
285
|
+
returned_images.push({size: image['Size'], src: image['Target']})
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
returned_images
|
290
|
+
end
|
291
|
+
|
292
|
+
# --
|
293
|
+
# ====================================================================================
|
294
|
+
# LINK HELPERS
|
295
|
+
# ====================================================================================
|
296
|
+
# ++
|
297
|
+
|
298
|
+
# A list of all available links.
|
299
|
+
def all_links
|
300
|
+
self.fulltext_links + self.non_fulltext_links
|
301
|
+
end
|
302
|
+
|
303
|
+
# The first fulltext link.
|
304
|
+
def fulltext_link
|
305
|
+
self.fulltext_links.first || {}
|
306
|
+
end
|
307
|
+
|
308
|
+
# All available fulltext links.
|
309
|
+
def fulltext_links
|
310
|
+
|
311
|
+
links = []
|
312
|
+
|
313
|
+
ebscolinks = @record.fetch('FullText',{}).fetch('Links',{})
|
314
|
+
if ebscolinks.count > 0
|
315
|
+
ebscolinks.each do |ebscolink|
|
316
|
+
if ebscolink['Type'] == 'pdflink'
|
317
|
+
link_label = 'PDF Full Text'
|
318
|
+
link_icon = 'PDF Full Text Icon'
|
319
|
+
link_url = ebscolink['Url'] || 'detail'
|
320
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'pdf'})
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
htmlfulltextcheck = @record.fetch('FullText',{}).fetch('Text',{}).fetch('Availability',{})
|
326
|
+
if htmlfulltextcheck == '1'
|
327
|
+
link_url = 'detail'
|
328
|
+
link_label = 'Full Text in Browser'
|
329
|
+
link_icon = 'Full Text in Browser Icon'
|
330
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'html'})
|
331
|
+
end
|
332
|
+
|
333
|
+
if ebscolinks.count > 0
|
334
|
+
ebscolinks.each do |ebscolink|
|
335
|
+
if ebscolink['Type'] == 'ebook-pdf'
|
336
|
+
link_label = 'PDF eBook Full Text'
|
337
|
+
link_icon = 'PDF eBook Full Text Icon'
|
338
|
+
link_url = ebscolink['Url'] || 'detail'
|
339
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'ebook-pdf'})
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
if ebscolinks.count > 0
|
345
|
+
ebscolinks.each do |ebscolink|
|
346
|
+
if ebscolink['Type'] == 'ebook-epub'
|
347
|
+
link_label = 'ePub eBook Full Text'
|
348
|
+
link_icon = 'ePub eBook Full Text Icon'
|
349
|
+
link_url = ebscolink['Url'] || 'detail'
|
350
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'ebook-epub'})
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
items = @record.fetch('Items',{})
|
356
|
+
if items.count > 0
|
357
|
+
items.each do |item|
|
358
|
+
if item['Group'] == 'Url'
|
359
|
+
if item['Data'].include? 'linkTerm="'
|
360
|
+
link_start = item['Data'].index('linkTerm="')+15
|
361
|
+
link_url = item['Data'][link_start..-1]
|
362
|
+
link_end = link_url.index('"')-1
|
363
|
+
link_url = link_url[0..link_end]
|
364
|
+
link_label_start = item['Data'].index('link>')+8
|
365
|
+
link_label = item['Data'][link_label_start..-1]
|
366
|
+
link_label = link_label.strip
|
367
|
+
else
|
368
|
+
link_url = item['Data']
|
369
|
+
link_label = item['Label']
|
370
|
+
end
|
371
|
+
link_icon = 'Catalog Link Icon'
|
372
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'cataloglink'})
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
if ebscolinks.count > 0
|
378
|
+
ebscolinks.each do |ebscolink|
|
379
|
+
if ebscolink['Type'] == 'other'
|
380
|
+
link_label = 'Linked Full Text'
|
381
|
+
link_icon = 'Linked Full Text Icon'
|
382
|
+
link_url = ebscolink['Url'] || 'detail'
|
383
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'smartlinks+'})
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
ft_customlinks = @record.fetch('FullText',{}).fetch('CustomLinks',{})
|
389
|
+
if ft_customlinks.count > 0
|
390
|
+
ft_customlinks.each do |ft_customlink|
|
391
|
+
link_url = ft_customlink['Url']
|
392
|
+
link_label = ft_customlink['Text']
|
393
|
+
link_icon = ft_customlink['Icon']
|
394
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'customlink-fulltext'})
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
links
|
399
|
+
end
|
400
|
+
|
401
|
+
# All available non-fulltext links.
|
402
|
+
def non_fulltext_links
|
403
|
+
links = []
|
404
|
+
other_customlinks = @record.fetch('CustomLinks',{})
|
405
|
+
if other_customlinks.count > 0
|
406
|
+
other_customlinks.each do |other_customlink|
|
407
|
+
link_url = other_customlink['Url']
|
408
|
+
link_label = other_customlink['Text']
|
409
|
+
link_icon = other_customlink['Icon']
|
410
|
+
links.push({url: link_url, label: link_label, icon: link_icon, type: 'customlink-other'})
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
links
|
415
|
+
end
|
416
|
+
|
417
|
+
#:nodoc: all
|
418
|
+
# No need to document methods below
|
419
|
+
|
420
|
+
# Experimental bibtex support.
|
421
|
+
def retrieve_bibtex
|
422
|
+
|
423
|
+
@bibtex.key = self.accession_number
|
424
|
+
@bibtex.title = self.title
|
425
|
+
if self.bib_authors_list.length > 0
|
426
|
+
@bibtex.author = self.bib_authors_list.join(' and ').chomp
|
427
|
+
end
|
428
|
+
@bibtex.year = self.publication_year.to_i
|
429
|
+
|
430
|
+
# bibtex type
|
431
|
+
_type = self.publication_type
|
432
|
+
case _type
|
433
|
+
when 'Academic Journal'
|
434
|
+
@bibtex.type = :article
|
435
|
+
@bibtex.journal = self.source_title
|
436
|
+
if self.issue
|
437
|
+
@bibtex.issue = self.issue
|
438
|
+
end
|
439
|
+
if self.volume
|
440
|
+
@bibtex.number = self.volume
|
441
|
+
end
|
442
|
+
if self.page_start && self.page_count
|
443
|
+
@bibtex.pages = self.page_start + '-' + (self.page_start.to_i + self.page_count.to_i-1).to_s
|
444
|
+
end
|
445
|
+
if self.bib_publication_month
|
446
|
+
@bibtex.month = self.bib_publication_month.to_i
|
447
|
+
end
|
448
|
+
when 'Conference'
|
449
|
+
@bibtex.type = :conference
|
450
|
+
@bibtex.booktitle = self.source_title
|
451
|
+
if self.issue
|
452
|
+
@bibtex.issue = self.issue
|
453
|
+
end
|
454
|
+
if self.volume
|
455
|
+
@bibtex.number = self.volume
|
456
|
+
end
|
457
|
+
if self.page_start && self.page_count
|
458
|
+
@bibtex.pages = self.page_start + '-' + (self.page_start.to_i + self.page_count.to_i-1).to_s
|
459
|
+
end
|
460
|
+
if self.bib_publication_month
|
461
|
+
@bibtex.month = self.bib_publication_month.to_i
|
462
|
+
end
|
463
|
+
if self.publisher_info
|
464
|
+
@bibtex.publisher = self.publisher_info
|
465
|
+
end
|
466
|
+
if self.series
|
467
|
+
@bibtex.series = self.series
|
468
|
+
end
|
469
|
+
when 'Book', 'eBook'
|
470
|
+
@bibtex.type = :book
|
471
|
+
if self.publisher_info
|
472
|
+
@bibtex.publisher = self.publisher_info
|
473
|
+
end
|
474
|
+
if self.series
|
475
|
+
@bibtex.series = self.series
|
476
|
+
end
|
477
|
+
if self.bib_publication_month
|
478
|
+
@bibtex.month = self.bib_publication_month.to_i
|
479
|
+
end
|
480
|
+
if self.isbns
|
481
|
+
@bibtex.isbn = self.isbns.first
|
482
|
+
end
|
483
|
+
else
|
484
|
+
@bibtex.type = :other
|
485
|
+
end
|
486
|
+
@bibtex
|
487
|
+
end
|
488
|
+
|
489
|
+
# ====================================================================================
|
490
|
+
# HEADER: DbId, DbLabel, An, PubType, PubTypeId, AccessLevel
|
491
|
+
# ====================================================================================
|
492
|
+
|
493
|
+
def header_an
|
494
|
+
@record['Header']['An'].to_s
|
495
|
+
end
|
496
|
+
|
497
|
+
def header_db_id
|
498
|
+
@record['Header']['DbId'].to_s
|
499
|
+
end
|
500
|
+
|
501
|
+
# only available from search not retrieve
|
502
|
+
def header_score
|
503
|
+
@record['Header']['RelevancyScore']
|
504
|
+
end
|
505
|
+
|
506
|
+
def header_publication_type
|
507
|
+
@record['Header']['PubType']
|
508
|
+
end
|
509
|
+
|
510
|
+
def header_publication_type_id
|
511
|
+
@record['Header']['PubTypeId']
|
512
|
+
end
|
513
|
+
|
514
|
+
def header_db_label
|
515
|
+
DBS[self.database_id.upcase] || @record['Header']['DbLabel']
|
516
|
+
end
|
517
|
+
|
518
|
+
# not sure the rules for when this appears or not - RecordInfo.AccessInfo?
|
519
|
+
def header_access_level
|
520
|
+
@record['Header']['AccessLevel']
|
521
|
+
end
|
522
|
+
|
523
|
+
# ====================================================================================
|
524
|
+
# ITEMS
|
525
|
+
# ====================================================================================
|
526
|
+
|
527
|
+
# look up by 'Name' and return 'Data'
|
528
|
+
def get_item_data_by_name(name)
|
529
|
+
_item_property = @items.find{|item| item['Name'] == name}
|
530
|
+
if _item_property.nil?
|
531
|
+
nil
|
532
|
+
else
|
533
|
+
_item_property['Data']
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
# look up by 'Label' and return 'Data'
|
538
|
+
def get_item_data_by_label(label)
|
539
|
+
_item_property = @items.find{|item| item['Label'] == label}
|
540
|
+
if _item_property.nil?
|
541
|
+
nil
|
542
|
+
else
|
543
|
+
_item_property['Data']
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
def item_related_isbns
|
548
|
+
get_item_data_by_label('Related ISBNs').split(' ').map!{|item| item.gsub(/\.$/, '')}
|
549
|
+
end
|
550
|
+
|
551
|
+
# ====================================================================================
|
552
|
+
# BIB ENTITY
|
553
|
+
# ====================================================================================
|
554
|
+
|
555
|
+
def bib_title
|
556
|
+
@bib_entity.fetch('Titles', {}).find{|item| item['Type'] == 'main'}['TitleFull']
|
557
|
+
end
|
558
|
+
|
559
|
+
def bib_authors
|
560
|
+
@bib_relationships.deep_find('NameFull').join('; ')
|
561
|
+
end
|
562
|
+
|
563
|
+
def bib_authors_list
|
564
|
+
@bib_relationships.deep_find('NameFull')
|
565
|
+
end
|
566
|
+
|
567
|
+
def bib_subjects
|
568
|
+
@bib_entity.deep_find('SubjectFull')
|
569
|
+
end
|
570
|
+
|
571
|
+
def bib_languages
|
572
|
+
@bib_entity.fetch('Languages', {}).map{|lang| lang['Text']}
|
573
|
+
end
|
574
|
+
|
575
|
+
# def bib_pages
|
576
|
+
# @bib_entity.fetch('PhysicalDescription', {})['Pagination']
|
577
|
+
# end
|
578
|
+
|
579
|
+
def bib_page_count
|
580
|
+
@bib_entity.deep_find('PageCount').first
|
581
|
+
end
|
582
|
+
|
583
|
+
def bib_page_start
|
584
|
+
@bib_entity.deep_find('StartPage').first
|
585
|
+
end
|
586
|
+
|
587
|
+
def bib_doi
|
588
|
+
@bib_entity.fetch('Identifiers',{}).find{|item| item['Type'] == 'doi'}['Value']
|
589
|
+
end
|
590
|
+
|
591
|
+
# ====================================================================================
|
592
|
+
# BIB - IS PART OF (journal, book)
|
593
|
+
# ====================================================================================
|
594
|
+
|
595
|
+
def bib_source_title
|
596
|
+
@bib_part.fetch('BibEntity',{}).fetch('Titles',{}).find{|item| item['Type'] == 'main'}['TitleFull']
|
597
|
+
end
|
598
|
+
|
599
|
+
def bib_issn_print
|
600
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).find{|item| item['Type'] == 'issn-print'}['Value']
|
601
|
+
end
|
602
|
+
|
603
|
+
def bib_issn_electronic
|
604
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).find{|item| item['Type'] == 'issn-electronic'}['Value']
|
605
|
+
end
|
606
|
+
|
607
|
+
def bib_issns
|
608
|
+
issns = []
|
609
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).each do |id|
|
610
|
+
if id['Type'].include?('issn') && !id['Type'].include?('locals')
|
611
|
+
issns.push(id['Value'])
|
612
|
+
end
|
613
|
+
end
|
614
|
+
issns
|
615
|
+
end
|
616
|
+
|
617
|
+
def bib_isbn_print
|
618
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).find{|item| item['Type'] == 'isbn-print'}['Value']
|
619
|
+
end
|
620
|
+
|
621
|
+
def bib_isbn_electronic
|
622
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).find{|item| item['Type'] == 'isbn-electronic'}['Value']
|
623
|
+
end
|
624
|
+
|
625
|
+
# todo: make this generic and take an optional parameter for type
|
626
|
+
def bib_isbns
|
627
|
+
isbns = []
|
628
|
+
@bib_part.fetch('BibEntity',{}).fetch('Identifiers',{}).each do |id|
|
629
|
+
if id['Type'].include?('isbn') && !id['Type'].include?('locals')
|
630
|
+
isbns.push(id['Value'])
|
631
|
+
end
|
632
|
+
end
|
633
|
+
isbns
|
634
|
+
end
|
635
|
+
|
636
|
+
def bib_publication_date
|
637
|
+
_date = @bib_part.fetch('BibEntity',{}).fetch('Dates',{}).find{|item| item['Type'] == 'published'}
|
638
|
+
if _date
|
639
|
+
if _date.has_key?('Y') && _date.has_key?('M') && _date.has_key?('D')
|
640
|
+
_date['Y'] + '-' + _date['M'] + '-' + _date['D']
|
641
|
+
else
|
642
|
+
nil
|
643
|
+
end
|
644
|
+
else
|
645
|
+
nil
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
def bib_publication_year
|
650
|
+
_date = @bib_part.fetch('BibEntity',{}).fetch('Dates',{}).find{|item| item['Type'] == 'published'}
|
651
|
+
if _date
|
652
|
+
_date.has_key?('Y') ? _date['Y'] : nil
|
653
|
+
else
|
654
|
+
nil
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def bib_publication_month
|
659
|
+
_date = @bib_part.fetch('BibEntity',{}).fetch('Dates',{}).find{|item| item['Type'] == 'published'}
|
660
|
+
if _date
|
661
|
+
_date.has_key?('M') ? _date['M'] : nil
|
662
|
+
else
|
663
|
+
nil
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
def bib_volume
|
668
|
+
@bib_part.fetch('BibEntity',{}).fetch('Numbering',{}).find{|item| item['Type'] == 'volume'}['Value']
|
669
|
+
end
|
670
|
+
|
671
|
+
def bib_issue
|
672
|
+
@bib_part.fetch('BibEntity',{}).fetch('Numbering',{}).find{|item| item['Type'] == 'issue'}['Value']
|
673
|
+
end
|
674
|
+
|
675
|
+
def to_hash
|
676
|
+
hash = {}
|
677
|
+
hash['id'] = database_id + '-' + accession_number
|
678
|
+
hash['title_display'] = title.gsub('<highlight>', '').gsub('</highlight>', '')
|
679
|
+
hash['pub_date'] = publication_year
|
680
|
+
hash
|
681
|
+
end
|
682
|
+
|
683
|
+
end # Class Record
|
684
|
+
end # Module EDS
|
685
|
+
end # Module EBSCO
|
686
|
+
|
687
|
+
|
688
|
+
# monkey patches
|
689
|
+
class Hash
|
690
|
+
def deep_find(key, object=self, found=[])
|
691
|
+
if object.respond_to?(:key?) && object.key?(key)
|
692
|
+
found << object[key]
|
693
|
+
end
|
694
|
+
if object.is_a? Enumerable
|
695
|
+
found << object.collect { |*a| deep_find(key, a.last) }
|
696
|
+
end
|
697
|
+
found.flatten.compact
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|