delayer 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +40 -0
- data/README.md +2 -0
- data/Steepfile +19 -0
- data/delayer.gemspec +1 -1
- data/lib/delayer.rb +8 -3
- data/lib/delayer/delayed_procedure.rb +56 -0
- data/lib/delayer/error.rb +2 -0
- data/lib/delayer/extend.rb +83 -23
- data/lib/delayer/procedure.rb +1 -1
- data/lib/delayer/version.rb +1 -1
- data/sig/delayer.rbs +150 -0
- data/test/test_delayer.rb +108 -0
- metadata +11 -7
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e7fea45fe078293c50cf946662ce8aace4acf2aa40b30abf894cedf117473b30
         | 
| 4 | 
            +
              data.tar.gz: d4f0e01ce8dfce355d90022b73431d695061d6bff5fe15280d47c95b3b60f28f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 27c1f3aca5d5e4745d341667d5ce2cdb3a032402b9fe94269017bb59535e70f6f97d00d3d4d68ddb7932d0bcb9dc13f9f3bf57a693c52fb06adc762b4d181b12
         | 
| 7 | 
            +
              data.tar.gz: 8d80f9c8d5c06707d68f9df0017e6598a18212322c3065ffdf497e5ee5c427e703a83ea2c975bd8a66f6be3fd956171b109ee3ca44de71d933f98baeaebd0483
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            version: '2.1'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            executors:
         | 
| 4 | 
            +
              ruby:
         | 
| 5 | 
            +
                parameters:
         | 
| 6 | 
            +
                  tag:
         | 
| 7 | 
            +
                    type: string
         | 
| 8 | 
            +
                docker:
         | 
| 9 | 
            +
                  - image: circleci/ruby:<< parameters.tag >>
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            jobs:
         | 
| 12 | 
            +
              build:
         | 
| 13 | 
            +
                parameters:
         | 
| 14 | 
            +
                   ruby-version:
         | 
| 15 | 
            +
                     type: string
         | 
| 16 | 
            +
                executor:
         | 
| 17 | 
            +
                  name: ruby
         | 
| 18 | 
            +
                  tag: << parameters.ruby-version >>
         | 
| 19 | 
            +
                steps:
         | 
| 20 | 
            +
                - checkout
         | 
| 21 | 
            +
                - run:
         | 
| 22 | 
            +
                    name: Which bundler?
         | 
| 23 | 
            +
                    command: bundle -v
         | 
| 24 | 
            +
                - run:
         | 
| 25 | 
            +
                    command: bundle install --path vendor/bundle
         | 
| 26 | 
            +
                - run:
         | 
| 27 | 
            +
                    name: test
         | 
| 28 | 
            +
                    command: bundle exec rake test
         | 
| 29 | 
            +
            workflows:
         | 
| 30 | 
            +
              build:
         | 
| 31 | 
            +
                jobs:
         | 
| 32 | 
            +
                  - build:
         | 
| 33 | 
            +
                      name: 'ruby-2.6'
         | 
| 34 | 
            +
                      ruby-version: '2.6.7'
         | 
| 35 | 
            +
                  - build:
         | 
| 36 | 
            +
                      name: 'ruby-2.7'
         | 
| 37 | 
            +
                      ruby-version: '2.7.3'
         | 
| 38 | 
            +
                  - build:
         | 
| 39 | 
            +
                      name: 'ruby-3.0'
         | 
| 40 | 
            +
                      ruby-version: '3.0.1'
         | 
    
        data/README.md
    CHANGED
    
    
    
        data/Steepfile
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            target :lib do
         | 
| 2 | 
            +
              signature "sig"
         | 
| 3 | 
            +
              check "lib"                       # Directory name
         | 
| 4 | 
            +
              # ignore "lib/templates/*.rb"
         | 
| 5 | 
            +
              # library "pathname", "set"       # Standard libraries
         | 
| 6 | 
            +
              # library "strong_json"           # Gems
         | 
| 7 | 
            +
              # library "instance_storage"
         | 
| 8 | 
            +
              library "monitor"
         | 
| 9 | 
            +
              library "set"
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # target :spec do
         | 
| 13 | 
            +
            #   signature "sig", "sig-private"
         | 
| 14 | 
            +
            #
         | 
| 15 | 
            +
            #   check "spec"
         | 
| 16 | 
            +
            #
         | 
| 17 | 
            +
            #   # library "pathname", "set"       # Standard libraries
         | 
| 18 | 
            +
            #   # library "rspec"
         | 
| 19 | 
            +
            # end
         | 
    
        data/delayer.gemspec
    CHANGED
    
    | @@ -12,7 +12,7 @@ Gem::Specification.new do |spec| | |
