tjplurker 1.3.1 → 1.3.2

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.
@@ -0,0 +1,489 @@
1
+ require 'logger'
2
+ require 'json'
3
+ require 'oauth'
4
+ require 'net/http'
5
+
6
+ $tjpLog = Logger.new(STDOUT)
7
+ $tjpLog.level = Logger::INFO
8
+ $tjpLog.formatter = proc{ |severity, datetime, progname, msg|
9
+ "#{severity} [#{datetime}] in #{progname} -- #{msg}\n"
10
+ }
11
+
12
+ # == 注意
13
+ # 這是舊的函式庫,如果你想學習如何使用最新的TJPlurker,建議你應該參考 {此頁}[link:GETSTART.html]
14
+ #
15
+ # 如果你堅持享用舊版本,你應該在程式中如下引用以支援舊式的寫法:
16
+ # require "tjplurker/legacy"
17
+ # include Legacy
18
+ # 而不是
19
+ # require "tjplurker"
20
+ # include TJP
21
+ module Legacy
22
+ # == 注意
23
+ # 這是舊的函式庫,如果你想學習如何使用最新的TJPlurker,建議你應該參考 {此頁}[link:GETSTART.html]
24
+ #
25
+ # 如果你堅持享用舊版本,你應該在程式中如下引用以支援舊式的寫法:
26
+ # require "tjplurker/legacy"
27
+ # include Legacy
28
+ # 而不是
29
+ # require "tjplurker"
30
+ # include TJP
31
+ #
32
+ # 這是TJPlurker的核心類別,大部分的情況下此類別的方法都會回傳一個由Plurk Server產生的JSON物件。
33
+ # 所有的方法會在timeout發生的時候重新呼叫
34
+ #
35
+ # It's core class of TJPlurker.
36
+ # Note that every methods in this class returns a JSON object
37
+ # which was converted from Plurk server's response.
38
+ # All mehtods will retry again when request timeout occurs.
39
+ class TJPlurker
40
+ # 噗浪帳號
41
+ # Plurk user ID.
42
+ attr_reader :user
43
+
44
+ =begin
45
+ [auto_login] 是否在建構時自動登入
46
+ If +auto_login+ sets +true+, it will autologin while constructing.
47
+ =end
48
+ def initialize api_key, user, passwd, auto_login=true
49
+ @user, @passwd, @api_key = user, passwd, api_key
50
+ @cookie = nil
51
+ @user_channel = nil
52
+ @id_buffer = nil
53
+ login if auto_login
54
+ end
55
+
56
+
57
+ =begin
58
+ :section: Offical API wrapping
59
+ 對Plurk官方API做包裹
60
+
61
+ Plurk API wrapping
62
+ =end
63
+
64
+ =begin
65
+ 登入
66
+ [no_data] 是否將登入成功後的訊息簡化成:
67
+ {"success_text": "ok"}
68
+ 否則將回傳使用者的詳細資料
69
+
70
+ If no_data sets true, the successful login message was simplified as follow:
71
+ {"success_text": "ok"}
72
+ Otherwise, more details of user's profile were retured.
73
+ =end
74
+ def login no_data=true
75
+ method = "/API/Users/login"
76
+ attr = {:username=>@user, :password=>@passwd, :api_key=>@api_key}
77
+ attr[:no_data] = '1' if no_data
78
+ api(method, attr)
79
+ end
80
+
81
+ =begin
82
+ 發噗
83
+
84
+ 範例:
85
+ require 'tjplurker'
86
+ tjp = TJPlurker.new("API Key", "帳號", "密碼")
87
+ tjp.plurk_add("Hello TJPlurker")
88
+ =end
89
+ def plurk_add content, qualifier=':', limited_to=nil, no_comments=nil, lang='tr_ch'
90
+ method = "/API/Timeline/plurkAdd"
91
+ attr = {:api_key=>@api_key, :content=>content, :qualifier=>qualifier,:limited_to=>limited_to, :no_comments=>no_comments, :lang=>lang}
92
+ api(method, attr)
93
+ end
94
+
95
+ =begin
96
+ 回噗
97
+ [qualifier] 可以是如下的字串:
98
+
99
+ Can be the following string:
100
+ loves, likes, shares, gives, hates, wants, has, will,
101
+ asks, wishes, was, feels, thinks, says, is, :, freestyle, hopes, needs, wonders
102
+ 範例:
103
+ require 'tjplurker'
104
+ tjp = TJPlurker.new("API Key", "帳號", "密碼")
105
+ json_obj = tjp.plurk_add("Hello TJPlurker")
106
+ tjp.response_add(json_obj["plurk_id"], "This is a reply.", "says")
107
+ =end
108
+ def response_add plurk_id, content, qualifier=':'
109
+ method = "/API/Responses/responseAdd"
110
+ attr = {:api_key=>@api_key, :plurk_id=>plurk_id, :content=>content, :qualifier=>qualifier}
111
+ api(method, attr)
112
+ end
113
+
114
+ =begin
115
+ 成為粉絲
116
+ [fan_id] 你想追蹤的人的ID
117
+
118
+ The ID of the user you want to become fan of
119
+ =end
120
+ def become_fan fan_id
121
+ method = "/API/FriendsFans/becomeFan"
122
+ attr = {:api_key=>@api_key, :fan_id=>fan_id}
123
+ api(method, attr)
124
+ end
125
+
126
+ =begin
127
+ 接受所有的好友邀請
128
+
129
+ Accept all friendship requests as friends.
130
+ Successful return:
131
+ {"success_text": "ok"}
132
+ =end
133
+ def add_all_as_friends
134
+ method = "/API/Alerts/addAllAsFriends"
135
+ attr = {:api_key=>@api_key}
136
+ api(method, attr)
137
+ end
138
+
139
+ =begin
140
+ 取得使用者的好友名單
141
+
142
+ Returns user_id's friend list
143
+ [limit] The max number of friends to be returned (default 10).
144
+ [Successful return] 好友名單陣列
145
+
146
+ Returns a list of JSON objects users, e.g.
147
+ [{"id": 3, "nick_name": "alvin", ...}, ...]
148
+ [warnning] +limit+的最大值被官方設定為100,這個方法沒有很好用,建議你用tjp_get_friends取代
149
+ This maximum of +limit+ is set 100 officially, this method is not that useful.
150
+ We suggest you use get_friend_list instead of get_friends_by_offset.
151
+ =end
152
+ def get_friends_by_offset user_id, limit=100, offset='0'
153
+ method = "/API/FriendsFans/getFriendsByOffset"
154
+ attr = {:api_key=>@api_key, :user_id=>user_id, :offset=>offset, :limit=>limit}
155
+ api(method, attr)
156
+ end
157
+
158
+ =begin
159
+ Fetches public information such as a user's public plurks and basic information.
160
+ Fetches also if the current user is following the user, are friends with or is a fan.
161
+ [Successful return] Returns a JSON object with a lot of information
162
+ that can be used to construct a user's public profile and timeline.
163
+ [Error returns] HTTP 400 BAD REQUEST with {"error_text": "Invalid user_id"} as body
164
+ HTTP 400 BAD REQUEST with {"error_text": "User not found"} as body
165
+ =end
166
+ def get_public_profile user_id
167
+ method = "/API/Profile/getPublicProfile"
168
+ attr = {:api_key=>@api_key, :user_id=>user_id}
169
+ api(method, attr)
170
+ end
171
+
172
+ # Warning:: It has bugs in offecial Plurk API.
173
+ def get_plurks limit=nil, offset=nil
174
+ method = "/API/Polling/getPlurks"
175
+ attr = {:api_key=>@api_key, :limit=>limit, :offset=>offset}
176
+ api(method, attr)
177
+ end
178
+
179
+ def get_user_channel
180
+ method = "/API/Realtime/getUserChannel"
181
+ attr = {:api_key=>@api_key}
182
+ api(method, attr)
183
+ end
184
+
185
+ def comet_channel
186
+ #Assign new channel if @user_channel is nil
187
+ @user_channel ||= get_user_channel
188
+ begin
189
+ res = Net::HTTP.get_response(URI.parse(@user_channel['comet_server']))
190
+ json = JSON.parse(res.body.sub!(/CometChannel\.scriptCallback\((.*)\);/){|match| $1})
191
+ rescue Timeout::Error => ex
192
+ $tjpLog.warn(self.class){"Request timeout, retry."}
193
+ retry
194
+ rescue Errno::ECONNRESET => ex
195
+ $tjpLog.warn(self.class){"Connection reset, retry."}
196
+ retry
197
+ rescue => ex
198
+ $tjpLog.fatal(self.class){"Unknown error, skip."}
199
+ puts ex.class, ex.message, ex.backtrace
200
+ return
201
+ end
202
+ #Update the offset
203
+ @user_channel['comet_server'].sub!(/[\d]+$/, json["new_offset"].to_s)
204
+ if json['data']
205
+ json['data'].each{|member|
206
+ notification = NotificationData.new(member)
207
+ return if notification.id == @id_buffer
208
+ $tjpLog.info(self.class){"Notification: #{notification.user_id}: \"#{notification.content}\""}
209
+ @id_buffer = notification.id
210
+ yield(notification)
211
+ }
212
+ end
213
+ json
214
+ end
215
+
216
+ =begin
217
+ :section: TJPlurker provided
218
+ 由TJPlurker提供的工具,非官方有的方法
219
+
220
+ Those methos were all provided by TJPlukrer instead of plurk
221
+ =end
222
+
223
+ =begin
224
+ 這個方法游TJPlurker提供的非官方功能,改良自get_friends_by_offset,用於取得使用者所有的好友
225
+
226
+ This method is provided by TJPlurker. Improved from get_friends_by_offset for getting all friends of a user
227
+ [max] 取得多少好友,nil則無限制
228
+
229
+ The maximum number of your request. Set +nil+ for unlimited.
230
+ [return] 陣列
231
+
232
+ An array contains friends
233
+ 範例:
234
+ require 'tjplurker'
235
+ tjp = TJPlurker.new("API Key", "帳號", "密碼")
236
+ friend_list = tjp.tjp_get_friends("5874158")
237
+ friend_list.each{|friend| puts friend["uid"]}
238
+ =end
239
+ def tjp_get_friends user_id, max=nil
240
+ list = []
241
+ offset = 0;
242
+ loop{
243
+ set = get_friends_by_offset(user_id, 100, offset)
244
+ size = set.size
245
+ break if size == 0
246
+ list |= set
247
+ break if max && list.size>max
248
+ offset += size
249
+ }
250
+ return list
251
+ end
252
+
253
+ =begin
254
+ 用於追蹤大量使用者的河道
255
+ [level] 深度,如等於1會追蹤使用者的所有好友,等於2則會追蹤使用者所有的好友以及好友的好友
256
+ =end
257
+ def tjp_super_become_fan fan_id, level=1
258
+ return if level<=0
259
+ become_fan(fan_id)
260
+ list = []
261
+ offset = 0;
262
+ loop{
263
+ set = get_friends_by_offset(fan_id, 100, offset)
264
+ size = set.size
265
+ break if size == 0
266
+ tg = ThreadGroup.new
267
+ set.each{|i|
268
+ tg.add Thread.new{
269
+ wait_sec = 1
270
+ until become_fan(i["uid"]).key?("success_text")
271
+ $tjpLog.info(self.class){"Trying to become #{i["uid"]}'s fan in #{wait_sec} seconds"}
272
+ sleep(wait_sec)
273
+ wait_sec *= 2
274
+ end
275
+ $tjpLog.info(self.class){"Become #{i["uid"]}'s fan successfully"}
276
+ }
277
+ }
278
+ tg.list.each{|i| i.join }
279
+ list |= set
280
+ offset += size
281
+ }
282
+ list.each{|i|
283
+ super_become_fan(i["uid"], level-1)
284
+ }
285
+ end
286
+
287
+ private
288
+ def api method, attr
289
+ #Build POST Request
290
+ req = Net::HTTP::Post.new(method)
291
+ req.set_form_data(attr)
292
+ req["Cookie"] = @cookie
293
+ #Build GET Request
294
+ #path = method + "?" + URI.encode_www_form(attr)
295
+ #req2 = Net::HTTP::Get.new(path)
296
+ #req2["Cookie"] = @cookie
297
+
298
+ #Build HTTP connection
299
+ http = Net::HTTP.new('www.plurk.com', 80)
300
+ begin
301
+ resp = http.start{
302
+ $tjpLog.debug(self.class){"Request: #{method}, #{attr}"}
303
+ http.request(req)
304
+ }
305
+ @cookie ||= resp['set-cookie']
306
+ json = JSON.parse(resp.body)
307
+ $tjpLog.debug(self.class){"Response: #{json}"}
308
+ $tjpLog.error(self.class){json["error_text"]} if json.is_a?(Hash) && json["error_text"]
309
+ rescue Timeout::Error => ex
310
+ $tjpLog.warn(self.class){"Request timeout, retrying."}
311
+ retry
312
+ rescue Errno::ECONNRESET => ex
313
+ $tjpLog.warn(self.class){"Connection reset, retry."}
314
+ retry
315
+ rescue JSON::ParserError => ex
316
+ $tjpLog.error(self.class){"JSON parse error, request failed."}
317
+ rescue => ex
318
+ $tjpLog.fatal(self.class){"Unknown error, skip."}
319
+ puts ex.class, ex.message, ex.backtrace
320
+ return
321
+ end
322
+ return json
323
+ end
324
+
325
+ # Format the json from the comet server. See TJPlurker#comet_channel
326
+ class NotificationData
327
+ # Can be +new_plurk+ or +new_response+.
328
+ attr_reader :type
329
+ attr_reader :response_count
330
+ attr_reader :plurk_id
331
+ attr_reader :lang
332
+ attr_reader :user_id
333
+ attr_reader :qualifier
334
+ attr_reader :content
335
+ # Notification ID.
336
+ attr_reader :id
337
+ # Time of the listened post.
338
+ attr_reader :posted
339
+ attr_reader :owner_id
340
+ # The original JSON object from server response.
341
+ attr_reader :origin
342
+
343
+ def initialize member
344
+ @type = member['type']
345
+ @response_count = member['response_count']
346
+ @plurk_id = member['plurk_id']
347
+
348
+ @lang = @type=="new_plurk" ? member['lang'] : member['response']['lang']
349
+ @user_id = @type=="new_plurk" ? member['user_id'] : member['response']['user_id']
350
+ @qualifier = @type=="new_plurk" ? member['qualifier'] : member['response']['qualifier']
351
+ @content = @type=="new_plurk" ? member['content'] : member['response']['content']
352
+ @id = @type=="new_plurk" ? member['id'] : member['response']['id']
353
+ @posted = @type=="new_plurk" ? member['posted'] : member['response']['posted']
354
+
355
+ @owner_id = @type=="new_plurk" ? member['owner_id'] : member['plurk']['owner_id']
356
+
357
+ @origin = member
358
+ end
359
+ end
360
+
361
+ class Robot
362
+ def initialize *params
363
+ case params.size
364
+ when 1
365
+ @tjplurker = params[0]
366
+ when 3
367
+ api_key, user, passwd = params
368
+ @tjplurker = TJPlurker.new(api_key, user, passwd)
369
+ when 4
370
+ api_key, user, passwd, auto_login = params
371
+ @tjplurker = TJPlurker.new(api_key, user, passwd, auto_login)
372
+ end
373
+ @services = []
374
+ end
375
+
376
+ # Starting a loop and invokes services when a notification was listened.
377
+ def start
378
+ $tjpLog.info(self.class){"Start robot."}
379
+ Thread.new{
380
+ loop{
381
+ @tjplurker.add_all_as_friends
382
+ sleep(60)
383
+ }
384
+ }
385
+ loop{
386
+ @tjplurker.comet_channel{|data|
387
+ @services.each{|service|
388
+ begin
389
+ service.serve(@tjplurker, data)
390
+ rescue => ex
391
+ $tjpLog.error(self.class){"An error occured in #{service.class}, class: #{ex.class}, message: #{ex.message}, backtrace: #{ex.backtrace}"}
392
+ end
393
+ }
394
+ }
395
+ }
396
+ end
397
+
398
+ # +service+:: Can be instance TJPlurker::Service or class TJPlurker::Service or it's descendant classes.
399
+ def add_service service
400
+ if service.is_a? Service
401
+ @services << service
402
+ $tjpLog.info(self.class){"Add service: #{service.name}"}
403
+ elsif service <= Service
404
+ tmp = service.new
405
+ @services << tmp
406
+ $tjpLog.info(self.class){"Add service: #{tmp.name}"}
407
+ else
408
+ $tjpLog.warn(self.class){"Unrecognized service, ignored."}
409
+ end
410
+ end
411
+ end
412
+
413
+ class Service
414
+ attr_reader :name
415
+ def initialize name=self.class.to_s, &proc
416
+ @name = name
417
+ if block_given?
418
+ @serve_proc = proc
419
+ end
420
+ end
421
+
422
+ # Invoke when listened a new plurk.
423
+ def decide tjplurker, data
424
+ true
425
+ end
426
+
427
+ def action tjplurker, data
428
+ if @serve_proc
429
+ @serve_proc[tjplurker, data]
430
+ else
431
+ p data
432
+ end
433
+ end
434
+
435
+ def serve tjplurker, data
436
+ action(tjplurker, data) if decide(tjplurker, data)
437
+ end
438
+ end
439
+
440
+ class ThreadService < Service
441
+ # +lasting+:: How long in second will a thread lives. If one plurk just be responsed, then it will live another +lasting+ time.
442
+ # +refresh+:: Interval that checks if thread should terminate.
443
+ def initialize name=self.class.to_s, lasting=60, refresh=1, &proc
444
+ super name
445
+ @lasting = lasting
446
+ @refresh = refresh
447
+ @plurk_id_hash = Hash.new
448
+ @mutex = Mutex.new
449
+ end
450
+
451
+ # Invoke after thread termination.
452
+ # You can use this to tell users this service just terminate.
453
+ def final tjplurker, data
454
+
455
+ end
456
+
457
+ def serve tjplurker, data
458
+ if data.type=='new_plurk' && decide(tjplurker, data)
459
+ @plurk_id_hash[data.plurk_id] = Thread.new(data.plurk_id){|plurk_id|
460
+ $tjpLog.debug(self.class){"Create thread in plurk ##{plurk_id}"}
461
+ Thread.current[:last_time] = Time.now.to_i
462
+ loop{
463
+ sleep(@refresh)
464
+ $tjpLog.debug(self.class){"Plurk ##{plurk_id} remain #{Thread.current[:last_time]+@lasting-Time.now.to_i} seconds."}
465
+ @mutex.lock
466
+ if Time.now.to_i - Thread.current[:last_time] > @lasting
467
+ @mutex.unlock
468
+ break
469
+ end
470
+ @mutex.unlock
471
+ }
472
+ $tjpLog.debug(self.class){"Terminate thread in plurk ##{plurk_id}"}
473
+ @mutex.lock
474
+ @plurk_id_hash.delete(plurk_id)
475
+ @mutex.unlock
476
+ final(tjplurker, data)
477
+ }
478
+ else
479
+ @mutex.lock
480
+ if data.type=='new_response' && @plurk_id_hash.has_key?(data.plurk_id)
481
+ @plurk_id_hash[data.plurk_id][:last_time] = Time.now.to_i
482
+ action(tjplurker, data)
483
+ end
484
+ @mutex.unlock
485
+ end
486
+ end
487
+ end
488
+ end
489
+ end
@@ -0,0 +1,145 @@
1
+ # encoding: utf-8
2
+
3
+ module TJP
4
+ class Robot
5
+ attr_reader :tjplurker
6
+
7
+ # :call-seq: new(tjplurker)
8
+ # new(key, screte)
9
+ # new(key, secret, access_token, access_token_screte)
10
+ # key:: consumer key
11
+ # secret:: consumer secret
12
+ def initialize *params
13
+ case params.size
14
+ when 1
15
+ @tjplurker = params[0]
16
+ when 2
17
+ key, screte = params
18
+ @tjplurker = TJPlurker.new(key, screte)
19
+ when 4
20
+ key, secret, access_token, access_token_screte = params
21
+ @tjplurker = TJPlurker.new(key, secret, access_token, access_token_screte)
22
+ end
23
+ @services = []
24
+ end
25
+
26
+ # Starting a loop and invokes services when a notification was listened.
27
+ def start
28
+ $tjpLog.info(self.class){"Start robot."}
29
+ Thread.new{
30
+ loop{
31
+ @tjplurker.add_all_as_friends
32
+ sleep(60)
33
+ }
34
+ }
35
+ loop{
36
+ @tjplurker.comet_channel{|data|
37
+ @services.each{|service|
38
+ begin
39
+ service.serve(@tjplurker, data)
40
+ rescue => ex
41
+ $tjpLog.error(self.class){"An error occured in #{service.class}, class: #{ex.class}, message: #{ex.message}, backtrace: #{ex.backtrace}"}
42
+ end
43
+ }
44
+ }
45
+ }
46
+ end
47
+
48
+ # service:: Can be instance TJPlurker::Service or class TJPlurker::Service or it's descendant classes.
49
+ def add_service service
50
+ if service.is_a? Service
51
+ @services << service
52
+ $tjpLog.info(self.class){"Add service: #{service.name}"}
53
+ elsif service <= Service
54
+ tmp = service.new
55
+ @services << tmp
56
+ $tjpLog.info(self.class){"Add service: #{tmp.name}"}
57
+ else
58
+ $tjpLog.warn(self.class){"Unrecognized service, ignored."}
59
+ end
60
+ end
61
+ end
62
+
63
+ class Service
64
+ attr_reader :name
65
+ def initialize name=self.class.to_s, &proc
66
+ @name = name
67
+ if block_given?
68
+ @serve_proc = proc
69
+ end
70
+ end
71
+
72
+ # Invoke when listened a new plurk.
73
+ # data:: notification data
74
+ def decide tjplurker, data
75
+ true
76
+ end
77
+
78
+ # Invoke when decide return true
79
+ # data:: notification data
80
+ def action tjplurker, data
81
+ if @serve_proc
82
+ @serve_proc[tjplurker, data]
83
+ else
84
+ p data
85
+ end
86
+ end
87
+
88
+ # It has higher priority than decide and action
89
+ # data:: notification data
90
+ def serve tjplurker, data
91
+ action(tjplurker, data) if decide(tjplurker, data)
92
+ end
93
+ end
94
+
95
+ class ThreadService < Service
96
+ # lasting:: How long in second will a thread lives. If one plurk just be responsed,
97
+ # then it will live another +lasting+ time.
98
+ # refresh:: Interval that checks if thread should terminate.
99
+ def initialize name=self.class.to_s, lasting=60, refresh=1, &proc
100
+ super name
101
+ @lasting = lasting
102
+ @refresh = refresh
103
+ @plurk_id_hash = Hash.new
104
+ @mutex = Mutex.new
105
+ end
106
+
107
+ # Invoke after thread termination.
108
+ # You can use this to tell users this service just terminate.
109
+ # data:: notification data
110
+ def final tjplurker, data
111
+
112
+ end
113
+
114
+ def serve tjplurker, data
115
+ if data.type=='new_plurk' && decide(tjplurker, data)
116
+ @plurk_id_hash[data.plurk_id] = Thread.new(data.plurk_id){|plurk_id|
117
+ $tjpLog.debug(self.class){"Create thread in plurk ##{plurk_id}"}
118
+ Thread.current[:last_time] = Time.now.to_i
119
+ loop{
120
+ sleep(@refresh)
121
+ $tjpLog.debug(self.class){"Plurk ##{plurk_id} remain #{Thread.current[:last_time]+@lasting-Time.now.to_i} seconds."}
122
+ @mutex.lock
123
+ if Time.now.to_i - Thread.current[:last_time] > @lasting
124
+ @mutex.unlock
125
+ break
126
+ end
127
+ @mutex.unlock
128
+ }
129
+ $tjpLog.debug(self.class){"Terminate thread in plurk ##{plurk_id}"}
130
+ @mutex.lock
131
+ @plurk_id_hash.delete(plurk_id)
132
+ @mutex.unlock
133
+ final(tjplurker, data)
134
+ }
135
+ else
136
+ @mutex.lock
137
+ if data.type=='new_response' && @plurk_id_hash.has_key?(data.plurk_id)
138
+ @plurk_id_hash[data.plurk_id][:last_time] = Time.now.to_i
139
+ action(tjplurker, data)
140
+ end
141
+ @mutex.unlock
142
+ end
143
+ end
144
+ end
145
+ end
data/lib/tjplurker.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'tjplurker/core'
2
+ require 'tjplurker/robot'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tjplurker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,14 +10,40 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
  date: 2012-03-20 00:00:00.000000000 Z
13
- dependencies: []
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &17951592 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *17951592
25
+ - !ruby/object:Gem::Dependency
26
+ name: oauth
27
+ requirement: &17951256 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *17951256
14
36
  description: A safe Plurk API wrapper based on Ruby and mainly designed for easily
15
37
  making plurk robot. installgem install tjplurker.
16
38
  email: tonytonyjan@gmail.com
17
39
  executables: []
18
40
  extensions: []
19
41
  extra_rdoc_files: []
20
- files: []
42
+ files:
43
+ - lib/tjplurker/core.rb
44
+ - lib/tjplurker/legacy.rb
45
+ - lib/tjplurker/robot.rb
46
+ - lib/tjplurker.rb
21
47
  homepage: http://code.google.com/p/tjplurker/
22
48
  licenses: []
23
49
  post_install_message: