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.
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"}