| 12 12 | 
             
              spec.summary       = %q{Delay the processing}
         | 
| 13 13 | 
             
              spec.homepage      = "https://github.com/toshia/delayer"
         | 
| 14 14 | 
             
              spec.license       = "MIT"
         | 
| 15 | 
            -
              spec.required_ruby_version = '>= 2. | 
| 15 | 
            +
              spec.required_ruby_version = '>= 2.6.0'
         | 
| 16 16 |  | 
| 17 17 | 
             
              spec.files         = `git ls-files`.split($/)
         | 
| 18 18 | 
             
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
    
        data/lib/delayer.rb
    CHANGED
    
    | @@ -3,6 +3,7 @@ require "delayer/version" | |
| 3 3 | 
             
            require "delayer/error"
         | 
| 4 4 | 
             
            require "delayer/extend"
         | 
| 5 5 | 
             
            require "delayer/procedure"
         | 
| 6 | 
            +
            require "delayer/delayed_procedure"
         | 
| 6 7 | 
             
            require "monitor"
         | 
| 7 8 |  | 
| 8 9 | 
             
            module Delayer
         | 
| @@ -23,7 +24,7 @@ module Delayer | |
| 23 24 | 
             
                    include ::Delayer
         | 
| 24 25 | 
             
                    @expire = options[:expire] || 0
         | 
| 25 26 | 
             
                    if options.has_key?(:priority)
         | 
| 26 | 
            -
                      @priorities = options[:priority]
         | 
| 27 | 
            +
                      @priorities = options[:priority].to_a.freeze
         | 
| 27 28 | 
             
                      @default_priority = options[:default]
         | 
| 28 29 | 
             
                    else
         | 
| 29 30 | 
             
                      @priorities = [:normal]
         | 
| @@ -32,8 +33,12 @@ module Delayer | |
| 32 33 | 
             
                  end
         | 
| 33 34 | 
             
                end
         | 
| 34 35 |  | 
| 35 | 
            -
                def method_missing(*args, &proc)
         | 
| 36 | 
            -
                   | 
| 36 | 
            +
                def method_missing(fn, *args, **kwrest, &proc)
         | 
| 37 | 
            +
                  if kwrest.empty?
         | 
| 38 | 
            +
                    (@default ||= generate_class).__send__(fn, *args, &proc)
         | 
| 39 | 
            +
                  else
         | 
| 40 | 
            +
                    (@default ||= generate_class).__send__(fn, *args, **kwrest, &proc)
         | 
| 41 | 
            +
                  end
         | 
| 37 42 | 
             
                end
         | 
| 38 43 | 
             
              end
         | 
| 39 44 | 
             
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Delayer
         | 
| 4 | 
            +
              class DelayedProcedure
         | 
| 5 | 
            +
                include Comparable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                attr_reader :state, :delayer, :reserve_at
         | 
| 8 | 
            +
                def initialize(delayer, delay:, &proc)
         | 
| 9 | 
            +
                  @delayer = delayer
         | 
| 10 | 
            +
                  @proc = proc
         | 
| 11 | 
            +
                  case delay
         | 
| 12 | 
            +
                  when Time
         | 
| 13 | 
            +
                    @reserve_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay.to_f - Time.now.to_f
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    @reserve_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay.to_f
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  @cancel = false
         | 
| 18 | 
            +
                  @procedure = nil
         | 
| 19 | 
            +
                  @delayer.class.reserve(self)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def register
         | 
| 23 | 
            +
                  if !canceled?
         | 
| 24 | 
            +
                    @procedure = Procedure.new(@delayer, &@proc)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                  self
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def <=>(other)
         | 
| 30 | 
            +
                  @reserve_at <=> other.reserve_at
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # Cancel this job
         | 
| 34 | 
            +
                # ==== Exception
         | 
| 35 | 
            +
                # Delayer::TooLate :: if already called run()
         | 
| 36 | 
            +
                # ==== Return
         | 
| 37 | 
            +
                # self
         | 
| 38 | 
            +
                def cancel
         | 
| 39 | 
            +
                  @procedure&.cancel
         | 
| 40 | 
            +
                  @cancel = true
         | 
| 41 | 
            +
                  self
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                # Return true if canceled this task
         | 
| 45 | 
            +
                # ==== Return
         | 
| 46 | 
            +
                # true if canceled this task
         | 
| 47 | 
            +
                def canceled?
         | 
| 48 | 
            +
                  procedure = @procedure
         | 
| 49 | 
            +
                  if procedure
         | 
| 50 | 
            +
                    procedure.canceled?
         | 
