ws-aboutme 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Aboutme webservice API client Development Team
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,30 @@
1
+ = WebService::Aboutme - Aboutme web service API client
2
+
3
+ == SYNOPSIS
4
+
5
+ require 'rubygems'
6
+ require 'webservice/aboutme'
7
+
8
+ client = WebService::Aboutme::API.new
9
+
10
+ # look up users with nickname 'aboutme'
11
+ response = client.search_user(:nickname => 'aboutme')
12
+ response.users.each do |user|
13
+ # display information of this user or something...
14
+ end
15
+
16
+ == NOTES
17
+
18
+ See http://webservice.nifty.com/aboutme/ for WebAPI documentation.
19
+
20
+ == Installation
21
+
22
+ sudo gem install ws-aboutme
23
+
24
+ == License
25
+
26
+ WebService::Aboutme is released under the MIT license.
27
+
28
+ == Authors
29
+
30
+ SAWADA Tadashi <moc.liamg.cesare+ws-aboutme@gmail.com>
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/clean'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'rake/rdoctask'
9
+ require 'rake/testtask'
10
+
11
+ dir = File.dirname(__FILE__)
12
+ $LOAD_PATH.unshift(File.join(dir, "lib"))
13
+
14
+ require 'webservice/aboutme/version'
15
+
16
+ spec = Gem::Specification.new do |s|
17
+ s.name = 'ws-aboutme'
18
+ s.version = WebService::Aboutme::Version.to_version
19
+ s.author = 'SAWADA Tadashi'
20
+ s.email = 'moc.liamg.cesare+ws-aboutme@gmail.com'
21
+ s.platform = Gem::Platform::RUBY
22
+ s.summary = 'API client Library for @nifty Aboutme web service'
23
+
24
+ files = FileList["{test,lib,examples,doc}/**/*"].exclude("doc/rdoc").to_a
25
+ files |= ['Rakefile', 'MIT-LICENSE']
26
+ s.files = files
27
+
28
+ s.require_path = 'lib'
29
+ s.has_rdoc = true
30
+ s.rdoc_options = ['--charset', 'UTF-8', '--main', 'README']
31
+ s.extra_rdoc_files = ['README']
32
+
33
+ s.required_ruby_version = ">= 1.8.2"
34
+ end
35
+
36
+ if $0 == __FILE__
37
+ Gem::manage_gems
38
+ Gem::Builder.new(spec).build
39
+ end
40
+
41
+ task :default => ['clean', 'clobber', 'test', 'rdoc', 'package']
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.need_tar_gz = true
45
+ pkg.need_tar_bz2 = true
46
+ pkg.need_zip = true
47
+ end
48
+
49
+
50
+ Rake::TestTask.new do |t|
51
+ t.libs << 'test'
52
+ t.test_files = FileList['test/tc_*.rb']
53
+ t.verbose = true
54
+ end
55
+
56
+
57
+ Rake::RDocTask.new('rdoc') do |t|
58
+ t.rdoc_dir = 'doc/rdoc'
59
+ t.rdoc_files.include('README', 'lib/**/*.rb')
60
+ t.main = 'README'
61
+ t.title = 'WebService::Aboutme Documentation'
62
+ end
@@ -0,0 +1,32 @@
1
+ #--
2
+ # Copyright (c) 2007 Aboutme webservice API client Development Team
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module WebService # :nodoc:
25
+ module Aboutme # :nodoc:
26
+ end
27
+ end
28
+
29
+ $KCODE = 'u'
30
+ require 'jcode'
31
+
32
+ require 'webservice/aboutme/api'
@@ -0,0 +1,505 @@
1
+ require 'date'
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'rexml/document'
5
+
6
+ require 'webservice/aboutme/xmlobjectmapping'
7
+ require 'webservice/aboutme/version'
8
+
9
+ module WebService #:nodoc:
10
+ module Aboutme #:nodoc:
11
+
12
+ REQUEST_URI_BASE = URI.parse('http://api.aboutme.jp/api/v1/')
13
+
14
+ DEFAULT_OPEN_TIMEOUT = 10
15
+ DEFAULT_READ_TIMEOUT = 20
16
+
17
+ class API
18
+
19
+ attr_accessor :config
20
+
21
+ # Takes initialization parameters or a block to override default setttings.
22
+ # You can pass parameters like this,
23
+ # client = WebService::Aboutme::API.new(
24
+ # :open_timeout => 5,
25
+ # :read_timeout => 7,
26
+ # )
27
+ # or, override default parameters with a block,
28
+ # client = WebService::Aboutme::API.new do |c|
29
+ # c.open_timeout = 5
30
+ # c.read_timeout = 7
31
+ # end
32
+ #
33
+ # Or, just call new with no argument to create default instance.
34
+ # client = WebService::Aboutme::API.new
35
+ #
36
+ # See Config class for further information.
37
+ #
38
+ def initialize(args = {}, &block)
39
+ uri = REQUEST_URI_BASE
40
+ @config = Config.new do |c|
41
+ c.request_path_base = uri.path
42
+ c.request_domain = args[:request_domain] || REQUEST_URI_BASE.host
43
+ c.request_port = args[:request_port] || REQUEST_URI_BASE.port
44
+ c.open_timeout = args[:open_timeout] || DEFAULT_OPEN_TIMEOUT
45
+ c.read_timeout = args[:read_timeout] || DEFAULT_READ_TIMEOUT
46
+ c.user_agent = "Aboutme API client for Ruby ver-#{Version.to_version}"
47
+ end
48
+
49
+ if block_given?
50
+ block.call @config
51
+ end
52
+ end
53
+
54
+ def request(request_class, response_class, params = {})
55
+ req = request_class.new(@config)
56
+ response = req.request(params)
57
+ xml = REXML::Document.new(response.body)
58
+ response_class.unmarshal(xml.root)
59
+ end
60
+ private :request
61
+
62
+ # Takes numeric id and returns information of the user.
63
+ #
64
+ # response = client.show_user(1) # => #<ShowUserResponse>
65
+ # user = response.user
66
+ #
67
+ def show_user(id)
68
+ request(ShowUserRequest, ShowUserResponse, :id => id)
69
+ end
70
+
71
+ # Looks up and returns a list of users.
72
+ # Lookup key should be one of :nickname, :interest, :followers, or :contacts.
73
+ #
74
+ # response = client.search_user(:nickname => 'aboutme-user',
75
+ # :order => 'now_to_old,
76
+ # :hits => 20,
77
+ # :page => 1)
78
+ # response.users.each {|user| do_something }
79
+ #
80
+ def search_user(params = {})
81
+ request(SearchUserRequest, SearchUserResponse, params)
82
+ end
83
+
84
+ # Takes numeric id and returns information of the question.
85
+ #
86
+ # response = client.show_question(123) # => #<ShowQuestionResponse>
87
+ # question = response.question
88
+ #
89
+ def show_question(id)
90
+ request(ShowQuestionRequest, ShowQuestionResponse, :id => id)
91
+ end
92
+
93
+ # Looks up and returns a list of questions.
94
+ # Lookup key should be one of :owenr, :answerer, or :text.
95
+ #
96
+ # response = client.search_question(:owner => 'aboutme-user',
97
+ # :order => 'hot',
98
+ # :hits => 20,
99
+ # :page => 1)
100
+ # response.questions.each {|q| do_something }
101
+ #
102
+ def search_question(params)
103
+ request(SearchQuestionRequest, SearchQuestionResponse, params)
104
+ end
105
+
106
+ # Takes numeric id and returns information of the answer.
107
+ #
108
+ # response = client.show_question(987) # => #<ShowAnswerResponse>
109
+ # answer = response.answer
110
+ #
111
+ def show_answer(id)
112
+ request(ShowAnswerRequest, ShowAnswerResponse, :id => id)
113
+ end
114
+
115
+ # Looks up and returns a list of answers.
116
+ # Lookup key should be one of :user, :text, :gender, or :age,
117
+ # and :question is required.
118
+ #
119
+ # response = client.search_answer(:question => 987,
120
+ # :age => '30s',
121
+ # :order => 'new_to_old',
122
+ # :hits => 20,
123
+ # :page => 1)
124
+ # response.answers.each {|ans| do_something }
125
+ #
126
+ def search_answer(params)
127
+ request(SearchAnswerRequest, SearchAnswerResponse, params)
128
+ end
129
+
130
+ # Takes numeric question id and returns summary of answers for the question.
131
+ #
132
+ # response = client.show_answer_digest(987) # => #<ShowAnswerDigestResponse>
133
+ # response.digest.each {|d| do_something }
134
+ #
135
+ def show_answer_digest(id)
136
+ request(ShowAnswerDigestRequest, ShowAnswerDigestResponse, :id => id)
137
+ end
138
+ end
139
+
140
+ # The Config class contains information of the client configuration.
141
+ class Config
142
+ # base path of the request URI. You should not change this value.
143
+ attr_accessor :request_path_base
144
+
145
+ # domain name of the request URI.
146
+ attr_accessor :request_domain
147
+
148
+ # port number of the request URI.
149
+ attr_accessor :request_port
150
+
151
+ # connection timeout (in seconds).
152
+ attr_accessor :open_timeout
153
+
154
+ # IO read timeout (in seconds).
155
+ attr_accessor :read_timeout
156
+
157
+ # name of user-agent for the client.
158
+ attr_accessor :user_agent
159
+
160
+ def initialize(&block)
161
+ block.call(self)
162
+ end
163
+ end
164
+
165
+ class ValidationError < ArgumentError
166
+ end
167
+
168
+ class Request #:nodoc:
169
+
170
+ class << self
171
+ def validators(*methods)
172
+ self.class_eval do
173
+ unless defined? @param_validators
174
+ @param_validators = []
175
+ end
176
+ @param_validators += methods
177
+ end
178
+ end
179
+
180
+ def known_params(*keys)
181
+ self.class_eval do
182
+ unless defined? @known_parameters
183
+ @known_parameters = []
184
+ end
185
+ @known_parameters += keys
186
+ end
187
+ end
188
+ end
189
+
190
+
191
+ def initialize(config)
192
+ @config = config
193
+ end
194
+
195
+ def request(params = {})
196
+ validate(params)
197
+ path = create_request_path(params)
198
+ queries = collect_queries(params)
199
+ method = get_method
200
+ _request(path, method, queries)
201
+ end
202
+
203
+
204
+ private
205
+
206
+ def get_method
207
+ :get
208
+ end
209
+
210
+ def validate(params)
211
+ validators = self.class.class_eval { @param_validators }
212
+ return true if validators.nil?
213
+
214
+ errors = []
215
+ validators.each do |validator|
216
+ message = __send__ validator, params
217
+ errors << message if message
218
+ end
219
+
220
+ unless errors.empty?
221
+ raise ValidationError, errors.join("\n")
222
+ end
223
+ true
224
+ end
225
+
226
+ def collect_queries(params)
227
+ keys = self.class.class_eval { @known_parameters } || []
228
+
229
+ queries = {}
230
+ keys.each do |key|
231
+ if params.key? key
232
+ queries[key] = params[key]
233
+ end
234
+ end
235
+ queries
236
+ end
237
+
238
+ def _request(path, method = :get, params = {})
239
+ uri = create_request_uri(@config.request_path_base + path, params)
240
+ req = create_http_request(method, uri, params)
241
+ response = Net::HTTP.start(uri.host, uri.port) do |http|
242
+ http.open_timeout = @config.open_timeout
243
+ http.read_timeout = @config.read_timeout
244
+ http.request(req)
245
+ end
246
+
247
+ response
248
+ end
249
+
250
+ def create_http_request(method, uri, params)
251
+ initheader = {
252
+ 'User-Agent' => @config.user_agent
253
+ }
254
+
255
+ case method
256
+ when :get
257
+ Net::HTTP::Get.new(uri.request_uri)
258
+ when :post
259
+ req = Net::HTTP::Post.new(uri.path)
260
+ req.set_form_data(params)
261
+ req
262
+ end
263
+ end
264
+
265
+ def create_query_string(params = {})
266
+ queries = []
267
+ params.each_pair do |key, val|
268
+ queries << key.to_s + '=' + URI.encode(val.to_s)
269
+ end
270
+ queries.join('&')
271
+ end
272
+
273
+ def create_request_uri(request_path, params)
274
+ query = create_query_string(params)
275
+ URI::HTTP.build({ :host => @config.request_domain,
276
+ :port => @config.request_port,
277
+ :path => request_path,
278
+ :query => query,
279
+ })
280
+ end
281
+
282
+
283
+ def validate_id(params)
284
+ id = params[:id]
285
+ unless id
286
+ return "id missing."
287
+ end
288
+ end
289
+ end
290
+
291
+ class ShowUserRequest < Request #:nodoc:
292
+ validators :validate_id
293
+
294
+ def create_request_path(params)
295
+ id = params[:id]
296
+ "users/show/#{id}"
297
+ end
298
+ end
299
+
300
+ class SearchUserRequest < Request #:nodoc:
301
+ known_params :nickname, :interest, :followers, :contacts, :order, :hits, :page
302
+ def create_request_path(params)
303
+ "users/search"
304
+ end
305
+ end
306
+
307
+ class ShowQuestionRequest < Request #:nodoc:
308
+ validators :validate_id
309
+
310
+ def create_request_path(params)
311
+ id = params[:id]
312
+ "questions/show/#{id}"
313
+ end
314
+ end
315
+
316
+ class SearchQuestionRequest < Request #:nodoc:
317
+ known_params :owner, :answerer, :text, :order, :hits, :page
318
+
319
+ def create_request_path(params)
320
+ "questions/search"
321
+ end
322
+ end
323
+
324
+ class ShowAnswerRequest < Request #:nodoc:
325
+ validators :validate_id
326
+
327
+ def create_request_path(params)
328
+ id = params[:id]
329
+ "answers/show/#{id}"
330
+ end
331
+ end
332
+
333
+ class SearchAnswerRequest < Request #:nodoc:
334
+ known_params :question, :user, :text, :gender, :age, :order, :hits, :page
335
+
336
+ def create_request_path(params)
337
+ "answers/search"
338
+ end
339
+ end
340
+
341
+ class ShowAnswerDigestRequest < Request #:nodoc:
342
+ validators :validate_id
343
+
344
+ def create_request_path(params)
345
+ id = params[:id]
346
+ "answers/digest/#{id}"
347
+ end
348
+ end
349
+
350
+
351
+ class ResponseStatus < XmlObjectMapping::Base
352
+ attr_mapping :code, :type => :integer
353
+ attr_mapping :message
354
+ attr_mapping :language
355
+ end
356
+
357
+ class IconImages < XmlObjectMapping::Base
358
+ attr_mapping :icon
359
+ attr_mapping :small
360
+ attr_mapping :medium
361
+ attr_mapping :large
362
+ end
363
+
364
+ class Birthday < XmlObjectMapping::Base
365
+ attr_mapping :year, :type => :integer
366
+ attr_mapping :month, :type => :integer
367
+ attr_mapping :day, :type => :integer
368
+ end
369
+
370
+ class User < XmlObjectMapping::Base
371
+ attr_mapping :id, :type => :integer
372
+ attr_mapping :nickname
373
+ attr_mapping :url
374
+ attr_mapping :images, :type => IconImages
375
+ attr_mapping :gender
376
+ attr_mapping :birthday, :type => Birthday
377
+ attr_mapping :age, :type => :integer
378
+ attr_mapping :horoscope
379
+ attr_mapping :blood_type
380
+ attr_mapping :prefecture
381
+ attr_mapping :area
382
+ attr_mapping :introduction
383
+ attr_array :interests, :subnode => 'interest'
384
+ end
385
+
386
+ class Choice < XmlObjectMapping::Base
387
+ attr_mapping :priority, :type => :integer
388
+ attr_mapping :title
389
+ attr_mapping :answer_count, :type => :integer, :path => 'answers_count'
390
+ end
391
+
392
+ class Question < XmlObjectMapping::Base
393
+ attr_mapping :id, :type => :integer
394
+ attr_mapping :title
395
+ attr_mapping :url
396
+ attr_mapping :image
397
+ attr_mapping :creator, :type => User
398
+ attr_mapping :created_at, :type => :datetime
399
+ attr_array :choices, :type => Choice, :path => 'options', :subnode => 'option'
400
+ end
401
+
402
+ class Answer < XmlObjectMapping::Base
403
+ attr_mapping :id, :type => :integer
404
+ attr_mapping :title
405
+ attr_mapping :question_id, :type => :integer
406
+ attr_mapping :updated_at, :type => :datetime
407
+ attr_mapping :priority, :type => :integer
408
+ attr_mapping :answerer, :type => User
409
+ end
410
+
411
+ class AnswerDigest < XmlObjectMapping::Base
412
+ attr_mapping :id, :type => :integer
413
+ attr_mapping :count, :type => :integer, :path => 'answers_count'
414
+ attr_array :choices, :type => Choice, :path => 'options', :subnode => 'option'
415
+ end
416
+
417
+ class Summary < XmlObjectMapping::Base
418
+ attr_mapping :total, :type => :integer
419
+ attr_mapping :page, :type => :integer
420
+ attr_mapping :page_count, :type => :integer
421
+ end
422
+
423
+
424
+ class ResultBase < XmlObjectMapping::Base
425
+ attr_mapping :summary, :type => Summary
426
+ end
427
+
428
+ class SearchUserResult < ResultBase
429
+ attr_array :users, :type => User, :subnode => 'user'
430
+ end
431
+
432
+ class SearchQuestionResult < ResultBase
433
+ attr_array :questions, :type => Question, :subnode => 'question'
434
+ end
435
+
436
+ class SearchAnswerResult < ResultBase
437
+ attr_array :answers, :type => Answer, :subnode => 'answer'
438
+ end
439
+
440
+
441
+
442
+ class ResponseBase < XmlObjectMapping::Base
443
+ attr_mapping :status, :type => ResponseStatus
444
+ end
445
+
446
+ class ShowUserResponse < ResponseBase
447
+ attr_mapping :user, :type => User, :path => 'result', :subnode => 'user'
448
+ end
449
+
450
+ class SearchUserResponse < ResponseBase
451
+ attr_mapping :result, :type => SearchUserResult, :private => true
452
+ attr_accessor :summary
453
+ attr_accessor :users
454
+
455
+ private
456
+ def post_population
457
+ if @result
458
+ @summary = @result.summary
459
+ @users = @result.users
460
+ end
461
+ end
462
+ end
463
+
464
+ class ShowQuestionResponse < ResponseBase
465
+ attr_mapping :question, :type => Question, :path => 'result', :subnode => 'question'
466
+ end
467
+
468
+ class SearchQuestionResponse < ResponseBase
469
+ attr_mapping :result, :type => SearchQuestionResult, :private => true
470
+ attr_accessor :summary
471
+ attr_accessor :questions
472
+
473
+ private
474
+ def post_population
475
+ if @result
476
+ @summary = @result.summary
477
+ @questions = @result.questions
478
+ end
479
+ end
480
+ end
481
+
482
+ class ShowAnswerResponse < ResponseBase
483
+ attr_mapping :answer, :type => Answer, :path => 'result', :subnode => 'answer'
484
+ end
485
+
486
+ class SearchAnswerResponse < ResponseBase
487
+ attr_mapping :result, :type => SearchAnswerResult, :private => true
488
+ attr_accessor :summary
489
+ attr_accessor :answers
490
+
491
+ private
492
+ def post_population
493
+ if @result
494
+ @summary = @result.summary
495
+ @answers = @result.answers
496
+ end
497
+ end
498
+ end
499
+
500
+ class ShowAnswerDigestResponse < ResponseBase
501
+ attr_mapping :digest, :type => AnswerDigest, :path => 'result', :subnode => 'answers_digest'
502
+ end
503
+
504
+ end
505
+ end