earthquake 0.0.2 → 0.1.0

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/Gemfile CHANGED
@@ -6,10 +6,12 @@ source "http://rubygems.org"
6
6
  gem 'twitter-stream', :require => 'twitter/json_stream'
7
7
  gem 'notify'
8
8
  gem 'i18n'
9
- gem 'activesupport', :require => 'active_support/core_ext'
9
+ gem 'activesupport', :require => ['active_support/core_ext', 'active_support/dependencies']
10
10
  gem 'awesome_print', :require => 'ap'
11
11
  gem 'launchy'
12
12
  gem 'oauth'
13
+ gem 'twitter_oauth'
14
+ gem 'termcolor'
13
15
 
14
16
  # Add dependencies to develop your gem here.
15
17
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -7,14 +7,17 @@ GEM
7
7
  diff-lcs (1.1.2)
8
8
  eventmachine (0.12.10)
9
9
  git (1.2.5)
10
+ highline (1.6.1)
10
11
  i18n (0.5.0)
11
12
  jeweler (1.5.2)
12
13
  bundler (~> 1.0.0)
13
14
  git (>= 1.2.5)
14
15
  rake
16
+ json (1.5.1)
15
17
  launchy (0.4.0)
16
18
  configuration (>= 0.0.5)
17
19
  rake (>= 0.8.1)
20
+ mime-types (1.16)
18
21
  notify (0.3.0)
19
22
  oauth (0.4.4)
20
23
  rake (0.8.7)
@@ -28,9 +31,15 @@ GEM
28
31
  rspec-expectations (2.3.0)
29
32
  diff-lcs (~> 1.1.2)
30
33
  rspec-mocks (2.3.0)
34
+ termcolor (1.2.1)
35
+ highline (>= 1.5.0)
31
36
  twitter-stream (0.1.12)
32
37
  eventmachine (>= 0.12.8)
33
38
  roauth (>= 0.0.2)
39
+ twitter_oauth (0.4.3)
40
+ json (>= 1.1.9)
41
+ mime-types (>= 1.16)
42
+ oauth (>= 0.4.1)
34
43
 
35
44
  PLATFORMS
36
45
  ruby
@@ -46,4 +55,6 @@ DEPENDENCIES
46
55
  oauth
47
56
  rcov
48
57
  rspec (~> 2.3.0)
58
+ termcolor
49
59
  twitter-stream
60
+ twitter_oauth
data/README.md CHANGED
@@ -3,6 +3,8 @@ Earthquake
3
3
 
4
4
  Twitter Client on Terminal with Streaming API.
5
5
 
6
+ It supports ruby 1.9 only.
7
+
6
8
  Install
7
9
  ----
8
10
 
@@ -19,9 +21,7 @@ TODO
19
21
  ----
20
22
 
21
23
  * plugin system
22
- * command
23
24
  * filter
24
- * colorize
25
25
  * reconnect
26
26
 