| 51 | 
            +
                  else
         | 
| 52 | 
            +
                    @cancel
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
    
        data/lib/delayer/error.rb
    CHANGED
    
    
    
        data/lib/delayer/extend.rb
    CHANGED
    
    | @@ -3,10 +3,20 @@ | |
| 3 3 | 
             
            module Delayer
         | 
| 4 4 | 
             
              attr_reader :priority
         | 
| 5 5 |  | 
| 6 | 
            -
              Bucket | 
| 6 | 
            +
              class Bucket
         | 
| 7 | 
            +
                attr_accessor :first, :last, :priority_of, :stashed
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(first, last, priority_of, stashed)
         | 
| 10 | 
            +
                  @first = first
         | 
| 11 | 
            +
                  @last = last
         | 
| 12 | 
            +
                  @priority_of = priority_of
         | 
| 13 | 
            +
                  @stashed = stashed
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 7 16 | 
             
                def stash_size
         | 
| 8 | 
            -
                   | 
| 9 | 
            -
             | 
| 17 | 
            +
                  s = stashed
         | 
| 18 | 
            +
                  if s
         | 
| 19 | 
            +
                    1 + s.stash_size
         | 
| 10 20 | 
             
                  else
         | 
| 11 21 | 
             
                    0
         | 
| 12 22 | 
             
                  end
         | 
| @@ -19,10 +29,14 @@ module Delayer | |
| 19 29 | 
             
                end
         | 
| 20 30 | 
             
              end
         | 
| 21 31 |  | 
| 22 | 
            -
              def initialize(priority = self.class.instance_eval { @default_priority }, *_args, &proc)
         | 
| 32 | 
            +
              def initialize(priority = self.class.instance_eval { @default_priority }, *_args, delay: 0, &proc)
         | 
| 23 33 | 
             
                self.class.validate_priority priority
         | 
| 24 34 | 
             
                @priority = priority
         | 
| 25 | 
            -
                 | 
| 35 | 
            +
                if delay == 0
         | 
| 36 | 
            +
                  @procedure = Procedure.new(self, &proc)
         | 
| 37 | 
            +
                else
         | 
| 38 | 
            +
                  @procedure = DelayedProcedure.new(self, delay: delay, &proc)
         | 
| 39 | 
            +
                end
         | 
| 26 40 | 
             
              end
         | 
| 27 41 |  | 
| 28 42 | 
             
              # Cancel this job
         | 
| @@ -46,8 +60,22 @@ module Delayer | |
| 46 60 | 
             
                    @remain_hook = nil
         | 
| 47 61 | 
             
                    @exception = nil
         | 
| 48 62 | 
             
                    @remain_received = false
         | 
| 49 | 
            -
                    @lock =  | 
| 63 | 
            +
                    @lock = Monitor.new
         | 
| 50 64 | 
             
                    @bucket = Bucket.new(nil, nil, {}, nil)
         | 
| 65 | 
            +
                    @last_reserve = nil
         | 
| 66 | 
            +
                    @reserves = Set.new
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def pop_reserve(start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC))
         | 
| 71 | 
            +
                  if @last_reserve&.reserve_at&.<=(start_time)
         | 
| 72 | 
            +
                    lock.synchronize do
         | 
| 73 | 
            +
                      while @last_reserve&.reserve_at&.<=(start_time)
         | 
| 74 | 
            +
                        @last_reserve.register
         | 
| 75 | 
            +
                        @last_reserve = @reserves.min
         | 
| 76 | 
            +
                        @reserves.delete(@last_reserve)
         | 
| 77 | 
            +
                      end
         | 
| 78 | 
            +
                    end
         | 
| 51 79 | 
             
                  end
         | 
| 52 80 | 
             
                end
         | 
| 53 81 |  | 
| @@ -57,11 +85,13 @@ module Delayer | |
| 57 85 | 
             
                # ==== Return
         | 
| 58 86 | 
             
                # self
         | 
| 59 87 | 
             
                def run(current_expire = @expire)
         | 
| 88 | 
            +
                  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC).to_f
         | 
| 89 | 
            +
                  pop_reserve(start_time)
         | 
| 60 90 | 
             
                  if current_expire == 0
         | 
| 61 | 
            -
                     | 
| 91 | 
            +
                    run_once_without_pop_reserve until empty?
         | 
| 62 92 | 
             
                  else
         | 
| 63 | 
            -
                    @end_time =  | 
| 64 | 
            -
                     | 
| 93 | 
            +
                    @end_time = end_time = start_time + @expire
         | 
| 94 | 
            +
                    run_once_without_pop_reserve while !empty? && (end_time >= Process.clock_gettime(Process::CLOCK_MONOTONIC))
         | 
