yanapi 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,22 +1,33 @@
1
- === COMPLETED
2
- ==== 0.3.1
1
+ == COMPLETED
2
+ === 0.3.2
3
+ The main class +Query+ reimplemented and covered by tests.
4
+
5
+ The overall documentation enhanced.
6
+ === 0.3.1
3
7
  All four search methods implemented.
4
- ==== 0.1.1
8
+
9
+ WARNING! This is the first release with a new two dimensional interface! Consult
10
+ README for further details.
11
+ === 0.1.1
5
12
  Small fixes in the documentation.
6
- ==== 0.1.0
7
- The search methods <tt>questionSearch</tt> and <tt>getByCategory</tt>.
8
- ==== 0.0.1
13
+ === 0.1.0
14
+ The search methods <tt>questionSearch</tt> and <tt>getByCategory</tt>
15
+ implemented without tests.
16
+ === 0.0.1
9
17
  Initial release of the lib.
10
18
 
11
19
 
12
- === PLANNED
13
- ==== 0.4.0
20
+ == PLANNED
21
+ === 0.4.0
14
22
  Enhance the documentation.
15
23
 
16
24
  Implement multivalue parameters.
17
- ==== 0.5.0
18
- ==== 0.6.0
19
- ==== 0.7.0
20
- ==== 0.8.0
21
- ==== 0.9.0
22
- ==== 1.0.0
25
+ === 0.5.0
26
+ Implement semantic checks for all query types.
27
+
28
+ Enhance the documentation.
29
+ === 0.6.0
30
+ === 0.7.0
31
+ === 0.8.0
32
+ === 0.9.0
33
+ === 1.0.0
data/README CHANGED
@@ -21,13 +21,25 @@ It is possible to restrict key word based search through a category.
21
21
 
22
22
  Question Search and User Search cannot be extended by key words or category IDs.
23
23
 
24
- Yanapi tries to as flexible as possible. It restricts unallowed parameter
24
+ YANAPI tries to as flexible as possible. It restricts unallowed parameter
25
25
  combinations and forces using mandatory ones. But it doesn't care about defaults.
26
26
  For example, as for this writing the default output value is an xml based format.
27
27
  If it changes in the future, the user will be responsible to choose the format.
28
28
  No defaults are hardcoded in YANAPI.
29
+
29
30
  YANAPI provides the minimal acceptable query.
30
31
 
32
+ == INSTALLATION
33
+ To install YANAPI ussue the following command:
34
+ $ gem install yanapi
35
+
36
+ You might want to install versions prior to +0.3.1+:
37
+ $ gem install yanapi -v 0.1.1
38
+
39
+ If you want to do a system wide installation, do this as root
40
+ (possibly using +sudo+).
41
+
42
+ Alternatively use your Gemfile for dependency management.
31
43
  == SYNOPSIS
32
44
 
33
45
  YANAPI requires a parameter hash with two dimensions:
@@ -57,7 +69,7 @@ A small example shall demostrate the usage:
57
69
  api.get # => default xml structure
58
70
 
59
71
 
