Skip to content

Commit a17c89e

Browse files
committed
IVar now uses ns_initialize.
1 parent dd4e7bf commit a17c89e

File tree

5 files changed

+54
-23
lines changed

5 files changed

+54
-23
lines changed

lib/concurrent/future.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Future < IVar
2424
# @raise [ArgumentError] if no block is given
2525
def initialize(opts = {}, &block)
2626
raise ArgumentError.new('no block given') unless block_given?
27-
super(IVar::NO_VALUE, opts)
27+
super(IVar::NO_VALUE, opts, &nil)
2828
@state = :unscheduled
2929
@task = block
3030
@executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor

lib/concurrent/ivar.rb

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,13 @@ class IVar < Synchronization::Object
5757
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
5858
# the internal value and returning the value returned from the proc
5959
def initialize(value = NO_VALUE, opts = {})
60-
#FIXME use ns_initialize
61-
super(&:nil)
62-
init_obligation(self)
63-
self.observers = CopyOnWriteObserverSet.new
64-
set_deref_options(opts)
65-
@state = :pending
66-
67-
set(value) unless value == NO_VALUE
60+
if value != NO_VALUE && block_given?
61+
raise ArgumentError.new('provide only a value or a block')
62+
end
63+
value = yield if block_given?
64+
super
6865
end
6966

70-
protected :synchronize
71-
7267
# Add an observer on this object that will receive notification on update.
7368
#
7469
# Upon completion the `IVar` will notify all observers in a thread-safe way.
@@ -118,10 +113,13 @@ def set(value = NO_VALUE)
118113

119114
begin
120115
value = yield if block_given?
121-
complete(true, value, nil)
116+
complete_without_notification(true, value, nil)
122117
rescue => ex
123-
complete(false, nil, ex)
118+
complete_without_notification(false, nil, ex)
124119
end
120+
121+
notify_observers(self.value, reason)
122+
self
125123
end
126124

127125
# @!macro [attach] ivar_fail_method
@@ -150,19 +148,39 @@ def try_set(value = NO_VALUE, &block)
150148

151149
protected
152150

153-
# @!visibility private
154-
def complete(success, value, reason) # :nodoc:
155-
synchronize do
156-
raise MultipleAssignmentError if [:fulfilled, :rejected].include? @state
157-
set_state(success, value, reason)
158-
event.set
151+
def ns_initialize(value, opts)
152+
init_obligation(self)
153+
self.observers = CopyOnWriteObserverSet.new
154+
set_deref_options(opts)
155+
156+
if value == NO_VALUE
157+
@state = :pending
158+
else
159+
ns_complete_without_notification(true, value, nil)
159160
end
161+
end
160162

161-
time = Time.now
162-
observers.notify_and_delete_observers{ [time, self.value, reason] }
163+
def complete(success, value, reason)
164+
complete_without_notification(success, value, reason)
165+
notify_observers(self.value, reason)
163166
self
164167
end
165168

169+
def complete_without_notification(success, value, reason)
170+
synchronize { ns_complete_without_notification(success, value, reason) }
171+
self
172+
end
173+
174+
def notify_observers(value, reason)
175+
observers.notify_and_delete_observers{ [Time.now, value, reason] }
176+
end
177+
178+
def ns_complete_without_notification(success, value, reason)
179+
raise MultipleAssignmentError if [:fulfilled, :rejected].include? @state
180+
set_state(success, value, reason)
181+
event.set
182+
end
183+
166184
# @!visibility private
167185
def check_for_block_or_value!(block_given, value) # :nodoc:
168186
if (block_given && value != NO_VALUE) || (! block_given && value == NO_VALUE)

lib/concurrent/promise.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class Promise < IVar
203203
# @see http://promises-aplus.github.io/promises-spec/
204204
def initialize(opts = {}, &block)
205205
opts.delete_if { |k, v| v.nil? }
206-
super(IVar::NO_VALUE, opts)
206+
super(IVar::NO_VALUE, opts, &nil)
207207

208208
@executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor
209209
@args = get_arguments_from(opts)

lib/concurrent/scheduled_task.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def initialize(delay, opts = {}, &block)
159159
raise ArgumentError.new('no block given') unless block_given?
160160
@delay = TimerSet.calculate_delay!(delay)
161161

162-
super(NO_VALUE, opts)
162+
super(IVar::NO_VALUE, opts, &nil)
163163

164164
self.observers = CopyOnNotifyObserverSet.new
165165
@state = :unscheduled

spec/concurrent/ivar_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ def trigger_observable(observable)
6363
it 'can set an initial value' do
6464
i = IVar.new(14)
6565
expect(i).to be_complete
66+
expect(i.value).to eq 14
67+
end
68+
69+
it 'can set an initial value with a block' do
70+
i = IVar.new{ 42 }
71+
expect(i).to be_complete
72+
expect(i.value).to eq 42
73+
end
74+
75+
it 'raises an exception if given both a value and a block' do
76+
expect {
77+
IVar.new(42){ 42 }
78+
}.to raise_error(ArgumentError)
6679
end
6780
end
6881

0 commit comments

Comments
 (0)