dnz-client 0.0.4 → 0.0.5
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.
- data/History.txt +6 -0
- data/lib/dnz/client.rb +76 -20
- data/lib/dnz/search.rb +42 -5
- data/lib/dnz.rb +1 -1
- data/spec/dnz/client_spec.rb +85 -0
- data/spec/spec.opts +2 -1
- metadata +2 -2
data/History.txt
CHANGED
data/lib/dnz/client.rb
CHANGED
@@ -23,7 +23,7 @@ module DNZ
|
|
23
23
|
|
24
24
|
APIS = {
|
25
25
|
:search => 'records/${version}.xml/',
|
26
|
-
:custom_search => 'custom_searches/${version}/${
|
26
|
+
:custom_search => 'custom_searches/${version}/${custom_search}.xml'
|
27
27
|
}
|
28
28
|
|
29
29
|
ARGS = {
|
@@ -37,9 +37,43 @@ module DNZ
|
|
37
37
|
:direction,
|
38
38
|
:facets,
|
39
39
|
:facet_num_results,
|
40
|
-
:facet_start
|
40
|
+
:facet_start
|
41
|
+
]),
|
42
|
+
:custom_search => Set.new([
|
43
|
+
:custom_search,
|
44
|
+
:search_text,
|
45
|
+
:api_key,
|
46
|
+
:num_results,
|
47
|
+
:start,
|
48
|
+
:sort,
|
49
|
+
:direction
|
50
|
+
])
|
51
|
+
},
|
52
|
+
:v2 => {
|
53
|
+
:search => Set.new([
|
54
|
+
:search_text,
|
55
|
+
:api_key,
|
56
|
+
:num_results,
|
57
|
+
:start,
|
58
|
+
:sort,
|
59
|
+
:direction,
|
60
|
+
:facets,
|
61
|
+
:facet_num_results,
|
62
|
+
:facet_start
|
63
|
+
]),
|
64
|
+
:custom_search => Set.new([
|
65
|
+
:custom_search,
|
66
|
+
:search_text,
|
67
|
+
:api_key,
|
68
|
+
:num_results,
|
69
|
+
:start,
|
70
|
+
:sort,
|
71
|
+
:direction,
|
72
|
+
:facets,
|
73
|
+
:facet_num_results,
|
74
|
+
:facet_start
|
41
75
|
])
|
42
|
-
}
|
76
|
+
}
|
43
77
|
}
|
44
78
|
|
45
79
|
# List of available facets that can be passed to search
|
@@ -56,7 +90,7 @@ module DNZ
|
|
56
90
|
# search.results.each do |result|
|
57
91
|
# puts result.title
|
58
92
|
# end
|
59
|
-
def initialize(api_key, base_url = 'http://api.digitalnz.org'
|
93
|
+
def initialize(api_key, version = 'v1', base_url = 'http://api.digitalnz.org')
|
60
94
|
@api_key = api_key
|
61
95
|
@base_url = base_url
|
62
96
|
@version = version
|
@@ -81,6 +115,7 @@ module DNZ
|
|
81
115
|
# * <tt>:start</tt> - The starting offset of the results.
|
82
116
|
# * <tt>:facets</tt> - The facets to return for this search.
|
83
117
|
# * <tt>:filter</tt> - A hash of filters to apply to the results
|
118
|
+
# * <tt>:custom_search</tt> - The name of a custom search created at http://digitalnz.org
|
84
119
|
#
|
85
120
|
# ==== Example
|
86
121
|
# search = client.search('rubgy', :num_results => 50)
|
@@ -109,17 +144,12 @@ module DNZ
|
|
109
144
|
def fetch(api, options = {})
|
110
145
|
validate_options(api, options)
|
111
146
|
|
112
|
-
options = options.reverse_merge(
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
#
|
119
|
-
|
120
|
-
# qs = options.map{|k,v| '%s=%s' % [k,v] }.join('&')
|
121
|
-
qs = options.to_query
|
122
|
-
url = self.base_url + '/' + APIS[api].gsub('${version}', self.version) + '?' + qs
|
147
|
+
options = options.reverse_merge(
|
148
|
+
:api_key => self.api_key,
|
149
|
+
:version => self.version
|
150
|
+
)
|
151
|
+
|
152
|
+
url = create_url(api, options)
|
123
153
|
|
124
154
|
begin
|
125
155
|
open(url)
|
@@ -133,14 +163,40 @@ module DNZ
|
|
133
163
|
end
|
134
164
|
|
135
165
|
private
|
136
|
-
|
137
|
-
|
166
|
+
|
167
|
+
# Create a URL for a given API call with a hash of option
|
168
|
+
#
|
169
|
+
# * <tt>api</tt> - The api call to make. This must be listed in the APIS constant.
|
170
|
+
# * <tt>options</tt> - A hash of options.
|
171
|
+
def create_url(api, options)
|
138
172
|
options = options.symbolize_keys
|
139
173
|
|
140
|
-
|
174
|
+
path = APIS[api].dup
|
175
|
+
variable_regex = /\$\{(.+?)\}/m
|
176
|
+
|
177
|
+
while match = variable_regex.match(path)
|
178
|
+
variable_name = $1.to_sym
|
179
|
+
|
180
|
+
if options.has_key?(variable_name)
|
181
|
+
path.sub!(variable_regex, options.delete(variable_name))
|
182
|
+
else
|
183
|
+
raise ArgumentError.new("Required argument missing: #{variable_name}")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
url = self.base_url + '/' + path
|
188
|
+
url + '?' + options.to_query
|
189
|
+
end
|
141
190
|
|
142
|
-
|
143
|
-
|
191
|
+
# Validate an options hash for a given api
|
192
|
+
def validate_options(api, options = {})
|
193
|
+
options = options.symbolize_keys
|
194
|
+
version_args = ARGS[@version.to_sym]
|
195
|
+
|
196
|
+
if !version_args
|
197
|
+
raise ArgumentError.new("Invalid version API call: #{@version}, #{api}")
|
198
|
+
elsif version_args.has_key?(api) && !Set.new(options.keys).subset?(version_args[api])
|
199
|
+
raise ArgumentError.new("Valid options for #{api} are: #{version_args[api].to_a.join(', ')}, provided: #{options.keys.join(', ')}")
|
144
200
|
end
|
145
201
|
end
|
146
202
|
end
|
data/lib/dnz/search.rb
CHANGED
@@ -4,6 +4,8 @@ require 'dnz/facet_array'
|
|
4
4
|
require 'dnz/facet'
|
5
5
|
require 'dnz/memoizable'
|
6
6
|
|
7
|
+
# Load will_paginate if it's available
|
8
|
+
# to provide pagination
|
7
9
|
begin
|
8
10
|
gem 'mislav-will_paginate' rescue nil
|
9
11
|
require 'will_paginate/collection' rescue nil
|
@@ -18,6 +20,7 @@ module DNZ
|
|
18
20
|
# search = client.search('text')
|
19
21
|
# puts "%d results found on %d pages" % [search.result_count, search.pages]
|
20
22
|
class Search
|
23
|
+
# The total number of results returned by the search
|
21
24
|
attr_reader :result_count
|
22
25
|
|
23
26
|
extend DNZ::Memoizable
|
@@ -88,9 +91,16 @@ module DNZ
|
|
88
91
|
:pages => self.pages
|
89
92
|
}.inspect
|
90
93
|
end
|
94
|
+
|
95
|
+
# Return true if this search is using a custom search engine
|
96
|
+
def custom_search?
|
97
|
+
!@search_options.has_key?(:custom_search)
|
98
|
+
end
|
91
99
|
|
92
100
|
private
|
93
101
|
|
102
|
+
# Turn the filter hash into an array of strings
|
103
|
+
# in the format key:"value"
|
94
104
|
def parsed_search_filter
|
95
105
|
filter = @search_options[:filter]
|
96
106
|
filter = {} unless filter.is_a?(Hash)
|
@@ -99,6 +109,7 @@ module DNZ
|
|
99
109
|
end
|
100
110
|
memoize :parsed_search_filter
|
101
111
|
|
112
|
+
# Join the search text with any filters with " AND "
|
102
113
|
def parsed_search_text
|
103
114
|
if parsed_search_filter.any?
|
104
115
|
([text] + parsed_search_filter).join(' AND ')
|
@@ -107,12 +118,15 @@ module DNZ
|
|
107
118
|
end
|
108
119
|
end
|
109
120
|
|
121
|
+
# The facets option gets turned into a comma separated string
|
110
122
|
def parsed_search_facets
|
111
123
|
search_facets = @search_options[:facets] || []
|
112
124
|
search_facets = search_facets.join(',') if search_facets.is_a?(Array)
|
113
125
|
search_facets
|
114
126
|
end
|
115
127
|
|
128
|
+
# Turn the options into options acceptable for an API call.
|
129
|
+
# Removes the filter option and parses the other options.
|
116
130
|
def parsed_search_options
|
117
131
|
parsed_options = @search_options.dup
|
118
132
|
parsed_options.delete(:filter)
|
@@ -124,16 +138,28 @@ module DNZ
|
|
124
138
|
end
|
125
139
|
memoize :parsed_search_options
|
126
140
|
|
141
|
+
# Return a Nokogiri document for the XML
|
127
142
|
def doc
|
128
143
|
@doc ||= Nokogiri::XML(@xml)
|
129
144
|
end
|
145
|
+
|
146
|
+
# Choose which API call to make, either search or
|
147
|
+
# custom_search if a custom search engine is specified.
|
148
|
+
def execute_action
|
149
|
+
if custom_search?
|
150
|
+
:search
|
151
|
+
else
|
152
|
+
:custom_search
|
153
|
+
end
|
154
|
+
end
|
130
155
|
|
156
|
+
# Execute the search by making the API call
|
131
157
|
def execute
|
132
|
-
|
133
|
-
|
134
|
-
@
|
135
|
-
@xml = @client.send(:fetch, :search, parsed_search_options)
|
158
|
+
reset
|
159
|
+
|
160
|
+
@xml = @client.send(:fetch, execute_action, parsed_search_options)
|
136
161
|
|
162
|
+
# Parse the results
|
137
163
|
parse_attributes
|
138
164
|
parse_facets
|
139
165
|
parse_results
|
@@ -141,13 +167,22 @@ module DNZ
|
|
141
167
|
|
142
168
|
self
|
143
169
|
end
|
170
|
+
|
171
|
+
# Reset important instance variables
|
172
|
+
def reset
|
173
|
+
@doc = nil
|
174
|
+
@results = nil
|
175
|
+
@facets = nil
|
176
|
+
end
|
144
177
|
|
178
|
+
# Replace the results array with a paginated array
|
145
179
|
def paginate_results
|
146
180
|
@results = WillPaginate::Collection.create(self.page, num_results_requested, self.result_count) do |pager|
|
147
181
|
pager.replace @results
|
148
182
|
end
|
149
183
|
end
|
150
184
|
|
185
|
+
# Parse important global attributes into instance variables
|
151
186
|
def parse_attributes
|
152
187
|
%w(num-results-requested result-count start).each do |node|
|
153
188
|
if child = doc.root.xpath(node).first
|
@@ -158,13 +193,15 @@ module DNZ
|
|
158
193
|
end
|
159
194
|
end
|
160
195
|
|
196
|
+
# Parse the results into an array of DNZ::Result
|
161
197
|
def parse_results
|
162
198
|
@results = []
|
163
199
|
doc.xpath('//results/result').each do |result_xml|
|
164
200
|
@results << DNZ::Result.new(result_xml)
|
165
201
|
end
|
166
202
|
end
|
167
|
-
|
203
|
+
|
204
|
+
# Parse the facets into an array of DNZ::FacetArray
|
168
205
|
def parse_facets
|
169
206
|
@facets = FacetArray.new
|
170
207
|
|
data/lib/dnz.rb
CHANGED
data/spec/dnz/client_spec.rb
CHANGED
@@ -10,6 +10,91 @@ describe Client do
|
|
10
10
|
@search = mock(:search)
|
11
11
|
DNZ::Search.stub!(:new).and_return(@search)
|
12
12
|
end
|
13
|
+
|
14
|
+
describe 'APIs' do
|
15
|
+
describe 'v1' do
|
16
|
+
before do
|
17
|
+
@version = 'v1'
|
18
|
+
@client = Client.new('abc', @version)
|
19
|
+
@client.stub!(:open) # make sure open is never called
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'search' do
|
23
|
+
[:search_text,:api_key,:num_results,:start,:sort,:direction,:facets,:facet_num_results,:facet_start].each do |option|
|
24
|
+
it "should allow #{option}" do
|
25
|
+
lambda do
|
26
|
+
@client.send(:fetch, :search, {option => "test"})
|
27
|
+
end.should_not raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'custom_search' do
|
33
|
+
it 'should require custom_search' do
|
34
|
+
lambda do
|
35
|
+
@client.send(:fetch, :custom_search, {})
|
36
|
+
end.should raise_error(ArgumentError, "Required argument missing: custom_search")
|
37
|
+
end
|
38
|
+
|
39
|
+
[:search_text,:api_key,:num_results,:start,:sort,:direction].each do |option|
|
40
|
+
it "should allow #{option}" do
|
41
|
+
lambda do
|
42
|
+
@client.send(:fetch, :custom_search, {:custom_search => "test", option => "test"})
|
43
|
+
end.should_not raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
[:facets,:facet_num_results,:facet_start].each do |option|
|
47
|
+
it "should not allow #{option}" do
|
48
|
+
lambda do
|
49
|
+
@client.send(:fetch, :custom_search, {:custom_search => "test", option => "test"})
|
50
|
+
end.should raise_error(ArgumentError)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'v2' do
|
57
|
+
before do
|
58
|
+
@version = 'v2'
|
59
|
+
@client = Client.new('abc', @version)
|
60
|
+
@client.stub!(:open) # make sure open is never called
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'search' do
|
64
|
+
[:search_text,:api_key,:num_results,:start,:sort,:direction,:facets,:facet_num_results,:facet_start].each do |option|
|
65
|
+
it "should allow #{option}" do
|
66
|
+
lambda do
|
67
|
+
@client.send(:fetch, :search, {})
|
68
|
+
end.should_not raise_error(ArgumentError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'custom_search' do
|
74
|
+
it 'should require custom_search' do
|
75
|
+
lambda do
|
76
|
+
@client.send(:fetch, :custom_search, {})
|
77
|
+
end.should raise_error(ArgumentError, "Required argument missing: custom_search")
|
78
|
+
end
|
79
|
+
|
80
|
+
[:search_text,:api_key,:num_results,:start,:sort,:direction].each do |option|
|
81
|
+
it "should allow #{option}" do
|
82
|
+
lambda do
|
83
|
+
@client.send(:fetch, :custom_search, {:custom_search => "test", option => "test"})
|
84
|
+
end.should_not raise_error(ArgumentError)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
[:facets,:facet_num_results,:facet_start].each do |option|
|
88
|
+
it "should allow #{option}" do
|
89
|
+
lambda do
|
90
|
+
@client.send(:fetch, :custom_search, {:custom_search => "test", option => "test"})
|
91
|
+
end.should_not raise_error(ArgumentError)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
13
98
|
|
14
99
|
describe '#search' do
|
15
100
|
it 'should create a new search object and return it' do
|
data/spec/spec.opts
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dnz-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Wells
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-15 00:00:00 +13:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|