tweetwine 0.4.2 → 0.4.3
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 +5 -0
 - data/Gemfile +1 -1
 - data/README.md +2 -2
 - data/Rakefile +5 -0
 - data/benchmark/home_bm.rb +36 -0
 - data/lib/tweetwine/character_encoding.rb +1 -1
 - data/lib/tweetwine/http.rb +1 -1
 - data/lib/tweetwine/support.rb +28 -26
 - data/lib/tweetwine/twitter.rb +8 -5
 - data/lib/tweetwine/version.rb +1 -1
 - data/lib/tweetwine.rb +0 -2
 - data/man/tweetwine.7 +3 -3
 - data/man/tweetwine.7.ronn +2 -2
 - data/project.rb +2 -0
 - data/test/fixture/config_integration.yaml +1 -1
 - data/test/integration/authorization_test.rb +1 -1
 - data/test/integration/global_options_test.rb +1 -1
 - data/test/integration/invalid_config_file_test.rb +1 -1
 - data/test/integration/search_statuses_test.rb +1 -1
 - data/test/integration/show_followers_test.rb +1 -1
 - data/test/integration/show_friends_test.rb +1 -1
 - data/test/integration/show_home_test.rb +1 -1
 - data/test/integration/show_mentions_test.rb +1 -1
 - data/test/integration/show_user_test.rb +1 -1
 - data/test/integration/update_status_test.rb +42 -21
 - data/test/integration/use_http_proxy_test.rb +6 -6
 - data/test/integration/user_help_test.rb +2 -2
 - data/test/support/assertions.rb +58 -0
 - data/test/support/common.rb +10 -0
 - data/test/support/common_helpers.rb +43 -0
 - data/test/support/doubles.rb +35 -0
 - data/test/{integration/helper.rb → support/integration_test_case.rb} +12 -7
 - data/test/support/mocha_integration.rb +16 -0
 - data/test/support/tweets.rb +95 -0
 - data/test/support/unit_test_case.rb +28 -0
 - data/test/support/webmock_integration.rb +16 -0
 - data/test/unit/character_encoding_test.rb +1 -1
 - data/test/unit/cli_test.rb +4 -4
 - data/test/unit/config_test.rb +1 -1
 - data/test/unit/http_test.rb +1 -1
 - data/test/unit/oauth_test.rb +1 -1
 - data/test/unit/obfuscate_test.rb +1 -1
 - data/test/unit/option_parser_test.rb +1 -1
 - data/test/unit/promise_test.rb +1 -1
 - data/test/unit/support_test.rb +1 -1
 - data/test/unit/tweet_test.rb +3 -3
 - data/test/unit/twitter_test.rb +29 -27
 - data/test/unit/ui_test.rb +3 -3
 - data/test/unit/uri_test.rb +1 -1
 - data/test/unit/url_shortener_test.rb +1 -1
 - data/tweetwine.gemspec +5 -4
 - metadata +122 -97
 - data/test/helper.rb +0 -60
 - data/test/unit/helper.rb +0 -108
 - data/test/unit/tweet_helper.rb +0 -95
 
    
        data/CHANGELOG.rdoc
    CHANGED
    
    
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -24,7 +24,7 @@ Install Tweetwine with RubyGems: 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                $ gem install tweetwine
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
            The program is tested with  
     | 
| 
      
 27 
     | 
    
         
            +
            The program is tested with MRI 1.8.7, 1.9.2, and 1.9.3.
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
            The program requires [oauth](http://oauth.rubyforge.org/) gem to be installed.
         
     | 
| 
       30 
30 
     | 
    
         
             
            In addition, the program needs a JSON parser library, such as
         
     | 
| 
         @@ -81,7 +81,7 @@ enabled via `shorten_urls` field in the configuration file; for example: 
     | 
|
| 
       81 
81 
     | 
    
         
             
                shorten_urls:
         
     | 
| 
       82 
82 
     | 
    
         
             
                  service_url: http://is.gd/create.php
         
     | 
| 
       83 
83 
     | 
    
         
             
                  method: post
         
     | 
| 
       84 
     | 
    
         
            -
                  url_param_name:  
     | 
| 
      
 84 
     | 
    
         
            +
                  url_param_name: url
         
     | 
| 
       85 
85 
     | 
    
         
             
                  xpath_selector: //input[@id='short_url']/@value
         
     | 
| 
       86 
86 
     | 
    
         
             
                  disable: false    # optional
         
     | 
| 
       87 
87 
     | 
    
         | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -80,6 +80,11 @@ namespace :test do 
     | 
|
| 
       80 
80 
     | 
    
         
             
              task :all => [:unit, :integration]
         
     | 
| 
       81 
81 
     | 
    
         
             
            end
         
     | 
| 
       82 
82 
     | 
    
         | 
| 
      
 83 
     | 
    
         
            +
            desc "Profile fetching home timeline"
         
     | 
| 
      
 84 
     | 
    
         
            +
            task :profile do
         
     | 
| 
      
 85 
     | 
    
         
            +
              sh %{bundle exec ruby -I lib -I test benchmark/home_bm.rb}
         
     | 
| 
      
 86 
     | 
    
         
            +
            end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
       83 
88 
     | 
    
         
             
            desc "Find code smells"
         
     | 
| 
       84 
89 
     | 
    
         
             
            task :roodi do
         
     | 
| 
       85 
90 
     | 
    
         
             
              sh %{roodi "**/*.rb"}
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tweetwine'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'perftools'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'support/common_helpers'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'webmock'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            WebMock.disable_net_connect!
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Driver
         
     | 
| 
      
 12 
     | 
    
         
            +
              extend WebMock::API
         
     | 
| 
      
 13 
     | 
    
         
            +
              extend Tweetwine::Test::CommonHelpers
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              def self.run
         
     | 
| 
      
 16 
     | 
    
         
            +
                stub_http_request(:get, "https://api.twitter.com/1/statuses/home_timeline.json?count=20&page=1").to_return(:body => fixture_file('home.json'))
         
     | 
| 
      
 17 
     | 
    
         
            +
                yield
         
     | 
| 
      
 18 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 19 
     | 
    
         
            +
                WebMock.reset!
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            Driver.run do
         
     | 
| 
      
 24 
     | 
    
         
            +
              output_path = "/tmp/tweetwine_home_bm"
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              PerfTools::CpuProfiler.start(output_path) do
         
     | 
| 
      
 27 
     | 
    
         
            +
                1_000.times do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Tweetwine::CLI.start %w{home}
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              system %{pprof.rb --gif #{output_path} > #{output_path}.gif}
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              puts "Profiling output: #{output_path}"
         
     | 
| 
      
 35 
     | 
    
         
            +
              puts "Visualization:    #{output_path}.gif"
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tweetwine/http.rb
    CHANGED
    
    | 
         @@ -17,7 +17,7 @@ module Tweetwine 
     | 
|
| 
       17 
17 
     | 
    
         
             
                      if retries < max_retries
         
     | 
| 
       18 
18 
     | 
    
         
             
                        retries += 1
         
     | 
| 
       19 
19 
     | 
    
         
             
                        timeout = retry_base_wait_timeout**retries
         
     | 
| 
       20 
     | 
    
         
            -
                        CLI.ui.warn 
     | 
| 
      
 20 
     | 
    
         
            +
                        CLI.ui.warn "Could not connect -- retrying in #{timeout} seconds"
         
     | 
| 
       21 
21 
     | 
    
         
             
                        sleep timeout
         
     | 
| 
       22 
22 
     | 
    
         
             
                        retry
         
     | 
| 
       23 
23 
     | 
    
         
             
                      else
         
     | 
    
        data/lib/tweetwine/support.rb
    CHANGED
    
    | 
         @@ -36,15 +36,15 @@ module Tweetwine 
     | 
|
| 
       36 
36 
     | 
    
         
             
                  else [(difference/86400.0).round, "day"]
         
     | 
| 
       37 
37 
     | 
    
         
             
                  end
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                  [value, pluralize_unit(value, unit)]
         
     | 
| 
      
 39 
     | 
    
         
            +
                  [value, Helper.pluralize_unit(value, unit)]
         
     | 
| 
       40 
40 
     | 
    
         
             
                end
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
                def stringify_hash_keys(hash)
         
     | 
| 
       43 
     | 
    
         
            -
                  recursive_copy_hash(hash) { |key, value| [key.to_s, value] }
         
     | 
| 
      
 43 
     | 
    
         
            +
                  Helper.recursive_copy_hash(hash) { |key, value| [key.to_s, value] }
         
     | 
| 
       44 
44 
     | 
    
         
             
                end
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
                def symbolize_hash_keys(hash)
         
     | 
| 
       47 
     | 
    
         
            -
                  recursive_copy_hash(hash) { |key, value| [key.to_sym, value] }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Helper.recursive_copy_hash(hash) { |key, value| [key.to_sym, value] }
         
     | 
| 
       48 
48 
     | 
    
         
             
                end
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
                def parse_int_gt(value, default, min, name_for_error)
         
     | 
| 
         @@ -64,7 +64,7 @@ module Tweetwine 
     | 
|
| 
       64 
64 
     | 
    
         
             
                  dup_str = str.dup
         
     | 
| 
       65 
65 
     | 
    
         
             
                  str_pos, dup_pos = 0, 0
         
     | 
| 
       66 
66 
     | 
    
         
             
                  while str_pos < str.size && (match_data = regexp.match(str[str_pos..-1]))
         
     | 
| 
       67 
     | 
    
         
            -
                    matching_group_indexes = indexes_of_filled_matches(match_data)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    matching_group_indexes = Helper.indexes_of_filled_matches(match_data)
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
       69 
69 
     | 
    
         
             
                    matching_group_indexes.each do |i|
         
     | 
| 
       70 
70 
     | 
    
         
             
                      replacement = (yield match_data[i]).to_s
         
     | 
| 
         @@ -93,30 +93,32 @@ module Tweetwine 
     | 
|
| 
       93 
93 
     | 
    
         
             
                  end
         
     | 
| 
       94 
94 
     | 
    
         
             
                end
         
     | 
| 
       95 
95 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
                 
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                module Helper
         
     | 
| 
      
 97 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 98 
     | 
    
         
            +
                    def recursive_copy_hash(hash, &pair_modifier)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      hash.inject({}) do |result, pair|
         
     | 
| 
      
 100 
     | 
    
         
            +
                        value = pair.last
         
     | 
| 
      
 101 
     | 
    
         
            +
                        value = recursive_copy_hash(value, &pair_modifier) if value.is_a? Hash
         
     | 
| 
      
 102 
     | 
    
         
            +
                        key, value = pair_modifier.call(pair.first, value)
         
     | 
| 
      
 103 
     | 
    
         
            +
                        result[key] = value
         
     | 
| 
      
 104 
     | 
    
         
            +
                        result
         
     | 
| 
      
 105 
     | 
    
         
            +
                      end
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
      
 108 
     | 
    
         
            +
                    def pluralize_unit(value, unit)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      if %w{hour day}.include?(unit) && value > 1
         
     | 
| 
      
 110 
     | 
    
         
            +
                        unit = unit + 's'
         
     | 
| 
      
 111 
     | 
    
         
            +
                      end
         
     | 
| 
      
 112 
     | 
    
         
            +
                      unit
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
       114 
114 
     | 
    
         | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
      
 115 
     | 
    
         
            +
                    def indexes_of_filled_matches(match_data)
         
     | 
| 
      
 116 
     | 
    
         
            +
                      if match_data.size > 1
         
     | 
| 
      
 117 
     | 
    
         
            +
                        (1...match_data.size).to_a.reject { |i| match_data[i].nil? }
         
     | 
| 
      
 118 
     | 
    
         
            +
                      else
         
     | 
| 
      
 119 
     | 
    
         
            +
                        [0]
         
     | 
| 
      
 120 
     | 
    
         
            +
                      end
         
     | 
| 
      
 121 
     | 
    
         
            +
                    end
         
     | 
| 
       120 
122 
     | 
    
         
             
                  end
         
     | 
| 
       121 
123 
     | 
    
         
             
                end
         
     | 
| 
       122 
124 
     | 
    
         
             
              end
         
     | 
    
        data/lib/tweetwine/twitter.rb
    CHANGED
    
    | 
         @@ -184,8 +184,8 @@ module Tweetwine 
     | 
|
| 
       184 
184 
     | 
    
         
             
                    status.dup
         
     | 
| 
       185 
185 
     | 
    
         
             
                  end
         
     | 
| 
       186 
186 
     | 
    
         
             
                  status.strip!
         
     | 
| 
       187 
     | 
    
         
            -
                  shorten_urls_in 
     | 
| 
       188 
     | 
    
         
            -
                  truncate_status 
     | 
| 
      
 187 
     | 
    
         
            +
                  shorten_urls_in status if CLI.config[:shorten_urls] && !CLI.config[:shorten_urls][:disable]
         
     | 
| 
      
 188 
     | 
    
         
            +
                  truncate_status status if status.length > MAX_STATUS_LENGTH
         
     | 
| 
       189 
189 
     | 
    
         
             
                  status
         
     | 
| 
       190 
190 
     | 
    
         
             
                end
         
     | 
| 
       191 
191 
     | 
    
         | 
| 
         @@ -193,9 +193,12 @@ module Tweetwine 
     | 
|
| 
       193 
193 
     | 
    
         
             
                  url_pairs = Uri.
         
     | 
| 
       194 
194 
     | 
    
         
             
                    extract(status, %w{http https}).
         
     | 
| 
       195 
195 
     | 
    
         
             
                    uniq.
         
     | 
| 
       196 
     | 
    
         
            -
                    map { | 
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
      
 196 
     | 
    
         
            +
                    map { |url| [ url, CLI.url_shortener.shorten(url) ] }
         
     | 
| 
      
 197 
     | 
    
         
            +
                  failed, succeeded = *url_pairs.partition do |(full_url, short_url)|
         
     | 
| 
      
 198 
     | 
    
         
            +
                    Support.blank? short_url or full_url == short_url
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  failed.each { |(full_url, _)| CLI.ui.warn "No short URL for #{full_url}" }
         
     | 
| 
      
 201 
     | 
    
         
            +
                  succeeded.each { |(full_url, short_url)| status.gsub! full_url, short_url }
         
     | 
| 
       199 
202 
     | 
    
         
             
                rescue HttpError, LoadError => e
         
     | 
| 
       200 
203 
     | 
    
         
             
                  CLI.ui.warn "#{e}\nSkipping URL shortening..."
         
     | 
| 
       201 
204 
     | 
    
         
             
                end
         
     | 
    
        data/lib/tweetwine/version.rb
    CHANGED
    
    
    
        data/lib/tweetwine.rb
    CHANGED
    
    
    
        data/man/tweetwine.7
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .\" generated with Ronn/v0.7.3
         
     | 
| 
       2 
2 
     | 
    
         
             
            .\" http://github.com/rtomayko/ronn/tree/0.7.3
         
     | 
| 
       3 
3 
     | 
    
         
             
            .
         
     | 
| 
       4 
     | 
    
         
            -
            .TH "TWEETWINE" "7" " 
     | 
| 
      
 4 
     | 
    
         
            +
            .TH "TWEETWINE" "7" "November 2011" "Tuomas Kareinen" "Tweetwine Manual"
         
     | 
| 
       5 
5 
     | 
    
         
             
            .
         
     | 
| 
       6 
6 
     | 
    
         
             
            .SH "DESCRIPTION"
         
     | 
| 
       7 
7 
     | 
    
         
             
            Tweetwine shows the latest tweets from the command line quickly\.
         
     | 
| 
         @@ -40,7 +40,7 @@ $ gem install tweetwine 
     | 
|
| 
       40 
40 
     | 
    
         
             
            .IP "" 0
         
     | 
| 
       41 
41 
     | 
    
         
             
            .
         
     | 
| 
       42 
42 
     | 
    
         
             
            .P
         
     | 
| 
       43 
     | 
    
         
            -
            The program is tested with  
     | 
| 
      
 43 
     | 
    
         
            +
            The program is tested with MRI 1\.8\.7, 1\.9\.2, and 1\.9\.3\.
         
     | 
| 
       44 
44 
     | 
    
         
             
            .
         
     | 
| 
       45 
45 
     | 
    
         
             
            .P
         
     | 
| 
       46 
46 
     | 
    
         
             
            The program requires oauth \fIhttp://oauth\.rubyforge\.org/\fR gem to be installed\. In addition, the program needs a JSON parser library, such as json \fIhttp://json\.rubyforge\.org/\fR gem, on Ruby 1\.8\.
         
     | 
| 
         @@ -130,7 +130,7 @@ show_reverse: true 
     | 
|
| 
       130 
130 
     | 
    
         
             
            shorten_urls:
         
     | 
| 
       131 
131 
     | 
    
         
             
              service_url: http://is\.gd/create\.php
         
     | 
| 
       132 
132 
     | 
    
         
             
              method: post
         
     | 
| 
       133 
     | 
    
         
            -
              url_param_name:  
     | 
| 
      
 133 
     | 
    
         
            +
              url_param_name: url
         
     | 
| 
       134 
134 
     | 
    
         
             
              xpath_selector: //input[@id=\'short_url\']/@value
         
     | 
| 
       135 
135 
     | 
    
         
             
              disable: false    # optional
         
     | 
| 
       136 
136 
     | 
    
         
             
            .
         
     | 
    
        data/man/tweetwine.7.ronn
    CHANGED
    
    | 
         @@ -24,7 +24,7 @@ Install Tweetwine with RubyGems: 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                $ gem install tweetwine
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
            The program is tested with  
     | 
| 
      
 27 
     | 
    
         
            +
            The program is tested with MRI 1.8.7, 1.9.2, and 1.9.3.
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
            The program requires [oauth](http://oauth.rubyforge.org/) gem to be installed.
         
     | 
| 
       30 
30 
     | 
    
         
             
            In addition, the program needs a JSON parser library, such as
         
     | 
| 
         @@ -81,7 +81,7 @@ enabled via `shorten_urls` field in the configuration file; for example: 
     | 
|
| 
       81 
81 
     | 
    
         
             
                shorten_urls:
         
     | 
| 
       82 
82 
     | 
    
         
             
                  service_url: http://is.gd/create.php
         
     | 
| 
       83 
83 
     | 
    
         
             
                  method: post
         
     | 
| 
       84 
     | 
    
         
            -
                  url_param_name:  
     | 
| 
      
 84 
     | 
    
         
            +
                  url_param_name: url
         
     | 
| 
       85 
85 
     | 
    
         
             
                  xpath_selector: //input[@id='short_url']/@value
         
     | 
| 
       86 
86 
     | 
    
         
             
                  disable: false    # optional
         
     | 
| 
       87 
87 
     | 
    
         | 
    
        data/project.rb
    CHANGED
    
    | 
         @@ -1,6 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # coding: utf-8
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            name = 'tweetwine'
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Add lib dir to $LOAD_PATH so that `require 'tweetwine/version'`
         
     | 
| 
      
 5 
     | 
    
         
            +
            # (executed in tests) loads the version file only once on MRI 1.8.7.
         
     | 
| 
       4 
6 
     | 
    
         
             
            $LOAD_PATH.unshift File.expand_path('lib', File.dirname(__FILE__))
         
     | 
| 
       5 
7 
     | 
    
         
             
            require "#{name}/version"
         
     | 
| 
       6 
8 
     | 
    
         | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # coding: utf-8
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require ' 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'support/integration_test_case'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'yaml'
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            module Tweetwine::Test::Integration
         
     | 
| 
         @@ -8,17 +8,14 @@ module Tweetwine::Test::Integration 
     | 
|
| 
       8 
8 
     | 
    
         
             
            class UpdateStatusTest < TestCase
         
     | 
| 
       9 
9 
     | 
    
         
             
              RUBYGEMS_FIXTURE            = fixture_file 'shorten_rubygems.html'
         
     | 
| 
       10 
10 
     | 
    
         
             
              RUBYGEMS_FULL_URL           = 'http://rubygems.org/'
         
     | 
| 
       11 
     | 
    
         
            -
              RUBYGEMS_FULL_URL_ENC       = 'http%3a%2f%2frubygems.org%2f'
         
     | 
| 
       12 
11 
     | 
    
         
             
              RUBYGEMS_SHORT_URL          = 'http://is.gd/gGazV'
         
     | 
| 
       13 
     | 
    
         
            -
              RUBYGEMS_SHORT_URL_ENC      = 'http%3a%2f%2fis.gd%2fgGazV'
         
     | 
| 
       14 
12 
     | 
    
         
             
              RUBYLANG_FIXTURE            = fixture_file 'shorten_rubylang.html'
         
     | 
| 
       15 
13 
     | 
    
         
             
              RUBYLANG_FULL_URL           = 'http://ruby-lang.org/'
         
     | 
| 
       16 
     | 
    
         
            -
              RUBYLANG_FULL_URL_ENC       = 'http%3a%2f%2fruby-lang.org%2f'
         
     | 
| 
       17 
14 
     | 
    
         
             
              RUBYLANG_SHORT_URL          = 'http://is.gd/gGaM3'
         
     | 
| 
       18 
     | 
    
         
            -
              RUBYLANG_SHORT_URL_ENC      = 'http%3a%2f%2fis.gd%2fgGaM3'
         
     | 
| 
       19 
15 
     | 
    
         
             
              SHORTEN_CONFIG              = read_shorten_config
         
     | 
| 
       20 
16 
     | 
    
         
             
              SHORTEN_METHOD              = SHORTEN_CONFIG[:method].to_sym
         
     | 
| 
       21 
17 
     | 
    
         
             
              STATUS_WITH_FULL_URLS       = "ruby links: #{RUBYGEMS_FULL_URL} #{RUBYLANG_FULL_URL}"
         
     | 
| 
      
 18 
     | 
    
         
            +
              STATUS_WITH_MIXED_URLS      = "ruby links: #{RUBYGEMS_SHORT_URL} #{RUBYLANG_FULL_URL}"
         
     | 
| 
       22 
19 
     | 
    
         
             
              STATUS_WITH_SHORT_URLS      = "ruby links: #{RUBYGEMS_SHORT_URL} #{RUBYLANG_SHORT_URL}"
         
     | 
| 
       23 
20 
     | 
    
         
             
              STATUS_WITHOUT_URLS         = "bored. going to sleep."
         
     | 
| 
       24 
21 
     | 
    
         
             
              UPDATE_FIXTURE_WITH_URLS    = fixture_file 'update_with_urls.json'
         
     | 
| 
         @@ -26,8 +23,9 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       26 
23 
     | 
    
         
             
              UPDATE_FIXTURE_UTF8         = fixture_file 'update_utf8.json'
         
     | 
| 
       27 
24 
     | 
    
         
             
              UPDATE_URL                  = "https://api.twitter.com/1/statuses/update.json"
         
     | 
| 
       28 
25 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
              BODY_WITH_SHORT_URLS  =  
     | 
| 
       30 
     | 
    
         
            -
               
     | 
| 
      
 26 
     | 
    
         
            +
              BODY_WITH_SHORT_URLS  = { 'status' => STATUS_WITH_SHORT_URLS }
         
     | 
| 
      
 27 
     | 
    
         
            +
              BODY_WITH_MIXED_URLS  = { 'status' => STATUS_WITH_MIXED_URLS }
         
     | 
| 
      
 28 
     | 
    
         
            +
              BODY_WITHOUT_URLS     = { 'status' => STATUS_WITHOUT_URLS }
         
     | 
| 
       31 
29 
     | 
    
         | 
| 
       32 
30 
     | 
    
         
             
              describe "update my status from command line with colorization disabled" do
         
     | 
| 
       33 
31 
     | 
    
         
             
                before do
         
     | 
| 
         @@ -111,8 +109,7 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       111 
109 
     | 
    
         
             
                  before do
         
     | 
| 
       112 
110 
     | 
    
         
             
                    @status_utf8 = "résumé"
         
     | 
| 
       113 
111 
     | 
    
         
             
                    @status_latin1 = @status_utf8.encode('ISO-8859-1')
         
     | 
| 
       114 
     | 
    
         
            -
                     
     | 
| 
       115 
     | 
    
         
            -
                    stub_http_request(:post, UPDATE_URL).with(:body => url_encoded_body).to_return(:body => UPDATE_FIXTURE_UTF8)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    stub_http_request(:post, UPDATE_URL).with(:body => { 'status' => @status_utf8 }).to_return(:body => UPDATE_FIXTURE_UTF8)
         
     | 
| 
       116 
113 
     | 
    
         
             
                    at_snapshot do
         
     | 
| 
       117 
114 
     | 
    
         
             
                      @output = start_cli %W{--no-colors update #{@status_latin1}}, %w{y}
         
     | 
| 
       118 
115 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -131,8 +128,7 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       131 
128 
     | 
    
         
             
                  before do
         
     | 
| 
       132 
129 
     | 
    
         
             
                    @status_latin1 = "r\xe9sum\xe9"
         
     | 
| 
       133 
130 
     | 
    
         
             
                    @status_utf8 = "r\xc3\xa9sum\xc3\xa9"
         
     | 
| 
       134 
     | 
    
         
            -
                     
     | 
| 
       135 
     | 
    
         
            -
                    stub_http_request(:post, UPDATE_URL).with(:body => url_encoded_body).to_return(:body => UPDATE_FIXTURE_UTF8)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    stub_http_request(:post, UPDATE_URL).with(:body => { 'status' => @status_utf8 }).to_return(:body => UPDATE_FIXTURE_UTF8)
         
     | 
| 
       136 
132 
     | 
    
         
             
                    tmp_kcode('NONE') do
         
     | 
| 
       137 
133 
     | 
    
         
             
                      tmp_env(:LANG => 'latin1') do
         
     | 
| 
       138 
134 
     | 
    
         
             
                        Tweetwine::CharacterEncoding.forget_guess
         
     | 
| 
         @@ -153,14 +149,7 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       153 
149 
     | 
    
         | 
| 
       154 
150 
     | 
    
         
             
              describe "shorten URLs in status update" do
         
     | 
| 
       155 
151 
     | 
    
         
             
                before do
         
     | 
| 
       156 
     | 
    
         
            -
                   
     | 
| 
       157 
     | 
    
         
            -
                  @shorten_rubylang_body = "#{SHORTEN_CONFIG[:url_param_name]}=#{RUBYLANG_FULL_URL_ENC}"
         
     | 
| 
       158 
     | 
    
         
            -
                  stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
         
     | 
| 
       159 
     | 
    
         
            -
                    with(:body => @shorten_rubygems_body).
         
     | 
| 
       160 
     | 
    
         
            -
                    to_return(:body => RUBYGEMS_FIXTURE)
         
     | 
| 
       161 
     | 
    
         
            -
                  stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
         
     | 
| 
       162 
     | 
    
         
            -
                    with(:body => @shorten_rubylang_body).
         
     | 
| 
       163 
     | 
    
         
            -
                    to_return(:body => RUBYLANG_FIXTURE)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  stub_url_shortening(:rubygems => RUBYGEMS_FIXTURE, :rubylang => RUBYLANG_FIXTURE)
         
     | 
| 
       164 
153 
     | 
    
         
             
                  stub_http_request(:post, UPDATE_URL).
         
     | 
| 
       165 
154 
     | 
    
         
             
                    with(:body => BODY_WITH_SHORT_URLS).
         
     | 
| 
       166 
155 
     | 
    
         
             
                    to_return(:body => UPDATE_FIXTURE_WITH_URLS)
         
     | 
| 
         @@ -170,14 +159,31 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       170 
159 
     | 
    
         
             
                end
         
     | 
| 
       171 
160 
     | 
    
         | 
| 
       172 
161 
     | 
    
         
             
                it "shortens the URLs in the status before sending it" do
         
     | 
| 
       173 
     | 
    
         
            -
                  assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @ 
     | 
| 
       174 
     | 
    
         
            -
                  assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @ 
     | 
| 
      
 162 
     | 
    
         
            +
                  assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @request_bodies[:rubygems])
         
     | 
| 
      
 163 
     | 
    
         
            +
                  assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @request_bodies[:rubylang])
         
     | 
| 
       175 
164 
     | 
    
         
             
                  @output[1].must_equal STATUS_WITH_SHORT_URLS
         
     | 
| 
       176 
165 
     | 
    
         
             
                  @output[5].must_equal "#{USER}, 9 hours ago:"
         
     | 
| 
       177 
166 
     | 
    
         
             
                  @output[6].must_equal STATUS_WITH_SHORT_URLS
         
     | 
| 
       178 
167 
     | 
    
         
             
                end
         
     | 
| 
       179 
168 
     | 
    
         
             
              end
         
     | 
| 
       180 
169 
     | 
    
         | 
| 
      
 170 
     | 
    
         
            +
              describe "warn if URL shortening results in no shortened URL in status update" do
         
     | 
| 
      
 171 
     | 
    
         
            +
                before do
         
     | 
| 
      
 172 
     | 
    
         
            +
                  stub_url_shortening(:rubygems => RUBYGEMS_FIXTURE, :rubylang => '')
         
     | 
| 
      
 173 
     | 
    
         
            +
                  stub_http_request(:post, UPDATE_URL).
         
     | 
| 
      
 174 
     | 
    
         
            +
                    with(:body => BODY_WITH_MIXED_URLS).
         
     | 
| 
      
 175 
     | 
    
         
            +
                    to_return(:body => UPDATE_FIXTURE_WITH_URLS)
         
     | 
| 
      
 176 
     | 
    
         
            +
                  at_snapshot do
         
     | 
| 
      
 177 
     | 
    
         
            +
                    @output = start_cli %W{--no-colors update #{STATUS_WITH_FULL_URLS}}, %w{y}
         
     | 
| 
      
 178 
     | 
    
         
            +
                  end
         
     | 
| 
      
 179 
     | 
    
         
            +
                end
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                it "warns which URL was not shortened, falling back to using the original URL" do
         
     | 
| 
      
 182 
     | 
    
         
            +
                  @output[0].must_equal "Warning: No short URL for #{RUBYLANG_FULL_URL}"
         
     | 
| 
      
 183 
     | 
    
         
            +
                  @output[2].must_equal STATUS_WITH_MIXED_URLS
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
       181 
187 
     | 
    
         
             
              describe "disable URL shortening for status updates" do
         
     | 
| 
       182 
188 
     | 
    
         
             
                before do
         
     | 
| 
       183 
189 
     | 
    
         
             
                  stub_http_request(:post, UPDATE_URL).
         
     | 
| 
         @@ -194,6 +200,21 @@ class UpdateStatusTest < TestCase 
     | 
|
| 
       194 
200 
     | 
    
         
             
                  @output[6].must_equal STATUS_WITH_SHORT_URLS
         
     | 
| 
       195 
201 
     | 
    
         
             
                end
         
     | 
| 
       196 
202 
     | 
    
         
             
              end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
              private
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
              def stub_url_shortening(response_bodies)
         
     | 
| 
      
 207 
     | 
    
         
            +
                @request_bodies = {
         
     | 
| 
      
 208 
     | 
    
         
            +
                  :rubygems => { SHORTEN_CONFIG[:url_param_name] => RUBYGEMS_FULL_URL },
         
     | 
| 
      
 209 
     | 
    
         
            +
                  :rubylang => { SHORTEN_CONFIG[:url_param_name] => RUBYLANG_FULL_URL }
         
     | 
| 
      
 210 
     | 
    
         
            +
                }
         
     | 
| 
      
 211 
     | 
    
         
            +
                stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
         
     | 
| 
      
 212 
     | 
    
         
            +
                  with(:body => @request_bodies[:rubygems]).
         
     | 
| 
      
 213 
     | 
    
         
            +
                  to_return(:body => response_bodies[:rubygems])
         
     | 
| 
      
 214 
     | 
    
         
            +
                stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
         
     | 
| 
      
 215 
     | 
    
         
            +
                  with(:body => @request_bodies[:rubylang]).
         
     | 
| 
      
 216 
     | 
    
         
            +
                  to_return(:body => response_bodies[:rubylang])
         
     | 
| 
      
 217 
     | 
    
         
            +
              end
         
     | 
| 
       197 
218 
     | 
    
         
             
            end
         
     | 
| 
       198 
219 
     | 
    
         | 
| 
       199 
220 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # coding: utf-8
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require ' 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'support/integration_test_case'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Tweetwine::Test::Integration
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -22,7 +22,7 @@ class UseHttpProxyTest < TestCase 
     | 
|
| 
       22 
22 
     | 
    
         
             
                end
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
                it "uses the proxy to fetch my home timeline" do
         
     | 
| 
       25 
     | 
    
         
            -
                   
     | 
| 
      
 25 
     | 
    
         
            +
                  assert_use_proxy
         
     | 
| 
       26 
26 
     | 
    
         
             
                end
         
     | 
| 
       27 
27 
     | 
    
         
             
              end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
         @@ -33,7 +33,7 @@ class UseHttpProxyTest < TestCase 
     | 
|
| 
       33 
33 
     | 
    
         
             
                end
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
                it "uses the proxy to fetch my home timeline" do
         
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
      
 36 
     | 
    
         
            +
                  assert_use_proxy
         
     | 
| 
       37 
37 
     | 
    
         
             
                end
         
     | 
| 
       38 
38 
     | 
    
         
             
              end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
         @@ -50,16 +50,16 @@ class UseHttpProxyTest < TestCase 
     | 
|
| 
       50 
50 
     | 
    
         | 
| 
       51 
51 
     | 
    
         
             
              private
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
              def  
     | 
| 
      
 53 
     | 
    
         
            +
              def assert_use_proxy
         
     | 
| 
       54 
54 
     | 
    
         
             
                nh = net_http
         
     | 
| 
       55 
     | 
    
         
            -
                nh.proxy_class 
     | 
| 
      
 55 
     | 
    
         
            +
                assert nh.proxy_class?
         
     | 
| 
       56 
56 
     | 
    
         
             
                nh.instance_variable_get(:@proxy_address).must_equal PROXY_HOST
         
     | 
| 
       57 
57 
     | 
    
         
             
                nh.instance_variable_get(:@proxy_port).must_equal PROXY_PORT
         
     | 
| 
       58 
58 
     | 
    
         
             
                assert_requested(:get, HOME_URL)
         
     | 
| 
       59 
59 
     | 
    
         
             
              end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
       61 
61 
     | 
    
         
             
              def refute_use_proxy
         
     | 
| 
       62 
     | 
    
         
            -
                net_http.proxy_class 
     | 
| 
      
 62 
     | 
    
         
            +
                refute net_http.proxy_class?
         
     | 
| 
       63 
63 
     | 
    
         
             
                assert_requested(:get, HOME_URL)
         
     | 
| 
       64 
64 
     | 
    
         
             
              end
         
     | 
| 
       65 
65 
     | 
    
         | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # coding: utf-8
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require ' 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'support/integration_test_case'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Tweetwine::Test::Integration
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -14,7 +14,7 @@ class UserHelpTest < TestCase 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
                  it "shows version and exists with success status" do
         
     | 
| 
       17 
     | 
    
         
            -
                    @output.must_match(/\d+\.\d+\.\d 
     | 
| 
      
 17 
     | 
    
         
            +
                    @output.must_match(/\d+\.\d+\.\d+[\w\.]*$/)
         
     | 
| 
       18 
18 
     | 
    
         
             
                    @status.exitstatus.must_equal 0
         
     | 
| 
       19 
19 
     | 
    
         
             
                  end
         
     | 
| 
       20 
20 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tweetwine::Test
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Assertions
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Asserts whether an Enumeration-like object contains all the elements.
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Fails unless +actual+ contains the same elements as +expected+,
         
     | 
| 
      
 7 
     | 
    
         
            +
                # ignoring the order of the elements.
         
     | 
| 
      
 8 
     | 
    
         
            +
                def assert_contains_exactly(expected, actual, msg_diff_size = nil, msg_diff_elems = nil)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  assert_equal(expected.size, actual.size, message(msg_diff_size) {
         
     | 
| 
      
 10 
     | 
    
         
            +
                    'Expected %s to be of same size as %s' % [actual.inspect, expected.inspect]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  })
         
     | 
| 
      
 12 
     | 
    
         
            +
                  assert(Assertions.enumerable_minus_each_element(actual, expected).empty?, message(msg_diff_elems) {
         
     | 
| 
      
 13 
     | 
    
         
            +
                    'Expected %s to contain all the elements of %s' % [actual.inspect, expected.inspect]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  })
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # Fails unless +str+ is a full match to +regex+.
         
     | 
| 
      
 18 
     | 
    
         
            +
                def assert_full_match(regex, str, msg = nil)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  match_data = regex.match(str)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  assert(str == match_data.to_s, message(msg) {
         
     | 
| 
      
 21 
     | 
    
         
            +
                    'Expected %s to be a full match to %s' % [str, regex.inspect]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  })
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                # Fails if +str+ is a full match to +regex+.
         
     | 
| 
      
 26 
     | 
    
         
            +
                def assert_no_full_match(regex, str, msg = nil)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  match_data = regex.match(str)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  assert(str != match_data.to_s, message(msg) {
         
     | 
| 
      
 29 
     | 
    
         
            +
                    'Expected %s not to be a full match to %s' % [str, regex.inspect]
         
     | 
| 
      
 30 
     | 
    
         
            +
                  })
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Fails unless +fun.call(*args)+ is equal to +expected+ and
         
     | 
| 
      
 34 
     | 
    
         
            +
                # +fun.call(*args)+ is equal to +fun.call(*args.reverse)+.
         
     | 
| 
      
 35 
     | 
    
         
            +
                def assert_commutative(expected, args, msg_not_expected = nil, msg_not_commutative = nil, &fun)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  left_args = args
         
     | 
| 
      
 37 
     | 
    
         
            +
                  left_actual = fun.call(left_args)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  assert_equal(expected, left_actual, message(msg_not_expected) {
         
     | 
| 
      
 39 
     | 
    
         
            +
                    'Expected %s, not %s' % [expected.inspect, left_actual.inspect]
         
     | 
| 
      
 40 
     | 
    
         
            +
                  })
         
     | 
| 
      
 41 
     | 
    
         
            +
                  right_args = args.reverse
         
     | 
| 
      
 42 
     | 
    
         
            +
                  right_actual = fun.call(*right_args)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  assert_equal(left_actual, right_actual, message(msg_not_commutative) {
         
     | 
| 
      
 44 
     | 
    
         
            +
                    'Expected fun%s => %s to be commutative with fun%s => %s' %
         
     | 
| 
      
 45 
     | 
    
         
            +
                      [left_args.inspect, left_actual.inspect, right_args.inspect, right_actual.inspect]
         
     | 
| 
      
 46 
     | 
    
         
            +
                  })
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def self.enumerable_minus_each_element(enumerable, elements)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  remaining = enumerable.dup.to_a
         
     | 
| 
      
 51 
     | 
    
         
            +
                  elements.each do |e|
         
     | 
| 
      
 52 
     | 
    
         
            +
                    index = remaining.index(e)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    remaining.delete_at(index) if index
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  remaining
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     |