ivanvc-pft 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.textile +25 -0
- data/bin/pft +64 -0
- data/lib/pft/base.rb +107 -0
- data/lib/pft/oauth.rb +44 -0
- data/lib/pft/tiny_url.rb +14 -0
- data/lib/pft.rb +9 -0
- data/spec/base_spec.rb +59 -0
- data/spec/oauth_spec.rb +24 -0
- data/spec/tiny_url_spec.rb +23 -0
- metadata +93 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Iván Valdés
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
h1. pft!
|
2
|
+
|
3
|
+
A command line twitter client. It's intended to be as powerful as donkey.
|
4
|
+
|
5
|
+
h2. Requirements
|
6
|
+
|
7
|
+
* ruby
|
8
|
+
* rubyems
|
9
|
+
* Included in the gem:
|
10
|
+
** twitter
|
11
|
+
** choice (0.1.3.1)
|
12
|
+
** highline
|
13
|
+
** rspec
|
14
|
+
|
15
|
+
h2. Installation
|
16
|
+
|
17
|
+
Just hit
|
18
|
+
|
19
|
+
@gem install ivanvc-pft --source http://gems.github.com/@
|
20
|
+
|
21
|
+
Then you're ready to go. You should have the pft binary.
|
22
|
+
|
23
|
+
h2. Help
|
24
|
+
|
25
|
+
Use @pft -@ or @pft --help@
|
data/bin/pft
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
|
+
|
4
|
+
require 'pft'
|
5
|
+
require 'choice'
|
6
|
+
|
7
|
+
Choice.options do
|
8
|
+
banner "Usage: #{File.basename(__FILE__)} [-adhrt] [message]"
|
9
|
+
|
10
|
+
header ''
|
11
|
+
header 'Configuration options:'
|
12
|
+
|
13
|
+
option :authorize do
|
14
|
+
short '-a'
|
15
|
+
long '--authorize'
|
16
|
+
desc "Associate your twitter account using OAuth"
|
17
|
+
default false
|
18
|
+
end
|
19
|
+
|
20
|
+
separator ''
|
21
|
+
separator 'Tweet options:'
|
22
|
+
|
23
|
+
option :dm do
|
24
|
+
short '-d'
|
25
|
+
long '--dm=USERNAME'
|
26
|
+
desc "Send a direct message to username"
|
27
|
+
default nil
|
28
|
+
end
|
29
|
+
|
30
|
+
option :reply do
|
31
|
+
short '-r'
|
32
|
+
long '--reply=USERNAME'
|
33
|
+
desc "Send a reply to username's last tweet"
|
34
|
+
default nil
|
35
|
+
end
|
36
|
+
|
37
|
+
option :rt do
|
38
|
+
short '-t'
|
39
|
+
long '--rt=USERNAME'
|
40
|
+
desc "Post a retweet of username's last tweet"
|
41
|
+
default nil
|
42
|
+
end
|
43
|
+
|
44
|
+
separator ''
|
45
|
+
separator 'Common options: '
|
46
|
+
|
47
|
+
option :help do
|
48
|
+
long '--help'
|
49
|
+
desc 'Show this message'
|
50
|
+
end
|
51
|
+
|
52
|
+
option :version do
|
53
|
+
short '-v'
|
54
|
+
long '--version'
|
55
|
+
desc 'Show version'
|
56
|
+
action do
|
57
|
+
puts "#{File.basename(__FILE__)} v#{Pft::Base.version}"
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Pft::Base.tweet(Choice.choices, Choice.rest) rescue puts $!
|
64
|
+
#CIJoe::Server.start(options[:host], options[:port], Choice.rest[0])
|
data/lib/pft/base.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
module Pft
|
2
|
+
class Base
|
3
|
+
attr_accessor :oauth, :message, :configuration
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
options = args.pop || {}
|
7
|
+
@oauth = Oauth.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def reply_to(user, message)
|
11
|
+
user = get_user(user)
|
12
|
+
@oauth.client.update("@#{user.screen_name} #{message}", :in_reply_to_status_id => user.status.id)
|
13
|
+
message_for('reply', user)
|
14
|
+
end
|
15
|
+
|
16
|
+
def retweet(user)
|
17
|
+
user = get_user(user)
|
18
|
+
@oauth.client.update("RT @#{user.screen_name} #{user.status.text}")
|
19
|
+
message_for('retweet', user)
|
20
|
+
end
|
21
|
+
|
22
|
+
def direct_message(user, message)
|
23
|
+
user = get_user(user).screen_name
|
24
|
+
@oauth.client.direct_message_create(user, message)
|
25
|
+
message_for('direct message', user)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_user(user)
|
29
|
+
user = @oauth.client.user(user) rescue false
|
30
|
+
if !user || !user.status
|
31
|
+
raise "User or last tweet not found"
|
32
|
+
end
|
33
|
+
user
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_urls(message)
|
37
|
+
return message unless message.=~(/(?:http:\/\/|ftp:\/\/|https:\/\/|www\.|ftp\.[\w]+)(?:[\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])/)
|
38
|
+
parsed_message = ""
|
39
|
+
message.each(" ") do |word|
|
40
|
+
if word.=~(/(?:http:\/\/|ftp:\/\/|https:\/\/|www\.|ftp\.[\w]+)(?:[\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])/)
|
41
|
+
word = "#{TinyUrl.compact(word.delete(' '))} "
|
42
|
+
end
|
43
|
+
parsed_message << word
|
44
|
+
end
|
45
|
+
parsed_message
|
46
|
+
end
|
47
|
+
|
48
|
+
def message_for(type, user = nil)
|
49
|
+
"pft! successfully sent a #{type}#{" to #{user}" if user}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.tweet(*options)
|
53
|
+
base = self.new
|
54
|
+
message = options.pop || []
|
55
|
+
message = base.parse_urls(message.join(" "))
|
56
|
+
options = options.pop || {}
|
57
|
+
|
58
|
+
if options[:authorize]
|
59
|
+
base.oauth.authorize
|
60
|
+
elsif options[:reply]
|
61
|
+
puts base.reply_to(options[:reply], message)
|
62
|
+
elsif options[:rt]
|
63
|
+
puts base.retweet(options[:rt])
|
64
|
+
elsif options[:dm]
|
65
|
+
puts base.direct_message(options[:dm], message)
|
66
|
+
elsif message.size > 0
|
67
|
+
base.oauth.client.update(message)
|
68
|
+
puts base.message_for('tweet')
|
69
|
+
else
|
70
|
+
raise "Please provide a message"
|
71
|
+
# class HighLine
|
72
|
+
# public :get_character
|
73
|
+
# end
|
74
|
+
# input = HighLine.new
|
75
|
+
# while (c = input.get_character) != ?\e do
|
76
|
+
# puts "You typed #{c.chr.inspect}"
|
77
|
+
# end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.version
|
82
|
+
"0.1"
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.options(file=nil)
|
86
|
+
@@options ||= begin
|
87
|
+
@@file = File.expand_path(file || "~/.pftrc")
|
88
|
+
configuration = []
|
89
|
+
File.open(@@file).each do |line|
|
90
|
+
configuration << [$1.to_sym, $2.chomp] if line =~ /(\w+)=(.+)/
|
91
|
+
end rescue nil
|
92
|
+
Hash[*configuration.flatten]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.write_options
|
97
|
+
File.open(@@file, "w") do |f|
|
98
|
+
options.each { |key, value| f.puts "#{key}=#{value}" }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.input
|
103
|
+
@@input ||= IO.new(2,"r")
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
data/lib/pft/oauth.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Pft
|
2
|
+
class Oauth
|
3
|
+
attr_accessor :key, :secret
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
@key = "Imv819Ww77451xPcQ4Jxaw"
|
7
|
+
@secret = "MIcYaAqL62S2L3nLSasSu4YjMo1Mydeh46ItULi5Tc"
|
8
|
+
end
|
9
|
+
|
10
|
+
def client
|
11
|
+
@client ||= begin
|
12
|
+
client_token = Base.options[:token]
|
13
|
+
client_secret = Base.options[:secret]
|
14
|
+
if !client_secret || !client_token
|
15
|
+
raise "Please run it with -a"
|
16
|
+
end
|
17
|
+
oauth = Twitter::OAuth.new(@key, @secret)
|
18
|
+
oauth.authorize_from_access(client_token, client_secret)
|
19
|
+
Twitter::Base.new(oauth)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def authorize
|
24
|
+
puts "We are going to launch the brower, do you want to continue? [Y/n]"
|
25
|
+
authorize = Base.input.gets.chomp
|
26
|
+
raise "Cannot authorize the account" if authorize.downcase == "n"
|
27
|
+
consumer = OAuth::Consumer.new(@key, @secret, {:site => 'http://twitter.com'})
|
28
|
+
request_token = consumer.get_request_token
|
29
|
+
system "open #{request_token.authorize_url}"
|
30
|
+
puts "Please enter the provided PIN:"
|
31
|
+
pin = Base.input.gets.chomp
|
32
|
+
access_token = request_token.get_access_token(:oauth_verifier => pin) rescue false
|
33
|
+
if access_token
|
34
|
+
Base.options[:token] = access_token.token
|
35
|
+
Base.options[:secret] = access_token.secret
|
36
|
+
Base.write_options
|
37
|
+
puts "Great we're done! You can now ridicolous tweet from pft!@"
|
38
|
+
else
|
39
|
+
raise "The PIN provided is incorrect"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/pft/tiny_url.rb
ADDED
data/lib/pft.rb
ADDED
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/pft.rb'
|
2
|
+
|
3
|
+
describe "Pft::Base" do
|
4
|
+
|
5
|
+
it "should raise an error with no arguments" do
|
6
|
+
lambda { Pft::Base.tweet.should_not }.should raise_error("Please provide a message")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond with the version" do
|
10
|
+
Pft::Base.version
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should open not default configuration file" do
|
14
|
+
File.stub!(:open).and_return(["token=test"])
|
15
|
+
Pft::Base.options("blah")[:token].should eql("test")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "Pft::Base instance" do
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
@pft = Pft::Base.new
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a oauth client" do
|
27
|
+
@pft.oauth.should_not be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "handling no such user error" do
|
31
|
+
|
32
|
+
it "should raise it if the user is invalid when posting a reply" do
|
33
|
+
lambda { @pft.reply_to('123123wjas8duas8d', 'blah') }.should raise_error("User or last tweet not found")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise it if the user is invalid when posting a direct message" do
|
37
|
+
lambda { @pft.direct_message('123123wjas8duas8d', 'blah') }.should raise_error("User or last tweet not found")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should raise it if the user is invalid when posting a retweet" do
|
41
|
+
lambda { @pft.retweet('123123wjas8duas8d') }.should raise_error("User or last tweet not found")
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should print confirmation message" do
|
47
|
+
@pft.message_for('test').should == "pft! successfully sent a test"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should print confirmation message with an user" do
|
51
|
+
@pft.message_for('test', 'testo').should == "pft! successfully sent a test to testo"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should handle urls" do
|
55
|
+
original_text = "testing http://www.example.com/blaaaaaaaaaaaaaaaaaaaaaaaah a"
|
56
|
+
@pft.parse_urls(original_text).should_not == original_text
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/spec/oauth_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/pft.rb'
|
2
|
+
|
3
|
+
describe "Pft::OAuth" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@pft_oauth = Pft::Oauth.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have a key and a secret" do
|
10
|
+
@pft_oauth.key.should_not be_nil
|
11
|
+
@pft_oauth.secret.should_not be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should ask you to allow oauth client" do
|
15
|
+
Pft::Base.stub!(:options).and_return({})
|
16
|
+
lambda { @pft_oauth.client }.should raise_error("Please run it with -a")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not ask you to allow oauth client" do
|
20
|
+
Pft::Base.stub!(:options).and_return({:token => "aaa", :secret => "bbb"})
|
21
|
+
lambda { @pft_oauth.client }.should_not raise_error("Please run it with -a")
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/pft.rb'
|
2
|
+
|
3
|
+
describe "Pft::TinyUrl" do
|
4
|
+
|
5
|
+
it "should shorten one url" do
|
6
|
+
url = "http://example.org/1234567/abcdef/gtr"
|
7
|
+
shorten = Pft::TinyUrl.compact(url)
|
8
|
+
shorten.should_not == url
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should not short one bad formated url" do
|
12
|
+
url = "http://example.org/123334/3 "
|
13
|
+
shorten = Pft::TinyUrl.compact(url)
|
14
|
+
shorten.should == url
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should not short a non url" do
|
18
|
+
url = "test"
|
19
|
+
shorten = Pft::TinyUrl.compact(url)
|
20
|
+
shorten.should == url
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ivanvc-pft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Iv\xC3\xA1n Vald\xC3\xA9s"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-27 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: twitter
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.15
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ivanvc-choice
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.3.1
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: highline
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.5.1
|
44
|
+
version:
|
45
|
+
description: pft is a simple command line twitter client.
|
46
|
+
email: iv@nvald.es
|
47
|
+
executables:
|
48
|
+
- pft
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.textile
|
53
|
+
- LICENSE
|
54
|
+
files:
|
55
|
+
- bin/pft
|
56
|
+
- lib/pft.rb
|
57
|
+
- lib/pft/base.rb
|
58
|
+
- lib/pft/tiny_url.rb
|
59
|
+
- lib/pft/oauth.rb
|
60
|
+
- spec/base_spec.rb
|
61
|
+
- spec/oauth_spec.rb
|
62
|
+
- spec/tiny_url_spec.rb
|
63
|
+
- README.textile
|
64
|
+
- LICENSE
|
65
|
+
has_rdoc: false
|
66
|
+
homepage: http://github.com/ivanvc/pft
|
67
|
+
licenses:
|
68
|
+
post_install_message: pft! this is ridiculous
|
69
|
+
rdoc_options: []
|
70
|
+
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 2
|
91
|
+
summary: pft is a command line twitter client.
|
92
|
+
test_files: []
|
93
|
+
|