twtr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0 2008-05-22
2
+ * 1 major enhancement:
3
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ryota Maruko
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.txt ADDED
@@ -0,0 +1,90 @@
1
+ = twtr
2
+ * twtr.rubyforge.org
3
+
4
+ == DESCRIPTION:
5
+ twtr is a twitter client for Linux, OSX and Windows Console.
6
+
7
+ == DESCRIPTION:
8
+ twtr is a imprementaion of twitter client.
9
+ Features are
10
+ * Command line application.
11
+ * Simple Twitter library.
12
+ * Http Proxy available.
13
+ * Double Byte Encoding. e.g) ShiftJIS, EUC-JP, etc.
14
+
15
+ == SYNOPSIS:
16
+ * command line
17
+ twtr [subcommand] [options]
18
+ ex)
19
+ $ twtr setting # => (Re)set config file.
20
+ $ twtr ft # => Show friends timeline.
21
+ $ twtr pt -P 2 # => Show public timeline (page 2).
22
+ $ twtr ut -i bob # => Show someone's timeline.
23
+ $ twtr rp # => Show replies.
24
+ $ twtr up -m "hello world" # => Update message.
25
+
26
+ * ruby code
27
+ require "twtr"
28
+ tc = Twtr::Client.new(
29
+ "account" => {"user" => "bob", "password" => "secret"},
30
+ "proxy" => {"host" => "proxy.domain", "port" => 8080},
31
+ )
32
+
33
+ result_json = tc.update({:status => "hello world! from twtr", :format => :json})
34
+
35
+ result_xml = tc.friends_timeline({:page => 2, :format => :xml})
36
+
37
+
38
+ == SUBCMMAND:
39
+ setting (reset) # (Re)Set twtr configuration info.
40
+ friends_timeline (ft) # Show friends timeline.
41
+ putlic_timeline (pt) # Show public timeline.
42
+ user_timeline (ut) # Show user timeline. -i, --id option required.
43
+ replies (rp) # Show replies.
44
+ update (up) # Updates your status. -m, --message option required.
45
+
46
+
47
+ * twtr lib.
48
+ require "twtr"
49
+ tc = Twtr::Client.new(
50
+ Twtr::Config.load("/path/to/twtr.yml")
51
+ )
52
+
53
+ tc.message("hello!")
54
+ #=> [[foo, "hello1"]]
55
+
56
+ tc.timeline(:friends)
57
+ #=> [["foo", "hello!"],["bar","what's up?"],["bar","I'm Home."]]
58
+
59
+ tc.timeline(:timeline)
60
+ #=> [["superman", "hello!"],["badman","what's up?"],["ultraman","I'm Home."],["foo","hello!"]]
61
+
62
+
63
+ == INSTALL:
64
+
65
+ * gem install twtr
66
+
67
+ == LICENSE:
68
+
69
+ (The MIT License)
70
+
71
+ Copyright (c) 2008 Ryota Maruko
72
+
73
+ Permission is hereby granted, free of charge, to any person obtaining
74
+ a copy of this software and associated documentation files (the
75
+ 'Software'), to deal in the Software without restriction, including
76
+ without limitation the rights to use, copy, modify, merge, publish,
77
+ distribute, sublicense, and/or sell copies of the Software, and to
78
+ permit persons to whom the Software is furnished to do so, subject to
79
+ the following conditions:
80
+
81
+ The above copyright notice and this permission notice shall be
82
+ included in all copies or substantial portions of the Software.
83
+
84
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
87
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
88
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
89
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
90
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/twtr ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ TWTR_BASE = File.expand_path("#{File.dirname(__FILE__)}/..")
3
+ require "#{TWTR_BASE}/lib/twtr.rb"
4
+
5
+ console = Twtr::Console.new()
6
+ console.run(ARGV)
data/config/hoe.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'twtr/version'
2
+
3
+ AUTHOR = 'Ryota Maruko' # can also be an array of Authors
4
+ EMAIL = ""
5
+ DESCRIPTION = "twtr is a twitter client for Linux, OSX and Windows Console."
6
+ GEM_NAME = 'twtr' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'twtr' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Twtr::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'twtr documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.developer(AUTHOR, EMAIL)
52
+ p.description = DESCRIPTION
53
+ p.summary = DESCRIPTION
54
+ p.url = HOMEPATH
55
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
56
+ p.test_globs = ["test/**/test_*.rb"]
57
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
58
+
59
+ # == Optional
60
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
61
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
+
63
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
64
+
65
+ end
66
+
67
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
68
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
69
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
70
+ $hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
data/lib/twtr.rb ADDED
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Twtr
5
+ def self.is_win?
6
+ (RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/) ? true : false
7
+ end
8
+
9
+ require "kconv"
10
+ require "cgi"
11
+ require "rexml/document"
12
+ require "twtr/version"
13
+ require "twtr/config"
14
+ require "twtr/console"
15
+ require "twtr/client"
16
+ require "twtr/errors"
17
+ end
@@ -0,0 +1,116 @@
1
+ module Twtr
2
+ class Client
3
+ require 'net/http'
4
+
5
+ HOST = "twitter.com"
6
+ PORT = 80
7
+
8
+ DEFAULT_FORMAT = :xml
9
+ DEFAULT_METHOD = :get
10
+
11
+ SEC_SLEEP = 1 # wait update.
12
+
13
+ ATTR_NAMES = [:account_user, :account_password,
14
+ :proxy_host, :proxy_port]
15
+
16
+ ATTR_NAMES.each {|name| attr_accessor name }
17
+
18
+ def initialize(config = nil)
19
+ @account_user = @account_password = @proxy_host = @proxy_port = nil
20
+ ATTR_NAMES.each {|name| load_config(name, config) } if config
21
+ end
22
+
23
+ def load_config(attr_name, config)
24
+ if val = config_from_attr(attr_name, config)
25
+ self.instance_variable_set("@#{attr_name}", val )
26
+ end
27
+ end
28
+
29
+ def config_from_attr(attr_name, config)
30
+ section, name = attr_name.to_s.split("_")
31
+ val ||= (config[section] && config[section][name])
32
+ val ||= (config[section.to_sym] && config[section.to_sym][name.to_sym])
33
+ val
34
+ end
35
+
36
+ def public_timeline(options={})
37
+ get_status("/statuses/public_timeline", options)
38
+ end
39
+
40
+ def friends_timeline(options={})
41
+ get_status("/statuses/friends_timeline", options)
42
+ end
43
+
44
+ def user_timeline(options={})
45
+ id = options.delete(:id) || @account_user
46
+ get_status("/statuses/user_timeline/#{id}", options)
47
+ end
48
+
49
+ def replies(options={})
50
+ get_status("/statuses/replies", options)
51
+ end
52
+
53
+ def update(options={})
54
+ source = post_status("/statuses/update",options)
55
+ friends_timeline()
56
+ end
57
+
58
+ def test(options={})
59
+ request_status("/help/test", options)
60
+ end
61
+
62
+ def post_status(path,options = {})
63
+ options[:method] = :post
64
+ sleep(SEC_SLEEP)
65
+ request_status(path, options)
66
+ end
67
+
68
+ def get_status(path, options = {})
69
+ options[:method] = :get
70
+ request_status(path, options)
71
+ end
72
+
73
+ def request_status(path, options = {})
74
+ format = options.delete(:format) || DEFAULT_FORMAT
75
+ method = options.delete(:method) || DEFAULT_METHOD
76
+ case method
77
+ when :get
78
+ res = get("#{path}.#{format}", options)
79
+ when :post
80
+ res = post("#{path}.#{format}", options)
81
+ end
82
+
83
+ raise Twtr::ResponseErrorException.new("#{res.code}: #{HTTP_ERRORS[res.code]}") \
84
+ if Twtr::HTTP_ERRORS.has_key?(res.code)
85
+ res.body
86
+ end
87
+
88
+ def get(path, params = {})
89
+ query = params.to_a.map {|pair| "#{pair.shift}=#{CGI.escape(pair.pop.to_s)}" if pair.last}
90
+ path = path.gsub(/^#{HOST}/,'')
91
+ path += "?#{query.join('&')}" unless query.empty?
92
+ req = Net::HTTP::Get.new(path)
93
+ request(req)
94
+ end
95
+
96
+ def post(path, params = {})
97
+ req = Net::HTTP::Post.new(path)
98
+ req.set_form_data(params) unless params.empty?
99
+ request(req)
100
+ end
101
+
102
+ def request(req)
103
+ req.basic_auth(@account_user, @account_password) if @account_user
104
+ if(@proxy_host)
105
+ @proxy_host.gsub!(%r|http://|,'')
106
+ Net::HTTP::Proxy(@proxy_host, @proxy_port.to_i).start(HOST, PORT) do |http|
107
+ http.request(req)
108
+ end
109
+ else
110
+ Net::HTTP.start(HOST, PORT){|http| http.request(req)}
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,30 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+ require 'yaml/store'
4
+ require 'fileutils'
5
+
6
+
7
+ module Twtr
8
+ module Config
9
+
10
+ def self.load(config_file)
11
+ if File.exist?(config_file)
12
+ config = YAML::load(ERB.new(IO.read(config_file)).result)
13
+ else
14
+ raise Twtr::ConfigFileNotFoundException.new("#{config_file} not found!")
15
+ end
16
+ end
17
+
18
+ def self.save(config_file, config = {})
19
+ FileUtils.mkdir_p(File.dirname(config_file))
20
+ store = YAML::Store.new(config_file)
21
+ store.transaction do |yaml|
22
+ %W(account proxy).each do |name|
23
+ yaml.delete(name) if yaml[name]
24
+ yaml[name] = config[name] if config[name]
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,172 @@
1
+ require "optparse"
2
+
3
+ module Twtr
4
+ DESCRIPTION=<<-_TEXT_
5
+ Twtr Copyright (c) 2008 Ryota Maruko
6
+ DESCRIPTION
7
+ twtr is a imprementaion of twitter client.
8
+ Features are
9
+ * Command line application.
10
+ * Simple Twitter library.
11
+ * Http Proxy available.
12
+ * Double Byte Encoding. e.g) ShiftJIS, EUC-JP, etc.
13
+
14
+ SYNOPSIS
15
+ twtr [subcommand] [options]
16
+ ex)
17
+ $ twtr setting # => (Re)set config file.
18
+ $ twtr ft # => Show friends timeline.
19
+ $ twtr pt -P 2 # => Show public timeline (page 2).
20
+ $ twtr ut -i bob # => Show someone's timeline.
21
+ $ twtr rp # => Show replies.
22
+ $ twtr up -m "hello world" # => Update message.
23
+
24
+ SUBCMMAND
25
+ setting (reset) # (Re)Set twtr configuration info.
26
+ friends_timeline (ft) # Show friends timeline.
27
+ putlic_timeline (pt) # Show public timeline.
28
+ user_timeline (ut) # Show user timeline. -i, --id option required.
29
+ replies (rp) # Show replies.
30
+ update (up) # Updates your status. -m, --message option required.
31
+ _TEXT_
32
+
33
+ class Console
34
+ CONFIG_FILE = Twtr.is_win? ? File.expand_path("#{ENV['HOMEPATH']}/twtr/twtr.yml") \
35
+ : File.expand_path("~/.twtr/twtr.yml")
36
+ DEFAULT_DISPLAY_COUNT = 20
37
+ COUNT_WITH_UPDATE = 5
38
+ DEFAULT_DISPLAY_ENCODE = Twtr.is_win? ? :sjis : :utf8
39
+
40
+ SUBCOMMANDS = {
41
+ :public_timeline => :public_timeline,
42
+ :pt => :public_timeline,
43
+ :friends_timeline => :friends_timeline,
44
+ :ft => :friends_timeline,
45
+ :user_timeline => :user_timeline,
46
+ :ut => :user_timeline,
47
+ :replies => :replies,
48
+ :rp => :replies,
49
+ :update => :update,
50
+ :up => :update,
51
+ :setting => :setting,
52
+ :reset => :setting,
53
+ }
54
+
55
+ def run(args)
56
+ begin
57
+ parse(args)
58
+ rescue Exception => e
59
+ puts e.message
60
+ end
61
+
62
+ if @subcommand
63
+ @configfile ||= CONFIG_FILE
64
+ (edit_config(); return) if @subcommand == :setting
65
+
66
+ begin
67
+ client = Twtr::Client.new(Twtr::Config.load(@configfile))
68
+ show_status( client.send(@subcommand, @params) )
69
+ rescue Twtr::ConfigFileNotFoundException => e
70
+ puts e.message
71
+ edit_config()
72
+ rescue Exception => e
73
+ puts e.message
74
+ end
75
+ end
76
+ end
77
+
78
+ def edit_config()
79
+ puts ">> #{@configfile}"
80
+ print "Edit twtr config? [y/N]:"; replay = gets
81
+ exit if replay.to_s.chomp != 'y'
82
+
83
+ config = {}
84
+
85
+ account = {}
86
+ print "Twitter username: "; user = gets
87
+ print "Twitter password: "; password = gets
88
+ account["user"] = user.to_s.chomp
89
+ account["password"] = password.to_s.chomp
90
+ config["account"] = account
91
+
92
+ proxy = {}
93
+ print "Proxy host (option): "; proxy_host = gets
94
+ print "Proxy port (option): "; proxy_port = gets
95
+ proxy["host"] = proxy_host.chomp if proxy_host && !proxy_host.chomp.empty?
96
+ proxy["port"] = proxy_port.chomp if proxy_port && !proxy_port.chomp.empty?
97
+ config["proxy"] = proxy unless proxy.empty?
98
+
99
+ Twtr::Config.save(@configfile, config)
100
+ end
101
+
102
+ def parse(args)
103
+ @params = {}
104
+ args << '-h' if args.empty?
105
+ args.options do |opt|
106
+
107
+ opt.on('-v','--version','Show the version number and quit') do |val|
108
+ puts("twtr #{Twtr::VERSION::STRING}")
109
+ end
110
+
111
+ opt.on('-h','--help','Show this help message and quit.') do |val|
112
+ show_help(opt)
113
+ end
114
+
115
+ opt.on('-c','--count=number', 'Display number statuses.') do |val|
116
+ @params.merge!({:count => val})
117
+ @display_count = val.to_i
118
+ end
119
+
120
+ opt.on('-i','--id=userid','The ID or screen name of the user.') do |val|
121
+ @params.merge!({:id => val})
122
+ end
123
+
124
+ opt.on('-m','--message=message','Post message.') do |val|
125
+ @display_count ||= COUNT_WITH_UPDATE
126
+ @params.merge!({:source => "twtr", :status => val.toutf8})
127
+ end
128
+
129
+ opt.on('-p', '--page=number',"Gets the 20 next statuses.") do |val|
130
+ @params.merge!({:page => val.to_i})
131
+ end
132
+
133
+ opt.on('-C', '--config=path/to/configfile',"Use another config. (default: #{CONFIG_FILE})") do |val|
134
+ @configfile = val
135
+ end
136
+
137
+ opt.parse!
138
+ end
139
+
140
+ return unless args[0]
141
+ @subcommand = parse_subcommand(args.shift)
142
+ end
143
+
144
+ def parse_subcommand(cmd)
145
+ cmd = cmd.to_sym
146
+ if SUBCOMMANDS.has_key?(cmd)
147
+ @subcommand = SUBCOMMANDS[cmd]
148
+ else
149
+ raise UnknownSubcommandException.new("Unkown Subcommand [#{cmd}]. Please type 'twtr -h'.")
150
+ end
151
+ end
152
+
153
+ def show_help(opt)
154
+ puts "\n#{Twtr::DESCRIPTION}\n#{opt}"
155
+ end
156
+
157
+ def show_status(source)
158
+ @display_count ||= DEFAULT_DISPLAY_COUNT
159
+ doc = REXML::Document.new(source)
160
+ return if(!doc || !doc.elements['statuses'])
161
+ count = 0
162
+ doc.elements['statuses'].each_element do |e|
163
+ msg = e.elements['user/screen_name'].text + ': ' + e.elements['text'].text
164
+ msg = msg.tosjis if Twtr.is_win?
165
+ print "#{msg}\n"
166
+ break if((count+=1) >= @display_count)
167
+ end
168
+ puts ""
169
+ end
170
+
171
+ end
172
+ end