bento_search 1.5.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|