delayer-1.1.2/0000755000004100000410000000000013641340371013172 5ustar www-datawww-datadelayer-1.1.2/test/0000755000004100000410000000000013641340371014151 5ustar www-datawww-datadelayer-1.1.2/test/test_delayer.rb0000644000004100000410000002335413641340371017171 0ustar www-datawww-data# -*- coding: utf-8 -*- require 'rubygems' require 'bundler/setup' require 'test/unit' require 'delayer' class TestDelayer < Test::Unit::TestCase def setup Delayer.default = nil end def test_delayed delayer = Delayer.generate_class a = 0 delayer.new { a = 1 } assert_equal(0, a) delayer.run assert_equal(1, a) end def test_default a = 0 Delayer.new { a = 1 } assert_equal(0, a) Delayer.run assert_equal(1, a) end def test_timelimited delayer = Delayer.generate_class(expire: 0.01) a = 0 delayer.new { sleep 0.1 } delayer.new { a = 1 } assert_equal(0, a) delayer.run assert_equal(0, a) delayer.run assert_equal(1, a) end def test_busy delayer = Delayer.generate_class a = false delayer.new { a = delayer.busy? } assert_equal(false, a) assert_equal(false, delayer.busy?) delayer.run assert_equal(false, delayer.busy?) assert_equal(true, a) end def test_empty delayer = Delayer.generate_class a = false delayer.new { a = delayer.empty? } assert_equal(false, a) assert_equal(false, delayer.empty?) delayer.run assert_equal(true, delayer.empty?) assert_equal(true, a) end def test_size delayer = Delayer.generate_class a = 0 assert_equal(0, delayer.size) delayer.new { a += 1 } assert_equal(1, delayer.size) delayer.new { a += 1 } delayer.new { a += 1 } assert_equal(3, delayer.size) delayer.run assert_equal(0, delayer.size) end def test_cancel_begin delayer = Delayer.generate_class a = 0 d = delayer.new { a += 1 } delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) end def test_cancel_center delayer = Delayer.generate_class a = 0 delayer.new { a += 1 } d = delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) end def test_cancel_end delayer = Delayer.generate_class a = 0 delayer.new { a += 1 } delayer.new { a += 2 } d = delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) end def test_priority_asc delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:middle) { buffer << 2 } delayer.new(:low) { buffer << 3 } delayer.run assert_equal([1,2,3], buffer) end def test_priority_desc delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:low) { buffer << 3 } delayer.new(:middle) { buffer << 2 } delayer.new(:high) { buffer << 1 } delayer.run assert_equal([1,2,3], buffer) end def test_priority_complex delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:middle) { buffer << 2 } delayer.new(:low) { buffer << 3 } delayer.new(:middle) { buffer << 4 } delayer.new(:high) { buffer << 5 } delayer.new(:middle) { buffer << 6 } delayer.new(:low) { buffer << 7 } delayer.new(:middle) { buffer << 8 } delayer.new(:high) { buffer << 9 } delayer.run assert_equal([1,5,9,2,4,6,8,3,7], buffer) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:low) { buffer << 2 } delayer.new(:high) { buffer << 3 } delayer.new(:low) { buffer << 4 } delayer.run assert_equal([1,3,2,4], buffer) end def test_priority_cancel_begin delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 d = delayer.new { a += 1 } delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) a = 0 d = delayer.new(:low) { a += 1 } delayer.new(:high) { a += 2 } delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) a = 0 d = delayer.new(:high) { a += 1 } delayer.new(:low) { a += 2 } delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) end def test_priority_cancel_center delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 delayer.new { a += 1 } d = delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) a = 0 delayer.new(:low) { a += 1 } d = delayer.new(:high) { a += 2 } delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) a = 0 delayer.new(:high) { a += 1 } d = delayer.new(:low) { a += 2 } delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) end def test_priority_cancel_end delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 delayer.new { a += 1 } delayer.new { a += 2 } d = delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) a = 0 delayer.new(:low) { a += 1 } delayer.new(:low) { a += 2 } d = delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) a = 0 delayer.new(:high) { a += 1 } delayer.new(:high) { a += 2 } d = delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) end def test_multithread_register delayer = Delayer.generate_class buffer = [] threads = [] 10.times do threads << Thread.new do 1000.times do |number| delayer.new { buffer << number } end end end delayer.run threads.each(&:join) delayer.run assert_equal(10000, buffer.size) assert_equal((0..999).inject(&:+)*10, buffer.inject(&:+)) end def test_nested delayer = Delayer.generate_class buffer = [] delayer.new { buffer << 1 } delayer.new do delayer.new { buffer << 3 } delayer.new do delayer.new { buffer << 5 } delayer.new { buffer << 6 } end delayer.new { buffer << 4 } end delayer.new { buffer << 2 } delayer.run assert_equal([1,2,3,4,5,6], buffer) end def test_remain_hook delayer = Delayer.generate_class expire: 0.01 a = [] delayer.register_remain_hook { a << :remain } delayer.new { a << 0 } delayer.new { a << 1; sleep 0.1 } delayer.new { a << 2 } delayer.run delayer.new { a << 3 } delayer.new { a << 4 } delayer.run assert_equal([:remain, 0, 1, :remain, 2, 3, 4], a) end def test_recursive_mainloop delayer = Delayer.generate_class a = 0 delayer.new { a = 1 } assert_equal(0, delayer.stash_level) delayer.stash_enter! assert_equal(1, delayer.stash_level) delayer.new { a = 2 } assert_equal(0, a) delayer.run assert_equal(2, a) delayer.stash_exit! assert_equal(0, delayer.stash_level) delayer.run assert_equal(1, a) end def test_pop_recursive_mainloop_remain_jobs delayer = Delayer.generate_class delayer.stash_enter! delayer.new{ ; } assert_raise Delayer::RemainJobsError do delayer.stash_exit! end end def test_pop_recursive_mainloop_in_level_zero delayer = Delayer.generate_class assert_raise Delayer::NoLowerLevelError do delayer.stash_exit! end end def test_timer delayer = Delayer.generate_class expire: 0.01 a = [] delayer.new(delay: 0.01) { a << 0 } delayer.new { a << 1 } delayer.run delayer.new { a << 2 } sleep 0.1 delayer.run delayer.new { a << 3 } delayer.run assert_equal([1, 2, 0, 3], a) end def test_timer_give_time delayer = Delayer.generate_class expire: 0.01 a = [] delayer.new(delay: Time.new) { a << 0 } delayer.run assert_equal([0], a) end def test_plural_timer delayer = Delayer.generate_class expire: 0.01 a = [] delayer.new(delay: 0.01) { a << 0 } delayer.new(delay: 0.11) { a << 1 } delayer.new { a << 2 } delayer.run delayer.new { a << 3 } sleep 0.1 delayer.run sleep 0.1 delayer.new { a << 4 } delayer.run assert_equal([2, 3, 0, 4, 1], a) end def test_many_timer delayer = Delayer.generate_class expire: 0.01 a = [] (0..10).to_a.shuffle.each do |i| delayer.new(delay: i / 100.0) { a << i } end sleep 0.1 delayer.run assert_equal((0..10).to_a, a) end def test_cancel_timer delayer = Delayer.generate_class a = 0 delayer.new(delay: 0.01) { a += 1 } d = delayer.new(delay: 0.01) { a += 2 } delayer.new(delay: 0.01) { a += 4 } assert_equal(0, a) d.cancel sleep 0.1 delayer.run assert_equal(5, a) end def test_cancel_timer_after_expire delayer = Delayer.generate_class a = 0 delayer.new(delay: 0.01) { a += 1 } d = delayer.new(delay: 0.01) { a += 2 } delayer.new{ d.cancel } delayer.new(delay: 0.01) { a += 4 } assert_equal(0, a) sleep 0.1 delayer.run assert_equal(5, a) end def test_reserve_new_timer_after_cancel delayer = Delayer.generate_class a = 0 delayer.new(delay: 0.01) { a += 1 } d = delayer.new(delay: 0.02) { a += 2 } d.cancel delayer.new(delay: 0.03) { a += 4 } assert_equal(0, a) sleep 0.1 delayer.run assert_equal(5, a) end end delayer-1.1.2/test/test_priority.rb0000644000004100000410000001473613641340371017431 0ustar www-datawww-data# -*- coding: utf-8 -*- require 'rubygems' require 'bundler/setup' require 'test/unit' require 'delayer' class TestPriorityDelayer < Test::Unit::TestCase def test_asc delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:middle) { buffer << 2 } delayer.new(:low) { buffer << 3 } delayer.run assert_equal([1,2,3], buffer) end def test_desc delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:low) { buffer << 3 } delayer.new(:middle) { buffer << 2 } delayer.new(:high) { buffer << 1 } delayer.run assert_equal([1,2,3], buffer) end def test_complex delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:middle) { buffer << 2 } delayer.new(:low) { buffer << 3 } delayer.new(:middle) { buffer << 4 } delayer.new(:high) { buffer << 5 } delayer.new(:middle) { buffer << 6 } delayer.new(:low) { buffer << 7 } delayer.new(:middle) { buffer << 8 } delayer.new(:high) { buffer << 9 } delayer.run assert_equal([1,5,9,2,4,6,8,3,7], buffer) buffer = [] delayer.new(:high) { buffer << 1 } delayer.new(:low) { buffer << 2 } delayer.new(:high) { buffer << 3 } delayer.new(:low) { buffer << 4 } delayer.run assert_equal([1,3,2,4], buffer) end def test_timelimited delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle, expire: 0.01) a = 0 delayer.new { sleep 0.1 } delayer.new { a = 1 } assert_equal(0, a) delayer.run assert_equal(0, a) delayer.run assert_equal(1, a) end def test_busy delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = false delayer.new { a = delayer.busy? } assert_equal(false, a) assert_equal(false, delayer.busy?) delayer.run assert_equal(false, delayer.busy?) assert_equal(true, a) end def test_empty delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = false delayer.new { a = delayer.empty? } assert_equal(false, a) assert_equal(false, delayer.empty?) delayer.run assert_equal(true, delayer.empty?) assert_equal(true, a) end def test_size delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 assert_equal(0, delayer.size) delayer.new { a += 1 } assert_equal(1, delayer.size) delayer.new { a += 1 } delayer.new { a += 1 } assert_equal(3, delayer.size) delayer.run assert_equal(0, delayer.size) end def test_cancel_begin delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 d = delayer.new { a += 1 } delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) a = 0 d = delayer.new(:low) { a += 1 } delayer.new(:high) { a += 2 } delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) a = 0 d = delayer.new(:high) { a += 1 } delayer.new(:low) { a += 2 } delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(6, a) end def test_cancel_center delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 delayer.new { a += 1 } d = delayer.new { a += 2 } delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) a = 0 delayer.new(:low) { a += 1 } d = delayer.new(:high) { a += 2 } delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) a = 0 delayer.new(:high) { a += 1 } d = delayer.new(:low) { a += 2 } delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(5, a) end def test_cancel_end delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) a = 0 delayer.new { a += 1 } delayer.new { a += 2 } d = delayer.new { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) a = 0 delayer.new(:low) { a += 1 } delayer.new(:low) { a += 2 } d = delayer.new(:high) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) a = 0 delayer.new(:high) { a += 1 } delayer.new(:high) { a += 2 } d = delayer.new(:low) { a += 4 } assert_equal(0, a) d.cancel delayer.run assert_equal(3, a) end def test_multithread_register delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] threads = [] 10.times do threads << Thread.new do 1000.times do |number| delayer.new { buffer << number } end end end delayer.run threads.each(&:join) delayer.run assert_equal(10000, buffer.size) assert_equal((0..999).inject(&:+)*10, buffer.inject(&:+)) end def test_nested delayer = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) buffer = [] delayer.new { buffer << 1 } delayer.new do delayer.new { buffer << 3 } delayer.new do delayer.new { buffer << 5 } delayer.new { buffer << 6 } end delayer.new { buffer << 4 } end delayer.new { buffer << 2 } delayer.run assert_equal([1,2,3,4,5,6], buffer) end def test_invalid_priority delayer = Delayer.generate_class(priority: [:high, :middle, :low]) buffer = [] assert_raise Delayer::InvalidPriorityError do delayer.new(0) { buffer << 1 } end assert_raise Delayer::InvalidPriorityError do delayer.new("middle") { buffer << 2 } end assert_raise Delayer::InvalidPriorityError do delayer.new { buffer << 3 } end delayer.run assert_equal([], buffer) end end delayer-1.1.2/README.md0000644000004100000410000000212313641340371014447 0ustar www-datawww-data# Delayer [![toshia](https://circleci.com/gh/toshia/delayer.svg?style=svg)](https://circleci.com/gh/toshia/delayer) Delay Any task. Similar priority-queue. ## Installation Add this line to your application's Gemfile: gem 'delayer' And then execute: $ bundle Or install it yourself as: $ gem install delayer ## Usage Task = Delayer.generate_class # Define basic class Task = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) # or, Priority delayer Task = Delayer.generate_class(expire: 0.5) # and/or, Time limited delayer. task = Task.new { delayed code ... } # Register task task = Task.new(:high) { delayed code ... } # or, You can specify priority. task.cancel # Task can cancel before Delayer#run. Task.run # Execute all tasks. Task.run(1) # or, You can specify expire. ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request delayer-1.1.2/.circleci/0000755000004100000410000000000013641340371015025 5ustar www-datawww-datadelayer-1.1.2/.circleci/config.yml0000644000004100000410000000140213641340371017012 0ustar www-datawww-dataversion: '2.1' executors: ruby: parameters: tag: type: string docker: - image: circleci/ruby:<< parameters.tag >> jobs: build: parameters: ruby-version: type: string executor: name: ruby tag: << parameters.ruby-version >> steps: - checkout - run: name: Which bundler? command: bundle -v - run: command: bundle install --path vendor/bundle - run: name: test command: bundle exec rake test workflows: build: jobs: - build: name: 'ruby-2.5' ruby-version: '2.5.7' - build: name: 'ruby-2.6' ruby-version: '2.6.5' - build: name: 'ruby-2.7' ruby-version: '2.7.0' delayer-1.1.2/.gitignore0000644000004100000410000000024313641340371015161 0ustar www-datawww-data*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp /vendor/ delayer-1.1.2/Rakefile0000644000004100000410000000050713641340371014641 0ustar www-datawww-datarequire "bundler/gem_tasks" require 'rake/testtask' task :default => [:test] Rake::TestTask.new do |test| # $LOAD_PATH に追加するパス (デフォルトで 'lib' は入っている) test.libs << 'test' # テスト対象ファイルの指定 test.test_files = Dir[ 'test/**/test_*.rb' ] test.verbose = true enddelayer-1.1.2/lib/0000755000004100000410000000000013641340371013740 5ustar www-datawww-datadelayer-1.1.2/lib/delayer.rb0000644000004100000410000000210013641340371015703 0ustar www-datawww-data# -*- coding: utf-8 -*- require "delayer/version" require "delayer/error" require "delayer/extend" require "delayer/procedure" require "delayer/delayed_procedure" require "monitor" module Delayer class << self attr_accessor :default # Generate new Delayer class. # ==== Args # [options] # Hash # expire :: processing expire (secs, 0=unlimited) # priority :: priorities # default :: default priotity # ==== Return # A new class def generate_class(options = {}) Class.new do include ::Delayer @expire = options[:expire] || 0 if options.has_key?(:priority) @priorities = options[:priority] @default_priority = options[:default] else @priorities = [:normal] @default_priority = :normal end end end def method_missing(*args, **kwrest, &proc) if kwrest.empty? (@default ||= generate_class).__send__(*args, &proc) else (@default ||= generate_class).__send__(*args, **kwrest, &proc) end end end end delayer-1.1.2/lib/delayer/0000755000004100000410000000000013641340371015365 5ustar www-datawww-datadelayer-1.1.2/lib/delayer/version.rb0000644000004100000410000000010613641340371017374 0ustar www-datawww-data# frozen_string_literal: true module Delayer VERSION = '1.1.2' end delayer-1.1.2/lib/delayer/extend.rb0000644000004100000410000001514013641340371017202 0ustar www-datawww-data# frozen_string_literal: true module Delayer attr_reader :priority Bucket = Struct.new(:first, :last, :priority_of, :stashed) do def stash_size if stashed 1 + stashed.stash_size else 0 end end end def self.included(klass) klass.class_eval do extend Extend end end def initialize(priority = self.class.instance_eval { @default_priority }, *_args, delay: 0, &proc) self.class.validate_priority priority @priority = priority if delay == 0 @procedure = Procedure.new(self, &proc) else @procedure = DelayedProcedure.new(self, delay: delay, &proc) end end # Cancel this job # ==== Exception # Delayer::AlreadyExecutedError :: if already called run() # ==== Return # self def cancel @procedure.cancel self end module Extend attr_accessor :expire attr_reader :exception def self.extended(klass) klass.class_eval do @busy = false @expire = 0 @remain_hook = nil @exception = nil @remain_received = false @lock = Monitor.new @bucket = Bucket.new(nil, nil, {}, nil) @last_reserve = nil @reserves = Set.new end end def pop_reserve(start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)) if @last_reserve&.reserve_at&.<=(start_time) lock.synchronize do while @last_reserve&.reserve_at&.<=(start_time) @last_reserve.register @last_reserve = @reserves.min @reserves.delete(@last_reserve) end end end end # Run registered jobs. # ==== Args # [current_expire] expire for processing (secs, 0=unexpired) # ==== Return # self def run(current_expire = @expire) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) pop_reserve(start_time) if current_expire == 0 run_once_without_pop_reserve until empty? else @end_time = start_time + @expire run_once_without_pop_reserve while !empty? && (@end_time >= Process.clock_gettime(Process::CLOCK_MONOTONIC)) @end_time = nil end if @remain_hook @remain_received = !empty? @remain_hook.call if @remain_received end rescue Exception => e @exception = e raise e end def expire? if defined?(@end_time) && @end_time @end_time < Time.new.to_f else false end end # Run a job and forward pointer. # ==== Return # self def run_once pop_reserve run_once_without_pop_reserve end private def run_once_without_pop_reserve if @bucket.first @busy = true procedure = forward procedure = forward while @bucket.first && procedure.canceled? procedure.run unless procedure.canceled? end ensure @busy = false end # Return if some jobs processing now. # ==== Args # [args] # ==== Return # true if Delayer processing job def busy? @busy end # Return true if no jobs has. # ==== Return # true if no jobs has. def empty? !@bucket.first end # Return remain jobs quantity. # ==== Return # Count of remain jobs def size(node = @bucket.first) if node 1 + size(node.next) else 0 end end # register new job. # ==== Args # [procedure] job(Delayer::Procedure) # ==== Return # self def register(procedure) priority = procedure.delayer.priority lock.synchronize do last_pointer = get_prev_point(priority) if last_pointer @bucket.priority_of[priority] = last_pointer.break procedure else procedure.next = @bucket.first @bucket.priority_of[priority] = @bucket.first = procedure end @bucket.last = @bucket.priority_of[priority] if @bucket.last if @remain_hook && !@remain_received @remain_received = true @remain_hook.call end end self end # Register reserved job. # It does not execute immediately. # it calls register() in _procedure.reserve_at_. # ==== Args # [procedure] job(Delayer::DelayedProcedure) # ==== Return # self def reserve(procedure) lock.synchronize do if @last_reserve if @last_reserve > procedure @reserves.add(@last_reserve) @last_reserve = procedure else @reserves.add(procedure) end else @last_reserve = procedure end end self end def register_remain_hook(&proc) @remain_hook = proc end def get_prev_point(priority) if @bucket.priority_of[priority] @bucket.priority_of[priority] else next_index = @priorities.index(priority) - 1 get_prev_point @priorities[next_index] if next_index >= 0 end end def validate_priority(symbol) unless @priorities.include? symbol raise Delayer::InvalidPriorityError, "undefined priority '#{symbol}'" end end # DelayerのStashレベルをインクリメントする。 # このメソッドが呼ばれたら、その時存在するジョブは退避され、stash_exit!が呼ばれるまで実行されない。 def stash_enter! @bucket = Bucket.new(nil, nil, {}, @bucket) self end # DelayerのStashレベルをデクリメントする。 # このメソッドを呼ぶ前に、現在のレベルに存在するすべてのジョブを実行し、Delayer#empty?がtrueを返すような状態になっている必要がある。 # ==== Raises # [Delayer::NoLowerLevelError] stash_enter!が呼ばれていない時 # [Delayer::RemainJobsError] ジョブが残っているのにこのメソッドを呼んだ時 def stash_exit! raise Delayer::NoLowerLevelError, 'stash_exit! called in level 0.' unless @bucket.stashed raise Delayer::RemainJobsError, 'Current level has remain jobs. It must be empty current level jobs in call this method.' unless empty? @bucket = @bucket.stashed end # 現在のDelayer Stashレベルを返す。 def stash_level @bucket.stash_size end private def forward lock.synchronize do prev = @bucket.first @bucket.first = @bucket.first.next @bucket.last = nil unless @bucket.first @bucket.priority_of.each do |priority, pointer| @bucket.priority_of[priority] = @bucket.first if prev == pointer end prev.next = nil prev end end def lock @lock end end end delayer-1.1.2/lib/delayer/error.rb0000644000004100000410000000113513641340371017043 0ustar www-datawww-data# frozen_string_literal: true module Delayer class Error < ::StandardError; end class TooLate < Error; end class AlreadyExecutedError < TooLate; end class AlreadyCanceledError < TooLate; end class AlreadyRunningError < TooLate; end class InvalidPriorityError < Error; end class RecursiveError < Error; end class NoLowerLevelError < RecursiveError; end class RemainJobsError < RecursiveError; end def self.StateError(state) case state when :run AlreadyRunningError when :done AlreadyExecutedError when :cancel AlreadyCanceledError end end end delayer-1.1.2/lib/delayer/procedure.rb0000644000004100000410000000237713641340371017713 0ustar www-datawww-data# frozen_string_literal: true module Delayer class Procedure attr_reader :state, :delayer attr_accessor :next def initialize(delayer, &proc) @delayer = delayer @proc = proc @state = :stop @next = nil @delayer.class.register(self) end # Run a process # ==== Exception # Delayer::TooLate :: if already called run() # ==== Return # node def run unless @state == :stop raise Delayer::StateError(@state), 'call twice Delayer::Procedure' end @state = :run @proc.call @state = :done @proc = nil end # Cancel this job # ==== Exception # Delayer::TooLate :: if already called run() # ==== Return # self def cancel unless @state == :stop raise Delayer::StateError(@state), 'cannot cancel Delayer::Procedure' end @state = :cancel self end # Return true if canceled this task # ==== Return # true if canceled this task def canceled? @state == :cancel end # insert node between self and self.next # ==== Args # [node] insertion # ==== Return # node def break(node) tail = @next @next = node node.next = tail node end end end delayer-1.1.2/lib/delayer/delayed_procedure.rb0000644000004100000410000000223013641340371021366 0ustar www-datawww-data# frozen_string_literal: true module Delayer class DelayedProcedure include Comparable attr_reader :state, :delayer, :reserve_at def initialize(delayer, delay:, &proc) @delayer = delayer @proc = proc case delay when Time @reserve_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay.to_f - Time.now.to_f else @reserve_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay.to_f end @cancel = nil @procedure = nil @delayer.class.reserve(self) end def register if !canceled? @procedure = Procedure.new(@delayer, &@proc) end end def <=>(other) @reserve_at <=> other.reserve_at end # Cancel this job # ==== Exception # Delayer::TooLate :: if already called run() # ==== Return # self def cancel if @procedure @procedure.cancel else @cancel = true end end # Return true if canceled this task # ==== Return # true if canceled this task def canceled? if @procedure @procedure.canceled? else @cancel end end end end delayer-1.1.2/delayer.gemspec0000644000004100000410000000170213641340371016164 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'delayer/version' Gem::Specification.new do |spec| spec.name = "delayer" spec.version = Delayer::VERSION spec.authors = ["Toshiaki Asai"] spec.email = ["toshi.alternative@gmail.com"] spec.description = %q{Delay the processing} spec.summary = %q{Delay the processing} spec.homepage = "https://github.com/toshia/delayer" spec.license = "MIT" spec.required_ruby_version = '>= 2.4.0' spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_development_dependency "bundler" spec.add_development_dependency "rake", '>= 12.3.2' spec.add_development_dependency "test-unit", '>= 3.3.3', '< 4.0' end delayer-1.1.2/Gemfile0000644000004100000410000000013413641340371014463 0ustar www-datawww-datasource 'https://rubygems.org' # Specify your gem's dependencies in delayer.gemspec gemspec delayer-1.1.2/LICENSE.txt0000644000004100000410000000205613641340371015020 0ustar www-datawww-dataCopyright (c) 2013 Toshiaki Asai MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.