sru 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ # allow people to require sru and get all the goodies
2
+
3
+ require 'sru/client'
4
+ require 'sru/explain'
5
+ require 'sru/search_retrieve'
6
+ require 'sru/scan'
7
+ require 'sru/term'
8
+ require 'sru/exception'
@@ -0,0 +1,95 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/http'
4
+ require 'rexml/document'
5
+
6
+ module SRU
7
+
8
+ # A client for issuing requests to a particular SRU server.
9
+ # SRU is a RESTlike information retrieval protocol detailed at
10
+ # http://www.loc.gov/standards/sru/
11
+
12
+ class Client
13
+
14
+ # creates a client object which will automatically perform an
15
+ # explain request to determine the version to be used in
16
+ # subsequent requests.
17
+
18
+ def initialize(base)
19
+ @server = URI.parse base
20
+
21
+ # stash this away for future requests
22
+ @version = self.explain.version
23
+ end
24
+
25
+
26
+ # Send an explain request to the SRU server and return a
27
+ # SRU::ExplainResponse object.
28
+ #
29
+ # client = SRU::Client.new 'http://sru.example.com'
30
+ # explain = client.explain
31
+
32
+ def explain
33
+ doc = get_doc(:operation => 'explain')
34
+ return ExplainResponse.new(doc)
35
+ end
36
+
37
+
38
+ # Send a searchRetrieve request to the SRU server and return
39
+ # a SRU::SearchResponse object. The first argument is the required
40
+ # query option. Any remaining searchRetrieve options can be passed
41
+ # as an optional second argument.
42
+ #
43
+ # client = SRU::Client.new 'http://example.com/sru'
44
+ # response = client.search_retrieve('mark twain', maximumRecords => 1)
45
+
46
+ def search_retrieve(query, options={})
47
+ options['query'] = query
48
+ options['operation'] = 'searchRetrieve'
49
+ doc = get_doc(options)
50
+ return SearchResponse.new(doc)
51
+ end
52
+
53
+
54
+ # Send a scan request to the SRU server and return a SRU::ScanResponse
55
+ # object. You must supply the first parameter which is the searchClause.
56
+ # Other SRU options can be sent in a hash as the seond argument.
57
+ #
58
+ # scan_response = client.scan 'title
59
+
60
+ def scan(clause, options={})
61
+ options['scanClause'] = clause
62
+ options['operation'] = 'scan'
63
+ doc = get_doc(options)
64
+ return ScanResponse.new(doc)
65
+ end
66
+
67
+ private
68
+
69
+ # helper to fetch xml responses from the sru server
70
+ # given a set of options
71
+
72
+ def get_doc(hash)
73
+ # all requests get a version
74
+ hash['version'] = @version
75
+
76
+ # don't want to monkey with the original
77
+ uri = @server.clone
78
+
79
+ # no ruby class for building a query string!?!?
80
+ # probably just wasn't looking in the right place
81
+ parts = hash.entries.map { |entry|
82
+ "#{entry[0]}=#{CGI.escape(entry[1].to_s)}"
83
+ }
84
+ uri.query = parts.join('&')
85
+
86
+ # fetch the xml and build/return a document object from it
87
+ begin
88
+ xml = Net::HTTP.get(uri)
89
+ return REXML::Document.new(xml)
90
+ rescue
91
+ raise SRU::Exception, "exception during SRU operation", caller
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,5 @@
1
+ # wrapper for exceptions that happen during an sru operation
2
+ module SRU
3
+ class Exception < RuntimeError
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'sru/response'
2
+
3
+ module SRU
4
+ class ExplainResponse < Response
5
+ def version
6
+ version = xpath('.//zs:explainResponse/zs:version')
7
+ return version if version
8
+
9
+ # also look here
10
+ info = xpath_first('.//serverInfo')
11
+ return info.attributes['version'] if info
12
+
13
+ return nil
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ require 'rexml/xpath'
2
+
3
+ module SRU
4
+
5
+ # base class for all SRU responses
6
+ class Response
7
+ attr_reader :doc
8
+
9
+ # namespaces for use in xpath queries
10
+ @@namespaces = {'zs' => 'http://www.loc.gov/zing/srw/'}
11
+
12
+ def initialize(doc)
13
+ @doc = doc
14
+ end
15
+
16
+ protected
17
+
18
+ # get all nodes that match an xpath
19
+ def xpath_all(path)
20
+ return REXML::XPath.match(@doc, path, @@namespaces)
21
+ end
22
+
23
+ # get the first node that matches an xpath
24
+ def xpath_first(path)
25
+ elements = xpath_all(path)
26
+ return elements[0] if elements != nil
27
+ return nil
28
+ end
29
+
30
+ # get the text inside the first node that matches the xpath
31
+ def xpath(path)
32
+ e = xpath_first(path)
33
+ return e.text if e != nil
34
+ return nil
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,16 @@
1
+ require 'sru/response'
2
+
3
+ module SRU
4
+
5
+ # A wrapper for the scan response from a SRU server.
6
+ class ScanResponse < Response
7
+ include Enumerable
8
+
9
+ def each
10
+ for term_node in xpath_all('.//zs:term')
11
+ yield Term.new(term_node)
12
+ end
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,30 @@
1
+ require 'sru/response'
2
+
3
+ module SRU
4
+
5
+ # An iterator for search results which allows you to do stuff like:
6
+ #
7
+ # client = SRU::Client.new 'http://sru.example.com'
8
+ # for record in client.search_retrieve('Mark Twain')
9
+ # puts record
10
+ # end
11
+
12
+ class SearchResponse < Response
13
+ include Enumerable
14
+
15
+ def number_of_records
16
+ return Integer(xpath('.//zs:numberOfRecords'))
17
+ end
18
+
19
+ # Returns the contents of each recordData element in a
20
+ # SRU searchRetrieve response.
21
+
22
+ def each
23
+ for record_data in xpath_all('.//zs:recordData')
24
+ if record_data.elements.size > 0
25
+ yield record_data.elements[1]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module SRU
2
+
3
+ # a class for representing a term in the response from a sru server
4
+ class Term < Response
5
+ attr_accessor :value, :number_of_records, :displayTerm, :whereInList,
6
+ :extraTermData
7
+
8
+ def initialize(element)
9
+ super element
10
+ @value = xpath('value')
11
+ @number_of_records = xpath('numberOfRecords')
12
+ @display_term = xpath('displayTerm')
13
+ @whereInList = xpath('whereInList')
14
+ @extraTermData = xpath_first('extraTermData')
15
+ end
16
+ end
17
+ end
data/test.rb ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift 'lib'
4
+ require 'test/unit'
5
+ require 'sru'
6
+
7
+ class ClientTests < Test::Unit::TestCase
8
+
9
+ def test_explain
10
+ client = SRU::Client.new 'http://z3950.loc.gov:7090/voyager'
11
+ explain = client.explain
12
+ assert_equal SRU::ExplainResponse, explain.class
13
+ assert_equal '1.1', explain.version
14
+ end
15
+
16
+ def test_search_retrieve
17
+ client = SRU::Client.new 'http://z3950.loc.gov:7090/voyager'
18
+ results = client.search_retrieve 'twain', :maximumRecords => 5
19
+ assert_equal 5, results.entries.size
20
+ assert results.number_of_records > 2000
21
+ assert_equal REXML::Element, results.entries[0].class
22
+ assert_equal 'record', results.entries[0].name
23
+
24
+ # hopefully there isn't a document that matches this :)
25
+ results = client.search_retrieve 'fidkidkdiejfl'
26
+ assert_equal 0, results.entries.size
27
+ end
28
+
29
+ def test_scan
30
+ # this scan response appears to be canned might need to change
31
+ client = SRU::Client.new 'http://tweed.lib.ed.ac.uk:8080/elf/search/copac'
32
+ scan = client.scan('foobar')
33
+ assert scan.entries.size > 0
34
+ assert_equal SRU::Term, scan.entries[0].class
35
+ assert_equal 'low', scan.entries[0].value
36
+ assert_equal '1', scan.entries[0].number_of_records
37
+ end
38
+
39
+ def test_xml_exception
40
+ assert_raise(SRU::Exception) {SRU::Client.new 'http://www.google.com'}
41
+ end
42
+
43
+ def test_http_exception
44
+ assert_raise(SRU::Exception) {SRU::Client.new 'http://example.com'}
45
+ end
46
+
47
+ end
48
+
49
+
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: sru
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-04-16 00:00:00 -05:00
8
+ summary: talk to sru servers with ruby
9
+ require_paths:
10
+ - lib
11
+ email: ehs@pobox.com
12
+ homepage: http://www.textualize.com/sruby
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: sru
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - Ed Summers
31
+ files:
32
+ - lib/sru
33
+ - lib/sru.rb
34
+ - lib/sru/client.rb
35
+ - lib/sru/exception.rb
36
+ - lib/sru/explain.rb
37
+ - lib/sru/response.rb
38
+ - lib/sru/scan.rb
39
+ - lib/sru/search_retrieve.rb
40
+ - lib/sru/term.rb
41
+ test_files:
42
+ - test.rb
43
+ rdoc_options: []
44
+ extra_rdoc_files: []
45
+ executables: []
46
+ extensions: []
47
+ requirements: []
48
+ dependencies: []