sru 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []