tweetwine 0.2.12 → 0.3.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/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
|