bento_search 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +92 -90
  3. data/app/item_decorators/bento_search/decorator_base.rb +9 -6
  4. data/app/item_decorators/bento_search/standard_decorator.rb +24 -0
  5. data/app/search_engines/bento_search/ebsco_host_engine.rb +180 -179
  6. data/app/search_engines/bento_search/journal_tocs_for_journal.rb +179 -0
  7. data/app/views/bento_search/_std_item.html.erb +4 -4
  8. data/lib/bento_search/version.rb +1 -1
  9. data/test/decorator/decorator_base_test.rb +11 -1
  10. data/test/decorator/standard_decorator_test.rb +21 -0
  11. data/test/dummy/log/development.log +2 -0
  12. data/test/dummy/log/test.log +22324 -0
  13. data/test/{unit → search_engines}/ebsco_host_engine_test.rb +148 -130
  14. data/test/{unit → search_engines}/eds_engine_test.rb +0 -0
  15. data/test/{unit → search_engines}/google_books_engine_test.rb +0 -0
  16. data/test/{unit → search_engines}/google_site_search_test.rb +0 -0
  17. data/test/search_engines/journal_tocs_for_journal_test.rb +93 -0
  18. data/test/{unit → search_engines}/primo_engine_test.rb +0 -0
  19. data/test/{unit → search_engines}/scopus_engine_test.rb +0 -0
  20. data/test/{unit → search_engines}/search_engine_base_test.rb +0 -0
  21. data/test/{unit → search_engines}/search_engine_test.rb +0 -0
  22. data/test/{unit → search_engines}/summon_engine_test.rb +0 -0
  23. data/test/{unit → search_engines}/worldcat_sru_dc_engine_test.rb +0 -0
  24. data/test/{unit → search_engines}/xerxes_engine_test.rb +0 -0
  25. data/test/vcr_cassettes/ebscohost/RILM_record_with_ISSN_in__jid__element.yml +210 -0
  26. data/test/vcr_cassettes/journal_tocs/empty_results_on_bad_ISSN.yml +49 -0
  27. data/test/vcr_cassettes/journal_tocs/error_on_bad_registered_email.yml +41 -0
  28. data/test/vcr_cassettes/journal_tocs/error_on_error_response.yml +51 -0
  29. data/test/vcr_cassettes/journal_tocs/fetch_xml_with_hits.yml +328 -0
  30. data/test/vcr_cassettes/journal_tocs/fills_out_metadata.yml +396 -0
  31. data/test/vcr_cassettes/journal_tocs/smoke_test.yml +328 -0
  32. metadata +62 -61
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MWQzYTkxZjdiMjgwMGQ3NmNjN2NlYjZlZGRiNTY2NWFjMzBiZTc5Mw==
5
+ data.tar.gz: !binary |-
6
+ YzkyY2NkNTc2OGM1NmQwNjRkYTJjZjVlODI3OTUzMTY4OGUxMTM4YQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YWE4NDhlNjRjOWNkMWU5Y2E2NDk3MGZlYjJmYWNhN2I2OTM1NTFkNDRhMzZk
10
+ YjJlOWYzOWI2YmRmNmY0NmEzMDdhMTk5YjY1ZmNjNDhiODZiOGQ2ZDIzNzYz
11
+ MDg5MTA5OTllNzExNTZhMGY2Y2MxNmI4MmVhZDRiZDYzZmYzMjQ=
12
+ data.tar.gz: !binary |-
13
+ NDJhZDA5MzUyZGE4MDRjYTRmMmY4ZWUyZGEyZDM1ZjhhYzIxNzUzN2JiMjVk
14
+ YmZjODY3Y2IzOGE1NGNhYTljNGE4NmNlYWUwZDViZDhhYTI1YmMxNWYyYjE1
15
+ YjJkOWFlOTBmOGY0ZjMxNDQ2NjFkNmI1ODZkMTVmZTlkZTk4ODc=
data/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # BentoSearch
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/jrochkind/bento_search.png)](http://travis-ci.org/jrochkind/bento_search)
4
+ [![Gem Version](https://badge.fury.io/rb/bento_search.png)](http://badge.fury.io/rb/bento_search)
4
5
 
5
- bento_search provides an abstraction/normalization layer for querying and
6
+ bento_search provides an abstraction/normalization layer for querying and
6
7
  displaying results from external search engines, in Ruby on Rails. Requires
7
- Rails3 and tested only under ruby 1.9.3.
8
+ Rails3 and tested only under ruby 1.9.3.
8
9
 
9
10
  ### Goals: To help you
10
11
 
@@ -12,19 +13,19 @@ Rails3 and tested only under ruby 1.9.3.
12
13
  results from a third-party service. Solutions to idiosyncracies and
13
14
  undocumented workarounds are encoded in a shared codebase, which abstracts
14
15
  everything to a good, simple code API giving you building blocks to focus
15
- on your needs, not the search service's problems.
16
+ on your needs, not the search service's problems.
16
17
  * Let you switch out one search service for another in an already built
17
- application with as little code rewriting as possible. **Avoid vendor lock-in**.
18
+ application with as little code rewriting as possible. **Avoid vendor lock-in**.
18
19
  * Give you the harness to **write adapters for new search services**, without
19
20
  having to rewrite common general functionality, just focus on the interface
20
- with the new API you want to support.
21
+ with the new API you want to support.
21
22
 
22
23
  bento_search is focused on use cases for academic libraries, which is mainly
23
24
  evidenced by the search engine adapters currently included, and by the
24
25
  generalized domain models including fields that matter in our domain (issn,
25
- vol/issue/page, etc), and some targetted functionality (OpenURL generation).
26
+ vol/issue/page, etc), and some targetted functionality (OpenURL generation).
26
27
  But it ought to be useful for more general basic use
27
- cases too (we include a google site search adapter for instance).
28
+ cases too (we include a google site search adapter for instance).
28
29
 
29
30
  Adapters currently included in bento_search
30
31
 
@@ -36,6 +37,7 @@ Adapters currently included in bento_search
36
37
  * EBSCOHost 'traditional' API (requires license)
37
38
  * WorldCat Search (requires OCLC membership to get api key)
38
39
  * Google Site Search (requires sign-up for more than 100 searches/day)
40
+ * JournalTOCs (limited support for fetching current articles by ISSN, free but requires registration)
39
41
 
40
42
 
41
43
 
@@ -47,21 +49,21 @@ search' functionality, but it does not and will never support merging results
47
49
  from multiple engines into one result set. It is meant to support displaying the
48
50
  first few results from multiple engines on one page, "bento box" style (as
49
51
  named by Tito Sierra@NCSU), as well as more expanded single-search-on-a-page
50
- uses.
52
+ uses.
51
53
 
52
- * bento_search provides abstract functionality for pagination, sorting,
54
+ * bento_search provides abstract functionality for pagination, sorting,
53
55
  and single-field-specified queries. Faceting, generalized limiting, and 'advanced'
54
56
  multi-field searches are not yet supported, but possibly will be built
55
- out in the future.
57
+ out in the future.
56
58
 
57
59
  Not all search engine adapters support all features. Some engines offer
58
60
  engine-specific features, such as limiting. Search engine adapters can
59
61
  declare search fields and sort options with 'semantics', so you can for
60
62
  instance search or sort by 'title' across search engines without regard
61
- to internal engine-specific field names.
63
+ to internal engine-specific field names.
62
64
 
63
65
  bento_search is designed to allow code to be written agnostic of the search
64
- provider, so you can switch out the search provider.
66
+ provider, so you can switch out the search provider.
65
67
 
66
68
  See code-level api documentation for more details, especially at
67
69
  BentoSearch::SearchEngine. http://rubydoc.info/gems/bento_search/frames/
@@ -76,8 +78,8 @@ There is a short screencast showing that sample app in action here: http://scree
76
78
 
77
79
  When you instantiate an engine, you can provide configuration keys. There
78
80
  are a few standard keys (see BentoSearch::SearchEngine), and others that
79
- may be engine-specific. Some engine-specific keys (such as api auth keys)
80
- may be required for certain engines.
81
+ may be engine-specific. Some engine-specific keys (such as api auth keys)
82
+ may be required for certain engines.
81
83
 
82
84
  ~~~~ruby
83
85
  engine = BentoSearch::GoogleBooksEngine.new(:api_key => "my_gbs_api_key")
@@ -88,15 +90,15 @@ may be required for certain engines.
88
90
  [BentoSearch::Item](./app/models/bento_search/results.rb) objects, along with some meta-information about the
89
91
  search itself (pagination keys, etc). BentoSearch::Results and Item fields
90
92
  are standardized accross engines. BentoSearch::Items provide semantic
91
- values (title, author, etc.), as available from the particular engine.
93
+ values (title, author, etc.), as available from the particular engine.
92
94
 
93
- To see which engines come bundled with BentoSearch, and any special
95
+ To see which engines come bundled with BentoSearch, and any special
94
96
  engine-specific instructions, look at BentoSearch source in [`./app/search_engines/bento_search`](./app/search_engines/bento_search)
95
97
 
96
98
  ### Register engines in global configuration
97
99
 
98
- It can be convenient to register an engine in global configuration, and is
99
- required for certain functionality (like out-of-the-box AJAX loading).
100
+ It can be convenient to register an engine in global configuration, and is
101
+ required for certain functionality (like out-of-the-box AJAX loading).
100
102
 
101
103
  In an initializer in your app, like say `./config/initializers/bento_search.rb`:
102
104
 
@@ -107,7 +109,7 @@ In an initializer in your app, like say `./config/initializers/bento_search.rb`:
107
109
  # any other configuration
108
110
  end
109
111
  ~~~~
110
-
112
+
111
113
  Then you can refer to it, for instance in a controller, by the id you registered:
112
114
 
113
115
  ~~~~ruby
@@ -119,14 +121,14 @@ Then you can refer to it, for instance in a controller, by the id you registered
119
121
  You can of course write your own code to display a BentoSearch::Results object
120
122
  however you like. But BentoSearch comes with a helper method for displaying
121
123
  a list of BentoSearch::Results in a standard way, using the bento_search
122
- helper method.
124
+ helper method.
123
125
 
124
126
  ~~~~ruby
125
127
  <%= bento_search @results %>
126
128
  ~~~~
127
129
 
128
- See also the [Customizing Results Display wiki page](https://github.com/jrochkind/bento_search/wiki/Customizing-Results-Display).
129
-
130
+ See also the [Customizing Results Display wiki page](https://github.com/jrochkind/bento_search/wiki/Customizing-Results-Display).
131
+
130
132
  ### Fielded searching.
131
133
 
132
134
  You can search by an internal engine-specific field name:
@@ -146,11 +148,11 @@ You can find out what fields a particular engine supports.
146
148
 
147
149
  ~~~~ruby
148
150
  google_books_engine.search_keys # => internal keys
149
- google_books_engine.semantic_search_keys
151
+ google_books_engine.semantic_search_keys
150
152
  ~~~~
151
153
 
152
154
  A helper method for generating an html select of search field options is
153
- available in `bento_field_hash_for`, check it out.
155
+ available in `bento_field_hash_for`, check it out.
154
156
 
155
157
  You can also provide all arguments in a single hash when it's convenient
156
158
  to do so:
@@ -161,8 +163,8 @@ to do so:
161
163
 
162
164
  Search fields that are not recognized (semantic or internal) will normally
163
165
  be ignored, but set `:unrecognized_search_field => :raise` in configuration
164
- or search arg to get an ArgumentError instead.
165
-
166
+ or search arg to get an ArgumentError instead.
167
+
166
168
  ### Sorting
167
169
 
168
170
  An engine advertises what sort types it supports:
@@ -173,7 +175,7 @@ An engine advertises what sort types it supports:
173
175
 
174
176
  An array of sort identifiers, where possible
175
177
  chosen from a standard list of semantics. (See list in `./config/i18n/en.yml`,
176
- `bento_search.sort_keys`).
178
+ `bento_search.sort_keys`).
177
179
 
178
180
  ~~~~ruby
179
181
  google_books_engine.search("my query", :sort => "date_desc")
@@ -184,36 +186,36 @@ options_for_select:
184
186
 
185
187
  ~~~~ruby
186
188
  <%= options_for_select( bento_sort_hash_for(engine), params[:sort] ) %>
187
- ~~~~
188
-
189
-
189
+ ~~~~
190
+
191
+
190
192
  ### Pagination
191
193
 
192
- You can tell the search engine how many items you want per-page, and
194
+ You can tell the search engine how many items you want per-page, and
193
195
  use _either_ `:start` (0-based item offset) or `:page` (1-based page
194
- offset) keys to paginate into the results.
196
+ offset) keys to paginate into the results.
195
197
 
196
198
  ~~~~ruby
197
199
  results = google_books_engine.search("my query", :per_page => 20, :start => 40)
198
200
  results = google_books_engine.search("my query", :per_page => 20, :page => 2) # means same as above
199
201
  ~~~~
200
202
 
201
- An engine instance advertises it's maximum per-page values.
203
+ An engine instance advertises it's maximum per-page values.
202
204
 
203
205
  ~~~~ruby
204
206
  google_books_engine.max_per_page
205
207
  ~~~~
206
208
 
207
- bento_search fixes the default per_page at 10.
208
-
209
+ bento_search fixes the default per_page at 10.
210
+
209
211
  For help creating your UI, you can ask a BentoSearch::Results for
210
212
  `results.pagination`, which returns a [BentoSearch::Results::Pagination](app/models/bento_search/results/pagination.rb)
211
213
  object which should be suitable for passing to [kaminari](https://github.com/amatsuda/kaminari)
212
- `paginate`, or else have convenient methods for roll your own pagination UI.
214
+ `paginate`, or else have convenient methods for roll your own pagination UI.
213
215
  Kaminari's paginate method:
214
216
 
215
217
  ~~~~ruby
216
- <%= paginate results.pagination %>
218
+ <%= paginate results.pagination %>
217
219
  ~~~~
218
220
 
219
221
  ### Concurrent searching
@@ -223,23 +225,23 @@ those searches concurrently. For instance, if GoogleBooks results take 2 second
223
225
  to come in, and Scopus results take 3 seconds -- you don't want to first wait
224
226
  the 2 second then wait the 3 seconds for a total of 5 -- you instead want
225
227
  to execute concurrently in seperate threads, so the total wait time is the slowest
226
- engine, not the sum of the engines.
228
+ engine, not the sum of the engines.
227
229
 
228
- You can write your own logic using ruby threads to do this, but
230
+ You can write your own logic using ruby threads to do this, but
229
231
  BentoSearch provides a multi-searching helper using [Celluloid](https://github.com/celluloid/celluloid)
230
232
  to help you do this easily. Say, in a controller:
231
233
 
232
234
  ~~~~ruby
233
235
  # constructor takes id's registered with BentoSearch.register_engine
234
236
  searcher = BentoSearch::MultiSearcher.new(:gbs, :scopus, :summon)
235
-
237
+
236
238
  # Call 'search' with any parameters you would give to an_engine.search
237
239
  searcher.search("my query", :semantic_search_field => :author, :sort => "title")
238
-
240
+
239
241
  # At this point, all searches are executing asynchronously in seperate threads.
240
242
  # To get the results, blocking until all complete:
241
243
  @results = searcher.results
242
-
244
+
243
245
  # @results will be a hash, keyed by registered engine id, values
244
246
  # are BentoSearch::Results
245
247
  ~~~~
@@ -249,85 +251,85 @@ search execute in a seperate thread, so you can continue doing other work
249
251
  in the main thread (like search a local store of some kind outside of
250
252
  bento_search)
251
253
 
252
- You will need to add the 'celluloid' gem to your app to use this feature,
254
+ You will need to add the 'celluloid' gem to your app to use this feature,
253
255
  BentoSearch doesn't automatically include the celluloid dependency. Note
254
256
  that Celluloid uses multi-threading in such a way that you might need
255
257
  to turn Rails config.cache_classes=true even in development.
256
-
257
258
 
258
- For more info, see [BentoSearch::MultiSearcher](./app/models/bento_search/multi_searcher.rb).
259
+
260
+ For more info, see [BentoSearch::MultiSearcher](./app/models/bento_search/multi_searcher.rb).
259
261
 
260
262
  ### Delayed results loading via AJAX (actually more like AJAHtml)
261
263
 
262
264
  BentoSearch provides some basic support for initially displaying a placeholder
263
- progress spinner, and having Javascript call back to get the actual results.
265
+ progress spinner, and having Javascript call back to get the actual results.
264
266
 
265
267
  It's not a panacea for pathologically slow search results, and can be tricky
266
268
  for results that need access controls. But it can be useful
267
269
  in some situations, both for automatic on-page-load ajax loading, and triggered
268
- ajax loading.
270
+ ajax loading.
269
271
 
270
272
  See the [wiki page](https://github.com/jrochkind/bento_search/wiki/AJAX-results-loading)
271
- for more info.
273
+ for more info.
274
+
275
+
272
276
 
273
-
274
-
275
277
  ### Item Decorators, and Links
276
278
 
277
279
  You can configure Decorators, in the form of plain old ruby modules, to be
278
280
  applied to BentoSearch::Items, on an engine-by-engine basis. These can modify,
279
- add, or remove Item data, as well as over-ride some presentational methods.
281
+ add, or remove Item data, as well as over-ride some presentational methods.
280
282
 
281
283
  One common use for these Decorators is changing, adding, or removing links
282
- associated with an item. For instance, to link to your local OpenURL
284
+ associated with an item. For instance, to link to your local OpenURL
283
285
  link resolver.
284
286
 
285
- BentoSearch::Items can have a main link associated with them (generally
287
+ BentoSearch::Items can have a main link associated with them (generally
286
288
  hyperlinked from title), as well as a list of additional links. Most engines
287
289
  do not provide additional links by default, custom local Decorators would
288
- be used to add them. See [wiki on display cusotmization](https://github.com/jrochkind/bento_search/wiki/Customizing-Results-Display)
290
+ be used to add them. See [wiki on display cusotmization](https://github.com/jrochkind/bento_search/wiki/Customizing-Results-Display)
289
291
  for more info on decorators, and [BentoSearch::Link](app/models/bento_search/link.rb)
290
- for fields.
291
-
292
+ for fields.
293
+
292
294
  ### OpenURL and metadata
293
295
 
294
296
  Academic library uses often need openurl links from scholarly citations. One of
295
297
  the design goals of bento_search is to produce standardized normalized BentoSearch::ResultItem
296
- models, with sufficient semantics for translation to other formats.
298
+ models, with sufficient semantics for translation to other formats.
297
299
 
298
- See ResultItem#to_openurl_kev (string URL query encoding of OpenURL), and
299
- ResultItem#to_openurl (a [ruby OpenURL gem](https://github.com/openurl/openurl) object).
300
+ See ResultItem#to_openurl_kev (string URL query encoding of OpenURL), and
301
+ ResultItem#to_openurl (a [ruby OpenURL gem](https://github.com/openurl/openurl) object).
300
302
 
301
303
  Quality may vary, depending on how well the particular engine adapter captures semantics,
302
304
  especially the format/type of results (See bento_search's internal format/type vocabulary
303
305
  documented at ResultItem#format). As well as how well the #to_openurl routine
304
306
  handles all edge cases (OpenURL can be weird). As edge cases are discovered, they
305
- can be solved.
307
+ can be solved.
306
308
 
307
- See [`./app/item_decorators/bento_search/openurl_add_other_link.rb`](./app/item_decorators/bento_search/openurl_add_other_link.rb)
309
+ See [`./app/item_decorators/bento_search/openurl_add_other_link.rb`](./app/item_decorators/bento_search/openurl_add_other_link.rb)
308
310
  for an example of using item decorators to add a link to your openurl resover to an item when
309
311
  displayed.
310
312
 
311
313
  ### Exporting (eg as RIS) and get by unique_id
312
314
 
313
315
  A class is included to convert an individual BentoSearch::ResultItem to
314
- the RIS format, suitable for import into EndNote, Refworks, etc.
316
+ the RIS format, suitable for import into EndNote, Refworks, etc.
315
317
 
316
318
  ~~~ruby
317
- ris_data = RISCreator.new( bento_item ).export
319
+ ris_data = RISCreator.new( bento_item ).export
318
320
  ~~~
319
321
 
320
322
  Accomodating actual exports into the transactional flow of a web app can be
321
- tricky, and often requires use of the `result_item#unique_id` and
323
+ tricky, and often requires use of the `result_item#unique_id` and
322
324
  `engine.get( unique_id )` features. See the wiki on [exports and #unique_id](https://github.com/jrochkind/bento_search/wiki/Exports-and-the-get-by-unique_id-feature)
323
325
 
324
326
  ### Machine-readable serialization in Atom
325
327
 
326
328
  Translation of any BentoSearch::Results to an Atom response that is enhanced to
327
329
  include nearly all the elements of each BentoSearch::ResultItem, so can serves
328
- well as machine-readable api response in general, not just for Atom feed readers.
330
+ well as machine-readable api response in general, not just for Atom feed readers.
329
331
 
330
- You can use the [`bento_search/atom_results`](./app/views/bento_search/atom_results.atom.builder) view template, perhaps
332
+ You can use the [`bento_search/atom_results`](./app/views/bento_search/atom_results.atom.builder) view template, perhaps
331
333
  in your action method like so:
332
334
 
333
335
  ~~~ruby
@@ -335,76 +337,76 @@ in your action method like so:
335
337
  respond_to do |format|
336
338
  format.html # default view
337
339
  format.atom do
338
- render( :template => "bento_search/atom_results",
340
+ render( :template => "bento_search/atom_results",
339
341
  :locals => {
340
342
  :atom_results => @results,
341
343
  :feed_name => "Acme results",
342
344
  :feed_author_name => "MyCorp"
343
- }
344
- )
345
- end
345
+ }
346
+ )
347
+ end
346
348
  ~~~
347
349
 
348
- There are additional details that might matter to you, for more info see the
349
- [wiki page](https://github.com/jrochkind/bento_search/wiki/Machine-Readable-Serialization-With-Atom)
350
+ There are additional details that might matter to you, for more info see the
351
+ [wiki page](https://github.com/jrochkind/bento_search/wiki/Machine-Readable-Serialization-With-Atom)
350
352
 
351
353
  ## Planned Features
352
354
 
353
355
  I am trying to keep BentoSearch as simple as it can be to conveniently meet
354
356
  actual use cases. Trying to avoid premature over-engineering, and pave
355
- the cowpaths as needed.
357
+ the cowpaths as needed.
356
358
 
357
359
  Probably:
358
360
 
359
- * Support for display facets for engines that support such, as well as
361
+ * Support for display facets for engines that support such, as well as
360
362
  search with limits from controlled vocabulary (ie, selected facet, but
361
- also may be supported by some engines that do not support facetting).
363
+ also may be supported by some engines that do not support facetting).
362
364
  * Support for multi-field, multi-entry-box 'advanced search' UI's, in
363
- a normalized cross-engine way.
365
+ a normalized cross-engine way.
364
366
 
365
367
  Other needs or suggestions?
366
368
 
367
369
  ## Backwards compat
368
370
 
369
- We are going to try to be strictly backwards compatible with all post 1.0
370
- releases that do not increment the major version number (semantic versioning).
371
+ We are going to try to be strictly backwards compatible with all post 1.0
372
+ releases that do not increment the major version number (semantic versioning).
371
373
 
372
374
  As a general rule, we're going to let our tests enforce this -- if a test has
373
375
  to be changed to pass with new code, that's a very strong sign that it is
374
- not a backwards-compat change, and you should think _very_ carefully to
376
+ not a backwards-compat change, and you should think _very_ carefully to
375
377
  be sure it is an exception to this rule before changing any existing tests
376
- for new functionality.
378
+ for new functionality.
377
379
 
378
380
  ## Developing
379
381
 
380
382
  BentoSearch is fairly well covered by automated tests. We simply use Test::Unit.
381
- Run tests with `rake test`.
383
+ Run tests with `rake test`.
382
384
 
383
385
  The testing environment was generated with `rails plugin new`, and includes
384
- a dummy app used when testing at `./test/dummy`.
386
+ a dummy app used when testing at `./test/dummy`.
385
387
 
386
388
  For integration tests against live external search API's, we use the awesome
387
- [VCR](https://github.com/myronmarston/vcr) gem to cache responses.
388
- To write your own Test::Unit tests using VCR, take note of the
389
- `test_with_cassette` method provided in `./test/support/test_with_cassette.rb`.
389
+ [VCR](https://github.com/myronmarston/vcr) gem to cache responses.
390
+ To write your own Test::Unit tests using VCR, take note of the
391
+ `test_with_cassette` method provided in `./test/support/test_with_cassette.rb`.
390
392
 
391
393
  Also note use of VCR.filter_sensitive_data to make sure your API keys
392
394
  do not get saved in cached response in the repo, while still allowing
393
395
  tests to be run against cached responses even for engines that require
394
- auth.
396
+ auth.
395
397
 
396
- To re-generate cached responses, delete the relevant files in
398
+ To re-generate cached responses, delete the relevant files in
397
399
  `./test/vcr_cassettes` and re-run tests. You may have to set an ENV
398
400
  variable with your own API keys to re-run tests without cached response
399
- like this.
401
+ like this.
400
402
 
401
403
  Also note `BentoSearch::MockEngine`, a simple mock/dummy SearchEngine
402
404
  implementation that can be used in other tests, including in client
403
- software where convenient.
405
+ software where convenient.
404
406
 
405
407
  Pull requests welcome. Pull requests with additional search engine implementations
406
408
  welcome. See more info on writing a BentoSearch::SearchEngine in the inline
407
- docs in that file.
409
+ docs in that file.
408
410
 
409
411
 
410
412