<commit_before>require 'thread'

require 'concurrent/global_thread_pool'
require 'concurrent/obligation'

module Concurrent

  class Promise
    include Obligation
    include UsesGlobalThreadPool

    # Creates a new promise object. "A promise represents the eventual
    # value returned from the single completion of an operation."
    # Promises can be chained in a tree structure where each promise
    # has zero or more children. Promises are resolved asynchronously
    # in the order they are added to the tree. Parents are guaranteed
    # to be resolved before their children. The result of each promise
    # is passed to each of its children upon resolution. When
    # a promise is rejected all its children will be summarily rejected.
    # A promise that is neither resolved or rejected is pending.
    #
    # @param args [Array] zero or more arguments for the block
    # @param block [Proc] the block to call when attempting fulfillment
    #
    # @see http://wiki.commonjs.org/wiki/Promises/A
    # @see http://promises-aplus.github.io/promises-spec/
    def initialize(*args, &block)
      if args.first.is_a?(Promise)
        @parent = args.first
      else
        @parent = nil
        @chain = [self]
      end

      @lock = Mutex.new
      @handler = block || Proc.new{|result| result }
      @state = :pending
      @value = nil
      @reason = nil
      @rescued = false
      @children = []
      @rescuers = []

      init_obligation
      realize(*args) if root?
    end

    def rescued?
      return @rescued
    end

    # Create a new child Promise. The block argument for the child will
    # be the result of fulfilling its parent. If the child will
    # immediately be rejected if the parent has already been rejected.
    #
    # @param block [Proc] the block to call when attempting fulfillment
    #
    # @return [Promise] the new promise
    def then(&block)
      child = @lock.synchronize do
        block = Proc.new{|result| result } if block.nil?
        @children << Promise.new(self, &block)
        @children.last.on_reject(@reason) if rejected?
        push(@children.last)
        @children.last
      end
      return child
    end

    # Add a rescue handler to be run if the promise is rejected (via raised
    # exception). Multiple rescue handlers may be added to a Promise.
    # Rescue blocks will be checked in order and the first one with a
    # matching Exception class will be processed. The block argument
    # will be the exception that caused the rejection.
    #
    # @param clazz [Class] The class of exception to rescue
    # @param block [Proc] the block to call if the rescue is matched
    #
    # @return [self] so that additional chaining can occur
    def rescue(clazz = nil, &block)
      return self if fulfilled? || rescued? || block.nil?
      @lock.synchronize do
        rescuer = Rescuer.new(clazz, block)
        if pending?
          @rescuers << rescuer
        else
          try_rescue(reason, rescuer)
        end<commit_msg>Change how rescues are handled<commit_after>require 'thread'

require 'concurrent/global_thread_pool'
require 'concurrent/obligation'

module Concurrent

  class Promise
    include Obligation
    include UsesGlobalThreadPool

    # Creates a new promise object. "A promise represents the eventual
    # value returned from the single completion of an operation."
    # Promises can be chained in a tree structure where each promise
    # has zero or more children. Promises are resolved asynchronously
    # in the order they are added to the tree. Parents are guaranteed
    # to be resolved before their children. The result of each promise
    # is passed to each of its children upon resolution. When
    # a promise is rejected all its children will be summarily rejected.
    # A promise that is neither resolved or rejected is pending.
    #
    # @param args [Array] zero or more arguments for the block
    # @param block [Proc] the block to call when attempting fulfillment
    #
    # @see http://wiki.commonjs.org/wiki/Promises/A
    # @see http://promises-aplus.github.io/promises-spec/
    def initialize(*args, &block)
      if args.first.is_a?(Promise)
        @parent = args.first
      else
        @parent = nil
        @chain = [self]
      end

      @lock = Mutex.new
      @handler = block || Proc.new{|result| result }
      @state = :pending
      @value = nil
      @reason = nil
      @rescued = false
      @children = []
      @rescuers = []

      init_obligation
      realize(*args) if root?
    end

    def rescued?
      return @rescued
    end

    # Create a new child Promise. The block argument for the child will
    # be the result of fulfilling its parent. If the child will
    # immediately be rejected if the parent has already been rejected.
    #
    # @param block [Proc] the block to call when attempting fulfillment
    #
    # @return [Promise] the new promise
    def then(&block)
      child = @lock.synchronize do
        block = Proc.new{|result| result } if block.nil?
        @children << Promise.new(self, &block)
        @children.last.on_reject(@reason) if rejected?
        push(@children.last)
        @children.last
      end
      return child
    end

    # Add a rescue handler to be run if the promise is rejected (via raised
    # exception). Multiple rescue handlers may be added to a Promise.
    # Rescue blocks will be checked in order and the first one with a
    # matching Exception class will be processed. The block argument
    # will be the exception that caused the rejection.
    #
    # @param clazz [Class] The class of exception to rescue
    # @param block [Proc] the block to call if the rescue is matched
    #
    # @return [self] so that additional chaining can occur
    def rescue(clazz = nil, &block)
      return self if fulfilled? || rescued? || block.nil?
      @lock.synchronize do
        @rescuers << Rescuer.new(clazz, block)
        try_rescue(reason) unless pending?
{'fraction_non_alphanumeric': 0.07249039585769167, 'fraction_numerical': 0.0, 'mean_word_length': 2.583482944344704, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5799202', 'n_tokens_mistral': 1638, 'n_tokens_neox': 1594, 'n_words': 690}