rest-core 3.3.2 → 3.3.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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGES.md +22 -0
- data/README.md +4 -7
- data/lib/rest-core/engine/http-client.rb +0 -2
- data/lib/rest-core/event_source.rb +1 -1
- data/lib/rest-core/middleware/auth_basic.rb +1 -1
- data/lib/rest-core/middleware/error_handler.rb +1 -0
- data/lib/rest-core/middleware/oauth1_header.rb +2 -2
- data/lib/rest-core/promise.rb +20 -17
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +3 -3
- data/test/test_client.rb +41 -0
- data/test/test_error_handler.rb +15 -0
- data/test/test_simple.rb +1 -0
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 07acac398a096c63464e9dca43b964dbe0d6359a
         | 
| 4 | 
            +
              data.tar.gz: 887c818f4a83591b316511c709fbbf10e2d45c35
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 24e9ebd41021150461013695d6e7cf4d2e6c628ea5156787c7dd957d4cd72e9df3452529518cfc9a48d1c837379aebee3cc6485bbe6422ba196fb3951f02da19
         | 
| 7 | 
            +
              data.tar.gz: 6a0da34cf3b1221b9b791fb63eee8419c2ce93b6766e395019453f5dc65a8859f24a73a48ef46728ef7e9262186ff0d032334d82ddb777cfcad4b08ec920e4ad
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/CHANGES.md
    CHANGED
    
    | @@ -1,5 +1,27 @@ | |
| 1 1 | 
             
            # CHANGES
         | 
| 2 2 |  | 
| 3 | 
            +
            ## rest-core 3.3.3 -- 2014-11-07
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ### Bugs fixed
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * `RC::EventSource` would now properly reconnect for SystemCallError such as
         | 
| 8 | 
            +
              `Errno::ECONNRESET`.
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            * It would now always emit a warning whenever there's an exception raised
         | 
| 11 | 
            +
              asynchronously.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * All exceptions raised from a thread or thread pool would now have a
         | 
| 14 | 
            +
              proper backtrace. This was fixed by introducing `RC::Promise.backtrace`
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ### Enhancements
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            * Introduced `RC::Promise.backtrace`. Using this in a callback could give you
         | 
| 19 | 
            +
              proper backtrace, comparing to `caller` would only give you the backtrace
         | 
| 20 | 
            +
              for current thread.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            * Introduced `RC::Promise.set_backtrace`. Using this we could set exceptions
         | 
| 23 | 
            +
              with proper backtrace.
         | 
| 24 | 
            +
             | 
| 3 25 | 
             
            ## rest-core 3.3.2 -- 2014-10-11
         | 
| 4 26 |  | 
| 5 27 | 
             
            * Just use `File.join` for `RC::DefaultSite` as `File::SEPARATOR` is
         | 
    
        data/README.md
    CHANGED
    
    | @@ -14,6 +14,9 @@ talk is in Mandarin. | |
