concurrent-ruby 0.8.0.pre2-java → 0.9.0-java

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.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -3
  3. data/README.md +111 -55
  4. data/lib/concurrent.rb +90 -14
  5. data/lib/concurrent/async.rb +143 -51
  6. data/lib/concurrent/atom.rb +131 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +34 -3
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +34 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +27 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +234 -109
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +19 -7
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +51 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +196 -23
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  46. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  47. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  48. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  49. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  50. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  51. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  52. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  53. data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
  54. data/lib/concurrent/executor/timer_set.rb +96 -84
  55. data/lib/concurrent/executors.rb +1 -1
  56. data/lib/concurrent/future.rb +71 -38
  57. data/lib/concurrent/immutable_struct.rb +89 -0
  58. data/lib/concurrent/ivar.rb +152 -60
  59. data/lib/concurrent/lazy_register.rb +40 -20
  60. data/lib/concurrent/maybe.rb +226 -0
  61. data/lib/concurrent/mutable_struct.rb +227 -0
  62. data/lib/concurrent/mvar.rb +44 -43
  63. data/lib/concurrent/promise.rb +229 -136
  64. data/lib/concurrent/scheduled_task.rb +341 -43
  65. data/lib/concurrent/settable_struct.rb +127 -0
  66. data/lib/concurrent/synchronization.rb +17 -0
  67. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  68. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  69. data/lib/concurrent/synchronization/condition.rb +53 -0
  70. data/lib/concurrent/synchronization/java_object.rb +34 -0
  71. data/lib/concurrent/synchronization/lock.rb +32 -0
  72. data/lib/concurrent/synchronization/monitor_object.rb +26 -0
  73. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  74. data/lib/concurrent/synchronization/object.rb +78 -0
  75. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  76. data/lib/concurrent/timer_task.rb +92 -103
  77. data/lib/concurrent/tvar.rb +42 -38
  78. data/lib/concurrent/utilities.rb +3 -1
  79. data/lib/concurrent/utility/at_exit.rb +97 -0
  80. data/lib/concurrent/utility/engine.rb +44 -0
  81. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  82. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  83. data/lib/concurrent/utility/processor_counter.rb +156 -0
  84. data/lib/concurrent/utility/timeout.rb +18 -14
  85. data/lib/concurrent/utility/timer.rb +11 -6
  86. data/lib/concurrent/version.rb +2 -1
  87. data/lib/concurrent_ruby.rb +1 -0
  88. data/lib/concurrent_ruby_ext.jar +0 -0
  89. metadata +46 -66
  90. data/lib/concurrent/actor.rb +0 -103
  91. data/lib/concurrent/actor/behaviour.rb +0 -70
  92. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  93. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  94. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  95. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  96. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  97. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  98. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  99. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  100. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  101. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  102. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  103. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  104. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  105. data/lib/concurrent/actor/context.rb +0 -154
  106. data/lib/concurrent/actor/core.rb +0 -217
  107. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  108. data/lib/concurrent/actor/envelope.rb +0 -41
  109. data/lib/concurrent/actor/errors.rb +0 -27
  110. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  111. data/lib/concurrent/actor/public_delegations.rb +0 -40
  112. data/lib/concurrent/actor/reference.rb +0 -81
  113. data/lib/concurrent/actor/root.rb +0 -37
  114. data/lib/concurrent/actor/type_check.rb +0 -48
  115. data/lib/concurrent/actor/utils.rb +0 -10
  116. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  117. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  118. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  119. data/lib/concurrent/actor/utils/pool.rb +0 -59
  120. data/lib/concurrent/actress.rb +0 -3
  121. data/lib/concurrent/agent.rb +0 -209
  122. data/lib/concurrent/atomic.rb +0 -92
  123. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  124. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  125. data/lib/concurrent/atomic/synchronization.rb +0 -51
  126. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  127. data/lib/concurrent/channel/channel.rb +0 -41
  128. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  129. data/lib/concurrent/channel/waitable_list.rb +0 -40
  130. data/lib/concurrent/channels.rb +0 -5
  131. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  132. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  133. data/lib/concurrent/collections.rb +0 -3
  134. data/lib/concurrent/dereferenceable.rb +0 -108
  135. data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
  136. data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
  137. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
  138. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
  139. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  140. data/lib/concurrent/logging.rb +0 -20
  141. data/lib/concurrent/obligation.rb +0 -171
  142. data/lib/concurrent/observable.rb +0 -73
  143. data/lib/concurrent/options_parser.rb +0 -48
  144. data/lib/concurrent/utility/processor_count.rb +0 -152
  145. data/lib/extension_helper.rb +0 -37
