bento_search 1.5.0 → 2.0.0.rc1
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 +5 -5
- data/README.md +27 -24
- data/Rakefile +30 -11
- data/app/assets/javascripts/bento_search/ajax_load.js +54 -22
- data/app/controllers/bento_search/search_controller.rb +31 -30
- data/app/helpers/bento_search_helper.rb +72 -74
- data/app/models/bento_search/concurrent_searcher.rb +136 -0
- data/app/models/bento_search/result_item.rb +15 -12
- data/app/models/bento_search/results/serialization.rb +22 -13
- data/app/models/bento_search/search_engine.rb +170 -140
- data/app/search_engines/bento_search/doaj_articles_engine.rb +20 -20
- data/app/search_engines/bento_search/ebsco_host_engine.rb +3 -3
- data/app/search_engines/bento_search/eds_engine.rb +326 -206
- data/app/search_engines/bento_search/google_books_engine.rb +2 -2
- data/app/search_engines/bento_search/scopus_engine.rb +87 -87
- data/app/search_engines/bento_search/summon_engine.rb +1 -1
- data/app/views/bento_search/_ajax_loading.html.erb +17 -0
- data/app/views/bento_search/_item_title.html.erb +2 -4
- data/app/views/bento_search/_link.html.erb +3 -3
- data/lib/bento_search.rb +24 -9
- data/lib/bento_search/engine.rb +2 -0
- data/lib/bento_search/version.rb +1 -1
- data/lib/generators/bento_search/install/ajax_load_js_generator.rb +15 -0
- data/test/decorator/standard_decorator_test.rb +30 -30
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/config/application.rb +7 -0
- data/test/dummy/config/boot.rb +4 -9
- data/test/dummy/config/environments/development.rb +2 -0
- data/test/dummy/config/environments/production.rb +7 -1
- data/test/dummy/config/environments/test.rb +10 -3
- data/test/functional/bento_search/search_controller_test.rb +68 -58
- data/test/helper/bento_search_helper_test.rb +103 -103
- data/test/search_engines/doaj_articles_engine_test.rb +9 -9
- data/test/search_engines/eds_engine_test.rb +91 -59
- data/test/search_engines/google_site_search_test.rb +48 -48
- data/test/search_engines/scopus_engine_test.rb +51 -51
- data/test/search_engines/search_engine_base_test.rb +108 -86
- data/test/search_engines/search_engine_test.rb +68 -56
- data/test/support/atom.xsd.xml +3 -3
- data/test/support/xml.xsd +117 -0
- data/test/test_helper.rb +23 -12
- data/test/unit/concurrent_searcher_test.rb +75 -0
- data/test/unit/pagination_test.rb +12 -12
- data/test/vcr_cassettes/eds/FullText_CustomLink.yml +198 -0
- data/test/vcr_cassettes/eds/basic_search_smoke_test.yml +1036 -1729
- data/test/vcr_cassettes/eds/catalog_ebook_query.yml +218 -0
- data/test/vcr_cassettes/eds/catalog_query.yml +255 -0
- data/test/vcr_cassettes/eds/get_auth_token.yml +11 -44
- data/test/vcr_cassettes/eds/get_auth_token_failure.yml +10 -7
- data/test/vcr_cassettes/eds/get_with_auth.yml +144 -153
- data/test/vcr_cassettes/eds/get_with_auth_recovers_from_bad_auth.yml +167 -223
- data/test/view/atom_results_test.rb +94 -94
- metadata +36 -46
- data/app/assets/javascripts/bento_search.js +0 -3
- data/app/item_decorators/bento_search/ebscohost/conditional_openurl_main_link.rb +0 -36
- data/app/item_decorators/bento_search/only_premade_openurl.rb +0 -20
- data/app/item_decorators/bento_search/openurl_add_other_link.rb +0 -39
- data/app/item_decorators/bento_search/openurl_main_link.rb +0 -34
- data/app/models/bento_search/multi_searcher.rb +0 -131
- data/test/dummy/config/initializers/secret_token.rb +0 -8
- data/test/unit/multi_searcher_test.rb +0 -49
@@ -1,36 +0,0 @@
|
|
1
|
-
# DEPRECATED. Just write the logic into a custom Decorator yourself.
|
2
|
-
# See wiki on decorators.
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# For ebscohost connector, example of an Item Decorator that replaces the main
|
6
|
-
# 'link' with an openurl ONLY if there is NOT fulltext avail from EBSCO.
|
7
|
-
#
|
8
|
-
# This example uses crazy metaprogramming to dynamically create
|
9
|
-
# a module configured with your base url etc. You don't need to use
|
10
|
-
# crazy method like that; just define your own local decorator doing
|
11
|
-
# exactly what you need, it's meant to be simple.
|
12
|
-
#
|
13
|
-
# config.item_decorators = [ BentoSearch::Ebscohost::ConditionalOpenurlMainLink[:base_url => "http://resolve.somewhere.edu/foo", :extra_query => "&foo=bar"] ]
|
14
|
-
#
|
15
|
-
module BentoSearch::Ebscohost::ConditionalOpenurlMainLink
|
16
|
-
def self.[](options)
|
17
|
-
base_url = options[:base_url]
|
18
|
-
extra_query = options[:extra_query] || ""
|
19
|
-
Module.new do
|
20
|
-
|
21
|
-
define_method :link do
|
22
|
-
if custom_data["fulltext_formats"]
|
23
|
-
super()
|
24
|
-
elsif (ou = to_openurl)
|
25
|
-
"#{base_url}?#{ou.kev}#{extra_query}"
|
26
|
-
else
|
27
|
-
nil
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# DEPRECATED. Just write the logic into a custom Decorator yourself.
|
2
|
-
# See wiki on decorators.
|
3
|
-
|
4
|
-
|
5
|
-
require 'openurl'
|
6
|
-
|
7
|
-
# A Decorator that will make #to_openurl refuse to construct
|
8
|
-
# an openurl from individual elements, it'll use the #openurl_kev_co
|
9
|
-
# or nothing.
|
10
|
-
module BentoSearch::OnlyPremadeOpenurl
|
11
|
-
|
12
|
-
def to_openurl
|
13
|
-
if self.openurl_kev_co
|
14
|
-
return OpenURL::ContextObject.new_from_kev( self.openurl_kev_co )
|
15
|
-
else
|
16
|
-
return nil
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# DEPRECATED. Just write the logic into a custom Decorator yourself.
|
2
|
-
# See wiki on decorators.
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Example of an Item Decorator that ADDs an 'other link' with an openurl.
|
6
|
-
#
|
7
|
-
# This example uses crazy metaprogramming to dynamically create
|
8
|
-
# a module configured with your base url etc. You don't need to use
|
9
|
-
# crazy method like that; just define your own local decorator doing
|
10
|
-
# exactly what you need, it's meant to be simple.
|
11
|
-
#
|
12
|
-
# config.item_decorators = [ BentoSearch::OpenurlAddOtherLink[:base_url => "http://resolve.somewhere.edu/foo", :extra_query => "&foo=bar"] ]
|
13
|
-
#
|
14
|
-
module BentoSearch::OpenurlAddOtherLink
|
15
|
-
def self.[](options)
|
16
|
-
base_url = options[:base_url]
|
17
|
-
extra_query = options[:extra_query] || ""
|
18
|
-
link_name = options[:link_name] || "Find It"
|
19
|
-
# overwrite: if true, overwrite previously existing other_links, if
|
20
|
-
# false add on to previously existing.
|
21
|
-
overwrite = options.has_key?(:overwrite) ? options[:overwrite] : false
|
22
|
-
|
23
|
-
Module.new do
|
24
|
-
|
25
|
-
define_method :other_links do
|
26
|
-
start = overwrite ? [] : super()
|
27
|
-
if (ou = to_openurl)
|
28
|
-
start + [BentoSearch::Link.new(:url => "#{base_url}?#{ou.kev}#{extra_query}", :label => link_name)]
|
29
|
-
else
|
30
|
-
start
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# DEPRECATED. Just write the logic into a custom Decorator yourself.
|
2
|
-
# See wiki on decorators.
|
3
|
-
|
4
|
-
|
5
|
-
# Example of an Item Decorator that replaces the main 'link'
|
6
|
-
# with an openurl.
|
7
|
-
#
|
8
|
-
# This example uses crazy metaprogramming to dynamically create
|
9
|
-
# a module configured with your base url etc. You don't need to use
|
10
|
-
# crazy method like that; just define your own local decorator doing
|
11
|
-
# exactly what you need, it's meant to be simple.
|
12
|
-
#
|
13
|
-
# config.item_decorators = [ BentoSearch::OpenurlMainLink[:base_url => "http://resolve.somewhere.edu/foo", :extra_query => "&foo=bar"] ]
|
14
|
-
#
|
15
|
-
module BentoSearch::OpenurlMainLink
|
16
|
-
def self.[](options)
|
17
|
-
base_url = options[:base_url]
|
18
|
-
extra_query = options[:extra_query] || ""
|
19
|
-
Module.new do
|
20
|
-
|
21
|
-
define_method :link do
|
22
|
-
if (ou = to_openurl)
|
23
|
-
"#{base_url}?#{ou.kev}#{extra_query}"
|
24
|
-
else
|
25
|
-
nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
@@ -1,131 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'celluloid'
|
3
|
-
|
4
|
-
# Based on Celluloid, concurrently runs multiple searches in
|
5
|
-
# seperate threads. You must include 'celluloid' gem dependency
|
6
|
-
# into your local app to use this class. Requires celluloid 0.12.0
|
7
|
-
# or above (for new preferred async syntax).
|
8
|
-
#
|
9
|
-
# Warning, if you don't have celluloid in your app, this class simply
|
10
|
-
# won't load. TODO: We should put this file in a different directory
|
11
|
-
# so it's never auto-loaded, and requires a "require 'bento_search/multi_searcher'",
|
12
|
-
# such that it will raise without celluloid only then, and we don't need this
|
13
|
-
# rescue LoadError stuff.
|
14
|
-
#
|
15
|
-
# I am not an expert at use of Celluloid, it's possible there's a better
|
16
|
-
# way to do this all, but seems to work.
|
17
|
-
#
|
18
|
-
# ## Usage
|
19
|
-
#
|
20
|
-
# initialize with id's of registered engines:
|
21
|
-
# searcher = BentoBox::MultiSearcher.new(:gbs, :scopus)
|
22
|
-
#
|
23
|
-
# start the concurrent searches, params same as engine.search
|
24
|
-
# searcher.search( query_params )
|
25
|
-
#
|
26
|
-
# retrieve results, blocking until each is completed:
|
27
|
-
# searcher.results
|
28
|
-
#
|
29
|
-
# returns a Hash keyed by engine id, values BentoSearch::Results objects.
|
30
|
-
#
|
31
|
-
# Can only call #results once per #start, after that it'll return empty hash.
|
32
|
-
# (should we make it actually raise instead?). .
|
33
|
-
#
|
34
|
-
# important to call results at some point after calling start, in order
|
35
|
-
# to make sure Celluloid::Actors are properly terminated to avoid
|
36
|
-
# resource leakage. May want to do it in an ensure block.
|
37
|
-
#
|
38
|
-
# Note that celluloid uses multi-threading in such a way that you
|
39
|
-
# may have to set config.cache_classes=true even in development
|
40
|
-
# to avoid problems. Rails class reloading is not thread-safe.
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# TODO: have a method that returns Futures instead of only supplying the blocking
|
44
|
-
# results method? Several tricks, including making sure to properly terminate actors.
|
45
|
-
class BentoSearch::MultiSearcher
|
46
|
-
|
47
|
-
def initialize(*engine_ids)
|
48
|
-
@engines = []
|
49
|
-
@actors = []
|
50
|
-
engine_ids.each do |id|
|
51
|
-
add_engine( BentoSearch.get_engine id )
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Adds an instantiated engine directly, rather than by id from global
|
56
|
-
# registry.
|
57
|
-
def add_engine(engine)
|
58
|
-
@engines << engine
|
59
|
-
end
|
60
|
-
|
61
|
-
# Starts all searches, returns self so you can chain method calls if you like.
|
62
|
-
def search(*search_args)
|
63
|
-
@engines.each do |engine|
|
64
|
-
a = Actor.new(engine)
|
65
|
-
@actors << a
|
66
|
-
a.async.start *search_args
|
67
|
-
end
|
68
|
-
return self
|
69
|
-
end
|
70
|
-
alias_method :start, :search # backwards compat
|
71
|
-
|
72
|
-
# Call after #start. Blocks until each included engine is finished
|
73
|
-
# then returns a Hash keyed by engine registered id, value is a
|
74
|
-
# BentoSearch::Results object.
|
75
|
-
#
|
76
|
-
# Can only call _once_ per invocation of #start, after that it'll return
|
77
|
-
# an empty hash.
|
78
|
-
def results
|
79
|
-
results = {}
|
80
|
-
|
81
|
-
# we use #delete_if to get an iterator that deletes
|
82
|
-
# each item after iteration.
|
83
|
-
@actors.delete_if do |actor|
|
84
|
-
result_key = (actor.engine.configuration.id || actor.engine.class.name)
|
85
|
-
results[result_key] = actor.results
|
86
|
-
actor.terminate
|
87
|
-
|
88
|
-
true
|
89
|
-
end
|
90
|
-
|
91
|
-
return results
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
class Actor
|
96
|
-
include Celluloid
|
97
|
-
|
98
|
-
attr_accessor :engine
|
99
|
-
|
100
|
-
def initialize(a_engine)
|
101
|
-
self.engine = a_engine
|
102
|
-
end
|
103
|
-
|
104
|
-
# call as .async.start, to invoke async.
|
105
|
-
def start(*search_args)
|
106
|
-
begin
|
107
|
-
@results = self.engine.search(*search_args)
|
108
|
-
rescue StandardError => e
|
109
|
-
Rails.logger.error("\nBentoSearch:MultiSearcher caught exception: #{e}\n#{e.backtrace.join(" \n")}")
|
110
|
-
# Make a fake results with caught exception.
|
111
|
-
@results = BentoSearch::Results.new
|
112
|
-
self.engine.fill_in_search_metadata_for(@results, self.engine.normalized_search_arguments(search_args))
|
113
|
-
|
114
|
-
@results.error ||= {}
|
115
|
-
@results.error["exception"] = e
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def results
|
120
|
-
@results
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
rescue LoadError
|
128
|
-
# you can use bento_search without celluloid, just not
|
129
|
-
# this class.
|
130
|
-
end
|
131
|
-
|
@@ -1,8 +0,0 @@
|
|
1
|
-
# Be sure to restart your server when you modify this file.
|
2
|
-
|
3
|
-
# Your secret key for verifying the integrity of signed cookies.
|
4
|
-
# If you change this key, all old signed cookies will become invalid!
|
5
|
-
# Make sure the secret is at least 30 characters and all random,
|
6
|
-
# no regular words or you'll be exposed to dictionary attacks.
|
7
|
-
Dummy::Application.config.secret_token = '78ee4771fe1d7704b7dd8f47b879db32af098e4cf67f9910e9cf7fe8de18353ff52dc3ccb48ed341745aaedbad9ba79f031867b0e37680f2fb5b66b76838db22'
|
8
|
-
Dummy::Application.config.secret_key_base = '60f73d25f61301b1ea3119011efb9fd9a741fcc010757599341d45765fbda7676daf5d602fb17bb5085c3163a04e20c0750ad02562ee9cb7f03f813d1b62c639'
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
# Doesn't really test the concurrency, but basic smoke test with fake
|
4
|
-
# searchers.
|
5
|
-
class MultiSearcherTest < ActiveSupport::TestCase
|
6
|
-
setup do
|
7
|
-
BentoSearch.register_engine("one") do |conf|
|
8
|
-
conf.engine = "MockEngine"
|
9
|
-
end
|
10
|
-
BentoSearch.register_engine("two") do |conf|
|
11
|
-
conf.engine = "MockEngine"
|
12
|
-
end
|
13
|
-
BentoSearch.register_engine("three") do |conf|
|
14
|
-
conf.engine = "MockEngine"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
teardown do
|
19
|
-
BentoSearch.reset_engine_registrations!
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
def test_multisearch
|
24
|
-
searcher = BentoSearch::MultiSearcher.new(:one, :two, :three)
|
25
|
-
start_returnval = searcher.start("cancer")
|
26
|
-
|
27
|
-
assert_same searcher, start_returnval
|
28
|
-
|
29
|
-
results = searcher.results
|
30
|
-
|
31
|
-
assert_kind_of Hash, results
|
32
|
-
assert_equal ["one", "two", "three"].sort, results.keys.sort
|
33
|
-
|
34
|
-
["one", "two", "three"].each do |key|
|
35
|
-
assert_kind_of BentoSearch::Results, results[key]
|
36
|
-
end
|
37
|
-
|
38
|
-
# call results again, we get an empty hash, can only call
|
39
|
-
# results once per start.
|
40
|
-
new_results = searcher.results
|
41
|
-
assert_kind_of Hash, new_results
|
42
|
-
assert_empty new_results
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|