tweetwine 0.2.12 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/Gemfile +17 -0
- data/README.md +57 -47
- data/Rakefile +17 -26
- data/bin/tweetwine +11 -12
- data/contrib/tweetwine-completion.bash +2 -3
- data/example/application_behavior_example.rb +173 -0
- data/example/example_helper.rb +44 -28
- data/example/fixture/config.yaml +8 -0
- data/example/fixture/shorten_rubygems.html +5 -0
- data/example/fixture/shorten_rubylang.html +5 -0
- data/example/fixture/update_utf8.json +1 -0
- data/example/fixture/update_with_urls.json +1 -0
- data/example/fixture/{update.json → update_without_urls.json} +0 -0
- data/example/search_statuses_example.rb +49 -16
- data/example/show_followers_example.rb +7 -8
- data/example/show_friends_example.rb +7 -8
- data/example/show_home_example.rb +19 -16
- data/example/show_mentions_example.rb +8 -9
- data/example/show_user_example.rb +16 -13
- data/example/update_status_example.rb +143 -26
- data/example/use_http_proxy_example.rb +40 -20
- data/lib/tweetwine/basic_object.rb +19 -0
- data/lib/tweetwine/character_encoding.rb +59 -0
- data/lib/tweetwine/cli.rb +354 -230
- data/lib/tweetwine/config.rb +65 -0
- data/lib/tweetwine/http.rb +120 -0
- data/lib/tweetwine/oauth.rb +104 -0
- data/lib/tweetwine/obfuscate.rb +21 -0
- data/lib/tweetwine/option_parser.rb +31 -0
- data/lib/tweetwine/promise.rb +39 -0
- data/lib/tweetwine/twitter.rb +211 -0
- data/lib/tweetwine/{io.rb → ui.rb} +30 -21
- data/lib/tweetwine/url_shortener.rb +15 -9
- data/lib/tweetwine/util.rb +30 -15
- data/lib/tweetwine.rb +72 -12
- data/man/tweetwine.7 +43 -69
- data/man/tweetwine.7.ronn +57 -47
- data/test/character_encoding_test.rb +87 -0
- data/test/cli_test.rb +19 -6
- data/test/config_test.rb +244 -0
- data/test/fixture/oauth.rb +21 -0
- data/test/fixture/test_config.yaml +4 -4
- data/test/http_test.rb +199 -0
- data/test/oauth_test.rb +77 -0
- data/test/obfuscate_test.rb +16 -0
- data/test/option_parser_test.rb +60 -0
- data/test/promise_test.rb +56 -0
- data/test/test_helper.rb +76 -8
- data/test/twitter_test.rb +625 -0
- data/test/{io_test.rb → ui_test.rb} +92 -74
- data/test/url_shortener_test.rb +115 -135
- data/test/util_test.rb +136 -85
- data/tweetwine.gemspec +53 -0
- metadata +112 -56
- data/example/show_metadata_example.rb +0 -86
- data/lib/tweetwine/client.rb +0 -187
- data/lib/tweetwine/meta.rb +0 -5
- data/lib/tweetwine/options.rb +0 -24
- data/lib/tweetwine/retrying_http.rb +0 -99
- data/lib/tweetwine/startup_config.rb +0 -50
- data/man/tweetwine.1 +0 -109
- data/man/tweetwine.1.ronn +0 -69
- data/test/client_test.rb +0 -544
- data/test/options_test.rb +0 -45
- data/test/retrying_http_test.rb +0 -147
- data/test/startup_config_test.rb +0 -162
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
=== 0.3.0 released 2010-11-11
|
2
|
+
|
3
|
+
* OAuth for authentication and authorization
|
4
|
+
* Almost complete rewrite of the implementation with a lot of tests
|
5
|
+
* Configurable config file location with <tt>-f</tt> option
|
6
|
+
* Ensure encoding status update in UTF-8
|
7
|
+
|
1
8
|
=== 0.2.12 released 2010-04-17
|
2
9
|
|
3
10
|
* Since this is a command line application, provide documentation as gem
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem "nokogiri", "~> 1.4.3"
|
4
|
+
gem "oauth", "~> 0.4.4"
|
5
|
+
gem "json", ">= 1.0.0", :platforms => [:ruby_18, :jruby]
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "contest", "~> 0.1.2"
|
9
|
+
gem "coulda", "~> 0.6.0"
|
10
|
+
gem "gem-man", "~> 0.2.0"
|
11
|
+
gem "mcmire-matchy", "~> 0.5.2", :require => "matchy"
|
12
|
+
gem "mocha", "= 0.9.8"
|
13
|
+
gem "open4", "~> 1.0.1"
|
14
|
+
gem "ronn", "~> 0.7.3"
|
15
|
+
gem "timecop", "~> 0.3.5"
|
16
|
+
gem "webmock", "~> 1.5.0"
|
17
|
+
end
|
data/README.md
CHANGED
@@ -3,10 +3,13 @@ tweetwine -- a simple Twitter command line agent
|
|
3
3
|
|
4
4
|
## DESCRIPTION
|
5
5
|
|
6
|
-
Tweetwine
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
Tweetwine is designed for checking the latest tweets from the command line
|
7
|
+
quickly.
|
8
|
+
|
9
|
+
The program can show the home timeline of the authenticated user, the latest
|
10
|
+
tweets of friends and followers, and the latest tweets that mention the user.
|
11
|
+
If that's not enough, Tweetwine can search statuses with arbitrary terms and
|
12
|
+
send status updates.
|
10
13
|
|
11
14
|
Features:
|
12
15
|
|
@@ -22,14 +25,14 @@ Install Tweetwine with RubyGems:
|
|
22
25
|
|
23
26
|
$ gem install tweetwine
|
24
27
|
|
25
|
-
The program is
|
28
|
+
The program is tested with Ruby 1.8.7 and 1.9.2.
|
26
29
|
|
27
|
-
The program requires [
|
28
|
-
|
29
|
-
|
30
|
+
The program requires [oauth](http://oauth.rubyforge.org/) gem to be installed.
|
31
|
+
In addition, the program needs [json](http://json.rubyforge.org/) gem on Ruby
|
32
|
+
1.8.
|
30
33
|
|
31
|
-
|
32
|
-
[gem-man](http://github.com/defunkt/gem-man) to see
|
34
|
+
This documentation page is also provided as a manual page. Use
|
35
|
+
[gem-man](http://github.com/defunkt/gem-man) to see it:
|
33
36
|
|
34
37
|
$ gem man tweetwine
|
35
38
|
|
@@ -37,19 +40,7 @@ Documentation is provided as gem man pages. Use
|
|
37
40
|
|
38
41
|
In the command line, run the program by entering
|
39
42
|
|
40
|
-
$ tweetwine [
|
41
|
-
|
42
|
-
The program needs the user's username and password for authentication. This
|
43
|
-
information can be supplied either via a configuration file or as an option
|
44
|
-
(`-a USERNAME:PASSWORD`) to the program. It is recommended to use the former
|
45
|
-
method over the latter.
|
46
|
-
|
47
|
-
The configuration file, in `~/.tweetwine`, is in YAML syntax. The program
|
48
|
-
recognizes the following basic settings:
|
49
|
-
|
50
|
-
username: <your_username>
|
51
|
-
password: <your_password>
|
52
|
-
colors: true|false
|
43
|
+
$ tweetwine [global_options..] [command] [command_options...]
|
53
44
|
|
54
45
|
For all the global options and commands, see:
|
55
46
|
|
@@ -57,46 +48,65 @@ For all the global options and commands, see:
|
|
57
48
|
|
58
49
|
For information about a specific command and its options, enter:
|
59
50
|
|
60
|
-
$ tweetwine help <
|
51
|
+
$ tweetwine help <command>
|
52
|
+
|
53
|
+
In order to use to use the program, you must authorize it to access your
|
54
|
+
account on Twitter. This is done with
|
55
|
+
[OAuth](http://dev.twitter.com/pages/oauth_faq) protocol, and it is required
|
56
|
+
when the program is launched for the first time. After that, Tweetwine
|
57
|
+
remembers the access you granted by storing the access token into
|
58
|
+
`~/.tweetwine`. The file serves as your configuration file.
|
61
59
|
|
62
|
-
|
60
|
+
Because the access token is sensitive information, Tweetwine obfuscates it
|
61
|
+
when storing it into the configuration file. While this prevents simple plain
|
62
|
+
text reading attempts of the access token, it is not secure. You should
|
63
|
+
restrict access to the file only to yourself. If the configuration file does
|
64
|
+
not exist before running the program, Tweetwine sets the file accessible only
|
65
|
+
to you when storing the access token.
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
The configuration file is in YAML syntax. In addition to the OAuth access
|
68
|
+
token, the program recognizes the following settings:
|
69
|
+
|
70
|
+
colors: true|false
|
71
|
+
username: <your_username>
|
72
|
+
|
73
|
+
### URL shortening for a status update
|
74
|
+
|
75
|
+
Before actually sending a new status update, it is possible for the software
|
76
|
+
to shorten the URLs in the tweet by using an external web service. This can be
|
77
|
+
enabled via `shorten_urls` field in the configuration file; for example:
|
67
78
|
|
68
79
|
username: spoonman
|
69
|
-
password: withyourhands
|
70
80
|
colors: true
|
71
81
|
shorten_urls:
|
72
|
-
enable: true
|
73
82
|
service_url: http://is.gd/create.php
|
74
83
|
method: post
|
75
84
|
url_param_name: URL
|
76
85
|
xpath_selector: //input[@id='short_url']/@value
|
86
|
+
disable: false # optional
|
77
87
|
|
78
|
-
The supported methods (in `method`) are `get` and `post`.
|
79
|
-
affects whether parameters are passed as URL query
|
80
|
-
in the HTTP request, respectively. Extra parameters
|
81
|
-
`extra_params`
|
82
|
-
|
83
|
-
The `xpath_selector` is needed to extract the shortened URL from the result.
|
88
|
+
The supported HTTP request methods (in `method` field) are `get` and `post`.
|
89
|
+
The method chosen affects whether parameters are passed as URL query
|
90
|
+
parameters or as payload in the HTTP request, respectively. Extra parameters
|
91
|
+
can be given via `extra_params` field, as a hash.
|
84
92
|
|
85
|
-
|
93
|
+
The `xpath_selector` field is needed to locate the HTML element which contains
|
94
|
+
the shortened URL from the HTTP response.
|
86
95
|
|
87
|
-
|
88
|
-
|
89
|
-
|
96
|
+
URL shortening can be disabled by not defining `shorten_urls` field in the
|
97
|
+
configuration file, or by setting optional field `disable` to true. In order
|
98
|
+
to disable shortening only temporarily, use the command line option
|
99
|
+
`--no-url-shorten`.
|
90
100
|
|
91
|
-
*NOTE:* The use of
|
92
|
-
to be installed.
|
101
|
+
*NOTE:* The use of URL shortening requires [nokogiri](http://nokogiri.org/)
|
102
|
+
gem to be installed.
|
93
103
|
|
94
104
|
### HTTP proxy setting
|
95
105
|
|
96
106
|
If `$http_proxy` environment variable is set, Tweetwine attempts to use the
|
97
|
-
URL in the environment variable as HTTP proxy for
|
98
|
-
|
99
|
-
|
107
|
+
URL in the environment variable as HTTP proxy for its HTTP connections. This
|
108
|
+
setting can be overridden with `--http-proxy` and `--no-http-proxy` command
|
109
|
+
line options.
|
100
110
|
|
101
111
|
### Bash command line completion support
|
102
112
|
|
@@ -115,8 +125,8 @@ snippet to your Bash initialization script (such as `~/.bashrc`):
|
|
115
125
|
|
116
126
|
## COPYRIGHT
|
117
127
|
|
118
|
-
Tweetwine is Copyright (c) 2009-2010 Tuomas Kareinen
|
128
|
+
Tweetwine is Copyright (c) 2009-2010 Tuomas Kareinen.
|
119
129
|
|
120
130
|
## SEE ALSO
|
121
131
|
|
122
|
-
|
132
|
+
<http://github.com/tuomas/tweetwine>
|
data/Rakefile
CHANGED
@@ -4,18 +4,18 @@ require "rake/clean"
|
|
4
4
|
|
5
5
|
$LOAD_PATH.unshift(File.expand_path("../lib/", __FILE__))
|
6
6
|
name = "tweetwine"
|
7
|
-
require
|
7
|
+
require name
|
8
8
|
version = Tweetwine::VERSION.dup
|
9
9
|
|
10
10
|
namespace :gem do
|
11
11
|
CLOBBER.include "#{name}-*.gem"
|
12
12
|
|
13
|
-
file "#{name}.gem"
|
13
|
+
file "#{name}-#{version}.gem" do |f|
|
14
14
|
sh %{gem build #{name}.gemspec}
|
15
15
|
end
|
16
16
|
|
17
17
|
desc "Package the software as a gem"
|
18
|
-
task :build => [:"test:all", "#{name}.gem"]
|
18
|
+
task :build => [:"man:build", :"test:all", "#{name}-#{version}.gem"]
|
19
19
|
|
20
20
|
desc "Install the software as a gem"
|
21
21
|
task :install => :build do
|
@@ -36,37 +36,28 @@ namespace :man do
|
|
36
36
|
sh "ronn -br5 --manual='#{name.capitalize} Manual' --organization='Tuomas Kareinen' man/*.ronn"
|
37
37
|
end
|
38
38
|
|
39
|
-
desc "Show the manual section 1"
|
40
|
-
task :show1 => :build do
|
41
|
-
sh "man man/#{name}.1"
|
42
|
-
end
|
43
|
-
|
44
39
|
desc "Show the manual section 7"
|
45
|
-
task :
|
40
|
+
task :show => :build do
|
46
41
|
sh "man man/#{name}.7"
|
47
42
|
end
|
48
43
|
end
|
49
44
|
|
50
45
|
namespace :test do
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
def create_test_task(type, file_glob, options = {})
|
47
|
+
test_dir = file_glob[%r{(\w+)/}, 1]
|
48
|
+
test_desc = options[:desc] || "Run #{type} tests"
|
49
|
+
includes = (options[:includes] || ['lib', test_dir]).map { |dir| "-I #{dir}" }.join(' ')
|
50
|
+
warn_opt = options[:warn] ? "-w" : ""
|
51
|
+
|
52
|
+
desc test_desc
|
53
|
+
task type do
|
54
|
+
tests = FileList[file_glob].map { |f| "\"#{f[test_dir.size+1 .. -4]}\"" }.join(' ')
|
55
|
+
sh %{bundle exec ruby #{warn_opt} #{includes} -e 'ARGV.each { |f| require f }' #{tests}}
|
56
|
+
end
|
60
57
|
end
|
61
58
|
|
62
|
-
|
63
|
-
|
64
|
-
t.test_files = FileList["example/**/*_example.rb"]
|
65
|
-
t.verbose = true
|
66
|
-
t.warning = false
|
67
|
-
t.ruby_opts << "-rrubygems"
|
68
|
-
t.libs << "example"
|
69
|
-
end
|
59
|
+
create_test_task :unit, 'test/**/*_test.rb', :warn => true
|
60
|
+
create_test_task :example, 'example/**/*_example.rb', :warn => false, :includes => %w{lib test example}, :desc => "Run integration/example tests"
|
70
61
|
|
71
62
|
desc "Run all tests"
|
72
63
|
task :all => [:unit, :example]
|
data/bin/tweetwine
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
EXIT_SIGINT = 6
|
5
|
-
|
6
|
-
trap("INT") do
|
7
|
-
puts "\nAbort"
|
8
|
-
exit(EXIT_SIGINT)
|
9
|
-
end
|
10
|
-
|
11
4
|
require "tweetwine"
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
include Tweetwine
|
6
|
+
|
7
|
+
begin
|
8
|
+
CLI.start ARGV
|
9
|
+
rescue Error => e
|
10
|
+
CLI.ui.error e.message
|
11
|
+
exit e.status_code
|
12
|
+
rescue Interrupt
|
13
|
+
puts "Abort."
|
14
|
+
exit 1
|
15
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
_tweetwine_completion
|
2
|
-
{
|
1
|
+
_tweetwine_completion() {
|
3
2
|
local cur prev cmds gopts
|
4
3
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
5
4
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
6
5
|
cmds="followers friends home mentions search update user"
|
7
|
-
gopts="--
|
6
|
+
gopts="--colors --help --http-proxy --num --no-colors --no-http-proxy --no-url-shorten --page --version"
|
8
7
|
|
9
8
|
case "${prev}" in
|
10
9
|
followers | friends | home | mentions | search | update | user)
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require "example_helper"
|
4
|
+
require "fixture/oauth"
|
5
|
+
|
6
|
+
include Tweetwine::Test::Fixture::OAuth
|
7
|
+
|
8
|
+
Feature "application behavior" do
|
9
|
+
in_order_to "know about the application"
|
10
|
+
as_a "user"
|
11
|
+
i_want_to "see helpful messages"
|
12
|
+
|
13
|
+
%w{-v version ver v}.each do |arg|
|
14
|
+
Scenario "show version with '#{arg}'" do
|
15
|
+
When "I start the application with '#{arg}'" do
|
16
|
+
@status = start_app [arg] do |_, _, stdout|
|
17
|
+
@output = stdout.readlines.join
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Then "the application shows version and exists with success status" do
|
22
|
+
@output.should =~ /\d+\.\d+\.\d+$/
|
23
|
+
@status.exitstatus.should == 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
%w{-h help}.each do |arg|
|
29
|
+
Scenario "show general help with '#{arg}'" do
|
30
|
+
When "I start the application with '#{arg}'" do
|
31
|
+
@status = start_app [arg] do |_, _, stdout|
|
32
|
+
@output = stdout.readlines.join
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Then "the application shows help and exists with success status" do
|
37
|
+
@output.should == <<-END
|
38
|
+
A simple but tasty Twitter agent for command line use, made for fun.
|
39
|
+
|
40
|
+
Usage: #{CLI::EXEC_NAME} [global_options...] [<command>] [command_options...]
|
41
|
+
|
42
|
+
Global options:
|
43
|
+
|
44
|
+
-c, --colors Enable ANSI colors for output.
|
45
|
+
-f, --config <file> Configuration file (default #{CLI::DEFAULT_CONFIG[:config_file]}).
|
46
|
+
-h, --help Show this help and exit.
|
47
|
+
--http-proxy <url> Enable HTTP(S) proxy.
|
48
|
+
--no-colors Disable ANSI colors for output.
|
49
|
+
--no-http-proxy Disable HTTP(S) proxy.
|
50
|
+
--no-url-shorten Disable URL shortening.
|
51
|
+
-n, --num <n> Number of statuses per page (default 20).
|
52
|
+
-p, --page <p> Page number for statuses (default 1).
|
53
|
+
-u, --username <user> User to authenticate (default '#{USER}').
|
54
|
+
-v, --version Show version and exit.
|
55
|
+
|
56
|
+
Commands:
|
57
|
+
|
58
|
+
followers Show authenticated user's followers and their latest tweets.
|
59
|
+
friends Show authenticated user's friends and their latest tweets.
|
60
|
+
help Show help and exit. Try it with <command> argument.
|
61
|
+
home Show authenticated user's home timeline (the default command).
|
62
|
+
mentions Show latest tweets that mention or are replies to the authenticated user.
|
63
|
+
search Search latest public tweets.
|
64
|
+
update Send new tweet.
|
65
|
+
user Show user's timeline.
|
66
|
+
version Show program version and exit.
|
67
|
+
END
|
68
|
+
@status.exitstatus.should == 0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
%w{followers friends help home mentions search update user version}.each do |command|
|
73
|
+
Scenario "show command specific help with '#{arg} #{command}'" do
|
74
|
+
When "I start the application with '#{arg} #{command}'" do
|
75
|
+
@status = start_app [arg, command] do |_, _, stdout|
|
76
|
+
@output = stdout.readlines.join
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Then "the application shows help about the command and exits with success status" do
|
81
|
+
cmd_class = Tweetwine::CLI.const_get("#{command.capitalize}Command")
|
82
|
+
expected_about = cmd_class.about
|
83
|
+
expected_usage = "Usage: tweetwine #{command} #{cmd_class.usage}".strip
|
84
|
+
@output.should == <<-END
|
85
|
+
#{expected_about}
|
86
|
+
|
87
|
+
#{expected_usage}
|
88
|
+
END
|
89
|
+
@status.exitstatus.should == 0
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
Scenario "show help command's help with '#{arg} <invalid_command>'" do
|
95
|
+
When "I start the application with '#{arg} invalid'" do
|
96
|
+
@status = start_app [arg, 'invalid'] do |_, _, stdout, stderr|
|
97
|
+
@stdout = stdout.readlines.join
|
98
|
+
@stderr = stderr.readlines.join
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
Then "the application shows help about help command and exits with failure status" do
|
103
|
+
@stderr.should == "ERROR: unknown command: invalid\n\n"
|
104
|
+
@stdout.should == <<-END
|
105
|
+
Show help and exit. Try it with <command> argument.
|
106
|
+
|
107
|
+
Usage: tweetwine help [<command>]
|
108
|
+
|
109
|
+
If <command> is given, show specific help about that command. If no
|
110
|
+
<command> is given, show general help.
|
111
|
+
END
|
112
|
+
@status.exitstatus.should == CommandLineError.status_code
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
Scenario "show error and exit with failure status when invalid option" do
|
118
|
+
When "I start the application with invalid option" do
|
119
|
+
@status = start_app %w{-X} do |_, _, _, stderr|
|
120
|
+
@output = stderr.readlines.join.chomp
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
Then "the application exists with failure status" do
|
125
|
+
@output.should == 'ERROR: invalid option: -X'
|
126
|
+
@status.exitstatus.should == CommandLineError.status_code
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
Scenario "show error and exit with failure status when invalid command" do
|
131
|
+
When "I start the application with invalid command" do
|
132
|
+
@status = start_app %w{invalid} do |_, _, _, stderr|
|
133
|
+
@output = stderr.readlines.join.chomp
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
Then "the application exists with failure status" do
|
138
|
+
@output.should == 'ERROR: unknown command: invalid'
|
139
|
+
@status.exitstatus.should == UnknownCommandError.status_code
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
Scenario "authorize user with OAuth and save access token" do
|
144
|
+
When "I start the application with 'home' command and the command fails due to me being unauthorized" do
|
145
|
+
@command_url = "https://api.twitter.com/1/statuses/home_timeline.json?count=20&page=1"
|
146
|
+
stub_http_request(METHOD, REQUEST_TOKEN_URL).to_return(:body => REQUEST_TOKEN_RESPONSE)
|
147
|
+
stub_http_request(METHOD, ACCESS_TOKEN_URL).to_return(:body => ACCESS_TOKEN_RESPONSE)
|
148
|
+
stub_http_request(:get, @command_url).
|
149
|
+
to_return(:status => [401, 'Unauthorized']).then.
|
150
|
+
to_return(:body => fixture("home.json"))
|
151
|
+
@output = nil
|
152
|
+
@config_contents = nil
|
153
|
+
@config_mode = nil
|
154
|
+
config_file = 'tweetwine.tmp'
|
155
|
+
in_temp_dir do
|
156
|
+
@output = start_cli %W{--no-colors -f #{config_file} home}, [PIN], {}
|
157
|
+
@config_contents = YAML.load_file(config_file)
|
158
|
+
@config_mode = file_mode(config_file)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
Then "the application authorizes me, saves access token to config file, and tries the command again" do
|
163
|
+
assert_requested(METHOD, REQUEST_TOKEN_URL)
|
164
|
+
assert_requested(METHOD, ACCESS_TOKEN_URL)
|
165
|
+
assert_requested(:get, @command_url, :headers => {'Authorization' => /^OAuth /}, :times => 2)
|
166
|
+
@output[0].should == "Please authorize: #{AUTHORIZE_URL}"
|
167
|
+
@output[1].should =~ /^Enter PIN:/
|
168
|
+
@output[2].should == "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
|
169
|
+
@config_contents['oauth_access'].empty?.should == false
|
170
|
+
@config_mode.should == 0600
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
data/example/example_helper.rb
CHANGED
@@ -3,51 +3,67 @@
|
|
3
3
|
%w{
|
4
4
|
coulda
|
5
5
|
matchy
|
6
|
-
fakeweb
|
7
6
|
open4
|
8
7
|
stringio
|
8
|
+
tempfile
|
9
9
|
time
|
10
10
|
timecop
|
11
|
+
webmock/test_unit
|
11
12
|
}.each { |lib| require lib }
|
12
13
|
|
13
|
-
FakeWeb.clean_registry
|
14
|
-
FakeWeb.allow_net_connect = false
|
15
14
|
Timecop.freeze(Time.parse("2009-10-14 01:56:15 +0300"))
|
16
15
|
|
17
16
|
require "tweetwine"
|
17
|
+
require "test_helper"
|
18
18
|
|
19
19
|
module Tweetwine
|
20
|
-
module
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
TEST_PROXY_URL = "http://proxy.net:8080"
|
25
|
-
|
26
|
-
def launch_app(args, &blk)
|
27
|
-
lib = File.dirname(__FILE__) << "/../lib"
|
28
|
-
executable = File.dirname(__FILE__) << "/../bin/tweetwine"
|
29
|
-
launch_cmd = "ruby -rubygems -I#{lib} -- #{executable} #{args}"
|
30
|
-
Open4::popen4(launch_cmd, &blk)
|
31
|
-
end
|
20
|
+
module Example
|
21
|
+
module Helper
|
22
|
+
include WebMock::API
|
23
|
+
include Test::Helper
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
25
|
+
CONFIG_FILE = File.expand_path('../fixture/config.yaml', __FILE__)
|
26
|
+
PROXY_HOST = "proxy.net"
|
27
|
+
PROXY_PORT = 8123
|
28
|
+
PROXY_URL = "http://#{PROXY_HOST}:#{PROXY_PORT}"
|
29
|
+
USER = "fooman"
|
30
|
+
|
31
|
+
def start_app(args, &blk)
|
32
|
+
lib = File.dirname(__FILE__) << "/../lib"
|
33
|
+
executable = File.dirname(__FILE__) << "/../bin/tweetwine"
|
34
|
+
launch_cmd = "env USER='#{USER}' ruby -rubygems -I#{lib} -- #{executable} -f #{CONFIG_FILE} #{args.join(' ')}"
|
35
|
+
Open4::popen4(launch_cmd, &blk)
|
36
|
+
end
|
37
|
+
|
38
|
+
def start_cli(args, input = [], options = {:config_file => CONFIG_FILE})
|
39
|
+
input, output = StringIO.new(input.join("\n")), StringIO.new
|
40
|
+
options.merge!({ :in => input, :out => output })
|
41
|
+
CLI.start(args, options)
|
42
|
+
output.string.split("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
def fixture(filename)
|
46
|
+
filepath = File.expand_path("../fixture/#{filename}", __FILE__)
|
47
|
+
File.open(filepath) do |f|
|
48
|
+
f.readlines.join("\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def in_temp_dir
|
53
|
+
Dir.mktmpdir do |tmp_dir|
|
54
|
+
Dir.chdir(tmp_dir) do |dir|
|
55
|
+
yield dir
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
39
59
|
|
40
|
-
|
41
|
-
|
42
|
-
filepath = File.dirname(__FILE__) << "/fixture/" << filename
|
43
|
-
File.open(filepath) do |f|
|
44
|
-
contents = f.readlines.join("\n")
|
60
|
+
def read_shorten_config
|
61
|
+
Util.symbolize_hash_keys(YAML.load_file(CONFIG_FILE))[:shorten_urls]
|
45
62
|
end
|
46
|
-
contents
|
47
63
|
end
|
48
64
|
end
|
49
65
|
end
|
50
66
|
|
51
67
|
include Coulda
|
52
68
|
include Tweetwine
|
53
|
-
include Tweetwine::
|
69
|
+
include Tweetwine::Example::Helper
|
@@ -0,0 +1 @@
|
|
1
|
+
{"favorited":false,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>","in_reply_to_user_id":null,"in_reply_to_status_id":null,"user":{"profile_background_tile":false,"description":"just testing","verified":false,"profile_background_color":"1a1b1f","following":false,"profile_sidebar_fill_color":"24252b","profile_image_url":"","followers_count":0,"statuses_count":1,"time_zone":"Helsinki","profile_sidebar_border_color":"1a1b1f","url":"http://www.twitter.com/fooman","screen_name":"fooman","friends_count":0,"protected":false,"notifications":false,"favourites_count":0,"created_at":"Wed Oct 10 12:00:00 +0000 2009","profile_text_color":"6b6b6b","location":"Finland","name":"Fooman","profile_background_image_url":"http://s.twimg.com/a/1258674567/images/themes/theme5/bg.gif","id":29700570,"geo_enabled":false,"utc_offset":7200,"profile_link_color":"0070cc"},"created_at":"Sat Oct 13 14:23:41 +0000 2009","truncated":false,"id":5919326888,"text":"résumé"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"favorited":false,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>","in_reply_to_user_id":null,"in_reply_to_status_id":null,"user":{"profile_background_tile":false,"description":"just testing","verified":false,"profile_background_color":"1a1b1f","following":false,"profile_sidebar_fill_color":"24252b","profile_image_url":"","followers_count":0,"statuses_count":1,"time_zone":"Helsinki","profile_sidebar_border_color":"1a1b1f","url":"http://www.twitter.com/fooman","screen_name":"fooman","friends_count":0,"protected":false,"notifications":false,"favourites_count":0,"created_at":"Wed Oct 10 12:00:00 +0000 2009","profile_text_color":"6b6b6b","location":"Finland","name":"Fooman","profile_background_image_url":"http://s.twimg.com/a/1258674567/images/themes/theme5/bg.gif","id":29700570,"geo_enabled":false,"utc_offset":7200,"profile_link_color":"0070cc"},"created_at":"Sat Oct 13 14:23:41 +0000 2009","truncated":false,"id":5919326889,"text":"ruby links: http://is.gd/gGazV http://is.gd/gGaM3"}
|
File without changes
|