twat 0.6.3 → 0.9.2
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/.rvmrc +1 -1
- data/.travis.yml +6 -0
- data/Gemfile +1 -4
- data/Gemfile.lock +43 -23
- data/Gemfile.travis +12 -0
- data/Rakefile +9 -0
- data/TODO +4 -1
- data/lib/twat.rb +30 -26
- data/lib/twat/argparse.rb +36 -79
- data/lib/twat/config.rb +22 -34
- data/lib/twat/endpoint.rb +11 -5
- data/lib/twat/endpoints/base.rb +39 -0
- data/lib/twat/endpoints/identica.rb +5 -1
- data/lib/twat/endpoints/twitter.rb +5 -1
- data/lib/twat/exceptions.rb +93 -46
- data/lib/twat/follow_mixin.rb +134 -0
- data/lib/twat/options.rb +28 -12
- data/lib/twat/subcommand.rb +34 -0
- data/lib/twat/subcommands/add.rb +17 -0
- data/lib/twat/subcommands/base.rb +122 -0
- data/lib/twat/subcommands/config.rb +15 -0
- data/lib/twat/subcommands/delete.rb +24 -0
- data/lib/twat/subcommands/finger.rb +23 -0
- data/lib/twat/subcommands/follow.rb +18 -0
- data/lib/twat/subcommands/follow_tag.rb +19 -0
- data/lib/twat/subcommands/list.rb +17 -0
- data/lib/twat/subcommands/mentions.rb +20 -0
- data/lib/twat/subcommands/set.rb +19 -0
- data/lib/twat/subcommands/track.rb +33 -0
- data/lib/twat/subcommands/update.rb +21 -0
- data/lib/twat/subcommands/update_config.rb +16 -0
- data/lib/twat/subcommands/version.rb +14 -0
- data/lib/twat/twatopt.rb +0 -0
- data/lib/twat/tweetstack.rb +38 -0
- data/lib/twat/version.rb +7 -0
- data/man/twat.1 +8 -5
- data/spec/argparse_spec.rb +48 -0
- data/spec/helpers/environment.rb +47 -0
- data/spec/helpers/fileutils.rb +18 -0
- data/spec/helpers/fixtures/core.rb +30 -0
- data/spec/helpers/fixtures/migrations.rb +13 -0
- data/spec/helpers/oauth.rb +15 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/subcommands/add_spec.rb +61 -0
- data/spec/subcommands/config_spec.rb +13 -0
- data/spec/subcommands/delete_spec.rb +12 -0
- data/spec/subcommands/finger_spec.rb +41 -0
- data/spec/subcommands/follow_spec.rb +12 -0
- data/spec/subcommands/follow_tag_spec.rb +52 -0
- data/spec/subcommands/list_spec.rb +8 -0
- data/spec/subcommands/mentions_spec.rb +24 -0
- data/spec/subcommands/set_spec.rb +126 -0
- data/spec/subcommands/track_spec.rb +23 -0
- data/spec/subcommands/update_config_spec.rb +23 -0
- data/spec/subcommands/update_spec.rb +12 -0
- data/spec/subcommands/version_spec.rb +12 -0
- data/spec/twat_cli_spec.rb +102 -0
- data/spec/twat_spec.rb +12 -0
- data/twat.gemspec +6 -2
- metadata +135 -22
- data/lib/twat/actions.rb +0 -85
- data/lib/twat/actions/add.rb +0 -36
- data/lib/twat/actions/delete.rb +0 -14
- data/lib/twat/actions/follow.rb +0 -148
- data/lib/twat/actions/follow_user.rb +0 -11
- data/lib/twat/actions/setoption.rb +0 -14
- data/lib/twat/actions/show.rb +0 -12
- data/lib/twat/actions/tweet.rb +0 -14
- data/lib/twat/actions/updateconfig.rb +0 -9
- data/lib/twat/actions/user_feed.rb +0 -17
- data/lib/twat/actions/version.rb +0 -9
data/lib/twat/version.rb
ADDED
data/man/twat.1
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
.TH twat 1 "
|
1
|
+
.TH twat 1 "February 2012" "Rich Healey" ""
|
2
2
|
.SH NAME
|
3
3
|
twat \- a cli/ruby interface to twitter.
|
4
4
|
.SH SYNOPSIS
|
5
|
-
.B twat [-n account]
|
5
|
+
.B twat [-n account] [follow|finger|config|add|delete|set|version]
|
6
6
|
.B twat [-n account] tweet goes here
|
7
7
|
.SH DESCRIPTION
|
8
8
|
.B twat
|
9
9
|
gives a simple interface to twitter from the command line.
|
10
10
|
.SH USAGE
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
Configuration can be initially generated with
|
12
|
+
.IP twat config
|
13
|
+
and extended after this point with
|
14
|
+
.IP twat add ACCOUNTNAME
|
15
|
+
tweeting is achieved with
|
16
|
+
.IP twat tweet goes here
|
14
17
|
.SH OPTIONS
|
15
18
|
.IP -n account
|
16
19
|
Specify which account to connect with. If not specified, twat searches your
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
["-n", "--account"].each do |flag|
|
6
|
+
it "Should respect the #{flag} flag" do #{{{
|
7
|
+
with_config(Fixtures::multiuser_config) do
|
8
|
+
|
9
|
+
set_argv [flag, "secondAccount"]
|
10
|
+
|
11
|
+
$args = ::Twat::Args.new
|
12
|
+
conf = ::Twat::Config.new
|
13
|
+
|
14
|
+
conf.account.should == Fixtures::multiuser_config[:accounts][:secondAccount]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end #}}}
|
18
|
+
|
19
|
+
["-h", "--help"].each do |flag|
|
20
|
+
it "Should print help and bail on the #{flag} flag" do #{{{
|
21
|
+
set_argv [flag]
|
22
|
+
|
23
|
+
STDOUT.expects(:puts) # Getting the exact usage string TODO
|
24
|
+
lambda { args = ::Twat::Args.new }.should raise_error SystemExit
|
25
|
+
end #}}}
|
26
|
+
end
|
27
|
+
|
28
|
+
["-v", "--version"].each do |flag|
|
29
|
+
it "Should print the version and exit on #{flag}" do #{{{
|
30
|
+
set_argv [flag]
|
31
|
+
|
32
|
+
STDOUT.expects(:puts).with("twat #{::Twat::VERSION}")
|
33
|
+
lambda { args = ::Twat::Args.new }.should raise_error SystemExit
|
34
|
+
|
35
|
+
end #}}}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "Should print a nice error message when called with a nonexistant account" do #{{{
|
39
|
+
with_config(Fixtures::multiuser_config) do
|
40
|
+
|
41
|
+
set_argv ["-n", "nonexistantaccount", "rawr", "update"]
|
42
|
+
|
43
|
+
STDOUT.expects(:puts).with(Twat::Exceptions::NoSuchAccount.new.msg)
|
44
|
+
Twat::Twat.new.cli_run
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
def set_argv(ary)
|
2
|
+
while ARGV.length > 0
|
3
|
+
ARGV.pop
|
4
|
+
end
|
5
|
+
|
6
|
+
ary.each { |e| ARGV << e }
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_env(pairs)
|
10
|
+
orig = {}
|
11
|
+
begin
|
12
|
+
pairs.each do |k, v|
|
13
|
+
# TODO Check what happens when unsetting keys
|
14
|
+
orig[k] = ENV[k]
|
15
|
+
ENV[k] = v
|
16
|
+
end
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
orig.each do |k, v|
|
20
|
+
ENV[k] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_config(cfg)
|
26
|
+
FileUtils.mktemp do |dir|
|
27
|
+
set_env('TWAT_CONFIG' => "#{dir}/twatrc") do
|
28
|
+
File.open("#{dir}/twatrc", 'w') do |conf|
|
29
|
+
conf.chmod(0600)
|
30
|
+
conf.puts(cfg.to_yaml)
|
31
|
+
end
|
32
|
+
|
33
|
+
yield
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_no_config
|
40
|
+
FileUtils.mktemp do |dir|
|
41
|
+
set_env('TWAT_CONFIG' => "#{dir}/twatrc") do
|
42
|
+
|
43
|
+
yield
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'mktemp'
|
2
|
+
module FileUtils extend self
|
3
|
+
|
4
|
+
include MkTemp
|
5
|
+
|
6
|
+
# Shamelessly poached from homebrew
|
7
|
+
def mktemp(opts={})
|
8
|
+
tmp_prefix = ENV['TWAT_TEMP'] || Dir.pwd
|
9
|
+
tmp=Pathname.new MkTemp.mktempdir("#{tmp_prefix}/twat_spec-XXXX")
|
10
|
+
raise "Couldn't create build sandbox" if not tmp.directory?
|
11
|
+
begin
|
12
|
+
yield tmp
|
13
|
+
ensure
|
14
|
+
tmp.rmtree unless opts[:clean] == false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Fixtures
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def multiuser_config
|
5
|
+
{ accounts: {
|
6
|
+
:rich0H =>
|
7
|
+
{ oauth_token: "rich0h's token",
|
8
|
+
oauth_token_secret: "rich0H's secret",
|
9
|
+
endpoint: :twitter
|
10
|
+
},
|
11
|
+
:secondAccount =>
|
12
|
+
{ oauth_token: "secondAccount's token",
|
13
|
+
oauth_token_secret: "secondAccount's secret",
|
14
|
+
endpoint: :twitter
|
15
|
+
}
|
16
|
+
},
|
17
|
+
:default => :rich0H
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_config
|
22
|
+
{ accounts: {
|
23
|
+
:rich0H =>
|
24
|
+
{ oauth_token: "I'mtotallyatokenbrah",
|
25
|
+
oauth_token_secret: "I'mtotallyasecretbrah",
|
26
|
+
endpoint: :twitter
|
27
|
+
} } }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
STUB_URL = "url"
|
2
|
+
STUB_PIN = "1234"
|
3
|
+
def mock_request_token
|
4
|
+
t = mock()
|
5
|
+
t.expects(:authorize_url).returns(STUB_URL)
|
6
|
+
t.expects(:get_access_token).with(oauth_verifier: STUB_PIN).returns(mock_access_token)
|
7
|
+
return t
|
8
|
+
end
|
9
|
+
|
10
|
+
def mock_access_token
|
11
|
+
t = mock()
|
12
|
+
t.expects(:token).returns("I'mtotallyatokenbrah")
|
13
|
+
t.expects(:secret).returns("I'mtotallyasecretbrah")
|
14
|
+
return t
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should bail if add is called without an argument" do #{{{
|
6
|
+
set_argv ["add"]
|
7
|
+
STDOUT.expects(:puts).with(Twat::Subcommands::Add.usage)
|
8
|
+
|
9
|
+
lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
10
|
+
end #}}}
|
11
|
+
|
12
|
+
it "Should create a config file if one does not already exist" do #{{{
|
13
|
+
FileUtils.mktemp do |dir|
|
14
|
+
set_env('TWAT_CONFIG' => "#{dir}/twatrc") do
|
15
|
+
# stub out the io
|
16
|
+
|
17
|
+
STDOUT.expects(:puts).with("Please authenticate the application at #{STUB_URL}, then enter pin")
|
18
|
+
STDIN.expects(:gets).returns(STUB_PIN)
|
19
|
+
|
20
|
+
# Stub out any oauth calls that talk externally
|
21
|
+
|
22
|
+
OAuth::Consumer.any_instance.expects(:get_request_token).returns(mock_request_token)
|
23
|
+
|
24
|
+
set_argv ["add", "rich0H"]
|
25
|
+
|
26
|
+
Twat::Twat.new.cli_run
|
27
|
+
|
28
|
+
YAML.load_file(ENV['TWAT_CONFIG']).should == Fixtures::valid_config
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end #}}}
|
32
|
+
|
33
|
+
it "Should call the twitter endpoint if specified" do #{{{
|
34
|
+
Twat::Endpoints::Twitter.any_instance.expects(:authorize_account)
|
35
|
+
|
36
|
+
set_argv ["--endpoint", "twitter", "add", "rich0H"]
|
37
|
+
Twat::Twat.new.cli_run
|
38
|
+
end #}}}
|
39
|
+
|
40
|
+
it "Should call the identi.ca endpoint if specified" do #{{{
|
41
|
+
Twat::Endpoints::Identica.any_instance.expects(:authorize_account)
|
42
|
+
|
43
|
+
set_argv ["--endpoint", "identi.ca", "add", "rich0H"]
|
44
|
+
Twat::Twat.new.cli_run
|
45
|
+
end #}}}
|
46
|
+
|
47
|
+
it "Should call the twitter endpoint by default" do #{{{
|
48
|
+
Twat::Endpoints::Twitter.any_instance.expects(:authorize_account)
|
49
|
+
|
50
|
+
set_argv ["add", "rich0H"]
|
51
|
+
Twat::Twat.new.cli_run
|
52
|
+
end #}}}
|
53
|
+
|
54
|
+
it "Should fail if asked for an invalid endpoint" do #{{{
|
55
|
+
STDOUT.expects(:puts).with(Twat::Exceptions::NoSuchEndpoint.new.msg)
|
56
|
+
|
57
|
+
set_argv ["--endpoint", "rawk", "add", "rich0H"]
|
58
|
+
Twat::Twat.new.cli_run
|
59
|
+
end #}}}
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should bail if config already exists" do #{{{
|
6
|
+
with_config(Fixtures::multiuser_config) do
|
7
|
+
STDOUT.expects(:puts).with(Twat::Exceptions::AlreadyConfigured.new.msg)
|
8
|
+
set_argv ["config"]
|
9
|
+
Twat::Twat.new.cli_run
|
10
|
+
end
|
11
|
+
end #}}}
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should bail if delete is called without an argument" do #{{{
|
6
|
+
set_argv ["delete"]
|
7
|
+
STDOUT.expects(:puts).with(Twat::Subcommands::Delete.usage)
|
8
|
+
|
9
|
+
lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
10
|
+
end #}}}
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should bail if finger is called without an argument" do #{{{
|
6
|
+
with_config(Fixtures::multiuser_config) do
|
7
|
+
set_argv ["finger"]
|
8
|
+
STDOUT.expects(:puts).with(Twat::Subcommands::Finger.usage)
|
9
|
+
|
10
|
+
lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
11
|
+
end
|
12
|
+
end #}}}
|
13
|
+
|
14
|
+
it "Should retrieve a tweet for user if called with only a user" do #{{{
|
15
|
+
with_config(Fixtures::multiuser_config) do
|
16
|
+
tweet = mock()
|
17
|
+
tweet.expects(:each).yields(tweet)
|
18
|
+
Twitter.expects(:user_timeline).with("hanke", :count => 1).returns(tweet)
|
19
|
+
Twat::Subcommands::Finger.any_instance.expects(:format).with(tweet)
|
20
|
+
|
21
|
+
set_argv ["finger", "hanke"]
|
22
|
+
|
23
|
+
STDOUT.expects(:puts)
|
24
|
+
Twat::Twat.new.cli_run
|
25
|
+
end
|
26
|
+
end #}}}
|
27
|
+
|
28
|
+
it "Should retrieve n tweets for user if invoked with count" do #{{{
|
29
|
+
with_config(Fixtures::multiuser_config) do
|
30
|
+
tweet = mock()
|
31
|
+
Twitter.expects(:user_timeline).with("hanke", :count => 3).returns([tweet, tweet, tweet])
|
32
|
+
Twat::Subcommands::Finger.any_instance.expects(:format).with(tweet).times(3)
|
33
|
+
|
34
|
+
set_argv ["finger", "hanke", "3"]
|
35
|
+
|
36
|
+
STDOUT.expects(:puts).times(3)
|
37
|
+
Twat::Twat.new.cli_run
|
38
|
+
end
|
39
|
+
end #}}}
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should bail if follow is called without an argument" do #{{{
|
6
|
+
set_argv ["follow"]
|
7
|
+
STDOUT.expects(:puts).with(Twat::Subcommands::Follow.usage)
|
8
|
+
|
9
|
+
lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
10
|
+
end #}}}
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should search home_timeline when called sans args" do #{{{
|
6
|
+
with_config(Fixtures::multiuser_config) do
|
7
|
+
Twitter.expects(:home_timeline)
|
8
|
+
Twat::Subcommands::FollowTag.any_instance.expects(:untested).returns(false).at_least_once
|
9
|
+
set_argv []
|
10
|
+
|
11
|
+
# lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
12
|
+
Twat::Twat.new.cli_run
|
13
|
+
end
|
14
|
+
end #}}}
|
15
|
+
|
16
|
+
it "Should search home_timeline when called as follow_tag" do #{{{
|
17
|
+
with_config(Fixtures::multiuser_config) do
|
18
|
+
Twitter.expects(:home_timeline)
|
19
|
+
Twat::Subcommands::FollowTag.any_instance.expects(:untested).returns(false).at_least_once
|
20
|
+
set_argv ["follow_tag"]
|
21
|
+
|
22
|
+
# lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
23
|
+
Twat::Twat.new.cli_run
|
24
|
+
end
|
25
|
+
end #}}}
|
26
|
+
|
27
|
+
it "Should call search with the argument if called with one" do #{{{
|
28
|
+
with_config(Fixtures::multiuser_config) do
|
29
|
+
mock_opts = mock()
|
30
|
+
Twitter.expects(:search).with("#hackmelb", count: 5)
|
31
|
+
Twat::Subcommands::FollowTag.any_instance.expects(:untested).returns(false).at_least_once
|
32
|
+
set_argv ["follow_tag", "#hackmelb"]
|
33
|
+
|
34
|
+
# lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
35
|
+
Twat::Twat.new.cli_run
|
36
|
+
end
|
37
|
+
end #}}}
|
38
|
+
|
39
|
+
it "Should cat together all commandline args" do #{{{
|
40
|
+
with_config(Fixtures::multiuser_config) do
|
41
|
+
mock_opts = mock()
|
42
|
+
Twitter.expects(:search).with("#hackmelb richo", count: 5)
|
43
|
+
Twat::Subcommands::FollowTag.any_instance.expects(:untested).returns(false).at_least_once
|
44
|
+
set_argv ["follow_tag", "#hackmelb", "richo"]
|
45
|
+
|
46
|
+
# lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
47
|
+
Twat::Twat.new.cli_run
|
48
|
+
end
|
49
|
+
end #}}}
|
50
|
+
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Twat do
|
4
|
+
|
5
|
+
it "Should search recent mentions" do #{{{
|
6
|
+
with_config(Fixtures::multiuser_config) do
|
7
|
+
Twitter.expects(:mentions)
|
8
|
+
Twat::Subcommands::Mentions.any_instance.expects(:untested).returns(false).at_least_once
|
9
|
+
set_argv ["mentions"]
|
10
|
+
|
11
|
+
Twat::Twat.new.cli_run
|
12
|
+
end
|
13
|
+
end #}}}
|
14
|
+
|
15
|
+
it "Should bail if called with arguments" do #{{{
|
16
|
+
with_config(Fixtures::multiuser_config) do
|
17
|
+
STDOUT.expects(:puts).with(Twat::Subcommands::Mentions.usage)
|
18
|
+
set_argv ["mentions", "rawr"]
|
19
|
+
|
20
|
+
lambda { Twat::Twat.new.cli_run }.should raise_error SystemExit
|
21
|
+
end
|
22
|
+
end #}}}
|
23
|
+
|
24
|
+
end
|