• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jdantonio / concurrent-ruby / #812

23 May 2014 08:08PM UTC coverage: 39.344% (-57.9%) from 97.237%
#812

push

jdantonio
Merge pull request #96 from jdantonio/refactor/errors

Moved all custom errors into a single file and into the Concurrent module

17 of 18 new or added lines in 10 files covered. (94.44%)

1435 existing lines in 57 files now uncovered.

1187 of 3017 relevant lines covered (39.34%)

0.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.97
/lib/concurrent/delay.rb
1
require 'thread'
1✔
2
require 'concurrent/obligation'
1✔
3

4
module Concurrent
1✔
5

6
  # Lazy evaluation of a block yielding an immutable result. Useful for expensive
7
  # operations that may never be needed.
8
  #
9
  # A `Delay` is similar to `Future` but solves a different problem.
10
  # Where a `Future` schedules an operation for immediate execution and
11
  # performs the operation asynchronously, a `Delay` (as the name implies)
12
  # delays execution of the operation until the result is actually needed.
13
  # 
14
  # When a `Delay` is created its state is set to `pending`. The value and
15
  # reason are both `nil`. The first time the `#value` method is called the
16
  # enclosed opration will be run and the calling thread will block. Other
17
  # threads attempting to call `#value` will block as well. Once the operation
18
  # is complete the *value* will be set to the result of the operation or the
19
  # *reason* will be set to the raised exception, as appropriate. All threads
20
  # blocked on `#value` will return. Subsequent calls to `#value` will immediately
21
  # return the cached value. The operation will only be run once. This means that
22
  # any side effects created by the operation will only happen once as well.
23
  #
24
  # `Delay` includes the `Concurrent::Dereferenceable` mixin to support thread
25
  # safety of the reference returned by `#value`.
26
  #
27
  # @since 0.6.0
28
  #
29
  # @see Concurrent::Dereferenceable
30
  #
31
  # @see http://clojuredocs.org/clojure_core/clojure.core/delay
32
  # @see http://aphyr.com/posts/306-clojure-from-the-ground-up-state
33
  class Delay
1✔
34
    include Obligation
1✔
35

36
    # Create a new `Delay` in the `:pending` state.
37
    #
38
    # @yield the delayed operation to perform
39
    #
40
    # @param [Hash] opts the options to create a message with
41
    # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
42
    # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
43
    # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing the internal value and
44
    #   returning the value returned from the proc
45
    #
46
    # @raise [ArgumentError] if no block is given
47
    def initialize(opts = {}, &block)
1✔
48
      raise ArgumentError.new('no block given') unless block_given?
5✔
49

50
      init_obligation
5✔
51
      @state = :pending
5✔
52
      @task  = block
5✔
53
      set_deref_options(opts)
5✔
54
    end
55

56
    # Return the (possibly memoized) value of the delayed operation.
57
    # 
58
    # If the state is `:pending` then the calling thread will block while the
59
    # operation is performed. All other threads simultaneously calling `#value`
60
    # will block as well. Once the operation is complete (either `:fulfilled` or
61
    # `:rejected`) all waiting threads will unblock and the new value will be
62
    # returned.
63
    #
64
    # If the state is not `:pending` when `#value` is called the (possibly memoized)
65
    # value will be returned without blocking and without performing the operation
66
    # again.
67
    #
68
    # Regardless of the final disposition all `Dereferenceable` options set during
69
    # object construction will be honored.
70
    #
71
    # @return [Object] the (possibly memoized) result of the block operation
72
    #
73
    # @see Concurrent::Dereferenceable
74
    def value
1✔
75
      mutex.lock
9✔
76
      execute_task_once
9✔
77
      apply_deref_options(@value)
9✔
78
    ensure
79
      mutex.unlock
9✔
80
    end
81

82
    # reconfigures the block returning the value if still #incomplete?
83
    # @yield the delayed operation to perform
84
    # @return [true, false] if success
85
    def reconfigure(&block)
1✔
UNCOV
86
      mutex.lock
×
UNCOV
87
      raise ArgumentError.new('no block given') unless block_given?
×
UNCOV
88
      if @state == :pending
×
UNCOV
89
        @task = block
×
UNCOV
90
        true
×
91
      else
UNCOV
92
        false
×
93
      end
94
    ensure
UNCOV
95
      mutex.unlock
×
96
    end
97

98
    private
1✔
99

100
    def execute_task_once
1✔
101
      if @state == :pending
9✔
102
        begin
103
          @value = @task.call
4✔
104
          @state = :fulfilled
4✔
105
        rescue => ex
UNCOV
106
          @reason = ex
×
UNCOV
107
          @state  = :rejected
×
108
        end
109
      end
110
    end
111
  end
112
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc