dnz-client 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -8,8 +8,10 @@ lib/dnz.rb
8
8
  lib/dnz/attributes.rb
9
9
  lib/dnz/client.rb
10
10
  lib/dnz/facet.rb
11
+ lib/dnz/facet_array.rb
11
12
  lib/dnz/result.rb
12
13
  lib/dnz/search.rb
14
+ lib/dnz/error/invalid_api_key.rb
13
15
  script/console
14
16
  script/destroy
15
17
  script/generate
data/README.rdoc CHANGED
@@ -18,13 +18,13 @@
18
18
 
19
19
  == INSTALL:
20
20
 
21
- * sudo gem install dnz-client / sudo gem install boost-dnz-client
21
+ * sudo gem install dnz-client
22
22
 
23
23
  == LICENSE:
24
24
 
25
25
  (The MIT License)
26
26
 
27
- Copyright (c) 2009 Boost New Media (http:/www.boost.co.nz)
27
+ Copyright (c) 2009 Boost New Media (http://www.boost.co.nz)
28
28
 
29
29
  Permission is hereby granted, free of charge, to any person obtaining
30
30
  a copy of this software and associated documentation files (the
data/lib/dnz/client.rb CHANGED
@@ -3,6 +3,7 @@ require 'open-uri'
3
3
  require 'set'
4
4
  require 'active_support'
5
5
  require 'dnz/search'
6
+ require 'dnz/error/invalid_api_key'
6
7
 
7
8
  module DNZ
8
9
  # This is a simple client for accessing the digitalnz.org API
@@ -26,17 +27,19 @@ module DNZ
26
27
  }
27
28
 
28
29
  ARGS = {
29
- :search => Set.new([
30
- :search_text,
31
- :api_key,
32
- :num_results,
33
- :start,
34
- :sort,
35
- :direction,
36
- :facets,
37
- :facet_num_results,
38
- :facet_start,
39
- ])
30
+ :v1 => {
31
+ :search => Set.new([
32
+ :search_text,
33
+ :api_key,
34
+ :num_results,
35
+ :start,
36
+ :sort,
37
+ :direction,
38
+ :facets,
39
+ :facet_num_results,
40
+ :facet_start,
41
+ ])
42
+ }
40
43
  }
41
44
 
42
45
  # List of available facets that can be passed to search
@@ -77,6 +80,7 @@ module DNZ
77
80
  # * <tt>:num_results</tt> - The number of results to return in this call. Defaults to 20.
78
81
  # * <tt>:start</tt> - The starting offset of the results.
79
82
  # * <tt>:facets</tt> - The facets to return for this search.
83
+ # * <tt>:filter</tt> - A hash of filters to apply to the results
80
84
  #
81
85
  # ==== Example
82
86
  # search = client.search('rubgy', :num_results => 50)
@@ -87,7 +91,8 @@ module DNZ
87
91
  options.reverse_merge!(
88
92
  :search_text => text,
89
93
  :num_results => 20,
90
- :start => 0
94
+ :start => 0,
95
+ :filter => {}
91
96
  )
92
97
 
93
98
  # Select the correct page
@@ -112,19 +117,30 @@ module DNZ
112
117
  #
113
118
  #
114
119
 
115
-
116
- qs = options.map{|k,v| '%s=%s' % [k,v] }.join('&')
120
+ # qs = options.map{|k,v| '%s=%s' % [k,v] }.join('&')
121
+ qs = options.to_query
117
122
  url = self.base_url + '/' + APIS[api].gsub('${version}', self.version) + '?' + qs
118
- open(url)
123
+
124
+ begin
125
+ open(url)
126
+ rescue OpenURI::HTTPError => e
127
+ if e.to_s =~ /^401/
128
+ raise InvalidApiKeyError.new(self.api_key)
129
+ else
130
+ raise
131
+ end
132
+ end
119
133
  end
120
134
 
121
135
  private
122
136
 
123
137
  def validate_options(path, options = {})
124
- options.symbolize_keys!
138
+ options = options.symbolize_keys
139
+
140
+ version_args = ARGS[@version.to_sym]
125
141
 
126
- if ARGS.has_key?(path) && !Set.new(options.keys).subset?(ARGS[path])
127
- raise ArgumentError.new("Valid options for #{path} are: #{ARGS[path].to_a.join(', ')}, provided: #{options.keys.join(', ')}")
142
+ if version_args.has_key?(path) && !Set.new(options.keys).subset?(version_args[path])
143
+ raise ArgumentError.new("Valid options for #{path} are: #{version_args[path].to_a.join(', ')}, provided: #{options.keys.join(', ')}")
128
144
  end
129
145
  end
130
146
  end
@@ -0,0 +1,13 @@
1
+ module DNZ
2
+ class InvalidApiKeyError < RuntimeError
3
+ attr_reader :api_key
4
+
5
+ def initialize(api_key)
6
+ @api_key = api_key
7
+ end
8
+
9
+ def to_s
10
+ "Invalid API key: #{api_key}"
11
+ end
12
+ end
13
+ end
data/lib/dnz/facet.rb CHANGED
@@ -5,17 +5,39 @@ module DNZ
5
5
  attr_reader :name
6
6
  attr_reader :values
7
7
  attr_reader :search
8
+
9
+ include Enumerable
8
10
 
9
11
  def initialize(client, search, doc)
10
12
  @name = doc.xpath('facet-field').text
11
- @values = []
13
+ @values = {}
12
14
  @search = search
13
15
 
14
16
  doc.xpath('values').first.children.each do |value_doc|
15
17
  value = DNZ::FacetValue.new(client, self, value_doc)
16
- @values << value if value.valid?
18
+ @values[value.name] = value if value.valid?
17
19
  end
18
20
  end
21
+
22
+ def values
23
+ @values.values
24
+ end
25
+
26
+ def [](index)
27
+ @values[index]
28
+ end
29
+
30
+ def each
31
+ @values.each {|key, value| yield value }
32
+ end
33
+
34
+ def to_s
35
+ values.join(', ')
36
+ end
37
+
38
+ def inspect
39
+ '[ %s ]' % values.collect(&:inspect).join(', ')
40
+ end
19
41
  end
20
42
 
21
43
  class FacetValue
@@ -42,7 +64,7 @@ module DNZ
42
64
  end
43
65
 
44
66
  def to_s
45
- self.name
67
+ '%s => %d' % [self.name, self.count]
46
68
  end
47
69
  end
48
70
  end
@@ -0,0 +1,16 @@
1
+ module DNZ
2
+ # Subclass of Array that allows retrieval by facet name
3
+ class FacetArray < Array
4
+ def names
5
+ self.collect(&:name).uniq
6
+ end
7
+
8
+ def [](value)
9
+ if value.is_a?(String) || value.is_a?(Symbol)
10
+ self.detect{|f| f.name == value.to_s }
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/dnz/search.rb CHANGED
@@ -18,6 +18,8 @@ module DNZ
18
18
  # puts "%d results found on %d pages" % [search.result_count, search.pages]
19
19
  class Search
20
20
  attr_reader :result_count
21
+
22
+ extend ActiveSupport::Memoizable
21
23
 
22
24
  # Constructor for Search class. Do not call this directly, instead use the <tt>Client.search</tt> method.
23
25
  def initialize(client, search_options)
@@ -39,11 +41,6 @@ module DNZ
39
41
 
40
42
  # An array of results. If the mislav-will_paginate gem is installed this will return a paginated array.
41
43
  def results
42
- if @results.nil?
43
- parse_results
44
- paginate_results if defined? WillPaginate::Collection
45
- end
46
-
47
44
  @results
48
45
  end
49
46
 
@@ -56,7 +53,6 @@ module DNZ
56
53
  # puts '%d results in category %s' % [category.count, category.name]
57
54
  # end
58
55
  def facets
59
- parse_facets if @facets.nil?
60
56
  @facets
61
57
  end
62
58
 
@@ -93,6 +89,39 @@ module DNZ
93
89
  end
94
90
 
95
91
  private
92
+
93
+ def parsed_search_filter
94
+ filter = @search_options[:filter]
95
+ filter = {} unless filter.is_a?(Hash)
96
+ filter.symbolize_keys!
97
+ filter.map{|k,v| '%s:"%s"' % [k,v]}
98
+ end
99
+ memoize :parsed_search_filter
100
+
101
+ def parsed_search_text
102
+ if parsed_search_filter.any?
103
+ ([text] + parsed_search_filter).join(' AND ')
104
+ else
105
+ text
106
+ end
107
+ end
108
+
109
+ def parsed_search_facets
110
+ search_facets = @search_options[:facets] || []
111
+ search_facets = search_facets.join(',') if search_facets.is_a?(Array)
112
+ search_facets
113
+ end
114
+
115
+ def parsed_search_options
116
+ parsed_options = @search_options.dup
117
+ parsed_options.delete(:filter)
118
+
119
+ parsed_options[:search_text] = parsed_search_text
120
+ parsed_options[:facets] = parsed_search_facets
121
+
122
+ parsed_options
123
+ end
124
+ memoize :parsed_search_options
96
125
 
97
126
  def doc
98
127
  @doc ||= Nokogiri::XML(@xml)
@@ -102,9 +131,12 @@ module DNZ
102
131
  @doc = nil
103
132
  @results = nil
104
133
  @facets = nil
105
- @xml = @client.send(:fetch, :search, @search_options)
134
+ @xml = @client.send(:fetch, :search, parsed_search_options)
106
135
 
107
136
  parse_attributes
137
+ parse_facets
138
+ parse_results
139
+ paginate_results if defined? WillPaginate::Collection
108
140
 
109
141
  self
110
142
  end
@@ -132,7 +164,7 @@ module DNZ
132
164
  end
133
165
  end
134
166
 
135
- def parse_facets
167
+ def parse_facets
136
168
  @facets = FacetArray.new
137
169
 
138
170
  doc.xpath('//facets/facet').each do |facet_xml|
data/lib/dnz.rb CHANGED
@@ -4,5 +4,5 @@ $:.unshift(File.dirname(__FILE__)) unless
4
4
  require 'dnz/client'
5
5
 
6
6
  module Dnz
7
- VERSION = '0.0.2'
7
+ VERSION = '0.0.3'
8
8
  end
@@ -28,9 +28,37 @@ describe Client do
28
28
  @client.should_receive(:open).with do |url|
29
29
  url.should include('http://api.digitalnz.org/records/v1.xml/?')
30
30
  url.should include('api_key=abc')
31
- url.should include('search_text=*:*')
31
+ url.should include('search_text=%2A%3A%2A')
32
32
  end
33
33
  @client.fetch(:search, :search_text => '*:*')
34
34
  end
35
+
36
+ it 'should raise an InvalidApiKey error if the status is 401' do
37
+ @client.should_receive(:open).and_raise(OpenURI::HTTPError.new('401 Unauthorized', nil))
38
+ lambda do
39
+ @client.fetch(:search, :search_text => '*:*')
40
+ end.should raise_error(InvalidApiKeyError)
41
+ end
42
+ end
43
+
44
+ describe '#categories' do
45
+ before do
46
+ @categories = mock(:categories)
47
+ @category = mock(:facet)
48
+ @category.stub!(:values).and_return(@categories)
49
+ @facets = mock(:facets)
50
+ @facets.stub!(:[]).with('category').and_return(@category)
51
+ @search.stub!(:facets).and_return(@facets)
52
+ @client.stub!(:search).and_return(@search)
53
+ end
54
+
55
+ it 'should run a search for categories facet' do
56
+ @client.should_receive(:search).with('*:*', :facets => 'category', :facet_num_results => 100).and_return(@search)
57
+ @client.categories
58
+ end
59
+
60
+ it 'should return the categories facet' do
61
+ @client.categories.should == @categories
62
+ end
35
63
  end
36
64
  end
@@ -34,7 +34,7 @@ describe Search do
34
34
 
35
35
  describe 'Search.new' do
36
36
  it 'should call @client.fetch' do
37
- @client.should_receive(:fetch).with(:search, :search_text => 'test').and_return(@xml)
37
+ @client.should_receive(:fetch).with(:search, :search_text => 'test', :facets => "").and_return(@xml)
38
38
  Search.new(@client, @options)
39
39
  end
40
40
 
@@ -52,4 +52,19 @@ describe Search do
52
52
  Search.new(@client, @options).facets.should be_a(FacetArray)
53
53
  end
54
54
  end
55
+
56
+ describe 'filtering' do
57
+ before do
58
+ @options = {:search_text => 'test', :filter => {:category => 'Images'}}
59
+ end
60
+
61
+ it 'should call @client.fetch with the search text set to \'test AND category:"Images"\'' do
62
+ @client.should_receive(:fetch).with(
63
+ :search,
64
+ :search_text => 'test AND category:"Images"',
65
+ :facets => ""
66
+ ).and_return(@xml)
67
+ Search.new(@client, @options)
68
+ end
69
+ end
55
70
  end
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.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Wells
@@ -65,8 +65,10 @@ files:
65
65
  - lib/dnz/attributes.rb
66
66
  - lib/dnz/client.rb
67
67
  - lib/dnz/facet.rb
68
+ - lib/dnz/facet_array.rb
68
69
  - lib/dnz/result.rb
69
70
  - lib/dnz/search.rb
71
+ - lib/dnz/error/invalid_api_key.rb
70
72
  - script/console
71
73
  - script/destroy
72
74
  - script/generate