tweetwine 0.2.12 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG.rdoc +7 -0
  2. data/Gemfile +17 -0
  3. data/README.md +57 -47
  4. data/Rakefile +17 -26
  5. data/bin/tweetwine +11 -12
  6. data/contrib/tweetwine-completion.bash +2 -3
  7. data/example/application_behavior_example.rb +173 -0
  8. data/example/example_helper.rb +44 -28
  9. data/example/fixture/config.yaml +8 -0
  10. data/example/fixture/shorten_rubygems.html +5 -0
  11. data/example/fixture/shorten_rubylang.html +5 -0
  12. data/example/fixture/update_utf8.json +1 -0
  13. data/example/fixture/update_with_urls.json +1 -0
  14. data/example/fixture/{update.json → update_without_urls.json} +0 -0
  15. data/example/search_statuses_example.rb +49 -16
  16. data/example/show_followers_example.rb +7 -8
  17. data/example/show_friends_example.rb +7 -8
  18. data/example/show_home_example.rb +19 -16
  19. data/example/show_mentions_example.rb +8 -9
  20. data/example/show_user_example.rb +16 -13
  21. data/example/update_status_example.rb +143 -26
  22. data/example/use_http_proxy_example.rb +40 -20
  23. data/lib/tweetwine/basic_object.rb +19 -0
  24. data/lib/tweetwine/character_encoding.rb +59 -0
  25. data/lib/tweetwine/cli.rb +354 -230
  26. data/lib/tweetwine/config.rb +65 -0
  27. data/lib/tweetwine/http.rb +120 -0
  28. data/lib/tweetwine/oauth.rb +104 -0
  29. data/lib/tweetwine/obfuscate.rb +21 -0
  30. data/lib/tweetwine/option_parser.rb +31 -0
  31. data/lib/tweetwine/promise.rb +39 -0
  32. data/lib/tweetwine/twitter.rb +211 -0
  33. data/lib/tweetwine/{io.rb → ui.rb} +30 -21
  34. data/lib/tweetwine/url_shortener.rb +15 -9
  35. data/lib/tweetwine/util.rb +30 -15
  36. data/lib/tweetwine.rb +72 -12
  37. data/man/tweetwine.7 +43 -69
  38. data/man/tweetwine.7.ronn +57 -47
  39. data/test/character_encoding_test.rb +87 -0
  40. data/test/cli_test.rb +19 -6
  41. data/test/config_test.rb +244 -0
  42. data/test/fixture/oauth.rb +21 -0
  43. data/test/fixture/test_config.yaml +4 -4
  44. data/test/http_test.rb +199 -0
  45. data/test/oauth_test.rb +77 -0
  46. data/test/obfuscate_test.rb +16 -0
  47. data/test/option_parser_test.rb +60 -0
  48. data/test/promise_test.rb +56 -0
  49. data/test/test_helper.rb +76 -8
  50. data/test/twitter_test.rb +625 -0
  51. data/test/{io_test.rb → ui_test.rb} +92 -74
  52. data/test/url_shortener_test.rb +115 -135
  53. data/test/util_test.rb +136 -85
  54. data/tweetwine.gemspec +53 -0
  55. metadata +112 -56
  56. data/example/show_metadata_example.rb +0 -86
  57. data/lib/tweetwine/client.rb +0 -187
  58. data/lib/tweetwine/meta.rb +0 -5
  59. data/lib/tweetwine/options.rb +0 -24
  60. data/lib/tweetwine/retrying_http.rb +0 -99
  61. data/lib/tweetwine/startup_config.rb +0 -50
  62. data/man/tweetwine.1 +0 -109
  63. data/man/tweetwine.1.ronn +0 -69
  64. data/test/client_test.rb +0 -544
  65. data/test/options_test.rb +0 -45
  66. data/test/retrying_http_test.rb +0 -147
  67. 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 supports showing the home timeline of the authenticated user, the
7
- latest statuses of friends and followers, and the latest statuses that mention
8
- the user. If that's not enough, statuses can be searched with arbitrary terms.
9
- In addition, new statuses can be sent.
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 compatible with both Ruby 1.8 and 1.9.
28
+ The program is tested with Ruby 1.8.7 and 1.9.2.
26
29
 
27
- The program requires [rest-client](http://github.com/archiloque/rest-client)
28
- gem to be installed. In addition, the program needs
29
- [json](http://json.rubyforge.org/) gem on Ruby 1.8.
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
- Documentation is provided as gem man pages. Use
32
- [gem-man](http://github.com/defunkt/gem-man) to see them:
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 [ <GLOBAL_OPTIONS> ] [ <COMMAND> ] [ <COMMAND_OPTIONS> ]
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 <COMMAND>
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
- ### URL shortening for status update
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
- Before actually sending a status update, it is possible for the software to
65
- shorten the URLs in the update by using an external web service. This can be
66
- enabled via the `shorten_urls` key in configuration file; for example:
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`. The method chosen
79
- affects whether parameters are passed as URL query parameters or as payload
80
- in the HTTP request, respectively. Extra parameters can be given via
81
- `extra_params` key, as a hash.
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
- URL shortening can be disabled by
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
- * not defining `shorten_urls` key in the configuration file,
88
- * setting key `enable` to `false`, or
89
- * using the command line option `--no-url-shorten`.
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 the feature requires [nokogiri](http://nokogiri.org/) gem
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 all its HTTP connections.
98
- This setting can be overridden with `--http-proxy` and `--no-http-proxy`
99
- command line options.
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
- tweetwine(1), <http://github.com/tuomas/tweetwine>
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 "#{name}/meta"
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" => :"man:build" do |f|
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 :show7 => :build do
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
- require "rake/testtask"
52
-
53
- desc "Run unit tests"
54
- Rake::TestTask.new(:unit) do |t|
55
- t.test_files = FileList["test/**/*_test.rb"]
56
- t.verbose = true
57
- t.warning = true
58
- t.ruby_opts << "-rrubygems"
59
- t.libs << "test"
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
- desc "Run integration/example tests"
63
- Rake::TestTask.new(:example) do |t|
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
- exec_name = File.basename($0)
14
- config_file = ENV["HOME"] + "/.#{exec_name}"
15
-
16
- Tweetwine::CLI.launch(ARGV, exec_name, config_file)
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="--auth --colors --num --no-colors --no-url-shorten --page --version"
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
@@ -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 ExampleHelpers
21
- TEST_USER = "fooman"
22
- TEST_PASSWD = "barpwd"
23
- TEST_AUTH = "#{TEST_USER}:#{TEST_PASSWD}"
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
- def launch_cli(args, *input)
34
- input, output = StringIO.new(input.join("\n")), StringIO.new
35
- extra_opts = { :input => input, :output => output }
36
- CLI.launch(args, "test", nil, extra_opts)
37
- output.string.split("\n")
38
- end
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
- def fixture(filename)
41
- contents = nil
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::ExampleHelpers
69
+ include Tweetwine::Example::Helper
@@ -0,0 +1,8 @@
1
+ ---
2
+ username: fooman
3
+ colors: false
4
+ shorten_urls:
5
+ service_url: http://is.gd/create.php
6
+ method: post
7
+ url_param_name: URL
8
+ xpath_selector: //input[@id='short_url']/@value
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <input type="text" id="short_url" value="http://is.gd/gGazV" />
4
+ </body>
5
+ </html>
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <input type="text" id="short_url" value="http://is.gd/gGaM3" />
4
+ </body>
5
+ </html>
@@ -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"}