| 65 95 | 
             
                    @end_time = nil
         | 
| 66 96 | 
             
                  end
         | 
| 67 97 | 
             
                  if @remain_hook
         | 
| @@ -74,22 +104,25 @@ module Delayer | |
| 74 104 | 
             
                end
         | 
| 75 105 |  | 
| 76 106 | 
             
                def expire?
         | 
| 77 | 
            -
                   | 
| 78 | 
            -
                    @end_time < Time.new.to_f
         | 
| 79 | 
            -
                  else
         | 
| 80 | 
            -
                    false
         | 
| 81 | 
            -
                  end
         | 
| 107 | 
            +
                  !!@end_time&.<(Time.new.to_f)
         | 
| 82 108 | 
             
                end
         | 
| 83 109 |  | 
| 84 110 | 
             
                # Run a job and forward pointer.
         | 
| 85 111 | 
             
                # ==== Return
         | 
| 86 112 | 
             
                # self
         | 
| 87 113 | 
             
                def run_once
         | 
| 114 | 
            +
                  pop_reserve
         | 
| 115 | 
            +
                  run_once_without_pop_reserve
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                private def run_once_without_pop_reserve
         | 
| 88 119 | 
             
                  if @bucket.first
         | 
| 89 120 | 
             
                    @busy = true
         | 
| 90 121 | 
             
                    procedure = forward
         | 
| 91 | 
            -
                    procedure = forward while @bucket.first && procedure | 
| 92 | 
            -
                    procedure | 
| 122 | 
            +
                    procedure = forward while @bucket.first && procedure&.canceled?
         | 
| 123 | 
            +
                    if procedure && !procedure.canceled?
         | 
| 124 | 
            +
                      procedure.run
         | 
| 125 | 
            +
                    end
         | 
| 93 126 | 
             
                  end
         | 
| 94 127 | 
             
                ensure
         | 
| 95 128 | 
             
                  @busy = false
         | 
| @@ -146,6 +179,29 @@ module Delayer | |
| 146 179 | 
             
                  self
         | 
| 147 180 | 
             
                end
         | 
| 148 181 |  | 
| 182 | 
            +
                # Register reserved job.
         | 
| 183 | 
            +
                # It does not execute immediately.
         | 
| 184 | 
            +
                # it calls register() in _procedure.reserve_at_.
         | 
| 185 | 
            +
                # ==== Args
         | 
| 186 | 
            +
                # [procedure] job(Delayer::DelayedProcedure)
         | 
| 187 | 
            +
                # ==== Return
         | 
| 188 | 
            +
                # self
         | 
| 189 | 
            +
                def reserve(procedure)
         | 
| 190 | 
            +
                  lock.synchronize do
         | 
| 191 | 
            +
                    if @last_reserve
         | 
| 192 | 
            +
                      if @last_reserve > procedure
         | 
| 193 | 
            +
                        @reserves.add(@last_reserve)
         | 
| 194 | 
            +
                        @last_reserve = procedure
         | 
| 195 | 
            +
                      else
         | 
| 196 | 
            +
                        @reserves.add(procedure)
         | 
| 197 | 
            +
                      end
         | 
| 198 | 
            +
                    else
         | 
| 199 | 
            +
                      @last_reserve = procedure
         | 
| 200 | 
            +
                    end
         | 
| 201 | 
            +
                  end
         | 
| 202 | 
            +
                  self
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
             | 
| 149 205 | 
             
                def register_remain_hook(&proc)
         | 
| 150 206 | 
             
                  @remain_hook = proc
         | 
| 151 207 | 
             
                end
         | 
| @@ -154,8 +210,10 @@ module Delayer | |
| 154 210 | 
             
                  if @bucket.priority_of[priority]
         | 
| 155 211 | 
             
                    @bucket.priority_of[priority]
         | 
| 156 212 | 
             
                  else
         | 
| 157 | 
            -
                     | 
| 158 | 
            -
             | 
| 213 | 
            +
                    @priorities.index(priority)&.yield_self do |index|
         | 
| 214 | 
            +
                      next_index = index - 1
         | 
| 215 | 
            +
                      get_prev_point @priorities[next_index] if next_index >= 0
         | 
| 216 | 
            +
                    end
         | 
| 159 217 | 
             
                  end
         | 
| 160 218 | 
             
                end
         | 
| 161 219 |  | 
| @@ -178,10 +236,11 @@ module Delayer | |
| 178 236 | 
             
                # [Delayer::NoLowerLevelError] stash_enter!が呼ばれていない時
         | 
