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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +27 -24
  3. data/Rakefile +30 -11
  4. data/app/assets/javascripts/bento_search/ajax_load.js +54 -22
  5. data/app/controllers/bento_search/search_controller.rb +31 -30
  6. data/app/helpers/bento_search_helper.rb +72 -74
  7. data/app/models/bento_search/concurrent_searcher.rb +136 -0
  8. data/app/models/bento_search/result_item.rb +15 -12
  9. data/app/models/bento_search/results/serialization.rb +22 -13
  10. data/app/models/bento_search/search_engine.rb +170 -140
  11. data/app/search_engines/bento_search/doaj_articles_engine.rb +20 -20
  12. data/app/search_engines/bento_search/ebsco_host_engine.rb +3 -3
  13. data/app/search_engines/bento_search/eds_engine.rb +326 -206
  14. data/app/search_engines/bento_search/google_books_engine.rb +2 -2
  15. data/app/search_engines/bento_search/scopus_engine.rb +87 -87
  16. data/app/search_engines/bento_search/summon_engine.rb +1 -1
  17. data/app/views/bento_search/_ajax_loading.html.erb +17 -0
  18. data/app/views/bento_search/_item_title.html.erb +2 -4
  19. data/app/views/bento_search/_link.html.erb +3 -3
  20. data/lib/bento_search.rb +24 -9
  21. data/lib/bento_search/engine.rb +2 -0
  22. data/lib/bento_search/version.rb +1 -1
  23. data/lib/generators/bento_search/install/ajax_load_js_generator.rb +15 -0
  24. data/test/decorator/standard_decorator_test.rb +30 -30
  25. data/test/dummy/app/assets/config/manifest.js +4 -0
  26. data/test/dummy/config/application.rb +7 -0
  27. data/test/dummy/config/boot.rb +4 -9
  28. data/test/dummy/config/environments/development.rb +2 -0
  29. data/test/dummy/config/environments/production.rb +7 -1
  30. data/test/dummy/config/environments/test.rb +10 -3
  31. data/test/functional/bento_search/search_controller_test.rb +68 -58
  32. data/test/helper/bento_search_helper_test.rb +103 -103
  33. data/test/search_engines/doaj_articles_engine_test.rb +9 -9
  34. data/test/search_engines/eds_engine_test.rb +91 -59
  35. data/test/search_engines/google_site_search_test.rb +48 -48
  36. data/test/search_engines/scopus_engine_test.rb +51 -51
  37. data/test/search_engines/search_engine_base_test.rb +108 -86
  38. data/test/search_engines/search_engine_test.rb +68 -56
  39. data/test/support/atom.xsd.xml +3 -3
  40. data/test/support/xml.xsd +117 -0
  41. data/test/test_helper.rb +23 -12
  42. data/test/unit/concurrent_searcher_test.rb +75 -0
  43. data/test/unit/pagination_test.rb +12 -12
  44. data/test/vcr_cassettes/eds/FullText_CustomLink.yml +198 -0
  45. data/test/vcr_cassettes/eds/basic_search_smoke_test.yml +1036 -1729
  46. data/test/vcr_cassettes/eds/catalog_ebook_query.yml +218 -0
  47. data/test/vcr_cassettes/eds/catalog_query.yml +255 -0
  48. data/test/vcr_cassettes/eds/get_auth_token.yml +11 -44
  49. data/test/vcr_cassettes/eds/get_auth_token_failure.yml +10 -7
  50. data/test/vcr_cassettes/eds/get_with_auth.yml +144 -153
  51. data/test/vcr_cassettes/eds/get_with_auth_recovers_from_bad_auth.yml +167 -223
  52. data/test/view/atom_results_test.rb +94 -94
  53. metadata +36 -46
  54. data/app/assets/javascripts/bento_search.js +0 -3
  55. data/app/item_decorators/bento_search/ebscohost/conditional_openurl_main_link.rb +0 -36
  56. data/app/item_decorators/bento_search/only_premade_openurl.rb +0 -20
  57. data/app/item_decorators/bento_search/openurl_add_other_link.rb +0 -39
  58. data/app/item_decorators/bento_search/openurl_main_link.rb +0 -34
  59. data/app/models/bento_search/multi_searcher.rb +0 -131
  60. data/test/dummy/config/initializers/secret_token.rb +0 -8
  61. data/test/unit/multi_searcher_test.rb +0 -49
@@ -1,3 +0,0 @@
1
- // require all bento_search javascript.
2
- //
3
- //= require_tree ./bento_search
@@ -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