27
27
  Copyright
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.1.0
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{earthquake}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["jugyo"]
12
+ s.date = %q{2011-03-16}
13
+ s.default_executable = %q{earthquake}
14
+ s.description = %q{Twitter Client on Terminal with Twitter Streaming API.}
15
+ s.email = %q{jugyo.org@gmail.com}
16
+ s.executables = ["earthquake"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rspec",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README.md",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "bin/earthquake",
31
+ "earthquake.gemspec",
32
+ "lib/earthquake.rb",
33
+ "lib/earthquake/commands.rb",
34
+ "lib/earthquake/core.rb",
35
+ "lib/earthquake/ext.rb",
36
+ "lib/earthquake/get_access_token.rb",
37
+ "lib/earthquake/input.rb",
38
+ "lib/earthquake/output.rb",
39
+ "lib/earthquake/twitter.rb",
40
+ "spec/earthquake_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/jugyo/earthquake}
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.6.0}
47
+ s.summary = %q{Twitter Client on Terminal.}
48
+ s.test_files = [
49
+ "spec/earthquake_spec.rb",
50
+ "spec/spec_helper.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<twitter-stream>, [">= 0"])
58
+ s.add_runtime_dependency(%q<notify>, [">= 0"])
59
+ s.add_runtime_dependency(%q<i18n>, [">= 0"])
60
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
61
+ s.add_runtime_dependency(%q<awesome_print>, [">= 0"])
62
+ s.add_runtime_dependency(%q<launchy>, [">= 0"])
63
+ s.add_runtime_dependency(%q<oauth>, [">= 0"])
64
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
65
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
66
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
67
+ s.add_development_dependency(%q<rcov>, [">= 0"])
68
+ else
69
+ s.add_dependency(%q<twitter-stream>, [">= 0"])
70
+ s.add_dependency(%q<notify>, [">= 0"])
71
+ s.add_dependency(%q<i18n>, [">= 0"])
72
+ s.add_dependency(%q<activesupport>, [">= 0"])
73
+ s.add_dependency(%q<awesome_print>, [">= 0"])
74
+ s.add_dependency(%q<launchy>, [">= 0"])
75
+ s.add_dependency(%q<oauth>, [">= 0"])
76
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ end
81
+ else
82
+ s.add_dependency(%q<twitter-stream>, [">= 0"])
83
+ s.add_dependency(%q<notify>, [">= 0"])
84
+ s.add_dependency(%q<i18n>, [">= 0"])
85
+ s.add_dependency(%q<activesupport>, [">= 0"])
86
+ s.add_dependency(%q<awesome_print>, [">= 0"])
87
+ s.add_dependency(%q<launchy>, [">= 0"])
88
+ s.add_dependency(%q<oauth>, [">= 0"])
89
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
90
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
91
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
92
+ s.add_dependency(%q<rcov>, [">= 0"])
93
+ end
94
+ end
95
+
data/lib/earthquake.rb CHANGED
@@ -4,10 +4,14 @@ require 'readline'
4
4
  require 'bundler/setup'
5
5
  Bundler.require :default
6
6
 
7
- $:.unshift File.expand_path('..', __FILE__)
7
+ Thread.abort_on_exception = true
8
8
 
9
- require 'earthquake/core'
10
-
11
- module Earthquake
12
- extend Earthquake::Core
13
- end
9
+ %w(
10
+ ext
11
+ core
12
+ output
13
+ input
14
+ get_access_token
15
+ twitter
16
+ commands
17
+ ).each { |name| require_dependency File.expand_path("../earthquake/#{name}", __FILE__) }
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+ module Earthquake
3
+ init do
4
+ command :exit do |m|
5
+ stop
6
+ end
7
+
8
+ command :help do |m|
9
+ puts "TODO..."
10
+ end
11
+
12
+ command :restart do |m|
13
+ puts 'restarting...'
14
+ exec File.expand_path('../../..//bin/earthquake', __FILE__)
15
+ end
16
+
17
+ command :eval do |m|
18
+ ap eval(m[1])
19
+ end
20
+
21
+ # update
22
+ command %r|^[^/]+| do |m|
23
+ twitter.update(m[0]) if confirm(m[0])
24
+ end
25
+
26
+ command %r|^/reply (\d+)\s+(.*)|, :as => :reply do |m|
27
+ # TODO
28
+ ap m
29
+ end
30
+
31
+ command :status do |m|
32
+ puts_item twitter.status(m[1])
33
+ end
34
+
35
+ command :delete do |m|
36
+ twitter.status_destroy(m[1])
37
+ end
38
+
39
+ command :retweet do |m|
40
+ twitter.retweet(m[1])
41
+ end
42
+
43
+ command :favorite do |m|
44
+ twitter.favorite(m[1])
45
+ end
46
+
47
+ command :unfavorite do |m|
48
+ twitter.unfavorite(m[1])
49
+ end
50
+ end
51
+ end
@@ -1,9 +1,33 @@
1
+ # encoding: UTF-8
1
2
  module Earthquake
2
3
  module Core
3
4
  attr_accessor :config
4
- attr_reader :item_queue
5
5
 
6
- def init(*argv)
6
+ def item_queue
7
+ @item_queue ||= []
8
+ end
9
+
10
+ def inits
11
+ @inits ||= []
12
+ end
13
+
14
+ def init(&block)
15
+ inits << block
16
+ end
17
+
18
+ def init_all
19
+ inits.each { |block| block.call }
20
+ inits.clear
21
+ end
22
+
23
+ def reload
24
+ loaded = ActiveSupport::Dependencies.loaded.dup
25
+ ActiveSupport::Dependencies.clear
26
+ loaded.each { |lib| require_dependency lib }
27
+ init_all
28
+ end
29
+
30
+ def load_config(*argv)
7
31
  # TODO: parse argv
8
32
  self.config = {
9
33
  :dir => File.expand_path('~/.earthquake'),
@@ -13,84 +37,37 @@ module Earthquake
13
37
  config[:file] ||= File.join(config[:dir], 'config')
14
38
  load config[:file]
15
39
 
16
- get_access_token unless self.config[:access_key] && self.config[:access_secret]
17
- end
18
-
19
- def get_access_token
20
- consumer = OAuth::Consumer.new(
21
- self.config[:consumer_key],
22
- self.config[:consumer_secret],
23
- :site => 'http://api.twitter.com'
24
- )
25
- request_token = consumer.get_request_token
26
-
27
- puts "1) open: #{request_token.authorize_url}"
28
- Launchy::Browser.run(request_token.authorize_url)
29
-
30
- print "2) Enter the PIN: "
31
- pin = gets.strip
32
-
33
- access_token = request_token.get_access_token(:oauth_verifier => pin)
34
- config[:access_key] = access_token.token
35
- config[:access_secret] = access_token.secret
36
-
37
- puts "Saving 'access_key' and 'access_secret' to '#{config[:file]}'"
38
- File.open(config[:file], 'a') do |f|
39
- f << "\n"
40
- f << "Earthquake.config[:access_key] = '#{config[:access_key]}'"
41
- f << "\n"
42
- f << "Earthquake.config[:access_secret] = '#{config[:access_secret]}'"
43
- end
40
+ get_access_token unless self.config[:token] && self.config[:secret]
44
41
  end
45
42
 
46
43
  def start(*argv)
47
- init(*argv)
48
-
49
- @item_queue = []
44
+ load_config(*argv)
50
45
 
51
- Thread.abort_on_exception = true
46
+ init_all
52
47
 
53
48
  Thread.start do
54
- while buf = Readline.readline("[earthquake] ", true)
55
- begin
56
- buf = buf.strip
57
-
58
- if buf == '/exit'
59
- # TODO: refactor
60
- @stream.stop if @stream
61
- EventMachine.stop if EventMachine.reactor_running?
62
- end
63
- rescue => e
64
- notify "[ERROR] #{e}"
65
- end
49
+ while buf = Readline.readline(" ", true)
50
+ input(buf.strip)
66
51
  end
67
52
  end
68
53
 
69
54
  Thread.start do
70
55
  loop do
71
- # TODO: handle the response that include friends
72
- if Readline.line_buffer.empty?
73
- while item = item_queue.shift
74
- begin
75
- insert "#{item["user"]["screen_name"]}: #{item["text"]}"
76
- rescue => e
77
- insert do
78
- ap item
79
- end
80
- # notify "[ERROR] #{e}"
81
- end
82
- end
56
+ if Readline.line_buffer.nil? || Readline.line_buffer.empty?
57
+ output
58
+ sleep 1
59
+ else
60
+ sleep 2
83
61
  end
84
- sleep 1
85
62
  end
86
63
  end
87
64
 
88
65
  EventMachine::run {
89
- @stream = Twitter::JSONStream.connect(
66
+ @stream = ::Twitter::JSONStream.connect(
90
67
  :ssl => true,
91
68
  :host => 'userstream.twitter.com',
92
69
  :path => '/2/user.json',
93
- :oauth => config.slice(:consumer_key, :consumer_secret, :access_key, :access_secret)
70
+ :oauth => config.slice(:consumer_key, :consumer_secret).merge(:access_key => config[:token], :access_secret => config[:secret])
94
71
  )
95
72
 
96
73
  @stream.each_item do |item|
@@ -112,27 +89,19 @@ module Earthquake
112
89
  $stdout.flush
113
90
  end
114
91
 
115
- trap('TERM') {
116
- @stream.stop
117
- EventMachine.stop if EventMachine.reactor_running?
118
- }
92
+ trap('TERM') { stop }
119
93
  }
120
94
  end
121
95
 
122
- def notify(message)
123
- Notify.notify 'earthquake', message
96
+ def stop
97
+ @stream.stop
98
+ EventMachine.stop if EventMachine.reactor_running?
124
99
  end
125
100
 
126
- def insert(*messages)
127
- clear_line
128
- puts messages unless messages.empty?
129
- yield if block_given?
130
- ensure
131
- Readline.refresh_line
132
- end
133
-
134
- def clear_line
135
- print "\e[0G" + "\e[K"
101
+ def notify(message)
102
+ Notify.notify 'earthquake', message
136
103
  end
137
104
  end
105
+
106
+ extend Core
138
107
  end
@@ -0,0 +1,7 @@
1
+ class String
2
+ alias_method :t, :termcolor
3
+
4
+ def e
5
+ TermColor.escape(self)
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ module Earthquake
2
+ module GetAccessToken
3
+ def get_access_token
4
+ consumer = OAuth::Consumer.new(
5
+ self.config[:consumer_key],
6
+ self.config[:consumer_secret],
7
+ :site => 'http://api.twitter.com'
8
+ )
9
+ request_token = consumer.get_request_token
10
+
11
+ puts "1) open: #{request_token.authorize_url}"
12
+ Launchy::Browser.run(request_token.authorize_url)
13
+
14
+ print "2) Enter the PIN: "
15
+ pin = gets.strip
16
+
17
+ access_token = request_token.get_access_token(:oauth_verifier => pin)
18
+ config[:token] = access_token.token
19
+ config[:secret] = access_token.secret
20
+
21
+ puts "Saving 'token' and 'secret' to '#{config[:file]}'"
22
+ File.open(config[:file], 'a') do |f|
23
+ f << "\n"
24
+ f << "Earthquake.config[:token] = '#{config[:token]}'"
25
+ f << "\n"
26
+ f << "Earthquake.config[:secret] = '#{config[:secret]}'"
27
+ end
28
+ end
29
+ end
30
+
31
+ extend GetAccessToken
32
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+ module Earthquake
3
+ module Input
4
+ def commands
5
+ @commands ||= []
6
+ end
7
+
8
+ def command_names
9
+ @command_names ||= []
10
+ end
11
+
12
+ def input(text)
13
+ begin
14
+ reload if config[:debug]
15
+ if command = commands.detect { |c| c[:pattern] =~ text }
16
+ command[:block].call($~)
17
+ elsif !text.empty?
18
+ puts "<yellow>Command not found</yellow>".t
19
+ end
20
+ rescue Exception => e
21
+ puts "<on_red>[ERROR] #{e.message.e}\n#{e.backtrace.join("\n").e}</on_red>".t
22
+ end
23
+ end
24
+
25
+ def command(pattern, options = {}, &block)
26
+ if block
27
+ if pattern.is_a?(String) || pattern.is_a?(Symbol)
28
+ command_name = "#{config[:command_prefix]}#{pattern}"
29
+ command_names << command_name
30
+ pattern = /^#{Regexp.quote(command_name)}\s*(.*)$/
31
+ end
32
+ command_names << "#{config[:command_prefix]}#{options[:as]}" if options[:as]
33
+ commands << {:pattern => pattern, :block => block}
34
+ else
35
+ commands.detect { |c| c[:name] == name }
36
+ end
37
+ end
38
+
39
+ def confirm(message, type = :y)
40
+ case type
41
+ when :y
42
+ print "#{message} [Yn] "
43
+ return !(gets.strip =~ /^n$/i)
44
+ when :n
45
+ print "#{message} [yN] "
46
+ return !!(gets.strip =~ /^y$/i)
47
+ else
48
+ raise "type must be :y or :n"
49
+ end
50
+ end
51
+ end
52
+
53
+ init do
54
+ Readline.completion_proc = lambda { |text|
55
+ command_names.grep /^#{Regexp.quote(text)}/
56
+ }
57
+
58
+ config[:command_prefix] ||= '/'
59
+
60
+ commands.clear
61
+ end
62
+
63
+ extend Input
64
+ end
@@ -0,0 +1,71 @@
1
+ module Earthquake
2
+ module Output
3
+ def output
4
+ return if item_queue.empty?
5
+ insert do
6
+ while item = item_queue.shift
7
+ puts_item(item)
8
+ end
9
+ end
10
+ end
11
+
12
+ def puts_item(item)
13
+ output_handers.each { |p| p.call(item) }
14
+ rescue => e
15
+ puts e, e.backtrace
16
+ end
17
+
18
+ def output_handers
19
+ @output_handers ||= []
20
+ end
21
+
22
+ def output_hander(&block)
23
+ output_handers << block
24
+ end
25
+
26
+ def insert(*messages)
27
+ clear_line
28
+ puts messages unless messages.empty?
29
+ yield if block_given?
30
+ ensure
31
+ Readline.refresh_line
32
+ end
33
+
34
+ def clear_line
35
+ print "\e[0G" + "\e[K"
36
+ end
37
+
38
+ def color_of(screen_name)
39
+ config[:colors][screen_name.to_i(36) % config[:colors].size]
40
+ end
41
+ end
42
+
43
+ init do
44
+ output_handers.clear
45
+
46
+ config[:colors] = (31..36).to_a + (91..96).to_a
47
+
48
+ output_hander do |item|
49
+ if item["text"]
50
+ misc = (item["in_reply_to_status_id"] ? " (reply to #{item["in_reply_to_status_id"]})" : "")
51
+ user_color = color_of(item["user"]["screen_name"])
52
+ text = item["text"].e.gsub(/@([0-9A-Za-z_]+)/) do |i|
53
+ c = color_of($1)
54
+ "<#{c}>#{i}</#{c}>"
55
+ end
56
+ status = "<90>[#{item["id"].to_s.e}]</90> " +
57
+ "<#{user_color}>#{item["user"]["screen_name"].e}</#{user_color}>: " +
58
+ "#{text}<90>#{misc.e}</90>"
59
+ puts status.t
60
+ end
61
+ end
62
+
63
+ output_hander do |item|
64
+ if item["delete"]
65
+ puts "[deleted] #{item["delete"]["status"]["id"]}"
66
+ end
67
+ end
68
+ end
69
+
70
+ extend Output
71
+ end
@@ -0,0 +1,11 @@
1
+ module Earthquake
2
+ module Twitter
3
+ attr_reader :twitter
4
+ end
5
+
6
+ init do
7
+ @twitter = TwitterOAuth::Client.new(config.slice(:consumer_key, :consumer_secret, :token, :secret))
8
+ end
9
+
10
+ extend Twitter
11
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: earthquake
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - jugyo
@@ -153,8 +153,15 @@ files:
153
153
  - Rakefile
154
154
  - VERSION
155
155
  - bin/earthquake
156
+ - earthquake.gemspec
156
157
  - lib/earthquake.rb
158
+ - lib/earthquake/commands.rb
157
159
  - lib/earthquake/core.rb
160
+ - lib/earthquake/ext.rb
161
+ - lib/earthquake/get_access_token.rb
162
+ - lib/earthquake/input.rb
163
+ - lib/earthquake/output.rb
164
+ - lib/earthquake/twitter.rb
158
165
  - spec/earthquake_spec.rb
159
166
  - spec/spec_helper.rb
160
167
  has_rdoc: true