File: tools.rb

package info (click to toggle)
ruby-delayer-deferred 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 308 kB
  • sloc: ruby: 1,650; sh: 4; makefile: 2
file content (82 lines) | stat: -rw-r--r-- 2,869 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# -*- coding: utf-8 -*-
require 'delayer/deferred/error'

module Delayer::Deferred
  module Tools
    def next(&proc)
      new.next(&proc) end

    def trap(&proc)
      new.trap(&proc) end

    # 実行中のDeferredを失敗させる。raiseと違って、Exception以外のオブジェクトをtrap()に渡すことができる。
    # Deferredのnextとtrapの中でだけ呼び出すことができる。
    # ==== Args
    # [value] trap()に渡す値
    # ==== Throw
    # :__deferredable_fail をthrowする
    def fail(value)
      throw(:__deferredable_fail, value) end

    # 実行中のDeferredを、Delayerのタイムリミットが来ている場合に限り一旦中断する。
    # 長期に渡る可能性のある処理で、必要に応じて他のタスクを先に実行してもよい場合に呼び出す。
    def pass
      Fiber.yield(Request::PASS) if delayer.expire?
    end

    # 複数のdeferredを引数に取って、それら全ての実行が終了したら、
    # その結果を引数の順番通りに格納したArrayを引数に呼ばれるDeferredを返す。
    # 引数のDeferredが一つでも失敗するとこのメソッドの返すDeferredも失敗する。
    # ==== Args
    # [*args] 終了を待つDeferredオブジェクト
    # ==== Return
    # Deferred
    def when(*args)
      args = args.flatten
      return self.next{ [].freeze } if args.empty?
      args.each_with_index{|d, index|
        unless d.is_a?(Deferredable::Chainable) || d.is_a?(Deferredable::Awaitable)
          raise TypeError, "Argument #{index} of Deferred.when must be #{Deferredable::Chainable}, but given #{d.class}"
        end
        if d.respond_to?(:has_child?) && d.has_child?
          raise "Already assigned child for argument #{index}"
        end
      }
      defer, *follow = *args
      defer.next{|res|
        [res, *follow.map{|d| +d }]
      }
    end

    # Kernel#systemを呼び出して、コマンドが成功たら成功するDeferredを返す。
    # 失敗した場合、trap{}ブロックには $? の値(Process::Status)か、例外が発生した場合それが渡される
    # ==== Args
    # [*args] Kernel#spawn の引数
    # ==== Return
    # Deferred
    def system(*args)
      delayer.Deferred.Thread.new {
        Process.waitpid2(Kernel.spawn(*args))
      }.next{|_pid, status|
        if status && status.success?
          status
        else
          raise ForeignCommandAborted.new("command aborted: #{args.join(' ')}", process: status) end
      }
    end

    # _sec_ 秒後にsuccessとなるPromiseを返す
    # ==== Args
    # [sec] 待つ秒数
    # ==== Return
    # Deferred
    def sleep(sec)
      # pp [sec]
      delayer.Promise.new(true).tap do |promise|
        delayer.new(delay: sec) do
          promise.call()
        end
      end
    end
  end
end