chirpstream 0.0.1

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.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |s|
4
+ s.name = "chirpstream"
5
+ s.description = s.summary = "Eventmachine-based Chirpstream client"
6
+ s.email = "joshbuddy@gmail.com"
7
+ s.homepage = "http://github.com/joshbuddy/chirpstream"
8
+ s.authors = ["Joshua Hull"]
9
+ s.files = FileList["[A-Z]*", "{lib}/**/*"]
10
+ end
11
+ Jeweler::GemcutterTasks.new
12
+ rescue LoadError
13
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
14
+ end
data/Readme.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = Chirpstream
2
+
3
+ == About
4
+
5
+ This is an experimental client for http://chirpstream.twitter.com.
6
+
7
+ == Usage
8
+
9
+ require 'rubygems'
10
+ require 'chirpstream'
11
+ require 'rainbow'
12
+
13
+ chirp = Chirpstream.new('joshbuddy', 'xxxxxxxx')
14
+ chirp.reconnect{ puts "reconnecting..." }
15
+ chirp.tweet {|t| puts "#{t['text']} (from #{t['user']['name'].foreground(:red)} (#{('@' + t['user']['screen_name']).foreground(:green)}))" }
16
+ chirp.follow {|t| puts "#{t.data['source'].data['screen_name'].foreground(:green)} following #{t.data['target'].data['screen_name'].foreground(:green)}" }
17
+ chirp.favorite {|t| puts "#{t.data['source'].data['screen_name'].foreground(:green)} <3 -> #{t.data['target_object'].data['text']}" }
18
+ chirp.retweet {|t| puts "#{t.data['source'].data['screen_name'].foreground(:green)} RT -> #{t.data['target_object'].data['text']}" }
19
+ chirp.connect
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,4 @@
1
+ class Chirpstream
2
+ class Delete < Event
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ class Chirpstream
2
+ class Favorite < Event
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ class Chirpstream
2
+ class Follow < Event
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ class Chirpstream
2
+ class Retweet < Event
3
+ end
4
+ end
@@ -0,0 +1,19 @@
1
+ class Chirpstream
2
+
3
+ class Event
4
+
5
+ attr_reader :data
6
+
7
+ def initialize(data)
8
+ @data = data
9
+ end
10
+
11
+ def load_all(&block)
12
+ if unloaded_data = @data.values.find{|d| d.respond_to?(:loaded?) && !d.loaded? }
13
+ unloaded_data.load { load_all(&block) }
14
+ else
15
+ block.call(self)
16
+ end
17
+ end
18
+ end
19
+ end
File without changes
@@ -0,0 +1,29 @@
1
+ class Chirpstream
2
+ class Tweet
3
+
4
+ URL = "http://api.twitter.com/1/statuses/show/%s.json"
5
+
6
+ attr_reader :id, :data
7
+
8
+ def initialize(base, id)
9
+ @base = base
10
+ @id = id
11
+ end
12
+
13
+ def load
14
+ unless loaded?
15
+ http = EM::HttpRequest.new(URL % id).get(:head => {'authorization' => [@base.username, @base.password]})
16
+ http.callback {
17
+ if http.response_header.status == 200
18
+ @data = JSON.parse(http.response)
19
+ yield self
20
+ end
21
+ }
22
+ end
23
+ end
24
+
25
+ def loaded?
26
+ @data
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ class Chirpstream
2
+ class User
3
+
4
+ URL = "http://api.twitter.com/1/users/show/%s.json"
5
+
6
+ attr_reader :id, :data
7
+
8
+ def initialize(base, id)
9
+ @base = base
10
+ @id = id
11
+ end
12
+
13
+ def load
14
+ unless loaded?
15
+ http = EM::HttpRequest.new(URL % id).get(:head => {'authorization' => [@base.username, @base.password]})
16
+ http.callback {
17
+ if http.response_header.status == 200
18
+ @data = JSON.parse(http.response)
19
+ yield self
20
+ end
21
+ }
22
+ end
23
+ end
24
+
25
+ def loaded?
26
+ @data
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,170 @@
1
+ require 'eventmachine'
2
+ require 'em-http'
3
+ require 'json'
4
+ require 'pp'
5
+ require 'load_path_find'
6
+
7
+ $LOAD_PATH.add_current
8
+
9
+ require 'chirpstream/event'
10
+ require 'chirpstream/event/follow'
11
+ require 'chirpstream/event/retweet'
12
+ require 'chirpstream/event/favorite'
13
+ require 'chirpstream/event/delete'
14
+ require 'chirpstream/user'
15
+ require 'chirpstream/tweet'
16
+
17
+ class Chirpstream
18
+
19
+ attr_reader :handlers
20
+
21
+ Handlers = Struct.new(:friend, :tweet, :follow, :favorite, :retweet, :delete, :reconnect)
22
+
23
+ attr_reader :username, :password
24
+
25
+ def initialize(username, password)
26
+ @username = username
27
+ @password = password
28
+ @connect_url = "http://chirpstream.twitter.com/2b/user.json"
29
+ @handlers = Handlers.new([], [], [], [], [], [], [])
30
+ @data = ''
31
+ end
32
+
33
+ def friend(&block)
34
+ @handlers.friend << block
35
+ end
36
+
37
+ def tweet(&block)
38
+ @handlers.tweet << block
39
+ end
40
+
41
+ def follow(&block)
42
+ @handlers.follow << block
43
+ end
44
+
45
+ def favorite(&block)
46
+ @handlers.favorite << block
47
+ end
48
+
49
+ def retweet(&block)
50
+ @handlers.retweet << block
51
+ end
52
+
53
+ def delete(&block)
54
+ @handlers.delete << block
55
+ end
56
+
57
+ def reconnect(&block)
58
+ @handlers.reconnect << block
59
+ end
60
+
61
+ def dispatch_friend(data)
62
+ unless @handlers.friend.empty?
63
+ data['friends'].each_slice(100) do |friend_ids|
64
+ friend_http = EM::HttpRequest.new("http://api.twitter.com/1/users/lookup.json").post(:body => {'user_id' => friend_ids.join(',')}, :head => {'authorization' => [@username, @password]})
65
+ friend_http.callback do
66
+ friends = JSON.parse(friend_http.response)
67
+ friends.each do |friend|
68
+ @handlers.friend.each{|h| h.call(friend)}
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ def dispatch_tweet(data)
76
+ unless @handlers.tweet.empty?
77
+ @handlers.tweet.each{|h| h.call(data)}
78
+ end
79
+ end
80
+
81
+ def dispatch_follow(data)
82
+ unless @handlers.follow.empty?
83
+ data['target'] = User.new(self, data['target']['id'])
84
+ data['source'] = User.new(self, data['source']['id'])
85
+ e = Follow.new(data)
86
+ e.load_all {
87
+ @handlers.follow.each{|h| h.call(e)}
88
+ }
89
+ end
90
+ end
91
+
92
+ def dispatch_favorite(data)
93
+ return if @handlers.follow.empty?
94
+ data['target'] = User.new(self, data['target']['id'])
95
+ data['source'] = User.new(self, data['source']['id'])
96
+ data['target_object'] = Tweet.new(self, data['target_object']['id'])
97
+ e = Favorite.new(data)
98
+ e.load_all {
99
+ @handlers.favorite.each{|h| h.call(e)}
100
+ }
101
+ end
102
+
103
+ def dispatch_retweet(data)
104
+ return if @handlers.retweet.empty?
105
+ data['target'] = User.new(self, data['target']['id'])
106
+ data['source'] = User.new(self, data['source']['id'])
107
+ data['target_object'] = Tweet.new(self, data['target_object']['id'])
108
+ e = Retweet.new(data)
109
+ e.load_all {
110
+ @handlers.retweet.each{|h| h.call(e)}
111
+ }
112
+ end
113
+
114
+ def dispatch_delete(data)
115
+ return if @handlers.delete.empty?
116
+ data['delete']['user_id'] = User.new(self, data['delete']['user_id'])
117
+ e = Delete.new(data)
118
+ e.load_all {
119
+ @handlers.delete.each{|h| h.call(e)}
120
+ }
121
+ end
122
+
123
+ def dispatch_reconnect
124
+ return if @handlers.reconnect.empty?
125
+ @handlers.reconnect.each{|h| h.call}
126
+ end
127
+
128
+ def connect
129
+ unless EM.reactor_running?
130
+ EM.run { connect }
131
+ else
132
+ http = EM::HttpRequest.new(@connect_url).get :head => {'authorization' => [@username, @password]}
133
+ http.errback { |e, err|
134
+ dispatch_reconnect
135
+ connect
136
+ }
137
+ http.stream { |chunk|
138
+ @data << chunk
139
+ begin
140
+ parsed_data = JSON.parse(@data)
141
+ @data = ''
142
+ if parsed_data['friends']
143
+ dispatch_friend(parsed_data)
144
+ elsif parsed_data['text']
145
+ dispatch_tweet(parsed_data)
146
+ elsif parsed_data['event']
147
+ case parsed_data['event']
148
+ when 'follow'
149
+ dispatch_follow(parsed_data)
150
+ when 'favorite'
151
+ dispatch_favorite(parsed_data)
152
+ when 'retweet'
153
+ dispatch_retweet(parsed_data)
154
+ else
155
+ puts "weird event"
156
+ pp parsed_data
157
+ end
158
+ elsif parsed_data['delete']
159
+ dispatch_delete(parsed_data)
160
+ else
161
+ puts "i didn't know what to do with this!"
162
+ pp parsed_data
163
+ end
164
+ rescue JSON::ParserError
165
+ #puts "need more"
166
+ end
167
+ }
168
+ end
169
+ end
170
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chirpstream
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Joshua Hull
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-22 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Eventmachine-based Chirpstream client
22
+ email: joshbuddy@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Rakefile
31
+ - Readme.rdoc
32
+ - VERSION
33
+ - lib/chirpstream.rb
34
+ - lib/chirpstream/event.rb
35
+ - lib/chirpstream/event/delete.rb
36
+ - lib/chirpstream/event/favorite.rb
37
+ - lib/chirpstream/event/follow.rb
38
+ - lib/chirpstream/event/retweet.rb
39
+ - lib/chirpstream/loadable.rb
40
+ - lib/chirpstream/tweet.rb
41
+ - lib/chirpstream/user.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/joshbuddy/chirpstream
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Eventmachine-based Chirpstream client
72
+ test_files: []
73
+