@@ -1,32 +0,0 @@
1
- if RUBY_PLATFORM == 'java'
2
-
3
- require 'concurrent/executor/java_thread_pool_executor'
4
-
5
- module Concurrent
6
-
7
- # @!macro cached_thread_pool
8
- class JavaCachedThreadPool < JavaThreadPoolExecutor
9
-
10
- # Create a new thread pool.
11
- #
12
- # @param [Hash] opts the options defining pool behavior.
13
- # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
14
- #
15
- # @raise [ArgumentError] if `fallback_policy` is not a known policy
16
- #
17
- # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
18
- def initialize(opts = {})
19
- @fallback_policy = opts.fetch(:fallback_policy, opts.fetch(:overflow_policy, :abort))
20
- warn '[DEPRECATED] :overflow_policy is deprecated terminology, please use :fallback_policy instead' if opts.has_key?(:overflow_policy)
21
- @max_queue = 0
22
-
23
- raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.keys.include?(@fallback_policy)
24
-
25
- @executor = java.util.concurrent.Executors.newCachedThreadPool
26
- @executor.setRejectedExecutionHandler(FALLBACK_POLICIES[@fallback_policy].new)
27
-
28
- set_shutdown_hook
29
- end
30
- end
31
- end
32
- end
@@ -1,31 +0,0 @@
1
- if RUBY_PLATFORM == 'java'
2
-
3
- require 'concurrent/executor/java_thread_pool_executor'
4
-
5
- module Concurrent
6
-
7
- # @!macro fixed_thread_pool
8
- class JavaFixedThreadPool < JavaThreadPoolExecutor
9
-
10
- # Create a new thread pool.
11
- #
12
- # @param [Hash] opts the options defining pool behavior.
13
- # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
14
- #
15
- # @raise [ArgumentError] if `num_threads` is less than or equal to zero
16
- # @raise [ArgumentError] if `fallback_policy` is not a known policy
17
- #
18
- # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
19
- def initialize(num_threads, opts = {})
20
-
21
- opts = {
22
- min_threads: num_threads,
23
- max_threads: num_threads
24
- }.merge(opts)
25
- super(opts)
26
-
27
- set_shutdown_hook
28
- end
29
- end
30
- end
31
- end
@@ -1,29 +0,0 @@
1
- require 'concurrent/executor/ruby_thread_pool_executor'
2
-
3
- module Concurrent
4
-
5
- # @!macro cached_thread_pool
6
- class RubyCachedThreadPool < RubyThreadPoolExecutor
7
-
8
- # Create a new thread pool.
9
- #
10
- # @param [Hash] opts the options defining pool behavior.
11
- # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
12
- #
13
- # @raise [ArgumentError] if `fallback_policy` is not a known policy
14
- def initialize(opts = {})
15
- fallback_policy = opts.fetch(:fallback_policy, opts.fetch(:overflow_policy, :abort))
16
-
17
- raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(fallback_policy)
18
-
19
- opts = opts.merge(
20
- min_threads: 0,
21
- max_threads: DEFAULT_MAX_POOL_SIZE,
22
- fallback_policy: fallback_policy,
23
- max_queue: DEFAULT_MAX_QUEUE_SIZE,
24
- idletime: DEFAULT_THREAD_IDLETIMEOUT
25
- )
26
- super(opts)
27
- end
28
- end
29
- end
@@ -1,32 +0,0 @@
1
- require 'concurrent/executor/ruby_thread_pool_executor'
2
-
3
- module Concurrent
4
-
5
- # @!macro fixed_thread_pool
6
- class RubyFixedThreadPool < RubyThreadPoolExecutor
7
-
8
- # Create a new thread pool.
9
- #
10
- # @param [Integer] num_threads the number of threads to allocate
11
- # @param [Hash] opts the options defining pool behavior.
12
- # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
13
- #
14
- # @raise [ArgumentError] if `num_threads` is less than or equal to zero
15
- # @raise [ArgumentError] if `fallback_policy` is not a known policy
16
- def initialize(num_threads, opts = {})
17
- fallback_policy = opts.fetch(:fallback_policy, opts.fetch(:overflow_policy, :abort))
18
-
19
- raise ArgumentError.new('number of threads must be greater than zero') if num_threads < 1
20
- raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(fallback_policy)
21
-
22
- opts = {
23
- min_threads: num_threads,
24
- max_threads: num_threads,
25
- fallback_policy: fallback_policy,
26
- max_queue: DEFAULT_MAX_QUEUE_SIZE,
27
- idletime: DEFAULT_THREAD_IDLETIMEOUT,
28
- }.merge(opts)
29
- super(opts)
30
- end
31
- end
32
- end
@@ -1,73 +0,0 @@
1
- require 'thread'
2
- require 'concurrent/logging'
3
-
4
- module Concurrent
5
-
6
- # @!visibility private
7
- class RubyThreadPoolWorker
8
- include Logging
9
-
10
- # @!visibility private
11
- def initialize(queue, parent)
12
- @queue = queue
13
- @parent = parent
14
- @mutex = Mutex.new
15
- @last_activity = Time.now.to_f
16
- @thread = nil
17
- end
18
-
19
- # @!visibility private
20
- def dead?
21
- return @mutex.synchronize do
22
- @thread.nil? ? false : ! @thread.alive?
23
- end
24
- end
25
-
26
- # @!visibility private
27
- def last_activity
28
- @mutex.synchronize { @last_activity }
29
- end
30
-
31
- def status
32
- @mutex.synchronize do
33
- return 'not running' if @thread.nil?
34
- @thread.status
35
- end
36
- end
37
-
38
- # @!visibility private
39
- def kill
40
- @mutex.synchronize do
41
- Thread.kill(@thread) unless @thread.nil?
42
- @thread = nil
43
- end
44
- end
45
-
46
- # @!visibility private
47
- def run(thread = Thread.current)
48
- @mutex.synchronize do
49
- raise StandardError.new('already running') unless @thread.nil?
50
- @thread = thread
51
- end
52
-
53
- loop do
54
- task = @queue.pop
55
- if task == :stop
56
- @thread = nil
57
- @parent.on_worker_exit(self)
58
- break
59
- end
60
-
61
- begin
62
- task.last.call(*task.first)
63
- rescue => ex
64
- # let it fail
65
- log DEBUG, ex
66
- ensure
67
- @last_activity = Time.now.to_f
68
- @parent.on_end_task
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,20 +0,0 @@
1
- require 'logger'
2
-
3
- module Concurrent
4
- # Include where logging is needed
5
- module Logging
6
- include Logger::Severity
7
-
8
- # Logs through {Configuration#logger}, it can be overridden by setting @logger
9
- # @param [Integer] level one of Logger::Severity constants
10
- # @param [String] progname e.g. a path of an Actor
11
- # @param [String, nil] message when nil block is used to generate the message
12
- # @yieldreturn [String] a message
13
- def log(level, progname, message = nil, &block)
14
- (@logger || Concurrent.configuration.logger).call level, progname, message, &block
15
- rescue => error
16
- $stderr.puts "`Concurrent.configuration.logger` failed to log #{[level, progname, message, block]}\n" +
17
- "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
18
- end
19
- end
20
- end
@@ -1,171 +0,0 @@
1
- require 'thread'
2
- require 'timeout'
3
-
4
- require 'concurrent/dereferenceable'
5
- require 'concurrent/atomic/event'
6
-
7
- module Concurrent
8
-
9
- module Obligation
10
- include Dereferenceable
11
-
12
- # Has the obligation been fulfilled?
13
- # @return [Boolean]
14
- def fulfilled?
15
- state == :fulfilled
16
- end
17
- alias_method :realized?, :fulfilled?
18
-
19
- # Has the obligation been rejected?
20
- # @return [Boolean]
21
- def rejected?
22
- state == :rejected
23
- end
24
-
25
- # Is obligation completion still pending?
26
- # @return [Boolean]
27
- def pending?
28
- state == :pending
29
- end
30
-
31
- # Is the obligation still unscheduled?
32
- # @return [Boolean]
33
- def unscheduled?
34
- state == :unscheduled
35
- end
36
-
37
- def completed?
38
- [:fulfilled, :rejected].include? state
39
- end
40
-
41
- def incomplete?
42
- [:unscheduled, :pending].include? state
43
- end
44
-
45
- # @return [Object] see Dereferenceable#deref
46
- def value(timeout = nil)
47
- wait timeout
48
- deref
49
- end
50
-
51
- # wait until Obligation is #complete?
52
- # @param [Numeric] timeout the maximum time in second to wait.
53
- # @return [Obligation] self
54
- def wait(timeout = nil)
55
- event.wait(timeout) if timeout != 0 && incomplete?
56
- self
57
- end
58
-
59
- # wait until Obligation is #complete?
60
- # @param [Numeric] timeout the maximum time in second to wait.
61
- # @return [Obligation] self
62
- # @raise [Exception] when #rejected? it raises #reason
63
- def no_error!(timeout = nil)
64
- wait(timeout).tap { raise self if rejected? }
65
- end
66
-
67
- # @raise [Exception] when #rejected? it raises #reason
68
- # @return [Object] see Dereferenceable#deref
69
- def value!(timeout = nil)
70
- wait(timeout)
71
- if rejected?
72
- raise self
73
- else
74
- deref
75
- end
76
- end
77
-
78
- def state
79
- mutex.lock
80
- @state
81
- ensure
82
- mutex.unlock
83
- end
84
-
85
- def reason
86
- mutex.lock
87
- @reason
88
- ensure
89
- mutex.unlock
90
- end
91
-
92
- # @example allows Obligation to be risen
93
- # rejected_ivar = Ivar.new.fail
94
- # raise rejected_ivar
95
- def exception(*args)
96
- raise 'obligation is not rejected' unless rejected?
97
- reason.exception(*args)
98
- end
99
-
100
- protected
101
-
102
- # @!visibility private
103
- def init_obligation # :nodoc:
104
- init_mutex
105
- @event = Event.new
106
- end
107
-
108
- # @!visibility private
109
- def event # :nodoc:
110
- @event
111
- end
112
-
113
- # @!visibility private
114
- def set_state(success, value, reason) # :nodoc:
115
- if success
116
- @value = value
117
- @state = :fulfilled
118
- else
119
- @reason = reason
120
- @state = :rejected
121
- end
122
- end
123
-
124
- # @!visibility private
125
- def state=(value) # :nodoc:
126
- mutex.lock
127
- @state = value
128
- ensure
129
- mutex.unlock
130
- end
131
-
132
- # atomic compare and set operation
133
- # state is set to next_state only if current state is == expected_current
134
- #
135
- # @param [Symbol] next_state
136
- # @param [Symbol] expected_current
137
- #
138
- # @return [Boolean] true is state is changed, false otherwise
139
- #
140
- # @!visibility private
141
- def compare_and_set_state(next_state, expected_current) # :nodoc:
142
- mutex.lock
143
- if @state == expected_current
144
- @state = next_state
145
- true
146
- else
147
- false
148
- end
149
- ensure
150
- mutex.unlock
151
- end
152
-
153
- # executes the block within mutex if current state is included in expected_states
154
- #
155
- # @return block value if executed, false otherwise
156
- #
157
- # @!visibility private
158
- def if_state(*expected_states) # :nodoc:
159
- mutex.lock
160
- raise ArgumentError.new('no block given') unless block_given?
161
-
162
- if expected_states.include? @state
163
- yield
164
- else
165
- false
166
- end
167
- ensure
168
- mutex.unlock
169
- end
170
- end
171
- end
@@ -1,73 +0,0 @@
1
- require 'concurrent/atomic/copy_on_notify_observer_set'
2
- require 'concurrent/atomic/copy_on_write_observer_set'
3
-
4
- module Concurrent
5
-
6
- # The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one of the most useful design pattern.
7
- #
8
- # The workflow is very simple:
9
- # - an `observer` can register itself to a `subject` via a callback
10
- # - many `observers` can be registered to the same `subject`
11
- # - the `subject` notifies all registered observers when its status changes
12
- # - an `observer` can deregister itself when is no more interested to receive event notifications
13
- #
14
- # In a single threaded environment the whole pattern is very easy: the `subject` can use a simple data structure to manage all its subscribed `observer`s and every `observer` can react directly to every event without caring about synchronization.
15
- #
16
- # In a multi threaded environment things are more complex.
17
- # The `subject` must synchronize the access to its data structure and to do so currently we're using two specialized ObserverSet: CopyOnWriteObserverSet and CopyOnNotifyObserverSet.
18
- #
19
- # When implementing and `observer` there's a very important rule to remember: **there are no guarantees about the thread that will execute the callback**
20
- #
21
- # Let's take this example
22
- # ```
23
- # class Observer
24
- # def initialize
25
- # @count = 0
26
- # end
27
- #
28
- # def update
29
- # @count += 1
30
- # end
31
- # end
32
- #
33
- # obs = Observer.new
34
- # [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) }
35
- # # execute [obj1, obj2, obj3, obj4]
36
- # ```
37
- #
38
- # `obs` is wrong because the variable `@count` can be accessed by different threads at the same time, so it should be synchronized (using either a Mutex or an AtomicFixum)
39
- module Observable
40
-
41
- # @return [Object] the added observer
42
- def add_observer(*args, &block)
43
- observers.add_observer(*args, &block)
44
- end
45
-
46
- # as #add_observer but it can be used for chaining
47
- # @return [Observable] self
48
- def with_observer(*args, &block)
49
- add_observer(*args, &block)
50
- self
51
- end
52
-
53
- # @return [Object] the deleted observer
54
- def delete_observer(*args)
55
- observers.delete_observer(*args)
56
- end
57
-
58
- # @return [Observable] self
59
- def delete_observers
60
- observers.delete_observers
61
- self
62
- end
63
-
64
- # @return [Integer] the observers count
65
- def count_observers
66
- observers.count_observers
67
- end
68
-
69
- protected
70
-
71
- attr_accessor :observers
72
- end
73
- end