whenner 0.1.1
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 +7 -0
 - data/.gitignore +4 -0
 - data/.rspec +6 -0
 - data/.travis.yml +4 -0
 - data/.yardopts +8 -0
 - data/Gemfile +2 -0
 - data/Gemfile.lock +30 -0
 - data/HISTORY.md +6 -0
 - data/LICENSE +20 -0
 - data/README.md +119 -0
 - data/Rakefile +15 -0
 - data/lib/whenner/callback.rb +55 -0
 - data/lib/whenner/conversions.rb +17 -0
 - data/lib/whenner/deferred.rb +173 -0
 - data/lib/whenner/promise.rb +44 -0
 - data/lib/whenner/version.rb +3 -0
 - data/lib/whenner.rb +63 -0
 - data/spec/whenner/conversions_spec.rb +19 -0
 - data/spec/whenner/deferred_spec.rb +141 -0
 - data/spec/whenner/promise_spec.rb +51 -0
 - data/spec/whenner_spec.rb +39 -0
 - data/whenner.gemspec +42 -0
 - metadata +131 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 9a4aa8af9fb47aa98f75a11bb2433eacf417ae87
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 69d6cbba0ed8f7549028e185618321b31be8a1a0
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 33fe745591cd305f62158756d6de021c3bdb82b1501c73826a9e6a06010db311c4bfbf1f4234ea09680af99d3cea32391a0cfabf0e8b4f33f229ac65601f40b9
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 97794e75339f30bf8de24b1325d51674fe96ee6a55a0e421ff17a54fdcc1e0b02fd97a21c0e1fa2ac28a0cb0b72dc17712fe55c45a424159043ba35f51708117
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/.yardopts
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                whenner (0.1.1)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 7 
     | 
    
         
            +
              remote: https://rubygems.org/
         
     | 
| 
      
 8 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 9 
     | 
    
         
            +
                diff-lcs (1.2.5)
         
     | 
| 
      
 10 
     | 
    
         
            +
                kramdown (1.3.0)
         
     | 
| 
      
 11 
     | 
    
         
            +
                rake (10.1.0)
         
     | 
| 
      
 12 
     | 
    
         
            +
                rspec (2.14.1)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  rspec-core (~> 2.14.0)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  rspec-expectations (~> 2.14.0)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  rspec-mocks (~> 2.14.0)
         
     | 
| 
      
 16 
     | 
    
         
            +
                rspec-core (2.14.7)
         
     | 
| 
      
 17 
     | 
    
         
            +
                rspec-expectations (2.14.4)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  diff-lcs (>= 1.1.3, < 2.0)
         
     | 
| 
      
 19 
     | 
    
         
            +
                rspec-mocks (2.14.4)
         
     | 
| 
      
 20 
     | 
    
         
            +
                yard (0.8.7.3)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 23 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 26 
     | 
    
         
            +
              kramdown
         
     | 
| 
      
 27 
     | 
    
         
            +
              rake
         
     | 
| 
      
 28 
     | 
    
         
            +
              rspec
         
     | 
| 
      
 29 
     | 
    
         
            +
              whenner!
         
     | 
| 
      
 30 
     | 
    
         
            +
              yard
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (C) 2013 Arjan van der Gaag
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy of
         
     | 
| 
      
 5 
     | 
    
         
            +
            this software and associated documentation files (the "Software"), to deal in
         
     | 
| 
      
 6 
     | 
    
         
            +
            the Software without restriction, including without limitation the rights to
         
     | 
| 
      
 7 
     | 
    
         
            +
            use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
         
     | 
| 
      
 8 
     | 
    
         
            +
            of the Software, and to permit persons to whom the Software is furnished to do
         
     | 