| 179 237 | 
             
                # [Delayer::RemainJobsError] ジョブが残っているのにこのメソッドを呼んだ時
         | 
| 180 238 | 
             
                def stash_exit!
         | 
| 181 | 
            -
                   | 
| 239 | 
            +
                  stashed = @bucket.stashed
         | 
| 240 | 
            +
                  raise Delayer::NoLowerLevelError, 'stash_exit! called in level 0.' unless stashed
         | 
| 182 241 | 
             
                  raise Delayer::RemainJobsError, 'Current level has remain jobs. It must be empty current level jobs in call this method.' unless empty?
         | 
| 183 242 |  | 
| 184 | 
            -
                  @bucket =  | 
| 243 | 
            +
                  @bucket = stashed
         | 
| 185 244 | 
             
                end
         | 
| 186 245 |  | 
| 187 246 | 
             
                # 現在のDelayer Stashレベルを返す。
         | 
| @@ -194,10 +253,11 @@ module Delayer | |
| 194 253 | 
             
                def forward
         | 
| 195 254 | 
             
                  lock.synchronize do
         | 
| 196 255 | 
             
                    prev = @bucket.first
         | 
| 197 | 
            -
                     | 
| 198 | 
            -
                    @bucket. | 
| 256 | 
            +
                    raise 'Current bucket not found' unless prev
         | 
| 257 | 
            +
                    nex = @bucket.first = prev.next
         | 
| 258 | 
            +
                    @bucket.last = nil unless nex
         | 
| 199 259 | 
             
                    @bucket.priority_of.each do |priority, pointer|
         | 
| 200 | 
            -
                      @bucket.priority_of[priority] =  | 
| 260 | 
            +
                      @bucket.priority_of[priority] = nex if prev == pointer
         | 
| 201 261 | 
             
                    end
         | 
| 202 262 | 
             
                    prev.next = nil
         | 
| 203 263 | 
             
                    prev
         | 
    
        data/lib/delayer/procedure.rb
    CHANGED
    
    
    
        data/lib/delayer/version.rb
    CHANGED
    
    
    
        data/sig/delayer.rbs
    ADDED
    
    | @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            # TypeProf 0.13.0
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Classes
         | 
| 4 | 
            +
            module Delayer
         | 
| 5 | 
            +
              type clock = Float | Integer | Rational
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              VERSION: String
         | 
| 8 | 
            +
              extend Extend
         | 
| 9 | 
            +
              extend Delayer
         | 
| 10 | 
            +
              self.@expire: clock
         | 
| 11 | 
            +
              self.@priorities: Array[Symbol]
         | 
| 12 | 
            +
              self.@default_priority: Symbol
         | 
| 13 | 
            +
              self.@default: singleton(Delayer)
         | 
| 14 | 
            +
              @procedure: Procedure | DelayedProcedure
         | 
| 15 | 
            +
              self.@busy: bool
         | 
| 16 | 
            +
              self.@remain_hook: ^() -> void
         | 
| 17 | 
            +
              self.@exception: Exception?
         | 
| 18 | 
            +
              self.@remain_received: bool
         | 
| 19 | 
            +
              self.@lock: Monitor
         | 
| 20 | 
            +
              self.@bucket: Bucket
         | 
| 21 | 
            +
              self.@last_reserve: nil
         | 
| 22 | 
            +
              self.@reserves: untyped
         | 
| 23 | 
            +
              @default_priority: Symbol
         | 
| 24 | 
            +
              self.@end_time: clock?
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              class GeneratedDelayerAbstract
         | 
| 27 | 
            +
                include ::Delayer
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def self.generate_class: (?Hash[Symbol,Integer|Symbol|Enumerable[Symbol]] options) -> singleton(Delayer)
         | 
| 31 | 
            +
              def self.method_missing: (Symbol, *untyped, **untyped) { (*untyped) -> untyped } -> untyped
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def self.StateError: (:cancel) -> singleton(AlreadyCanceledError)
         | 
| 34 | 
            +
                                 | (:done) -> singleton(AlreadyExecutedError)
         | 
| 35 | 
            +
                                 | (:run) -> singleton(AlreadyRunningError)
         | 
| 36 | 
            +
                                 | (Symbol) -> singleton(TooLate)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              attr_reader priority: Symbol
         | 
| 39 | 
            +
              def self.included: (singleton(Delayer) klass) -> void
         | 
| 40 | 
            +
              def initialize: (?untyped priority, *untyped _args, ?delay: Time | clock) -> void
         | 
| 41 | 
            +
              def cancel: -> Delayer
         | 
| 42 | 
            +
              def stash_size: -> (Integer)
         | 
