drip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Drip
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,64 @@
1
+ require 'drb/drb'
2
+
3
+ MyDrip = DRbObject.new_with_uri('drbunix:' + File.expand_path('~/.drip/port'))
4
+
5
+ def MyDrip.invoke
6
+ fork do
7
+ Process.daemon
8
+
9
+ require 'drip'
10
+ require 'fileutils'
11
+
12
+ dir = File.expand_path('~/.drip')
13
+ uri = 'drbunix:' + File.join(dir, 'port')
14
+ ro = DRbObject.new_with_uri(uri)
15
+ begin
16
+ ro.older(nil) #ping
17
+ exit
18
+ rescue
19
+ end
20
+
21
+ FileUtils.mkdir_p(dir)
22
+ FileUtils.cd(dir)
23
+
24
+ drip = Drip.new('drip')
25
+ def drip.quit
26
+ Thread.new do
27
+ synchronize do |key|
28
+ exit(0)
29
+ end
30
+ end
31
+ end
32
+
33
+ DRb.start_service(uri, drip)
34
+ File.open('pid', 'w') {|fp| fp.puts($$)}
35
+
36
+ DRb.thread.join
37
+ end
38
+ end
39
+
40
+ class DripCursor
41
+ def initialize(drip, bufsiz=10, at_least=10)
42
+ @drip = drip
43
+ @cur = nil
44
+ @bufsiz = bufsiz
45
+ @at_least = at_least
46
+ end
47
+ attr_accessor :cur
48
+
49
+ def now
50
+ @cur ? @drip.key_to_time(@cur) : nil
51
+ end
52
+
53
+ def seek_at(time)
54
+ @cur = @drip.time_to_key(time)
55
+ end
56
+
57
+ def past_each(tag=nil)
58
+ while kv = @drip.older(@cur, tag)
59
+ @cur, value = kv
60
+ yield(value)
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'drip_tw'
3
+ require 'my_drip'
4
+ require 'date'
5
+ require 'pp'
6
+
7
+ def dig(root, *keys)
8
+ keys.inject(root) do |node, key|
9
+ return nil if node.nil?
10
+ node[key] rescue nil
11
+ end
12
+ end
13
+
14
+ class CopoCopo
15
+ def initialize(drip=MyDrip)
16
+ @app = DripDemo.new('CopoCopo OAuth')
17
+ @drip = drip
18
+ _, @last = @drip.older(nil, 'CopoCopo Footprint')
19
+ @last = 0 if @last.nil?
20
+ @friends = %w(m_seki miwa719 hsbt vestige mame)
21
+ end
22
+ attr_reader :app
23
+
24
+ def extract(str)
25
+ ary = []
26
+ str.scan(/(([ぁ-ん]{2,})\2)|(([ァ-ヴ]{2,})\4)/) do |x|
27
+ ary << (x[1] || x[3])
28
+ end
29
+ ary.uniq
30
+ end
31
+
32
+ def retweet?(event)
33
+ event['retweeted_status'] ? true : false
34
+ end
35
+
36
+ def mention?(event)
37
+ event['in_reply_to_status_id_str'] ? true : false
38
+ end
39
+
40
+ def created_at(event)
41
+ DateTime.parse(event['created_at']).to_time
42
+ rescue
43
+ Time.at(1)
44
+ end
45
+
46
+ def make_status(ary, name)
47
+ "@#{name} " + ary.collect { |s|
48
+ "#{s}#{s}、#{s}"
49
+ }.join(", ") + " (by copocopo)"
50
+ end
51
+
52
+ def main_loop
53
+ while true
54
+ @last, event = @drip.read_tag(@last, 'DripDemo Event', 1)[0]
55
+ next if retweet?(event)
56
+ next if mention?(event)
57
+ next unless Time.now < created_at(event) + 60000
58
+ name = dig(event, 'user', 'screen_name')
59
+ next unless @friends.include?(name)
60
+ ary = extract(event['text'] || '')
61
+ next if ary.empty?
62
+ tweet_id = event['id']
63
+ # @app.update(make_status(ary, name), tweet_id)
64
+ p [make_status(ary, name)]
65
+ # @drip.write(@last, 'CopoCopo Footprint')
66
+ end
67
+ end
68
+ end
69
+
70
+ copo = CopoCopo.new
71
+ app = copo.app
72
+
73
+ unless app.has_token?
74
+ url = app.pin_url
75
+ puts url
76
+ system('open ' + url) # for OSX
77
+ app.set_pin(gets.scan(/\w+/)[0])
78
+ app.write_setting
79
+ end
80
+
81
+ copo.main_loop
82
+
@@ -0,0 +1,255 @@
1
+ require 'simple-oauth'
2
+ require 'drb'
3
+ require 'pp'
4
+ require 'json'
5
+ require 'my_drip'
6
+
7
+ class DripFiber
8
+ def initialize(app)
9
+ @app = app
10
+ @fiber = Fiber.new do |event|
11
+ story(event)
12
+ end
13
+ end
14
+
15
+ def story(event)
16
+ pending = []
17
+ while event['id_str'].nil?
18
+ pending << event
19
+ event = Fiber.yield
20
+ end
21
+
22
+ @app.fill_timeline(event['id_str'])
23
+
24
+ while event = pending.shift
25
+ @app.write(event)
26
+ end
27
+
28
+ while true
29
+ event = Fiber.yield
30
+ @app.write(event)
31
+ end
32
+ end
33
+
34
+ def push(event)
35
+ @fiber.resume(event)
36
+ end
37
+ end
38
+
39
+ class JSONStream
40
+ def initialize(drip)
41
+ @buf = ''
42
+ @drip = drip
43
+ end
44
+
45
+ def push(str)
46
+ @buf << str
47
+ while (line = @buf[/.+?(\r\n)+/m]) != nil
48
+ begin
49
+ @buf.sub!(line,"")
50
+ line.strip!
51
+ event = JSON.parse(line)
52
+ rescue
53
+ break
54
+ end
55
+ pp event if $DEBUG
56
+ @drip.push(event)
57
+ end
58
+ end
59
+ end
60
+
61
+ class SimpleOAuthS < SimpleOAuth
62
+ def http_class
63
+ return Net::HTTP unless ENV['http_proxy']
64
+ proxy_url = URI.parse(ENV['http_proxy'])
65
+ Net::HTTP.Proxy(proxy_url.host, proxy_url.port)
66
+ end
67
+
68
+ def request(method, url, body =nil, headers = {}, &block)
69
+ method = method.to_s
70
+ url = URI.parse(url)
71
+ request = create_http_request(method, url.request_uri, body, headers)
72
+ request['Authorization'] = auth_header(method, url, request.body)
73
+ http = http_class.new(url.host, url.port)
74
+ if url.scheme == 'https'
75
+ http.use_ssl = true
76
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
+ store = OpenSSL::X509::Store.new
78
+ store.set_default_paths
79
+ http.cert_store = store
80
+ end
81
+ http.request(request, &block)
82
+ end
83
+ end
84
+
85
+ class DripDemo
86
+ def initialize(oauth_tag = 'DripDemo OAuth')
87
+ @oauth_tag = oauth_tag
88
+ @oa = last_setting || {}
89
+ end
90
+
91
+ def has_token?
92
+ @oa.include?(:oauth_token)
93
+ end
94
+
95
+ def last_setting
96
+ MyDrip.older(nil, @oauth_tag)[1]
97
+ end
98
+
99
+ def write_setting
100
+ MyDrip.write(@oa, @oauth_tag)
101
+ end
102
+
103
+ def update_setting(body, keys=nil)
104
+ found = []
105
+ body.split('&').each do |pair|
106
+ k, v = pair.split('=')
107
+ if keys.nil? || keys.include?(k)
108
+ @oa[k.intern] = v
109
+ found << k
110
+ end
111
+ end
112
+ found
113
+ end
114
+
115
+ def oauth
116
+ SimpleOAuthS.new(@oa[:consumer_key],
117
+ @oa[:consumer_secret],
118
+ @oa[:oauth_token],
119
+ @oa[:oauth_token_secret])
120
+ end
121
+
122
+ def pin_url
123
+ @oa[:oauth_token] = ''
124
+ @oa[:oauth_token_secret] = ''
125
+ response = oauth.get('https://api.twitter.com/oauth/request_token')
126
+ raise response.message unless response.code == '200'
127
+ update_setting(response.body, ['oauth_token', 'oauth_token_secret'])
128
+
129
+ 'http://twitter.com/oauth/authorize?oauth_token=' + @oa[:oauth_token]
130
+ end
131
+
132
+ def set_pin(pin)
133
+ response = oauth.get('https://api.twitter.com/oauth/access_token',
134
+ 'oauth_token' => @oa[:oauth_token],
135
+ 'oauth_velifier' => pin)
136
+ raise response.message unless response.code == '200'
137
+ update_setting(response.body)
138
+ end
139
+
140
+ def drip_stream
141
+ json = JSONStream.new(DripFiber.new(self))
142
+ oauth.request(:GET, 'https://userstream.twitter.com/2/user.json') do |r|
143
+ r.read_body do |chunk|
144
+ json.push(chunk)
145
+ end
146
+ end
147
+ end
148
+
149
+ def home_timeline(since_id, max_id)
150
+ url = "http://api.twitter.com/1/statuses/home_timeline.json?count=200&include_entities=true"
151
+ url += "&since_id=#{since_id}" if since_id
152
+ url += "&max_id=#{max_id}" if max_id
153
+ r = oauth.request(:GET, url)
154
+ JSON.parse(r.body)
155
+ end
156
+
157
+ def user_timeline(since_id, max_id)
158
+ url = "http://api.twitter.com/1/statuses/user_timeline.json?count=200&include_entities=true&trim_user=t"
159
+ url += "&since_id=#{since_id}" if since_id
160
+ url += "&max_id=#{max_id}" if max_id
161
+ r = oauth.request(:GET, url)
162
+ JSON.parse(r.body)
163
+ end
164
+
165
+ def last_tweet_id
166
+ key = nil
167
+ while kv = MyDrip.older(key, 'DripDemo Event')
168
+ key, value = kv
169
+ return value['id_str'] if value.include?('text')
170
+ end
171
+ nil
172
+ end
173
+
174
+ def fill_timeline(max_id)
175
+ since_id = last_tweet_id
176
+ return unless since_id
177
+ timeline = []
178
+ 4.times do
179
+ return if since_id == max_id || max_id.nil?
180
+ ary = home_timeline(since_id, max_id)
181
+ pp [:fill_timeline, ary.size] if $DEBUG
182
+ max_id = nil
183
+ ary.reverse_each do |event|
184
+ next unless event['id']
185
+ max_id = event['id'] - 1
186
+ break
187
+ end
188
+ break if max_id.nil?
189
+ timeline += ary
190
+ end
191
+ timeline.reverse_each do |event|
192
+ write(event)
193
+ end
194
+ end
195
+
196
+ def compact_event(event)
197
+ return event unless Hash === event
198
+ result = {}
199
+ event.each do |k, v|
200
+ case v
201
+ when Hash
202
+ v = compact_event(v)
203
+ next if v.nil?
204
+ when [], '', 0, nil
205
+ next
206
+ when Array
207
+ v = v.collect {|vv| compact_event(vv)}
208
+ end
209
+ if k == 'user'
210
+ tmp = {}
211
+ %w(name screen_name id id_str).each {|attr| tmp[attr] = v[attr]}
212
+ v = tmp
213
+ end
214
+ result[k] = v
215
+ end
216
+ result.size == 0 ? nil : result
217
+ end
218
+
219
+ def write(event, tag='DripDemo Event')
220
+ event = compact_event(event)
221
+ key = MyDrip.write(event, tag)
222
+ pp [key, event['id_str'], event['text']] if $DEBUG
223
+ end
224
+
225
+ def update(str, in_reply_to=nil)
226
+ hash = { :status => str }
227
+ hash[:in_reply_to_status_id] = in_reply_to if in_reply_to
228
+ r = oauth.post('http://api.twitter.com/1/statuses/update.xml',
229
+ hash)
230
+ pp r.body if $DEBUG
231
+ end
232
+
233
+ def test
234
+ r = oauth.post('http://api.twitter.com/1/statuses/update.xml',
235
+ {:status => 'test'})
236
+ pp r.body if $DEBUG
237
+ end
238
+ end
239
+
240
+ if __FILE__ == $0
241
+ app = DripDemo.new
242
+
243
+ unless app.has_token?
244
+ url = app.pin_url
245
+ puts url
246
+ system('open ' + url) # for OSX
247
+ app.set_pin(gets.scan(/\w+/)[0])
248
+ app.write_setting
249
+ end
250
+
251
+ unless $DEBUG
252
+ Process.daemon
253
+ end
254
+ app.drip_stream
255
+ end
@@ -0,0 +1,70 @@
1
+ class GoogleChartApi
2
+ NtoS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
3
+ NtoE = NtoS + %w(- .)
4
+ URL = 'http://chart.apis.google.com/chart'
5
+
6
+ def initialize
7
+ @query = []
8
+ end
9
+
10
+ def as_s(n)
11
+ NtoS[n]
12
+ end
13
+
14
+ def as_e(n)
15
+ h, v = n.divmod(64)
16
+ NtoE[h] + NtoE[v]
17
+ end
18
+
19
+ def chd_s(*ary_ary)
20
+ @query << "chd=s:" + ary_ary.collect do |ary|
21
+ ary.collect {|n| as_s(n)}.join('')
22
+ end.join("|")
23
+ end
24
+
25
+ def chd_e(*ary_ary)
26
+ @query << "chd=e:" + ary_ary.collect do |ary|
27
+ ary.collect {|n| as_e(n)}.join('')
28
+ end.join("|")
29
+ end
30
+
31
+ def chd_t(*ary_ary)
32
+ @query << "chd=t:" + ary_ary.collect do |ary|
33
+ ary.join(',')
34
+ end.join("|")
35
+ end
36
+
37
+ def chs(w, h)
38
+ @query << "chs=#{w}x#{h}"
39
+ end
40
+
41
+ def chtt(title)
42
+ @query << "chtt=#{title.gsub(/ /, '+') .gsub(/\n/m, '|')}"
43
+ end
44
+
45
+ def method_missing(name, *args, &blk)
46
+ if /^ch/ =~ name
47
+ @query << "#{name}=#{args[0]}"
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def to_s
54
+ [URL, @query.join("&")].join("?")
55
+ end
56
+ end
57
+
58
+ gca = GoogleChartApi.new
59
+
60
+ gca.chs(460, 200)
61
+ gca.chd_t([62,12,5,2,19])
62
+ gca.cht('lc')
63
+ gca.chxt('r')
64
+ gca.chxr('0,60,130')
65
+ gca.chxl('0:80|100|120')
66
+ gca.chxp('0,80,100,120')
67
+
68
+ puts gca
69
+ system("open '#{gca}'")
70
+