| 14 14 | 
             
            * [github](https://github.com/godfat/rest-core)
         | 
| 15 15 | 
             
            * [rubygems](https://rubygems.org/gems/rest-core)
         | 
| 16 16 | 
             
            * [rdoc](http://rdoc.info/projects/godfat/rest-core)
         | 
| 17 | 
            +
            * [mailing list](http://www.freelists.org/list/rest-core)
         | 
| 18 | 
            +
              Send your questions to: <rest-core@freelists.org> and you could read
         | 
| 19 | 
            +
              through [archives](http://www.freelists.org/archives/rest-core)
         | 
| 17 20 |  | 
| 18 21 | 
             
            ## DESCRIPTION:
         | 
| 19 22 |  | 
| @@ -73,8 +76,6 @@ gem 'rest-core', :git => 'git://github.com/godfat/rest-core.git', | |
| 73 76 | 
             
            If you just want to use Facebook or Twitter clients, please take a look at
         | 
| 74 77 | 
             
            [rest-more][] which has a lot of clients built with rest-core.
         | 
| 75 78 |  | 
| 76 | 
            -
            [rest-more]: http://github.com/godfat/rest-more
         | 
| 77 | 
            -
             | 
| 78 79 | 
             
            ## Build Your Own Clients:
         | 
| 79 80 |  | 
| 80 81 | 
             
            You can use `RestCore::Builder` to build your own dedicated clients.
         | 
| @@ -374,12 +375,10 @@ client.request_full(RC::REQUEST_PATH   => 'godfat', | |
| 374 375 |  | 
| 375 376 | 
             
            Runnable example is at: [example/simple.rb][]. Please see [rest-more][]
         | 
| 376 377 | 
             
            for more complex examples to build clients, and [slides][] from
         | 
| 377 | 
            -
            [rubyconf.tw/2011][ | 
| 378 | 
            +
            [rubyconf.tw/2011][talk] for concepts.
         | 
| 378 379 |  | 
| 379 380 | 
             
            [example/simple.rb]: example/simple.rb
         | 
| 380 | 
            -
            [rest-more]: https://github.com/godfat/rest-more
         | 
| 381 381 | 
             
            [slides]: http://www.godfat.org/slide/2011-08-27-rest-core.html
         | 
| 382 | 
            -
            [rubyconf.tw]: http://rubyconf.tw/2011/#6
         | 
| 383 382 |  | 
| 384 383 | 
             
            ## Playing Around:
         | 
| 385 384 |  | 
| @@ -452,7 +451,6 @@ This is mostly for fun and experimenting, so it's only included in | |
| 452 451 | 
             
            installed before trying this.
         | 
| 453 452 |  | 
| 454 453 | 
             
            [rib]: https://github.com/godfat/rib
         | 
| 455 | 
            -
            [rest-more]: https://github.com/godfat/rest-more
         | 
| 456 454 |  | 
| 457 455 | 
             
            ## List of built-in Middleware:
         | 
| 458 456 |  | 
| @@ -683,7 +681,6 @@ all the possible use cases, you can also see: [example/use-cases.rb][]. It's | |
| 683 681 | 
             
            also served as a test for each possible combinations, so it's quite complex
         | 
| 684 682 | 
             
            and complete.
         | 
| 685 683 |  | 
| 686 | 
            -
            [example/simple.rb]: example/simple.rb
         | 
| 687 684 | 
             
            [example/use-cases.rb]: example/use-cases.rb
         | 
| 688 685 |  | 
| 689 686 | 
             
            ## rest-core users:
         | 
| @@ -47,7 +47,7 @@ class RestCore::Oauth1Header | |
| 47 47 |  | 
| 48 48 | 
             
              def signature env, params
         | 
| 49 49 | 
             
                [Hmac.sha1("#{consumer_secret(env)}&#{oauth_token_secret(env)}",
         | 
| 50 | 
            -
                           base_string(env, params))].pack(' | 
| 50 | 
            +
                           base_string(env, params))].pack('m0')
         | 
| 51 51 | 
             
              end
         | 
| 52 52 |  | 
| 53 53 | 
             
              def base_string env, oauth_params
         | 
| @@ -63,7 +63,7 @@ class RestCore::Oauth1Header | |
| 63 63 | 
             
              end
         | 
| 64 64 |  | 
| 65 65 | 
             
              def nonce
         | 
| 66 | 
            -
                [OpenSSL::Random.random_bytes(32)].pack(' | 
| 66 | 
            +
                [OpenSSL::Random.random_bytes(32)].pack('m0').tr("+/=", '')
         | 
| 67 67 | 
             
              end
         | 
| 68 68 |  | 
| 69 69 | 
             
              # according to OAuth 1.0a spec, only:
         | 
    
        data/lib/rest-core/promise.rb
    CHANGED
    
    | @@ -21,6 +21,14 @@ class RestCore::Promise | |
| 21 21 | 
             
                promise
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 | 
            +
              def self.backtrace
         | 
| 25 | 
            +
                Thread.current[:backtrace] || []
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def self.set_backtrace e
         | 
| 29 | 
            +
                e.set_backtrace((e.backtrace || caller) + backtrace)
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 24 32 | 
             
              def initialize env, k=RC.id, immediate=false, &job
         | 
| 25 33 | 
             
                self.env       = env
         | 
| 26 34 | 
             
                self.k         = [k]
         | 
| @@ -58,11 +66,13 @@ class RestCore::Promise | |
| 58 66 | 
             
                if pool_size < 0 # negative number for blocking call
         | 
| 59 67 | 
             
                  job.call
         | 
| 60 68 | 
             
                elsif pool_size > 0
         | 
| 69 | 
            +
                  backtrace = caller + self.class.backtrace
         | 
| 61 70 | 
             
                  self.task = client_class.thread_pool.defer do
         | 
| 62 | 
            -
                    synchronized_yield{ job.call }
         | 
| 71 | 
            +
                    synchronized_yield(backtrace){ job.call }
         | 
| 63 72 | 
             
                  end
         | 
| 64 73 | 
             
                else
         | 
| 65 | 
            -
                   | 
| 74 | 
            +
                  backtrace = caller + self.class.backtrace
         | 
| 75 | 
            +
                  Thread.new{ synchronized_yield(backtrace){ job.call } }
         | 
| 66 76 | 
             
                end
         | 
| 67 77 | 
             
                env[TIMER].on_timeout{ reject(env[TIMER].error) } if env[TIMER]
         | 
| 68 78 | 
             
              end
         | 
| @@ -85,7 +95,8 @@ class RestCore::Promise | |
| 85 95 | 
             
                self.body, self.status, self.headers, self.socket =
         | 
| 86 96 | 
             
                  body, status, headers, socket
         | 
| 87 97 | 
             
                # under ASYNC callback, should call immediately
         | 
| 88 | 
            -
                 | 
| 98 | 
            +
                callback if immediate
         | 
| 99 | 
            +
              ensure
         | 
| 89 100 | 
             
                condv.broadcast # client or response might be waiting
         | 
| 90 101 | 
             
              end
         | 
| 91 102 |  | 
| @@ -112,7 +123,7 @@ class RestCore::Promise | |
| 112 123 | 
             
              # For synchronous mode, since we're waiting for the callback anyway,
         | 
| 113 124 | 
             
              # we don't really have to check if it's called.
         | 
| 114 125 | 
             
              def done?
         | 
| 115 | 
            -
                !!status && ! | 
| 126 | 
            +
                !!status && (!immediate || called)
         | 
| 116 127 | 
             
              end
         | 
| 117 128 |  | 
| 118 129 | 
             
              protected
         | 
| @@ -124,14 +135,16 @@ class RestCore::Promise | |
| 124 135 | 
             
              private
         | 
| 125 136 | 
             
              # called in a new thread if pool_size == 0, otherwise from the pool
         | 
| 126 137 | 
             
              # i.e. requesting thread
         | 
| 127 | 
            -
              def synchronized_yield
         | 
| 138 | 
            +
              def synchronized_yield backtrace
         | 
| 139 | 
            +
                Thread.current[:backtrace] = backtrace
         | 
| 128 140 | 
             
                mutex.synchronize{ yield }
         | 
| 129 141 | 
             
              rescue Exception => e
         | 
| 142 | 
            +
                self.class.set_backtrace(e)
         | 
| 130 143 | 
             
                # nothing we can do here for an asynchronous exception,
         | 
| 131 144 | 
             
                # so we just log the error
         | 
| 132 145 | 
             
                # TODO: add error_log_method
         | 
| 133 146 | 
             
                warn "RestCore: ERROR: #{e}\n  from #{e.backtrace.inspect}"
         | 
| 134 | 
            -
                reject(e) | 
| 147 | 
            +
                reject(e) unless done?  # not done: i/o error; done: callback error
         | 
| 135 148 | 
             
              end
         | 
| 136 149 |  | 
| 137 150 | 
             
              # called in client thread, when yield is called
         | 
| @@ -144,18 +157,8 @@ class RestCore::Promise | |
| 144 157 | 
             
                            RESPONSE_SOCKET  => socket,
         | 
| 145 158 | 
             
                            FAIL             => ((env[FAIL]||[]) + [error]).compact,
         | 
| 146 159 | 
             
                            LOG              =>   env[LOG] ||[])){ |r, i| i.call(r) }
         | 
| 160 | 
            +
              ensure
         | 
| 147 161 | 
             
                self.called = true
         | 
| 148 | 
            -
                response
         | 
| 149 | 
            -
              end
         | 
| 150 | 
            -
             | 
| 151 | 
            -
              # called in requesting thread, whenever the request is done
         | 
| 152 | 
            -
              def callback_in_async
         | 
| 153 | 
            -
                callback
         | 
| 154 | 
            -
              rescue Exception => e
         | 
| 155 | 
            -
                # nothing we can do here for an asynchronous exception,
         | 
| 156 | 
            -
                # so we just log the error
         | 
| 157 | 
            -
                # TODO: add error_log_method
         | 
| 158 | 
            -
                warn "RestCore: ERROR: #{e}\n  from #{e.backtrace.inspect}"
         | 
| 159 162 | 
             
              end
         | 
| 160 163 |  | 
| 161 164 | 
             
              def client_class; env[CLIENT].class; end
         | 
    
        data/lib/rest-core/version.rb
    CHANGED
    
    
    
        data/rest-core.gemspec
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            -
            # stub: rest-core 3.3. | 
| 2 | 
            +
            # stub: rest-core 3.3.3 ruby lib
         | 
| 3 3 |  | 
| 4 4 | 
             
            Gem::Specification.new do |s|
         | 
| 5 5 | 
             
              s.name = "rest-core"
         | 
| 6 | 
            -
              s.version = "3.3. | 
| 6 | 
            +
              s.version = "3.3.3"
         | 
| 7 7 |  | 
| 8 8 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 9 9 | 
             
              s.require_paths = ["lib"]
         | 
| 10 10 | 
             
              s.authors = ["Lin Jen-Shin (godfat)"]
         | 
| 11 | 
            -
              s.date = "2014- | 
| 11 | 
            +
              s.date = "2014-11-07"
         | 
| 12 12 | 
             
              s.description = "Modular Ruby clients interface for REST APIs.\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/godfat/rest-more"
         | 
| 13 13 | 
             
              s.email = ["godfat (XD) godfat.org"]
         | 
| 14 14 | 
             
              s.files = [
         | 
    
        data/test/test_client.rb
    CHANGED
    
    | @@ -49,6 +49,7 @@ describe RC::Simple do | |
| 49 49 | 
             
                stub_request(:get, url).to_return do
         | 
| 50 50 | 
             
                  m.synchronize{ i += 1 }
         | 
| 51 51 | 
             
                  Thread.pass
         | 
| 52 | 
            +
                  {}
         | 
| 52 53 | 
             
                end
         | 
| 53 54 |  | 
| 54 55 | 
             
                client = RC::Builder.client
         | 
| @@ -131,4 +132,44 @@ describe RC::Simple do | |
| 131 132 | 
             
                stub_request(:get, url).to_return(:body => '123')
         | 
| 132 133 | 
             
                Class.new(RC::Simple).new.get(url).should.eq '123'
         | 
| 133 134 | 
             
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              would 'not deadlock when exception was raised in the callback' do
         | 
| 137 | 
            +
                client = Class.new(RC::Simple).new
         | 
| 138 | 
            +
                stub_request(:get, url).to_return(:body => 'nnf')
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                (0..1).each do |size|
         | 
| 141 | 
            +
                  mock(any_instance_of(RC::Promise)).warn(is_a(String)) do |msg|
         | 
| 142 | 
            +
                    msg.should.include?('nnf')
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  client.class.pool_size = size
         | 
| 145 | 
            +
                  client.get(url) do |body|
         | 
| 146 | 
            +
                    raise body
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
                  client.class.shutdown
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                client.class.pool_size = -1
         | 
| 152 | 
            +
                should.raise do
         | 
| 153 | 
            +
                  client.get(url) do |body|
         | 
| 154 | 
            +
                    raise body
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                end.message.should.eq 'nnf'
         | 
| 157 | 
            +
                client.class.shutdown
         | 
| 158 | 
            +
              end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
              would 'be able to access caller outside the callback' do
         | 
| 161 | 
            +
                client = RC::Simple.new
         | 
| 162 | 
            +
                stub_request(:get, url).to_return(:body => 'nnf')
         | 
| 163 | 
            +
                client.get(url) do
         | 
| 164 | 
            +
                  current_file = /^#{__FILE__}/
         | 
| 165 | 
            +
                                 caller.grep(current_file).should.empty?
         | 
| 166 | 
            +
                  RC::Promise.backtrace.grep(current_file).should.not.empty?
         | 
| 167 | 
            +
                  client.get(url) do
         | 
| 168 | 
            +
                    RC::Promise.backtrace.last.should.not =~ /promise\.rb:\d+:in/
         | 
| 169 | 
            +
                    client = nil
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
                client.wait
         | 
| 173 | 
            +
                client.should.nil? # to make sure the inner most block did run
         | 
| 174 | 
            +
              end
         | 
| 134 175 | 
             
            end
         | 
    
        data/test/test_error_handler.rb
    CHANGED
    
    | @@ -41,4 +41,19 @@ describe RC::ErrorHandler do | |
| 41 41 | 
             
                client.new(:error_handler => lambda{ |res| 1 }).
         | 
| 42 42 | 
             
                  request(RC::FAIL => [0], RC::RESPONSE_KEY => RC::FAIL).should.eq [0, 1]
         | 
| 43 43 | 
             
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              would 'set full backtrace' do
         | 
| 46 | 
            +
                url = 'http://example.com/'
         | 
| 47 | 
            +
                client = RC::Builder.client do
         | 
| 48 | 
            +
                  use RC::ErrorHandler, lambda{ |env|
         | 
| 49 | 
            +
                                          RuntimeError.new(env[RC::RESPONSE_BODY]) }
         | 
| 50 | 
            +
                  use RC::ErrorDetectorHttp
         | 
| 51 | 
            +
                end.new
         | 
| 52 | 
            +
                stub_request(:get, url).to_return(:status => 404, :body => 'nnf')
         | 
| 53 | 
            +
                client.get(url) do |error|
         | 
| 54 | 
            +
                  error.message.should.eq 'nnf'
         | 
| 55 | 
            +
                  error.backtrace.grep(/^#{__FILE__}/).should.not.empty?
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                client.wait
         | 
| 58 | 
            +
              end
         | 
| 44 59 | 
             
            end
         | 
    
        data/test/test_simple.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rest-core
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.3. | 
| 4 | 
            +
              version: 3.3.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Lin Jen-Shin (godfat)
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014- | 
| 11 | 
            +
            date: 2014-11-07 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: httpclient
         |