| 43 | 
            +
              def __send__: (Symbol, *untyped, **untyped) { (untyped) -> untyped } -> untyped
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              class DelayedProcedure
         | 
| 46 | 
            +
                include Comparable
         | 
| 47 | 
            +
                @proc: (^() -> void)
         | 
| 48 | 
            +
                @cancel: bool
         | 
| 49 | 
            +
                @procedure: Procedure?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                attr_reader state: untyped
         | 
| 52 | 
            +
                attr_reader delayer: Delayer
         | 
| 53 | 
            +
                attr_reader reserve_at: clock
         | 
| 54 | 
            +
                def initialize: (Delayer delayer, delay: Time | clock) { () -> void } -> void
         | 
| 55 | 
            +
                def register: -> self
         | 
| 56 | 
            +
                def <=>: (DelayedProcedure other) -> Integer?
         | 
| 57 | 
            +
                def cancel: -> self
         | 
| 58 | 
            +
                def canceled?: -> bool
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              class Error < StandardError
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              class TooLate < Error
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              class AlreadyExecutedError < TooLate
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              class AlreadyCanceledError < TooLate
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              class AlreadyRunningError < TooLate
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              class InvalidPriorityError < Error
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              class RecursiveError < Error
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              class NoLowerLevelError < RecursiveError
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              class RemainJobsError < RecursiveError
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              class Bucket
         | 
| 89 | 
            +
                attr_accessor first(): Procedure?
         | 
| 90 | 
            +
                attr_accessor last(): Procedure?
         | 
| 91 | 
            +
                attr_accessor priority_of(): Hash[Symbol, Procedure?]
         | 
| 92 | 
            +
                attr_accessor stashed(): Bucket?
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def initialize: (Procedure?,Procedure?,Hash[Symbol, Procedure],Bucket?) -> void
         | 
| 95 | 
            +
                def stash_size: () -> Integer
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              module Extend
         | 
| 99 | 
            +
                @last_reserve: untyped
         | 
| 100 | 
            +
                @lock: Monitor
         | 
| 101 | 
            +
                @end_time: clock?
         | 
| 102 | 
            +
                @bucket: Bucket
         | 
| 103 | 
            +
                @remain_hook: ^() -> void
         | 
| 104 | 
            +
                @remain_received: bool
         | 
| 105 | 
            +
                @busy: bool
         | 
| 106 | 
            +
                @priorities: Array[Symbol]
         | 
| 107 | 
            +
                @reserves: Set[DelayedProcedure]
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                attr_accessor expire: clock
         | 
| 110 | 
            +
                attr_reader exception: Exception?
         | 
| 111 | 
            +
                def self.extended: (singleton(Delayer) klass) -> singleton(Delayer)
         | 
| 112 | 
            +
                def pop_reserve: (?clock start_time) -> nil
         | 
| 113 | 
            +
                def run: (?clock? current_expire) -> void
         | 
| 114 | 
            +
                def expire?: -> bool
         | 
| 115 | 
            +
                def run_once: -> void
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                private
         | 
| 118 | 
            +
                def run_once_without_pop_reserve: -> void
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                public
         | 
| 121 | 
            +
                def busy?: -> bool
         | 
| 122 | 
            +
                def empty?: -> bool
         | 
| 123 | 
            +
                def size: (?Delayer::Procedure? node) -> Integer
         | 
| 124 | 
            +
                def register: (untyped procedure) -> Extend
         | 
| 125 | 
            +
                def reserve: (untyped procedure) -> Extend
         | 
| 126 | 
            +
                def register_remain_hook: () { () -> void } -> void
         | 
| 127 | 
            +
                def get_prev_point: (Symbol) -> ::Delayer::Procedure?
         | 
| 128 | 
            +
                def validate_priority: (Symbol) -> void
         | 
| 129 | 
            +
                def stash_enter!: -> Extend
         | 
| 130 | 
            +
                def stash_exit!: -> Bucket?
         | 
| 131 | 
            +
                def stash_level: -> untyped
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                private
         | 
| 134 | 
            +
                def forward: -> Procedure?
         | 
| 135 | 
            +
                def lock: -> Monitor
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
              class Procedure
         | 
| 139 | 
            +
                @proc: (^() -> void)?
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                attr_reader state: :cancel | :done | :run | :stop
         | 
| 142 | 
            +
                attr_reader delayer: untyped
         | 
| 143 | 
            +
                attr_accessor next: Delayer::Procedure?
         | 
| 144 | 
            +
                def initialize: (Delayer delayer) { () -> void } -> void
         | 
| 145 | 
            +
                def run: -> void
         | 
| 146 | 
            +
                def cancel: -> Procedure
         | 
