rubytter 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ = rubytter
2
+
3
+ http://github.com/jugyo/rubytter
4
+
5
+ == DESCRIPTION:
6
+
7
+ Rubytter is simple twitter library.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ implemented methods:
12
+
13
+ - /statuses/update
14
+ - /statuses/destroy/id
15
+ - /statuses/public_timeline
16
+ - /statuses/friends_timeline
17
+ - /statuses/replies
18
+ - /statuses/user_timeline/id
19
+ - /statuses/show/id
20
+ - /statuses/friends/id
21
+ - /statuses/followers/id
22
+ - /users/show/id
23
+ - /direct_messages
24
+ - /direct_messages/sent
25
+ - /direct_messages/new
26
+ - /direct_messages/destroy/id
27
+ - /friendships/create/id
28
+ - /friendships/destroy/id
29
+ - /friendships/exists
30
+ - /followers/ids/id
31
+ - /friends/ids/id
32
+ - /favorites
33
+ - /favorites/create/id
34
+ - /favorites/destroy/id
35
+ - /account/verify_credentials
36
+ - /account/end_session
37
+ - /account/update_delivery_device
38
+ - /account/update_profile_colors
39
+ - /account/rate_limit_status
40
+ - /account/update_profile
41
+ - /notifications/follow/id
42
+ - /notifications/leave/id
43
+ - /blocks/create/id
44
+ - /blocks/destroy/id
45
+
46
+ == SYNOPSIS:
47
+
48
+ update status
49
+
50
+ client = Rubytter.new(user_id, password)
51
+ client.update('hello twitter!!')
52
+
53
+ get friends timeline
54
+
55
+ client = Rubytter.new(user_id, password)
56
+ client.friends_timeline.each do |status|
57
+ puts "#{status.user.screen_name}: #{status.text}"
58
+ end
59
+
60
+ == REQUIREMENTS:
61
+
62
+ * json
63
+
64
+ == INSTALL:
65
+
66
+ gem source -a http://gems.github.com
67
+ sudo gem install jugyo-rubytter
68
+
69
+ == TODO:
70
+
71
+ - search
72
+ - favorite
73
+
74
+ == LICENSE:
75
+
76
+ (The MIT License)
77
+
78
+ Copyright (c) 2008-2009 jugyo
79
+
80
+ Permission is hereby granted, free of charge, to any person obtaining
81
+ a copy of this software and associated documentation files (the
82
+ 'Software'), to deal in the Software without restriction, including
83
+ without limitation the rights to use, copy, modify, merge, publish,
84
+ distribute, sublicense, and/or sell copies of the Software, and to
85
+ permit persons to whom the Software is furnished to do so, subject to
86
+ the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be
89
+ included in all copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
92
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
93
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
94
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
95
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
96
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
97
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rubytter'
5
+
6
+ if ARGV.size < 2
7
+ puts "Usage: ruby #{File.basename(__FILE__)} user_id password"
8
+ exit
9
+ end
10
+
11
+ client = Rubytter.new(ARGV[0], ARGV[1])
12
+ client.friends_timeline.each do |status|
13
+ puts "#{status.user.screen_name}: #{status.text}"
14
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rubytter'
5
+
6
+ if ARGV.size < 3
7
+ puts "Usage: ruby #{File.basename(__FILE__)} user_id password text"
8
+ exit
9
+ end
10
+
11
+ client = Rubytter.new(ARGV[0], ARGV[1])
12
+ client.update(ARGV[2])
@@ -0,0 +1,37 @@
1
+ class Rubytter
2
+ class Connection
3
+ attr_reader :protocol, :port, :proxy_uri
4
+
5
+ def initialize(options = {})
6
+ @proxy_host = options[:proxy_host]
7
+ @proxy_port = options[:proxy_port]
8
+ @proxy_user = options[:proxy_user_name]
9
+ @proxy_password = options[:proxy_password]
10
+ @proxy_uri = nil
11
+ @enable_ssl = options[:enable_ssl]
12
+
13
+ if @proxy_host
14
+ @http_class = Net::HTTP::Proxy(@proxy_host, @proxy_port,
15
+ @proxy_user, @proxy_password)
16
+ @proxy_uri = "http://" + @proxy_host + ":" + @proxy_port.to_s + "/"
17
+ else
18
+ @http_class = Net::HTTP
19
+ end
20
+
21
+ if @enable_ssl
22
+ @protocol = "https"
23
+ @port = 443
24
+ else
25
+ @protocol = "http"
26
+ @port = 80
27
+ end
28
+ end
29
+
30
+ def start(host, port = nil, &block)
31
+ http = @http_class.new(host, port || @port)
32
+ http.use_ssl = @enable_ssl
33
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
34
+ http.start(&block)
35
+ end
36
+ end
37
+ end
data/lib/rubytter.rb ADDED
@@ -0,0 +1,133 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'net/https'
4
+ require 'cgi'
5
+
6
+ require 'rubytter/connection'
7
+
8
+ class Rubytter
9
+ APP_NAME = 'Rubytter'
10
+ HOMEPAGE = 'http://github.com/jugyo/rubytter'
11
+
12
+ def initialize(login, password, options = {})
13
+ @login = login
14
+ @password = password
15
+ @host = options[:host] || 'twitter.com'
16
+ @connection = Connection.new(options)
17
+ end
18
+
19
+ def self.api_settings
20
+ # method name path for API http method
21
+ "
22
+ status_update /statuses/update post
23
+ destroy /statuses/destroy/%s delete
24
+ public_timeline /statuses/public_timeline
25
+ friends_timeline /statuses/friends_timeline
26
+ replies /statuses/replies
27
+ user_timeline /statuses/user_timeline/%s
28
+ show /statuses/show/%s
29
+ friends /statuses/friends/%s
30
+ followers /statuses/followers/%s
31
+ user /users/show/%s
32
+ direct_messages /direct_messages
33
+ sent_direct_messages /direct_messages/sent
34
+ send_direct_message /direct_messages/new post
35
+ destroy_direct_message /direct_messages/destroy/%s delete
36
+ create_friendship /friendships/create/%s post
37
+ destroy_friendship /friendships/destroy/%s delete
38
+ friendship_exists /friendships/exists
39
+ followers_ids /followers/ids/%s
40
+ friends_ids /friends/ids/%s
41
+ favorites /favorites
42
+ favorite /favorites/create/%s post
43
+ unfavorite /favorites/destroy/%s delete
44
+ verify_credentials /account/verify_credentials get
45
+ end_session /account/end_session post
46
+ update_delivery_device /account/update_delivery_device post
47
+ update_profile_colors /account/update_profile_colors post
48
+ rate_limit_status /account/rate_limit_status
49
+ update_profile /account/update_profile post
50
+ enable_notification /notifications/follow/%s post
51
+ disable_notification /notifications/leave/%s post
52
+ block /blocks/create/%s post
53
+ unblock /blocks/destroy/%s delete
54
+ ".strip.split("\n").map{|line| line.strip.split(/\s+/)}
55
+ end
56
+
57
+ api_settings.each do |array|
58
+ method, path, http_method = *array
59
+ http_method ||= 'get'
60
+ if /%s$/ =~ path
61
+ eval <<-EOS
62
+ def #{method}(id, params = {})
63
+ #{http_method}('#{path}' % id, params)
64
+ end
65
+ EOS
66
+ else
67
+ eval <<-EOS
68
+ def #{method}(params = {})
69
+ #{http_method}('#{path}', params)
70
+ end
71
+ EOS
72
+ end
73
+ end
74
+
75
+ def update(status, params = {})
76
+ status_update(params.merge({:status => status}))
77
+ end
78
+
79
+ def direct_message(user, text, params = {})
80
+ send_direct_message(params.merge({:user => user, :text => text}))
81
+ end
82
+
83
+ def get(path, params = {})
84
+ path += '.json'
85
+ param_str = '?' + params.to_a.map{|i| i[0].to_s + '=' + CGI.escape(i[1]) }.join('&')
86
+ path = path + param_str unless param_str.empty?
87
+ req = prepare_request(Net::HTTP::Get.new(path))
88
+ res_body = @connection.start(@host) do |http|
89
+ http.request(req).body
90
+ end
91
+ json_to_struct(JSON.parse(res_body))
92
+ end
93
+
94
+ def post(path, params = {})
95
+ path += '.json'
96
+ param_str = params.to_a.map{|i| i[0].to_s + '=' + CGI.escape(i[1]) }.join('&')
97
+ req = prepare_request(Net::HTTP::Post.new(path))
98
+ res_body = @connection.start(@host) do |http|
99
+ http.request(req, param_str).body
100
+ end
101
+ json_to_struct(JSON.parse(res_body))
102
+ end
103
+
104
+ alias delete post
105
+
106
+ def prepare_request(req)
107
+ req.add_field('User-Agent', "#{APP_NAME} #{HOMEPAGE}")
108
+ req.basic_auth(@login, @password)
109
+ return req
110
+ end
111
+
112
+ def json_to_struct(json)
113
+ case json
114
+ when Array
115
+ json.map{|i| json_to_struct(i)}
116
+ when Hash
117
+ struct_values = {}
118
+ json.each do |k, v|
119
+ case k
120
+ when String, Symbol
121
+ struct_values[k.to_sym] = json_to_struct(v)
122
+ end
123
+ end
124
+ unless struct_values.empty?
125
+ Struct.new(*struct_values.keys).new(*struct_values.values)
126
+ else
127
+ nil
128
+ end
129
+ else
130
+ json
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,132 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require File.dirname(__FILE__) + '/spec_helper'
4
+
5
+ class Rubytter
6
+ describe Rubytter do
7
+ before do
8
+ @rubytter = Rubytter.new('test', 'test')
9
+ end
10
+
11
+ it 'should receive ...' do
12
+ @rubytter.should_receive(:user_timeline).with(1)
13
+ @rubytter.user_timeline(1)
14
+ @rubytter.should_receive(:friend_timeline)
15
+ @rubytter.friend_timeline
16
+ @rubytter.should_receive(:replies).with({:page => 2})
17
+ @rubytter.replies(:page => 2)
18
+ # more...
19
+ end
20
+
21
+ it 'should get or post' do
22
+ # TODO: split specs
23
+ @rubytter.should_receive(:get).with('/statuses/replies', {})
24
+ @rubytter.replies
25
+
26
+ @rubytter.should_receive(:get).with('/statuses/replies', {:page => 2})
27
+ @rubytter.replies(:page => 2)
28
+
29
+ @rubytter.should_receive(:get).with('/statuses/user_timeline/1', {})
30
+ @rubytter.user_timeline(1)
31
+
32
+ @rubytter.should_receive(:get).with('/users/show/1', {})
33
+ @rubytter.user(1)
34
+
35
+ @rubytter.should_receive(:delete).with('/statuses/destroy/1', {})
36
+ @rubytter.destroy(1)
37
+ end
38
+
39
+ # direct_messages
40
+
41
+ it 'should respond to direct_messages' do
42
+ @rubytter.should_receive(:get).with('/direct_messages', {})
43
+ @rubytter.direct_messages()
44
+ end
45
+
46
+ it 'should respond to sent_direct_messages' do
47
+ @rubytter.should_receive(:get).with('/direct_messages/sent', {})
48
+ @rubytter.sent_direct_messages()
49
+ end
50
+
51
+ it 'should respond to send_direct_message' do
52
+ @rubytter.should_receive(:post).with('/direct_messages/new', {})
53
+ @rubytter.send_direct_message()
54
+ end
55
+
56
+ it 'should respond to destroy_direct_message' do
57
+ @rubytter.should_receive(:delete).with('/direct_messages/destroy/1', {})
58
+ @rubytter.destroy_direct_message(1)
59
+ end
60
+
61
+ it 'should respond to direct_message' do
62
+ @rubytter.should_receive(:post).with('/direct_messages/new', {:user => 'test', :text => 'aaaaaaaaaaaaa'})
63
+ @rubytter.direct_message('test', 'aaaaaaaaaaaaa')
64
+ end
65
+
66
+ # statuses
67
+
68
+ it 'should respond to update' do
69
+ @rubytter.should_receive(:post).with('/statuses/update', {:status => 'test'})
70
+ @rubytter.update('test')
71
+ end
72
+
73
+ it 'should respond to status_update' do
74
+ @rubytter.should_receive(:post).with('/statuses/update', {:status => 'test'})
75
+ @rubytter.status_update(:status => 'test')
76
+ end
77
+
78
+ # friendship
79
+
80
+ it 'should respond to create_friendship' do
81
+ @rubytter.should_receive(:post).with('/friendships/create/test', {})
82
+ @rubytter.create_friendship('test')
83
+ end
84
+
85
+ it 'should respond to destroy_friendship' do
86
+ @rubytter.should_receive(:delete).with('/friendships/destroy/test', {})
87
+ @rubytter.destroy_friendship('test')
88
+ end
89
+
90
+ it 'should respond to friendship_exists' do
91
+ @rubytter.should_receive(:get).with('/friendships/exists', {:user_a => 'a', :user_b => 'b'})
92
+ @rubytter.friendship_exists(:user_a => 'a', :user_b => 'b')
93
+ end
94
+
95
+ # Social Graph Methods
96
+
97
+ it 'should respond to followers_ids' do
98
+ @rubytter.should_receive(:get).with('/friends/ids/test', {})
99
+ @rubytter.friends_ids('test')
100
+ end
101
+
102
+ it 'should respond to followers_ids' do
103
+ @rubytter.should_receive(:get).with('/followers/ids/test', {})
104
+ @rubytter.followers_ids('test')
105
+ end
106
+
107
+ it 'should create struct from json' do
108
+ hash = {
109
+ :a => 'a',
110
+ 'b' => 1,
111
+ 1 => 'a',
112
+ /regex/ => 'regex',
113
+ nil => nil,
114
+ :c => {:a => 1, :b => 2},
115
+ :d => {:a => {:a => 1, :b => 2}, :b => 1},
116
+ :e => [{:a => 1, :b => 2}, {:c => 3}]
117
+ }
118
+ struct = @rubytter.json_to_struct(hash)
119
+ struct.a.should == 'a'
120
+ struct.b.should == 1
121
+ struct.c.a.should == 1
122
+ struct.c.b.should == 2
123
+ struct.d.a.a.should == 1
124
+ struct.e[0].a.should == 1
125
+ struct.e[0].b.should == 2
126
+ struct.e[1].c.should == 3
127
+ lambda {struct.x}.should raise_error(NoMethodError)
128
+ lambda {struct.regex}.should raise_error(NoMethodError)
129
+ end
130
+
131
+ end
132
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+ require 'rubytter'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubytter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.3
5
+ platform: ruby
6
+ authors:
7
+ - jugyo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-14 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json_pure
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.3
24
+ version:
25
+ description: Rubytter is a simple twitter client.
26
+ email: jugyo.org@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ - History.txt
34
+ files:
35
+ - lib/rubytter.rb
36
+ - lib/rubytter/connection.rb
37
+ - examples/friends_timeline.rb
38
+ - examples/update_status.rb
39
+ - spec/rubytter_spec.rb
40
+ - spec/spec_helper.rb
41
+ - README.rdoc
42
+ - History.txt
43
+ has_rdoc: true
44
+ homepage: http://github.com/jugyo/rubytter
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --main
48
+ - README.rdoc
49
+ - --exclude
50
+ - spec
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project: rubytter
68
+ rubygems_version: 1.3.1
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: Simple twitter client.
72
+ test_files: []
73
+