60
- For details on particular keys and defaults see {the official description}[http://developer.yahoo.com/answers/] and the RDoc documentation in this libruary.
72
+ For details on particular keys and defaults see {the official description}[http://developer.yahoo.com/answers/] and the RDoc documentation in this library.
61
73
 
62
74
  == EXCEPTION HIERARCHY
63
75
  While using YANAPI you can face three kinds of errors:
@@ -90,5 +102,6 @@ Please contact me with your suggestions, bug reports and feature requests.
90
102
  == LICENSE
91
103
 
92
104
  YANAPI is a copyrighted software by Andrei Beliankou, 2011.
105
+
93
106
  You may use, redistribute and change it under the terms
94
107
  provided in the LICENSE file.
data/lib/yanapi/api.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # :title: YANAPI, Yahoo! Answers API
2
- # :main: README.rdoc
2
+ # :main: README
3
3
 
4
4
  require 'yanapi/version'
5
5
  require 'yanapi/term_query'
data/lib/yanapi/error.rb CHANGED
@@ -20,9 +20,13 @@ module YANAPI
20
20
  # A technical error accessing the server,
21
21
  # may be caught and handled with a new attempt.
22
22
  class ExternalError < Error
23
- def initialize(exception)
24
- msg = "Some external error occured:\n" +
25
- "#{exception.class}: #{exception.message}"
23
+ def initialize(arg)
24
+ msg = "Some external error occured:\n"
25
+ if arg.kind_of?(String)
26
+ msg += arg
27
+ else
28
+ msg += "#{exception.class}: #{exception.message}"
29
+ end
26
30
  super(msg)
27
31
  end
28
32
  end
data/lib/yanapi/query.rb CHANGED
@@ -16,8 +16,8 @@ module YANAPI
16
16
  VALID_OUTPUT_FORMATS = [nil, 'xml', 'php', 'rss', 'json']
17
17
 
18
18
  # It accepts a two dimensional hash:
19
- # {:method => 'questionSearch', :query_params =>
20
- # {:appid => 'YahooDemo', :query => 'Haus'}}
19
+ # {:method => 'questionSearch', :query_params =>
20
+ # {:appid => 'YahooDemo', :query => 'Haus'}}
21
21
  def initialize(params)
22
22
  @method = params[:method]
23
23
  @params = check_params(params[:query_params])
@@ -25,43 +25,24 @@ module YANAPI
25
25
  @output = @params[:output] || 'xml'
26
26
  end
27
27
 
28
- # main method
28
+ # This is the main method. It gets the body of the HTTP response and
29
+ # invokes the respective check.
30
+ # It returns the response or <nil> if the response is emtpy.
29
31
  def get
30
- http_response = Net::HTTP.get_response(@url)
32
+
33
+ http_response = get_response(@url)
31
34
 
32
35
  case @output
33
36
  when 'xml'
34
- # Set the value to STRICT (0), otherwise no errors will be raised!
35
- xml = Nokogiri::XML::Document.parse(http_response.body, nil, nil, 0)
36
- result = prove_xml(xml) ? http_response.body : nil
37
+ prove_xml(http_response)
37
38
  when 'json'
38
- raise NotImplementedError, 'We do not handle JSON yet!'
39
+ fail NotImplementedError, 'We do not handle JSON yet!'
39
40
  when 'php'
40
- raise NotImplementedError, 'We do not handle PHP yet!'
41
+ fail NotImplementedError, 'We do not handle PHP yet!'
41
42
  when 'rss'
42
- raise NotImplementedError, 'We do not handle RSS yet!'
43
+ fail NotImplementedError, 'We do not handle RSS yet!'
43
44
  end
44
45
 
45
- # TODO: make a fine grained distinction
46
- case http_response
47
- when Net::HTTPSuccess
48
- return result
49
-
50
- when Net::HTTPBadRequest,
51
- Net::HTTPForbidden,
52
- Net::HTTPServiceUnavailable
53
- raise ExternalError.new("#{http_response}:\n\n#{result}")
54
- else
55
- raise ExternalError.new("#{http_response}:\n\n#{result}")
56
- end
57
-
58
- # are all external errors caught here?
59
- rescue Net::HTTPError, SocketError, Timeout::Error,
60
- IOError, SystemCallError => e
61
- raise ExternalError, e
62
- # add JSON, PHP, RSS errors here
63
- rescue Nokogiri::XML::SyntaxError => e
64
- raise ContentError.new(e)
65
46
  end # get
66
47
 
67
48
  #########
@@ -90,7 +71,7 @@ module YANAPI
90
71
  # Multiple values will be provided as Arrays:
91
72
  # :category_id => [123, 456, 789].
92
73
  params.each_pair do |k, v|
93
- unless (v.instance_of?(String) || v.instance_of?(Fixnum))
74
+ unless (v.kind_of?(String) || v.kind_of?(Fixnum))
94
75
  fail UserError, "The value <:#{k}> is not unique!"
95
76
  end
96
77
  end
@@ -107,7 +88,7 @@ module YANAPI
107
88
 
108
89
 
109
90
  expanded_params = expand_params(params) # It is an array now!
110
- escaped_params = params.collect do |k, v|
91
+ escaped_params = expanded_params.map do |k, v|
111
92
  k = URI.escape(k.to_s, unsafe = reserved_chars)
112
93
  v = URI.escape(v.to_s, unsafe = reserved_chars)
113
94
  "#{k}=#{v}"
@@ -135,26 +116,54 @@ module YANAPI
135
116
  expanded_params.sort_by { |k, v| [k.to_s, v.to_s] }
136
117
  end
137
118
 
138
- # proves the presense of an error
139
- # proves it the answer set is empty
140
- def prove_xml(xml)
119
+ # It sends a HTTP request, rescues any external errors issuing an
120
+ # YANAPI::ExternalError, checks the HTTP code and fails if it is not 200.
121
+ # Otherwise it returns the body of the HTTP response.
122
+ def get_response(url)
123
+ begin
124
+ http_response = Net::HTTP.get_response(url)
125
+ rescue Net::HTTPError, SocketError, Timeout::Error, IOError => e
126
+ fail ExternalError, e
127
+ end
128
+
129
+ case http_response
130
+ when Net::HTTPSuccess
131
+ http_response.body
132
+ when Net::HTTPBadRequest,
133
+ Net::HTTPForbidden,
134
+ Net::HTTPServiceUnavailable
135
+ # These errors are documented by Yahoo!.
136
+ fail(ExternalError, http_response.header)
137
+ else
138
+ fail(ExternalError, "Unexpected HTTP response: #{http_response.header}.")
139
+ end
140
+
141
+ end
142
+
143
+ # It parses the input, checks for xml validity and proves if it is empty.
144
+ # It returns then <xml> as string or <nil> if the answer is emtpy.
145
+ def prove_xml(xml_as_str)
146
+ begin
147
+ # Set the value to STRICT (0), otherwise no errors will be raised!
148
+ xml = Nokogiri::XML::Document.parse(xml_as_str, nil, nil, 0)
149
+ rescue Nokogiri::XML::SyntaxError
150
+ fail(ContentError, 'Erroneous XML response!')
151
+ end
152
+
141
153
  error = xml.at_xpath('/xmlns:Error', xml.root.namespaces)
142
154
  if error
143
155
  message = 'The following errors were detected:'
144
156
  error.xpath('//xmlns:Message', xml.root.namespaces).each do |msg|
145
157
  message << "\n" + msg.content
146
158
  end
147
- raise ContentError.new(message)
159
+ fail(ContentError, message)
148
160
  end
149
161
 
150
162
  question = xml.at_xpath('//xmlns:Question', xml.root.namespaces)
151
163
 
152
- if question
153
- xml
154
- else
155
- nil
156
- end
157
- end
164
+ question ? xml_as_str : nil
165
+ end
166
+
158
167
  end # Query
159
168
 
160
169
  end # YANAPI
@@ -1,3 +1,3 @@
1
1
  module YANAPI
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
data/test/test_query.rb CHANGED
@@ -40,8 +40,7 @@ class TestQuery < Test::Unit::TestCase
40
40
 
41
41
  # The following constants should have the given value and type.
42
42
  def test_values_of_constants
43
- assert_equal('http://answers.yahooapis.com',
44
- YANAPI::Query::HOST)
43
+ assert_equal('http://answers.yahooapis.com', YANAPI::Query::HOST)
45
44
  assert_equal('AnswersService', YANAPI::Query::SERVICE)
46
45
  assert_equal('V1', YANAPI::Query::SERVICE_VERSION)
47
46
  end
@@ -95,7 +94,18 @@ class TestQuery < Test::Unit::TestCase
95
94
 
96
95
 
97
96
  ## Functional tests
98
-
97
+
98
+ # It should create well formed urls.
99
+ def test_url_form
100
+ q = YANAPI::Query.new(@params)
101
+ print q.inspect
102
+ etalon_url = 'http://answers.yahooapis.com/AnswersService/V1/questionSearch?appid=YahooDemo&output=xml&query=Haus'
103
+ real_url = q.instance_variable_get(:@url).to_s
104
+ assert_equal(etalon_url, real_url)
105
+
106
+ warn "\nWARNING! Expand this test for multivalue parameters!\n"
107
+ end
108
+
99
109
  # It should return <nil> if the server response contains
100
110
  # no answer. It is possible if we out of range or search criteria
101
111
  # are too strict.
@@ -122,7 +132,7 @@ class TestQuery < Test::Unit::TestCase
122
132
  assert_instance_of(String, actual_api_answer, 'Not String!')
123
133
  assert_equal(expected_api_answer, actual_api_answer)
124
134
 
125
- warn "\nAdd tests for <php>, <json> and <rss>!\n"
135
+ warn "\nWANRING! Add tests for <php>, <json> and <rss>!\n"
126
136
  end
127
137
 
128
138
  # It should fail with an appropriate exception
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yanapi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 1
10
- version: 0.3.1
9
+ - 2
10
+ version: 0.3.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrei Beliankou
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-05 00:00:00 Z
18
+ date: 2011-08-10 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: nokogiri
@@ -32,9 +32,25 @@ dependencies:
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
35
- name: fakeweb
35
+ name: rdoc
36
36
  prerelease: false
37
37
  requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 33
43
+ segments:
44
+ - 3
45
+ - 9
46
+ - 1
47
+ version: 3.9.1
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: fakeweb
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
38
54
  none: false
39
55
  requirements:
40
56
  - - ">="
@@ -44,7 +60,7 @@ dependencies:
44
60
  - 0
45
61
  version: "0"
46
62
  type: :development
47
- version_requirements: *id002
63
+ version_requirements: *id003
48
64
  description: YANAPI is a programmatic API for Yahoo! Answers web services. It enables you to search for questions using key words, user IDs, category names and IDs and a pricise ID of a question. The output is provided in the xml format as well as json, php and rss.
49
65
  email: a.belenkow@uni-trier.de
50
66
  executables: []
@@ -124,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
140
  requirements: []
125
141
 
126
142
  rubyforge_project: yanapi
127
- rubygems_version: 1.7.2
143
+ rubygems_version: 1.8.7
128
144
  signing_key:
129
145
  specification_version: 3
130
146
  summary: YANAPI is an API for Yahoo! Answers web services.