| 147 | 
            +
                def canceled?: -> bool
         | 
| 148 | 
            +
                def break: (untyped node) -> untyped
         | 
| 149 | 
            +
              end
         | 
| 150 | 
            +
            end
         | 
    
        data/test/test_delayer.rb
    CHANGED
    
    | @@ -353,4 +353,112 @@ class TestDelayer < Test::Unit::TestCase | |
| 353 353 | 
             
                end
         | 
| 354 354 | 
             
              end
         | 
| 355 355 |  | 
| 356 | 
            +
              def test_timer
         | 
| 357 | 
            +
                delayer = Delayer.generate_class expire: 0.01
         | 
| 358 | 
            +
                a = []
         | 
| 359 | 
            +
                delayer.new(delay: 0.01) { a << 0 }
         | 
| 360 | 
            +
                delayer.new { a << 1 }
         | 
| 361 | 
            +
             | 
| 362 | 
            +
                delayer.run
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                delayer.new { a << 2 }
         | 
| 365 | 
            +
                sleep 0.1
         | 
| 366 | 
            +
             | 
| 367 | 
            +
                delayer.run
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                delayer.new { a << 3 }
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                delayer.run
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                assert_equal([1, 2, 0, 3], a)
         | 
| 374 | 
            +
              end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
              def test_timer_give_time
         | 
| 377 | 
            +
                delayer = Delayer.generate_class expire: 0.01
         | 
| 378 | 
            +
                a = []
         | 
| 379 | 
            +
                delayer.new(delay: Time.new) { a << 0 }
         | 
| 380 | 
            +
             | 
| 381 | 
            +
                delayer.run
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                assert_equal([0], a)
         | 
| 384 | 
            +
              end
         | 
| 385 | 
            +
             | 
| 386 | 
            +
              def test_plural_timer
         | 
| 387 | 
            +
                delayer = Delayer.generate_class expire: 0.01
         | 
| 388 | 
            +
                a = []
         | 
| 389 | 
            +
                delayer.new(delay: 0.01) { a << 0 }
         | 
| 390 | 
            +
                delayer.new(delay: 0.11) { a << 1 }
         | 
| 391 | 
            +
                delayer.new { a << 2 }
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                delayer.run
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                delayer.new { a << 3 }
         | 
| 396 | 
            +
                sleep 0.1
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                delayer.run
         | 
| 399 | 
            +
                sleep 0.1
         | 
| 400 | 
            +
             | 
| 401 | 
            +
                delayer.new { a << 4 }
         | 
| 402 | 
            +
             | 
| 403 | 
            +
                delayer.run
         | 
| 404 | 
            +
             | 
| 405 | 
            +
                assert_equal([2, 3, 0, 4, 1], a)
         | 
| 406 | 
            +
              end
         | 
| 407 | 
            +
             | 
| 408 | 
            +
              def test_many_timer
         | 
| 409 | 
            +
                delayer = Delayer.generate_class expire: 0.01
         | 
| 410 | 
            +
                a = []
         | 
| 411 | 
            +
                (0..10).to_a.shuffle.each do |i|
         | 
| 412 | 
            +
                  delayer.new(delay: i / 100.0) { a << i }
         | 
| 413 | 
            +
                end
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                sleep 0.1
         | 
| 416 | 
            +
             | 
| 417 | 
            +
                delayer.run
         | 
| 418 | 
            +
             | 
| 419 | 
            +
                assert_equal((0..10).to_a, a)
         | 
| 420 | 
            +
              end
         | 
| 421 | 
            +
             | 
| 422 | 
            +
              def test_cancel_timer
         | 
| 423 | 
            +
                delayer = Delayer.generate_class
         | 
| 424 | 
            +
                a = 0
         | 
| 425 | 
            +
                delayer.new(delay: 0.01) { a += 1 }
         | 
| 426 | 
            +
                d = delayer.new(delay: 0.01) { a += 2 }
         | 
| 427 | 
            +
                delayer.new(delay: 0.01) { a += 4 }
         | 
| 428 | 
            +
             | 
| 429 | 
            +
                assert_equal(0, a)
         | 
| 430 | 
            +
                d.cancel
         | 
| 431 | 
            +
                sleep 0.1
         | 
| 432 | 
            +
                delayer.run
         | 
| 433 | 
            +
                assert_equal(5, a)
         | 
| 434 | 
            +
              end
         | 
| 435 | 
            +
             | 
| 436 | 
            +
              def test_cancel_timer_after_expire
         | 
| 437 | 
            +
                delayer = Delayer.generate_class
         | 
| 438 | 
            +
                a = 0
         | 