| 
      
 9 
     | 
    
         
            +
            so, subject to the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 12 
     | 
    
         
            +
            copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 15 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 16 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 17 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 18 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 19 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 20 
     | 
    
         
            +
            SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,119 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Whenner [](http://travis-ci.org/avdgaag/whenner)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Introduction
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            A promise represents the eventual result of an asynchronous operation. The
         
     | 
| 
      
 6 
     | 
    
         
            +
            primary way of interacting with a promise is through its `done` and `fail`
         
     | 
| 
      
 7 
     | 
    
         
            +
            methods, which registers callbacks to receive either a promise’s eventual value
         
     | 
| 
      
 8 
     | 
    
         
            +
            or the reason why the promise cannot be fulfilled.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Whenner is distributed as a Ruby gem, which should be installed on most Macs and
         
     | 
| 
      
 13 
     | 
    
         
            +
            Linux systems. Once you have ensured you have a working installation of Ruby
         
     | 
| 
      
 14 
     | 
    
         
            +
            and Ruby gems, install the gem as follows from the command line:
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                $ gem install whenner
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            Whenner provides two basic methods to use deferreds:
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            * `Whenner.defer` to create a new deferred object and return its promise. In the
         
     | 
| 
      
 23 
     | 
    
         
            +
              block to the method you can fulfill or reject the deferred.
         
     | 
| 
      
 24 
     | 
    
         
            +
            * `Whenner.when` to convert one or more arguments into promises, combining them
         
     | 
| 
      
 25 
     | 
    
         
            +
              into a single new promise that you can attach callbacks to.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            Deferred objects can give you a promise that, at some point in the future, will
         
     | 
| 
      
 28 
     | 
    
         
            +
            resolve to either a fulfilled or rejected state. When that happens, appropriate
         
     | 
| 
      
 29 
     | 
    
         
            +
            callbacks are called. You can attach such callbacks on a deferred or promise
         
     | 
| 
      
 30 
     | 
    
         
            +
            using three methods:
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            * `done` to register blocks to be called when the promise is fulfilled;
         
     | 
| 
      
 33 
     | 
    
         
            +
            * `fail` to register blocks to be called when the promise is rejected;
         
     | 
| 
      
 34 
     | 
    
         
            +
            * `always` to register blocks to be called when the promise is resolved (either
         
     | 
| 
      
 35 
     | 
    
         
            +
              fulfilled or rejected);
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            Here's an example of making three asynchronous HTTP requests, waiting for them
         
     | 
| 
      
 38 
     | 
    
         
            +
            all to finish and acting on their results:
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 41 
     | 
    
         
            +
            $:.unshift File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 42 
     | 
    
         
            +
            require 'whenner'
         
     | 
| 
      
 43 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 44 
     | 
    
         
            +
            require 'net/http'
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            include Whenner
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            def async_get(uri)
         
     | 
| 
      
 49 
     | 
    
         
            +
              defer do |f|
         
     | 
| 
      
 50 
     | 
    
         
            +
                thread = Thread.new do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  response = Net::HTTP.get_response(URI(uri))
         
     | 
| 
      
 52 
     | 
    
         
            +
                  if response.code =~ /^2/
         
     | 
| 
      
 53 
     | 
    
         
            +
                    f.fulfill response.body
         
     | 
| 
      
 54 
     | 
    
         
            +
                  else
         
     | 
| 
      
 55 
     | 
    
         
            +
                    f.reject response.message
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
                at_exit { thread.join }
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            cnn     = async_get('http://edition.cnn.com')
         
     | 
| 
      
 63 
     | 
    
         
            +
            nytimes = async_get('http://www.nytimes.com')
         
     | 
| 
      
 64 
     | 
    
         
            +
            google  = async_get('http://www.google.nl')
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            Whenner.when(cnn, google, nytimes).done do |results|
         
     | 
| 
      
 67 
     | 
    
         
            +
              results.map { |str| str[/<title>(.+)<\/title>/, 1] }
         
     | 
| 
      
 68 
     | 
    
         
            +
            end.done do |titles|
         
     | 
| 
      
 69 
     | 
    
         
            +
              puts "Success: #{titles.inspect}"
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     | 
| 
      
 71 
     | 
    
         
            +
            ```
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            As methods in Ruby can only take a single block, Whenner does not support a
         
     | 
| 
      
 74 
     | 
    
         
            +
            `then` method yet, that would combine the `done` and `fail` methods. This might
         
     | 
| 
      
 75 
     | 
    
         
            +
            be implementing in the future using something like this:
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 78 
     | 
    
         
            +
            defer { async_get('http://google.com') }.then do |on|
         
     | 
| 
      
 79 
     | 
    
         
            +
              on.done { puts 'Success!' }
         
     | 
| 
      
 80 
     | 
    
         
            +
              on.fail { puts 'Success!' }
         
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
| 
      
 82 
     | 
    
         
            +
            ```
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            ### Documentation
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            See the inline [API
         
     | 
| 
      
 87 
     | 
    
         
            +
            docs](http://rubydoc.info/github/avdgaag/whenner/master/frames) for more
         
     | 
| 
      
 88 
     | 
    
         
            +
            information.
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            ## Other
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            ### Note on Patches/Pull Requests
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            1. Fork the project.
         
     | 
| 
      
 95 
     | 
    
         
            +
            2. Make your feature addition or bug fix.
         
     | 
| 
      
 96 
     | 
    
         
            +
            3. Add tests for it. This is important so I don't break it in a future version
         
     | 
| 
      
 97 
     | 
    
         
            +
               unintentionally.
         
     | 
| 
      
 98 
     | 
    
         
            +
            4. Commit, do not mess with rakefile, version, or history. (if you want to have
         
     | 
| 
      
 99 
     | 
    
         
            +
               your own version, that is fine but bump version in a commit by itself I can
         
     | 
| 
      
 100 
     | 
    
         
            +
               ignore when I pull)
         
     | 
| 
      
 101 
     | 
    
         
            +
            5. Send me a pull request. Bonus points for topic branches.
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            ### Issues
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            Please report any issues, defects or suggestions in the [Github issue
         
     | 
| 
      
 106 
     | 
    
         
            +
            tracker](https://github.com/avdgaag/whenner/issues).
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            ### What has changed?
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            See the [HISTORY](https://github.com/avdgaag/whenner/blob/master/HISTORY.md) file
         
     | 
| 
      
 111 
     | 
    
         
            +
            for a detailed changelog.
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            ### Credits
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
            Created by: Arjan van der Gaag  
         
     | 
| 
      
 116 
     | 
    
         
            +
            URL: [http://arjanvandergaag.nl](http://arjanvandergaag.nl)  
         
     | 
| 
      
 117 
     | 
    
         
            +
            Project homepage: [http://avdgaag.github.com/whenner](http://avdgaag.github.com/whenner)  
         
     | 
| 
      
 118 
     | 
    
         
            +
            Date: april 2012  
         
     | 
| 
      
 119 
     | 
    
         
            +
            License: [MIT-license](https://github.com/avdgaag/whenner/blob/master/LICENSE) (same as Ruby)
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env rake
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 3 
     | 
    
         
            +
            Bundler::GemHelper.install_tasks
         
     | 
| 
      
 4 
     | 
    
         
            +
            Bundler.setup
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            desc 'Default: run specs.'
         
     | 
| 
      
 7 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 10 
     | 
    
         
            +
            desc 'Run specs'
         
     | 
| 
      
 11 
     | 
    
         
            +
            RSpec::Core::RakeTask.new
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require 'yard'
         
     | 
| 
      
 14 
     | 
    
         
            +
            desc 'Generate API docs'
         
     | 
| 
      
 15 
     | 
    
         
            +
            YARD::Rake::YardocTask.new
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A Callback is used internally by {Deferred} to store its callbacks.
         
     | 
| 
      
 3 
     | 
    
         
            +
              # It provides the same `call` interface as regular blocks, but this
         
     | 
| 
      
 4 
     | 
    
         
            +
              # will always return a promise for the block's return value.
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # When the block in question returns a regular object, a new deferred for
         
     | 
| 
      
 7 
     | 
    
         
            +
              # that object is created and immediately fulfilled. When the block raises an
         
     | 
| 
      
 8 
     | 
    
         
            +
              # exception, the returned promise is rejected with that exception. When the
         
     | 
| 
      
 9 
     | 
    
         
            +
              # block returns a promise itself, the returned deferred will mimic that
         
     | 
| 
      
 10 
     | 
    
         
            +
              # promise -- as if that promise is what actually was returned.
         
     | 
| 
      
 11 
     | 
    
         
            +
              class Callback
         
     | 
| 
      
 12 
     | 
    
         
            +
                # A callable object, usually a Ruby block.
         
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # @return [#call]
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :block
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # @return [Deferred] the deferred object representing the block's return
         
     | 
| 
      
 18 
     | 
    
         
            +
                #   value.
         
     | 
| 
      
 19 
     | 
    
         
            +
                attr_reader :deferred
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def initialize(block)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @block    = block
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @deferred = Deferred.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                # Run the block, passing it any given arguments, and return a promise
         
     | 
| 
      
 27 
     | 
    
         
            +
                # for its return value.
         
     | 
| 
      
 28 
     | 
    
         
            +
                #
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @return [Promise]
         
     | 
| 
      
 30 
     | 
    
         
            +
                def call(*args)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  update_deferred(*args)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  deferred.promise
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                # @return [Promise] for this callback's {#deferred}.
         
     | 
| 
      
 36 
     | 
    
         
            +
                # @see #deferred
         
     | 
| 
      
 37 
     | 
    
         
            +
                def promise
         
     | 
| 
      
 38 
     | 
    
         
            +
                  deferred.promise
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                private
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def update_deferred(*args)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  retval = block.call(*args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if retval.kind_of?(Promise)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    retval.done { |arg| deferred.fulfill(arg) }
         
     | 
| 
      
 47 
     | 
    
         
            +
                    retval.fail { |arg| deferred.reject(arg) }
         
     | 
| 
      
 48 
     | 
    
         
            +
                  else
         
     | 
| 
      
 49 
     | 
    
         
            +
                    deferred.fulfill(retval)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 52 
     | 
    
         
            +
                  deferred.reject(e)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Conversions
         
     | 
| 
      
 3 
     | 
    
         
            +
                module_function
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                # Convert any object to a promise. When the object in question responds to
         
     | 
| 
      
 6 
     | 
    
         
            +
                # `to_promise`, the result of that method will be returned. If not, a new
         
     | 
| 
      
 7 
     | 
    
         
            +
                # deferred object is created and immediately fulfilled with the given
         
     | 
| 
      
 8 
     | 
    
         
            +
                # object.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # @param [Object] obj
         
     | 
| 
      
 11 
     | 
    
         
            +
                # @return [Promise]
         
     | 
| 
      
 12 
     | 
    
         
            +
                def Promise(obj)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  return obj.to_promise if obj.respond_to?(:to_promise)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  Deferred.new.fulfill(obj)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,173 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A deferred object is an operation that will eventually resolve to a result
         
     | 
| 
      
 3 
     | 
    
         
            +
              # value. A deferred can be in three possible states:
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              # * Pending: it has been created but not yet resolved.
         
     | 
| 
      
 6 
     | 
    
         
            +
              # * Fulfilled: it has been successfully resolved.
         
     | 
| 
      
 7 
     | 
    
         
            +
              # * Rejected: it has been unsuccessfully resolved.
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              # A deferred might transition from pending to fulfilled or rejected, but it
         
     | 
| 
      
 10 
     | 
    
         
            +
              # will not transition again once resolved (resolved can be either fulfilled
         
     | 
| 
      
 11 
     | 
    
         
            +
              # or rejected).
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              # When a deferred does resolve, it will trigger any applicable callbacks. You
         
     | 
| 
      
 14 
     | 
    
         
            +
              # can stack on callbacks on a deferred object before it has been resolved and
         
     | 
| 
      
 15 
     | 
    
         
            +
              # they will be called later. When you register callbacks on an already
         
     | 
| 
      
 16 
     | 
    
         
            +
              # resolved deferred, the callback will be called immediately. Note that a
         
     | 
| 
      
 17 
     | 
    
         
            +
              # callback will only be run once.
         
     | 
| 
      
 18 
     | 
    
         
            +
              #
         
     | 
| 
      
 19 
     | 
    
         
            +
              # When a callback is in the fulfilled state, it has a value that represents
         
     | 
| 
      
 20 
     | 
    
         
            +
              # its eventual outcome. When it is rejected, it has a reason.
         
     | 
| 
      
 21 
     | 
    
         
            +
              class Deferred
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @return [Promise] a promise for this deferred
         
     | 
| 
      
 23 
     | 
    
         
            +
                attr_reader :promise
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @promise             = Promise.new(self)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @state               = :pending
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @fulfilled_callbacks = []
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @rejected_callbacks  = []
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @always_callbacks    = []
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # The value the deferred was resolved with.
         
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                # @raise [UnresolvedError] when the deferred is still pending
         
     | 
| 
      
 36 
     | 
    
         
            +
                def value
         
     | 
| 
      
 37 
     | 
    
         
            +
                  raise UnresolvedError unless resolved?
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @value
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                # The reason the deferred was rejected.
         
     | 
| 
      
 42 
     | 
    
         
            +
                #
         
     | 
| 
      
 43 
     | 
    
         
            +
                # @raise [UnresolvedError] when the deferred is still pending
         
     | 
| 
      
 44 
     | 
    
         
            +
                def reason
         
     | 
| 
      
 45 
     | 
    
         
            +
                  raise UnresolvedError unless resolved?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @reason
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                # @return [Boolean] whether the deferred has not been resolved yet.
         
     | 
| 
      
 50 
     | 
    
         
            +
                def pending?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  state == :pending
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # @return [Boolean] whether the deferred was successfully resolved.
         
     | 
| 
      
 55 
     | 
    
         
            +
                def fulfilled?
         
     | 
| 
      
 56 
     | 
    
         
            +
                  state == :fulfilled
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                # @return [Boolean] whether the deferred was rejected.
         
     | 
| 
      
 60 
     | 
    
         
            +
                def rejected?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  state == :rejected
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                # @return [Boolean] whether the deferred was either fulfilled or rejected.
         
     | 
| 
      
 65 
     | 
    
         
            +
                def resolved?
         
     | 
| 
      
 66 
     | 
    
         
            +
                  fulfilled? || rejected?
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                # Fulfill this promise with an optional value. The value will be stored in
         
     | 
| 
      
 70 
     | 
    
         
            +
                # the deferred and passed along to any registered `done` callbacks.
         
     | 
| 
      
 71 
     | 
    
         
            +
                #
         
     | 
| 
      
 72 
     | 
    
         
            +
                # When fulfilling a deferred twice, nothing happens.
         
     | 
| 
      
 73 
     | 
    
         
            +
                #
         
     | 
| 
      
 74 
     | 
    
         
            +
                # @raise [CannotTransitionError] when it was already fulfilled.
         
     | 
| 
      
 75 
     | 
    
         
            +
                # @return [Deferred] self
         
     | 
| 
      
 76 
     | 
    
         
            +
                def fulfill(value = nil)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  raise CannotTransitionError if rejected?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  return if fulfilled?
         
     | 
| 
      
 79 
     | 
    
         
            +
                  unless resolved?
         
     | 
| 
      
 80 
     | 
    
         
            +
                    self.value = value
         
     | 
| 
      
 81 
     | 
    
         
            +
                    resolve_to(:fulfilled)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
                  self
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                # Reject this promise with an optional reason. The reason will be stored in
         
     | 
| 
      
 87 
     | 
    
         
            +
                # the deferred and passed along to any registered `fail` callbacks.
         
     | 
| 
      
 88 
     | 
    
         
            +
                #
         
     | 
| 
      
 89 
     | 
    
         
            +
                # When rejecting a deferred twice, nothing happens.
         
     | 
| 
      
 90 
     | 
    
         
            +
                #
         
     | 
| 
      
 91 
     | 
    
         
            +
                # @raise [CannotTransitionError] when it was already fulfilled.
         
     | 
| 
      
 92 
     | 
    
         
            +
                # @return [Deferred] self
         
     | 
| 
      
 93 
     | 
    
         
            +
                def reject(reason = nil)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  raise CannotTransitionError if fulfilled?
         
     | 
| 
      
 95 
     | 
    
         
            +
                  return if rejected?
         
     | 
| 
      
 96 
     | 
    
         
            +
                  unless resolved?
         
     | 
| 
      
 97 
     | 
    
         
            +
                    self.reason = reason
         
     | 
| 
      
 98 
     | 
    
         
            +
                    resolve_to(:rejected)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
                  self
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                # @return [Promise]
         
     | 
| 
      
 104 
     | 
    
         
            +
                def to_promise
         
     | 
| 
      
 105 
     | 
    
         
            +
                  promise
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                # Register a callback to be run when the deferred is fulfilled.
         
     | 
| 
      
 109 
     | 
    
         
            +
                #
         
     | 
| 
      
 110 
     | 
    
         
            +
                # @yieldparam [Object] value
         
     | 
| 
      
 111 
     | 
    
         
            +
                # @return [Promise] a new promise representing the return value
         
     | 
| 
      
 112 
     | 
    
         
            +
                #   of the callback, or -- when that return value is a promise itself
         
     | 
| 
      
 113 
     | 
    
         
            +
                #   -- a promise mimicking that promise.
         
     | 
| 
      
 114 
     | 
    
         
            +
                def done(&block)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  cb = Callback.new(block)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  fulfilled_callbacks << cb
         
     | 
| 
      
 117 
     | 
    
         
            +
                  cb.call(*callback_response) if fulfilled?
         
     | 
| 
      
 118 
     | 
    
         
            +
                  cb.promise
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                # Register a callback to be run when the deferred is rejected.
         
     | 
| 
      
 122 
     | 
    
         
            +
                #
         
     | 
| 
      
 123 
     | 
    
         
            +
                # @yieldparam [Object] reason
         
     | 
| 
      
 124 
     | 
    
         
            +
                # @return [Promise] a new promise representing the return value
         
     | 
| 
      
 125 
     | 
    
         
            +
                #   of the callback, or -- when that return value is a promise itself
         
     | 
| 
      
 126 
     | 
    
         
            +
                #   -- a promise mimicking that promise.
         
     | 
| 
      
 127 
     | 
    
         
            +
                def fail(&block)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  cb = Callback.new(block)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  rejected_callbacks << cb
         
     | 
| 
      
 130 
     | 
    
         
            +
                  cb.call(*callback_response) if rejected?
         
     | 
| 
      
 131 
     | 
    
         
            +
                  cb.promise
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                # Register a callback to be run when the deferred is resolved.
         
     | 
| 
      
 135 
     | 
    
         
            +
                #
         
     | 
| 
      
 136 
     | 
    
         
            +
                # @yieldparam [Object] value
         
     | 
| 
      
 137 
     | 
    
         
            +
                # @yieldparam [Object] reason
         
     | 
| 
      
 138 
     | 
    
         
            +
                # @return [Promise] a new promise representing the return value
         
     | 
| 
      
 139 
     | 
    
         
            +
                #   of the callback, or -- when that return value is a promise itself
         
     | 
| 
      
 140 
     | 
    
         
            +
                #   -- a promise mimicking that promise.
         
     | 
| 
      
 141 
     | 
    
         
            +
                def always(&block)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  cb = Callback.new(block)
         
     | 
| 
      
 143 
     | 
    
         
            +
                  always_callbacks << cb
         
     | 
| 
      
 144 
     | 
    
         
            +
                  cb.call(*callback_response) if resolved?
         
     | 
| 
      
 145 
     | 
    
         
            +
                  cb.promise
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                private
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                attr_accessor :state
         
     | 
| 
      
 151 
     | 
    
         
            +
                attr_writer :value, :reason
         
     | 
| 
      
 152 
     | 
    
         
            +
                attr_reader :fulfilled_callbacks, :rejected_callbacks, :always_callbacks
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                def resolve_to(state)
         
     | 
| 
      
 155 
     | 
    
         
            +
                  self.state = state
         
     | 
| 
      
 156 
     | 
    
         
            +
                  flush
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                def result_callbacks
         
     | 
| 
      
 160 
     | 
    
         
            +
                  fulfilled? ? fulfilled_callbacks : rejected_callbacks
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                def callback_response
         
     | 
| 
      
 164 
     | 
    
         
            +
                  fulfilled? ? value : reason
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                def flush
         
     | 
| 
      
 168 
     | 
    
         
            +
                  (result_callbacks + always_callbacks).each do |cb|
         
     | 
| 
      
 169 
     | 
    
         
            +
                    cb.call(callback_response)
         
     | 
| 
      
 170 
     | 
    
         
            +
                  end
         
     | 
| 
      
 171 
     | 
    
         
            +
                end
         
     | 
| 
      
 172 
     | 
    
         
            +
              end
         
     | 
| 
      
 173 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A promise represents the public face of a {Deferred} object. You can use it
         
     | 
| 
      
 3 
     | 
    
         
            +
              # to add more callbacks to the deferred or inspect its state -- but you
         
     | 
| 
      
 4 
     | 
    
         
            +
              # cannot resolve it.
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # The methods and attributes of the promise are basically forwarded to the
         
     | 
| 
      
 7 
     | 
    
         
            +
              # deferred.
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Promise
         
     | 
| 
      
 9 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # @!attribute [r] fulfilled?
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   @return [Boolean] whether the deferred was successfully resolved.
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @!attribute [r] resolved?
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   @return [Boolean] whether the deferred was either fulfilled or rejected.
         
     | 
| 
      
 15 
     | 
    
         
            +
                # @!attribute [r] rejected?
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   @return [Boolean] whether the deferred was rejected.
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @!attribute [r] pending?
         
     | 
| 
      
 18 
     | 
    
         
            +
                #   @return [Boolean] whether the deferred has not been resolved yet.
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @!attribute [r] reason
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   @return [Object] the reason for the deferred to be rejected.
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @!attribute [r] value
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   @return [Object] the value that the deferred was fulfilled with.
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @!method fail(&block)
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   Register a callback to fire when the deferred is rejected.
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   @return [Promise] a new promise for the return value of the block.
         
     | 
| 
      
 26 
     | 
    
         
            +
                # @!method done(&block)
         
     | 
| 
      
 27 
     | 
    
         
            +
                #   Register a callback to fire when the deferred is fulfilled.
         
     | 
| 
      
 28 
     | 
    
         
            +
                #   @return [Promise] a new promise for the return value of the block.
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @!method always(&block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                #   Register a callback to fire when the deferred is resolved.
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   @return [Promise] a new promise for the return value of the block.
         
     | 
| 
      
 32 
     | 
    
         
            +
                def_delegators :@deferred, *%i[
         
     | 
| 
      
 33 
     | 
    
         
            +
                  reason value pending? fulfilled? resolved? rejected? fail done always
         
     | 
| 
      
 34 
     | 
    
         
            +
                ]
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def initialize(deferred)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @deferred = deferred
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def to_promise
         
     | 
| 
      
 41 
     | 
    
         
            +
                  self
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/whenner.rb
    ADDED
    
    | 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'whenner/version'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'whenner/conversions'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'whenner/callback'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'whenner/deferred'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'whenner/promise'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Generic root exception for the Whenner library. Any other custom
         
     | 
| 
      
 11 
     | 
    
         
            +
              # exceptions inherit from WhennerError.
         
     | 
| 
      
 12 
     | 
    
         
            +
              class WhennerError < StandardError; end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              # Custom exception raised when trying to access a deferred's value or
         
     | 
| 
      
 15 
     | 
    
         
            +
              # reason before it is resolved.
         
     | 
| 
      
 16 
     | 
    
         
            +
              #
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @see WhennerError
         
     | 
| 
      
 18 
     | 
    
         
            +
              class UnresolvedError < WhennerError; end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              # Custom exception raised when trying to transition an already resolved
         
     | 
| 
      
 21 
     | 
    
         
            +
              # deferred.
         
     | 
| 
      
 22 
     | 
    
         
            +
              #
         
     | 
| 
      
 23 
     | 
    
         
            +
              # @see WhennerError
         
     | 
| 
      
 24 
     | 
    
         
            +
              class CannotTransitionError < WhennerError; end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              module_function
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              # Create a new deferred, resolve it in the block and get its promise back.
         
     | 
| 
      
 29 
     | 
    
         
            +
              #
         
     | 
| 
      
 30 
     | 
    
         
            +
              # @yieldparam [Deferred] deferred
         
     | 
| 
      
 31 
     | 
    
         
            +
              # @return [Promise]
         
     | 
| 
      
 32 
     | 
    
         
            +
              def defer
         
     | 
| 
      
 33 
     | 
    
         
            +
                deferred = Deferred.new
         
     | 
| 
      
 34 
     | 
    
         
            +
                yield deferred
         
     | 
| 
      
 35 
     | 
    
         
            +
                deferred.promise
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              # Create a new deferred based that will resolve if/when the given promises
         
     | 
| 
      
 39 
     | 
    
         
            +
              # are resolved. Use to combine multiple promises into a single deferred
         
     | 
| 
      
 40 
     | 
    
         
            +
              # object.
         
     | 
| 
      
 41 
     | 
    
         
            +
              #
         
     | 
| 
      
 42 
     | 
    
         
            +
              # When all the given promises are fulfilled, the resulting promise from
         
     | 
| 
      
 43 
     | 
    
         
            +
              # `when` if fulfilled with an array of all the values. When one of the given
         
     | 
| 
      
 44 
     | 
    
         
            +
              # promises is rejected, the resulting promise is rejected with that reason.
         
     | 
| 
      
 45 
     | 
    
         
            +
              #
         
     | 
| 
      
 46 
     | 
    
         
            +
              # @param [Object] promises
         
     | 
| 
      
 47 
     | 
    
         
            +
              # @return [Promise]
         
     | 
| 
      
 48 
     | 
    
         
            +
              def when(*promises)
         
     | 
| 
      
 49 
     | 
    
         
            +
                defer do |d|
         
     | 
| 
      
 50 
     | 
    
         
            +
                  promises.each_with_object([]) do |promise, values|
         
     | 
| 
      
 51 
     | 
    
         
            +
                    Conversions.Promise(promise).tap do |p|
         
     | 
| 
      
 52 
     | 
    
         
            +
                      p.done  do |value|
         
     | 
| 
      
 53 
     | 
    
         
            +
                        values << value
         
     | 
| 
      
 54 
     | 
    
         
            +
                        d.fulfill(values) if values.size == promises.size
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
      
 56 
     | 
    
         
            +
                      p.fail do |reason|
         
     | 
| 
      
 57 
     | 
    
         
            +
                        d.reject(reason)
         
     | 
| 
      
 58 
     | 
    
         
            +
                      end
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              describe '#Promise' do
         
     | 
| 
      
 3 
     | 
    
         
            +
                it 'returns a promise itself' do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  promise = Whenner::Deferred.new.promise
         
     | 
| 
      
 5 
     | 
    
         
            +
                  expect(Whenner::Conversions.Promise(promise)).to be(promise)
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                it 'returns a promise for a deferred' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  deferred = Whenner::Deferred.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  expect(Whenner::Conversions.Promise(deferred)).to be(deferred.promise)
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                it 'returns a resolved promise for an object' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  promise = Whenner::Conversions.Promise('foo')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  expect(promise.value).to eql('foo')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  expect(promise).to be_fulfilled
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,141 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              describe Deferred do
         
     | 
| 
      
 3 
     | 
    
         
            +
                it 'is pending by default' do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  expect(subject).to be_pending
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                context 'when pending' do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  it 'can be fulfilled' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    subject.fulfill
         
     | 
| 
      
 10 
     | 
    
         
            +
                    expect(subject).to be_fulfilled
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  it 'can be rejected' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                    subject.reject
         
     | 
| 
      
 15 
     | 
    
         
            +
                    expect(subject).to be_rejected
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  it 'has no value' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                    expect { subject.value }.to raise_error
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                context 'when fulfilled' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                  subject do
         
     | 
| 
      
 25 
     | 
    
         
            +
                    described_class.new.tap { |d| d.fulfill }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  it 'cannot transition to other states' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    expect { subject.reject }.to raise_error
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  it 'has a value' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                    expect(subject.value).to be_nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                context 'when rejected' do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  subject do
         
     | 
| 
      
 39 
     | 
    
         
            +
                    described_class.new.tap { |d| d.reject(:foo) }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  it 'cannot transition to other states' do
         
     | 
| 
      
 43 
     | 
    
         
            +
                    expect { subject.fulfill }.to raise_error
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  it 'has a reason' do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    expect(subject.reason).to eql(:foo)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                it 'creates a promise' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  expect(subject.promise).to be_kind_of(Promise)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                context 'callbacks' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                  it 'calls fulfillment callbacks when fulfilled' do
         
     | 
| 
      
 57 
     | 
    
         
            +
                    resolved = false
         
     | 
| 
      
 58 
     | 
    
         
            +
                    subject.done { resolved = true }
         
     | 
| 
      
 59 
     | 
    
         
            +
                    expect { subject.fulfill(:a) }.to change { resolved }.to(true)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  it 'calls rejection callbacks when rejected' do
         
     | 
| 
      
 63 
     | 
    
         
            +
                    resolved = false
         
     | 
| 
      
 64 
     | 
    
         
            +
                    subject.fail { resolved = true }
         
     | 
| 
      
 65 
     | 
    
         
            +
                    expect { subject.reject(:a) }.to change { resolved }.to(true)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  it 'calls always callbacks when resolved' do
         
     | 
| 
      
 69 
     | 
    
         
            +
                    resolved = false
         
     | 
| 
      
 70 
     | 
    
         
            +
                    subject.always { resolved = true }
         
     | 
| 
      
 71 
     | 
    
         
            +
                    expect { subject.fulfill(:a) }.to change { resolved }.to(true)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  it 'passes fulfillment callbacks the value' do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    resolved = nil
         
     | 
| 
      
 76 
     | 
    
         
            +
                    subject.done { |arg| resolved = arg }
         
     | 
| 
      
 77 
     | 
    
         
            +
                    expect { subject.fulfill(:a) }.to change { resolved }.to(:a)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  it 'passes rejection callbacks the reason' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                    resolved = nil
         
     | 
| 
      
 82 
     | 
    
         
            +
                    subject.done { |arg| resolved = arg }
         
     | 
| 
      
 83 
     | 
    
         
            +
                    expect { subject.fulfill(:a) }.to change { resolved }.to(:a)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  it 'passes the value and reason to always callbacks' do
         
     | 
| 
      
 87 
     | 
    
         
            +
                    subject.always do |value, reason|
         
     | 
| 
      
 88 
     | 
    
         
            +
                      expect(value).to eql(:a)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      expect(reason).to be_nil
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    subject.fulfill(:a)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  it 'calls callbacks only once' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                    called = 0
         
     | 
| 
      
 96 
     | 
    
         
            +
                    subject.done { called += 1 }
         
     | 
| 
      
 97 
     | 
    
         
            +
                    subject.fulfill(:a)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    subject.fulfill(:b)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    expect(called).to eql(1)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  it 'runs callbacks in order' do
         
     | 
| 
      
 103 
     | 
    
         
            +
                    output = ''
         
     | 
| 
      
 104 
     | 
    
         
            +
                    subject.done { output << 'a' }
         
     | 
| 
      
 105 
     | 
    
         
            +
                    subject.done { output << 'b' }
         
     | 
| 
      
 106 
     | 
    
         
            +
                    subject.fulfill
         
     | 
| 
      
 107 
     | 
    
         
            +
                    expect(output).to eql('ab')
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  it 'returns a new promise that fulfills to the value' do
         
     | 
| 
      
 111 
     | 
    
         
            +
                    new_promise = subject.done { 'foo' }
         
     | 
| 
      
 112 
     | 
    
         
            +
                    subject.fulfill
         
     | 
| 
      
 113 
     | 
    
         
            +
                    expect(new_promise.value).to eql('foo')
         
     | 
| 
      
 114 
     | 
    
         
            +
                    expect(new_promise).to be_fulfilled
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  it 'returns a new promise that rejects to the reason' do
         
     | 
| 
      
 118 
     | 
    
         
            +
                    new_promise = subject.fail { 'foo' }
         
     | 
| 
      
 119 
     | 
    
         
            +
                    subject.reject
         
     | 
| 
      
 120 
     | 
    
         
            +
                    expect(new_promise.value).to eql('foo')
         
     | 
| 
      
 121 
     | 
    
         
            +
                    expect(new_promise).to be_fulfilled
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  it 'returns a new promise that mimics a promise value' do
         
     | 
| 
      
 125 
     | 
    
         
            +
                    d = Deferred.new
         
     | 
| 
      
 126 
     | 
    
         
            +
                    new_promise = subject.done { d.promise }
         
     | 
| 
      
 127 
     | 
    
         
            +
                    subject.fulfill(:b)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    d.fulfill(:a)
         
     | 
| 
      
 129 
     | 
    
         
            +
                    expect(new_promise.value).to eql(:a)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  it 'is rejected on exception' do
         
     | 
| 
      
 133 
     | 
    
         
            +
                    called = false
         
     | 
| 
      
 134 
     | 
    
         
            +
                    promise = subject.done { raise 'arg' }
         
     | 
| 
      
 135 
     | 
    
         
            +
                    promise.fail { |e| called = e }
         
     | 
| 
      
 136 
     | 
    
         
            +
                    subject.fulfill
         
     | 
| 
      
 137 
     | 
    
         
            +
                    expect(called).to be_a(RuntimeError)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
              end
         
     | 
| 
      
 141 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whenner
         
     | 
| 
      
 2 
     | 
    
         
            +
              describe Promise do
         
     | 
| 
      
 3 
     | 
    
         
            +
                let(:deferred)    { Deferred.new }
         
     | 
| 
      
 4 
     | 
    
         
            +
                subject(:promise) { deferred.promise }
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                it 'converts into a promise as itself' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  expect(promise.to_promise).to be(promise)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                describe 'callbacks' do
         
     | 
| 
      
 11 
     | 
    
         
            +
                  it 'can add done callbacks to the deferred' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                    expect { promise.done { :a } }.to change { deferred.send(:fulfilled_callbacks).size }.by(1)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  it 'can add fail callbacks to the deferred' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    expect { promise.fail { :a } }.to change { deferred.send(:rejected_callbacks).size }.by(1)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  it 'can add always callbacks to the deferred' do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    expect { promise.always { :a } }.to change { deferred.send(:always_callbacks).size }.by(1)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                context 'when the deferred is fulfilled' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  let(:deferred) { Deferred.new.fulfill(:a) }
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  it 'has a value' do
         
     | 
| 
      
 28 
     | 
    
         
            +
                    expect(promise.value).to eql(:a)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  it 'knows its state' do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    expect(promise).to be_resolved
         
     | 
| 
      
 33 
     | 
    
         
            +
                    expect(promise).to be_fulfilled
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                context 'when the deferred is rejected' do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  let(:deferred) { Deferred.new.reject(:a) }
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  it 'has a reason' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    expect(promise.reason).to eql(:a)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  it 'knows its state' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect(promise).to be_resolved
         
     | 
| 
      
 47 
     | 
    
         
            +
                    expect(promise).to be_rejected
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            describe Whenner do
         
     | 
| 
      
 2 
     | 
    
         
            +
              describe '#defer' do
         
     | 
| 
      
 3 
     | 
    
         
            +
                it 'returns a new promise' do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  promise = Whenner.defer { 'bla' }
         
     | 
| 
      
 5 
     | 
    
         
            +
                  expect(promise).to be_kind_of(Whenner::Promise)
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                it 'yields a deferred' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  expect { |b| Whenner.defer(&b) }.to yield_with_args(Whenner::Deferred)
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              describe '#when' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                let(:deferred1) { Whenner::Deferred.new }
         
     | 
| 
      
 15 
     | 
    
         
            +
                let(:deferred2) { Whenner::Deferred.new }
         
     | 
| 
      
 16 
     | 
    
         
            +
                let!(:promise)  { Whenner.when(deferred1.promise, deferred2.promise) }
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                it 'returns a promise' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  expect(Whenner.when).to be_kind_of(Whenner::Promise)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                it 'resolves when all given promises are resolved' do
         
     | 
| 
      
 23 
     | 
    
         
            +
                  expect { deferred1.fulfill }.not_to change { promise.resolved? }.from(false)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  expect { deferred2.fulfill }.to change { promise.resolved? }.to(true)
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                it 'fulfills with all values' do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  deferred1.fulfill :a
         
     | 
| 
      
 29 
     | 
    
         
            +
                  deferred2.fulfill :b
         
     | 
| 
      
 30 
     | 
    
         
            +
                  expect(promise.value).to eql([:a, :b])
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                it 'rejects with the first reason' do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  deferred1.reject :a
         
     | 
| 
      
 35 
     | 
    
         
            +
                  deferred2.reject :b
         
     | 
| 
      
 36 
     | 
    
         
            +
                  expect(promise.reason).to eql(:a)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/whenner.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            require File.expand_path('../lib/whenner/version', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Metadata
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.name        = 'whenner'
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version     = Whenner::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.platform    = Gem::Platform::RUBY
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.authors     = ['Arjan van der Gaag']
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.email       = %q{arjan@arjanvandergaag.nl}
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.description = %q{A simple promises implementation in Ruby.}
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.homepage    = %q{http://avdgaag.github.com/whenner}
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.summary     = <<-EOS
         
     | 
| 
      
 14 
     | 
    
         
            +
            A promise represents the eventual result of an asynchronous operation. The
         
     | 
| 
      
 15 
     | 
    
         
            +
            primary way of interacting with a promise is through its `done` and `fail`
         
     | 
| 
      
 16 
     | 
    
         
            +
            methods, which registers callbacks to receive either a promise’s eventual value
         
     | 
| 
      
 17 
     | 
    
         
            +
            or the reason why the promise cannot be fulfilled.
         
     | 
| 
      
 18 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              # Files
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.files         = `git ls-files`.split("
         
     | 
| 
      
 22 
     | 
    
         
            +
            ")
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("
         
     | 
| 
      
 24 
     | 
    
         
            +
            ")
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("
         
     | 
| 
      
 26 
     | 
    
         
            +
            ").map{ |f| File.basename(f) }
         
     | 
| 
      
 27 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              # Rdoc
         
     | 
| 
      
 30 
     | 
    
         
            +
              s.rdoc_options = ['--charset=UTF-8']
         
     | 
| 
      
 31 
     | 
    
         
            +
              s.extra_rdoc_files = [
         
     | 
| 
      
 32 
     | 
    
         
            +
                 'LICENSE',
         
     | 
| 
      
 33 
     | 
    
         
            +
                 'README.md',
         
     | 
| 
      
 34 
     | 
    
         
            +
                 'HISTORY.md'
         
     | 
| 
      
 35 
     | 
    
         
            +
              ]
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              # Dependencies
         
     | 
| 
      
 38 
     | 
    
         
            +
              s.add_development_dependency 'kramdown'
         
     | 
| 
      
 39 
     | 
    
         
            +
              s.add_development_dependency 'yard'
         
     | 
| 
      
 40 
     | 
    
         
            +
              s.add_development_dependency 'rspec'
         
     | 
| 
      
 41 
     | 
    
         
            +
              s.add_development_dependency 'rake'
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,131 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: whenner
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Arjan van der Gaag
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2013-12-12 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: kramdown
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: yard
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            description: A simple promises implementation in Ruby.
         
     | 
| 
      
 70 
     | 
    
         
            +
            email: arjan@arjanvandergaag.nl
         
     | 
| 
      
 71 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 72 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 73 
     | 
    
         
            +
            extra_rdoc_files:
         
     | 
| 
      
 74 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 75 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 76 
     | 
    
         
            +
            - HISTORY.md
         
     | 
| 
      
 77 
     | 
    
         
            +
            files:
         
     | 
| 
      
 78 
     | 
    
         
            +
            - .gitignore
         
     | 
| 
      
 79 
     | 
    
         
            +
            - .rspec
         
     | 
| 
      
 80 
     | 
    
         
            +
            - .travis.yml
         
     | 
| 
      
 81 
     | 
    
         
            +
            - .yardopts
         
     | 
| 
      
 82 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 83 
     | 
    
         
            +
            - Gemfile.lock
         
     | 
| 
      
 84 
     | 
    
         
            +
            - HISTORY.md
         
     | 
| 
      
 85 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 86 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 87 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/whenner.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib/whenner/callback.rb
         
     | 
| 
      
 90 
     | 
    
         
            +
            - lib/whenner/conversions.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - lib/whenner/deferred.rb
         
     | 
| 
      
 92 
     | 
    
         
            +
            - lib/whenner/promise.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - lib/whenner/version.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - spec/whenner/conversions_spec.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - spec/whenner/deferred_spec.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - spec/whenner/promise_spec.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - spec/whenner_spec.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            - whenner.gemspec
         
     | 
| 
      
 99 
     | 
    
         
            +
            homepage: http://avdgaag.github.com/whenner
         
     | 
| 
      
 100 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 101 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 102 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 103 
     | 
    
         
            +
            rdoc_options:
         
     | 
| 
      
 104 
     | 
    
         
            +
            - --charset=UTF-8
         
     | 
| 
      
 105 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 106 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 107 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 108 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 109 
     | 
    
         
            +
              - - '>='
         
     | 
| 
      
 110 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 111 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 112 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 113 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 114 
     | 
    
         
            +
              - - '>='
         
     | 
| 
      
 115 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 116 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 117 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 118 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 119 
     | 
    
         
            +
            rubygems_version: 2.1.11
         
     | 
| 
      
 120 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 121 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 122 
     | 
    
         
            +
            summary: A promise represents the eventual result of an asynchronous operation. The
         
     | 
| 
      
 123 
     | 
    
         
            +
              primary way of interacting with a promise is through its `done` and `fail` methods,
         
     | 
| 
      
 124 
     | 
    
         
            +
              which registers callbacks to receive either a promise’s eventual value or the reason
         
     | 
| 
      
 125 
     | 
    
         
            +
              why the promise cannot be fulfilled.
         
     | 
| 
      
 126 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 127 
     | 
    
         
            +
            - spec/whenner/conversions_spec.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - spec/whenner/deferred_spec.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - spec/whenner/promise_spec.rb
         
     | 
| 
      
 130 
     | 
    
         
            +
            - spec/whenner_spec.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            has_rdoc: 
         
     |