| 439 | 
            +
                delayer.new(delay: 0.01) { a += 1 }
         | 
| 440 | 
            +
                d = delayer.new(delay: 0.01) { a += 2 }
         | 
| 441 | 
            +
                delayer.new{ d.cancel }
         | 
| 442 | 
            +
                delayer.new(delay: 0.01) { a += 4 }
         | 
| 443 | 
            +
             | 
| 444 | 
            +
                assert_equal(0, a)
         | 
| 445 | 
            +
                sleep 0.1
         | 
| 446 | 
            +
                delayer.run
         | 
| 447 | 
            +
                assert_equal(5, a)
         | 
| 448 | 
            +
              end
         | 
| 449 | 
            +
             | 
| 450 | 
            +
              def test_reserve_new_timer_after_cancel
         | 
| 451 | 
            +
                delayer = Delayer.generate_class
         | 
| 452 | 
            +
                a = 0
         | 
| 453 | 
            +
                delayer.new(delay: 0.01) { a += 1 }
         | 
| 454 | 
            +
                d = delayer.new(delay: 0.02) { a += 2 }
         | 
| 455 | 
            +
                d.cancel
         | 
| 456 | 
            +
                delayer.new(delay: 0.03) { a += 4 }
         | 
| 457 | 
            +
             | 
| 458 | 
            +
                assert_equal(0, a)
         | 
| 459 | 
            +
                sleep 0.1
         | 
| 460 | 
            +
                delayer.run
         | 
| 461 | 
            +
                assert_equal(5, a)
         | 
| 462 | 
            +
              end
         | 
| 463 | 
            +
             | 
| 356 464 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: delayer
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.0 | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Toshiaki Asai
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2021-04-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -65,24 +65,28 @@ executables: [] | |
| 65 65 | 
             
            extensions: []
         | 
| 66 66 | 
             
            extra_rdoc_files: []
         | 
| 67 67 | 
             
            files:
         | 
| 68 | 
            +
            - ".circleci/config.yml"
         | 
| 68 69 | 
             
            - ".gitignore"
         | 
| 69 70 | 
             
            - Gemfile
         | 
| 70 71 | 
             
            - LICENSE.txt
         | 
| 71 72 | 
             
            - README.md
         | 
| 72 73 | 
             
            - Rakefile
         | 
| 74 | 
            +
            - Steepfile
         | 
| 73 75 | 
             
            - delayer.gemspec
         | 
| 74 76 | 
             
            - lib/delayer.rb
         | 
| 77 | 
            +
            - lib/delayer/delayed_procedure.rb
         | 
| 75 78 | 
             
            - lib/delayer/error.rb
         | 
| 76 79 | 
             
            - lib/delayer/extend.rb
         | 
| 77 80 | 
             
            - lib/delayer/procedure.rb
         | 
| 78 81 | 
             
            - lib/delayer/version.rb
         | 
| 82 | 
            +
            - sig/delayer.rbs
         | 
| 79 83 | 
             
            - test/test_delayer.rb
         | 
| 80 84 | 
             
            - test/test_priority.rb
         | 
| 81 85 | 
             
            homepage: https://github.com/toshia/delayer
         | 
| 82 86 | 
             
            licenses:
         | 
| 83 87 | 
             
            - MIT
         | 
| 84 88 | 
             
            metadata: {}
         | 
| 85 | 
            -
            post_install_message: | 
| 89 | 
            +
            post_install_message:
         | 
| 86 90 | 
             
            rdoc_options: []
         | 
| 87 91 | 
             
            require_paths:
         | 
| 88 92 | 
             
            - lib
         | 
| @@ -90,15 +94,15 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 90 94 | 
             
              requirements:
         | 
| 91 95 | 
             
              - - ">="
         | 
| 92 96 | 
             
                - !ruby/object:Gem::Version
         | 
| 93 | 
            -
                  version: 2. | 
| 97 | 
            +
                  version: 2.6.0
         | 
| 94 98 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 95 99 | 
             
              requirements:
         | 
| 96 100 | 
             
              - - ">="
         | 
| 97 101 | 
             
                - !ruby/object:Gem::Version
         | 
| 98 102 | 
             
                  version: '0'
         | 
| 99 103 | 
             
            requirements: []
         | 
| 100 | 
            -
            rubygems_version: 3. | 
| 101 | 
            -
            signing_key: | 
| 104 | 
            +
            rubygems_version: 3.2.13
         | 
| 105 | 
            +
            signing_key:
         | 
| 102 106 | 
             
            specification_version: 4
         | 
| 103 107 | 
             
            summary: Delay the processing
         | 
| 104 108 | 
             
            test_files:
         |