garcun 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitattributes +17 -0
- data/.gitignore +197 -0
- data/.rspec +2 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +521 -0
- data/Rakefile +47 -0
- data/garcun.gemspec +83 -0
- data/lib/garcon.rb +290 -0
- data/lib/garcon/chef/chef_helpers.rb +343 -0
- data/lib/garcon/chef/coerce/coercer.rb +134 -0
- data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
- data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
- data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
- data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
- data/lib/garcon/chef/handler/devreporter.rb +127 -0
- data/lib/garcon/chef/log.rb +64 -0
- data/lib/garcon/chef/node.rb +100 -0
- data/lib/garcon/chef/provider/civilize.rb +209 -0
- data/lib/garcon/chef/provider/development.rb +159 -0
- data/lib/garcon/chef/provider/download.rb +420 -0
- data/lib/garcon/chef/provider/house_keeping.rb +265 -0
- data/lib/garcon/chef/provider/node_cache.rb +31 -0
- data/lib/garcon/chef/provider/partial.rb +183 -0
- data/lib/garcon/chef/provider/recovery.rb +80 -0
- data/lib/garcon/chef/provider/zip_file.rb +271 -0
- data/lib/garcon/chef/resource/attribute.rb +52 -0
- data/lib/garcon/chef/resource/base_dsl.rb +174 -0
- data/lib/garcon/chef/resource/blender.rb +140 -0
- data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
- data/lib/garcon/chef/resource/resource_name.rb +109 -0
- data/lib/garcon/chef/secret_bag.rb +204 -0
- data/lib/garcon/chef/validations.rb +76 -0
- data/lib/garcon/chef_inclusions.rb +151 -0
- data/lib/garcon/configuration.rb +138 -0
- data/lib/garcon/core_ext.rb +39 -0
- data/lib/garcon/core_ext/array.rb +27 -0
- data/lib/garcon/core_ext/binding.rb +64 -0
- data/lib/garcon/core_ext/boolean.rb +66 -0
- data/lib/garcon/core_ext/duration.rb +271 -0
- data/lib/garcon/core_ext/enumerable.rb +34 -0
- data/lib/garcon/core_ext/file.rb +127 -0
- data/lib/garcon/core_ext/filetest.rb +62 -0
- data/lib/garcon/core_ext/hash.rb +279 -0
- data/lib/garcon/core_ext/kernel.rb +159 -0
- data/lib/garcon/core_ext/lazy.rb +222 -0
- data/lib/garcon/core_ext/method_access.rb +243 -0
- data/lib/garcon/core_ext/module.rb +92 -0
- data/lib/garcon/core_ext/nil.rb +53 -0
- data/lib/garcon/core_ext/numeric.rb +44 -0
- data/lib/garcon/core_ext/object.rb +342 -0
- data/lib/garcon/core_ext/pathname.rb +152 -0
- data/lib/garcon/core_ext/process.rb +41 -0
- data/lib/garcon/core_ext/random.rb +497 -0
- data/lib/garcon/core_ext/string.rb +312 -0
- data/lib/garcon/core_ext/struct.rb +49 -0
- data/lib/garcon/core_ext/symbol.rb +170 -0
- data/lib/garcon/core_ext/time.rb +234 -0
- data/lib/garcon/exceptions.rb +101 -0
- data/lib/garcon/inflections.rb +237 -0
- data/lib/garcon/inflections/defaults.rb +79 -0
- data/lib/garcon/inflections/inflections.rb +182 -0
- data/lib/garcon/inflections/rules_collection.rb +37 -0
- data/lib/garcon/secret.rb +271 -0
- data/lib/garcon/stash/format.rb +114 -0
- data/lib/garcon/stash/journal.rb +226 -0
- data/lib/garcon/stash/queue.rb +83 -0
- data/lib/garcon/stash/serializer.rb +86 -0
- data/lib/garcon/stash/store.rb +435 -0
- data/lib/garcon/task.rb +31 -0
- data/lib/garcon/task/atomic.rb +151 -0
- data/lib/garcon/task/atomic_boolean.rb +127 -0
- data/lib/garcon/task/condition.rb +99 -0
- data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
- data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
- data/lib/garcon/task/count_down_latch.rb +92 -0
- data/lib/garcon/task/delay.rb +196 -0
- data/lib/garcon/task/dereferenceable.rb +144 -0
- data/lib/garcon/task/event.rb +119 -0
- data/lib/garcon/task/executor.rb +275 -0
- data/lib/garcon/task/executor_options.rb +59 -0
- data/lib/garcon/task/future.rb +107 -0
- data/lib/garcon/task/immediate_executor.rb +84 -0
- data/lib/garcon/task/ivar.rb +171 -0
- data/lib/garcon/task/lazy_reference.rb +74 -0
- data/lib/garcon/task/monotonic_time.rb +69 -0
- data/lib/garcon/task/obligation.rb +256 -0
- data/lib/garcon/task/observable.rb +101 -0
- data/lib/garcon/task/priority_queue.rb +234 -0
- data/lib/garcon/task/processor_count.rb +128 -0
- data/lib/garcon/task/read_write_lock.rb +304 -0
- data/lib/garcon/task/safe_task_executor.rb +58 -0
- data/lib/garcon/task/single_thread_executor.rb +97 -0
- data/lib/garcon/task/thread_pool/cached.rb +71 -0
- data/lib/garcon/task/thread_pool/executor.rb +294 -0
- data/lib/garcon/task/thread_pool/fixed.rb +61 -0
- data/lib/garcon/task/thread_pool/worker.rb +90 -0
- data/lib/garcon/task/timer.rb +44 -0
- data/lib/garcon/task/timer_set.rb +194 -0
- data/lib/garcon/task/timer_task.rb +377 -0
- data/lib/garcon/task/waitable_list.rb +58 -0
- data/lib/garcon/utility/ansi.rb +199 -0
- data/lib/garcon/utility/at_random.rb +77 -0
- data/lib/garcon/utility/crypto.rb +292 -0
- data/lib/garcon/utility/equalizer.rb +146 -0
- data/lib/garcon/utility/faker/extensions/array.rb +22 -0
- data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
- data/lib/garcon/utility/faker/faker.rb +164 -0
- data/lib/garcon/utility/faker/faker/company.rb +17 -0
- data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
- data/lib/garcon/utility/faker/faker/version.rb +3 -0
- data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
- data/lib/garcon/utility/faker/locales/en.yml +21 -0
- data/lib/garcon/utility/file_helper.rb +170 -0
- data/lib/garcon/utility/hookers.rb +178 -0
- data/lib/garcon/utility/interpolation.rb +90 -0
- data/lib/garcon/utility/memstash.rb +364 -0
- data/lib/garcon/utility/misc.rb +54 -0
- data/lib/garcon/utility/msg_from_god.rb +62 -0
- data/lib/garcon/utility/retry.rb +238 -0
- data/lib/garcon/utility/timeout.rb +58 -0
- data/lib/garcon/utility/uber/builder.rb +91 -0
- data/lib/garcon/utility/uber/callable.rb +7 -0
- data/lib/garcon/utility/uber/delegates.rb +13 -0
- data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
- data/lib/garcon/utility/uber/options.rb +101 -0
- data/lib/garcon/utility/uber/uber_version.rb +3 -0
- data/lib/garcon/utility/uber/version.rb +33 -0
- data/lib/garcon/utility/url_helper.rb +100 -0
- data/lib/garcon/utils.rb +29 -0
- data/lib/garcon/version.rb +62 -0
- data/lib/garcun.rb +24 -0
- metadata +680 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require 'thread'
|
|
21
|
+
|
|
22
|
+
require_relative 'ivar'
|
|
23
|
+
require_relative 'safe_task_executor'
|
|
24
|
+
require_relative 'executor_options'
|
|
25
|
+
|
|
26
|
+
module Garcon
|
|
27
|
+
|
|
28
|
+
class Future < IVar
|
|
29
|
+
include ExecutorOptions
|
|
30
|
+
|
|
31
|
+
# Create a new `Future` in the `:unscheduled` state.
|
|
32
|
+
#
|
|
33
|
+
# @yield the asynchronous operation to perform
|
|
34
|
+
#
|
|
35
|
+
# @!macro executor_and_deref_options
|
|
36
|
+
#
|
|
37
|
+
# @option opts [object, Array] :args
|
|
38
|
+
# Zero or more arguments to be passed the task block on execution.
|
|
39
|
+
#
|
|
40
|
+
# @raise [ArgumentError] if no block is given
|
|
41
|
+
#
|
|
42
|
+
def initialize(opts = {}, &block)
|
|
43
|
+
raise ArgumentError.new('no block given') unless block_given?
|
|
44
|
+
super(IVar::NO_VALUE, opts)
|
|
45
|
+
@state = :unscheduled
|
|
46
|
+
@task = block
|
|
47
|
+
@executor = get_executor_from(opts) || Garcon.global_io_executor
|
|
48
|
+
@args = get_arguments_from(opts)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Execute an `:unscheduled` `Future`. Immediately sets the state to
|
|
52
|
+
# `:pending` and passes the block to a new thread/thread pool for eventual
|
|
53
|
+
# execution. Does nothing if the `Future` is in any state other than
|
|
54
|
+
# `:unscheduled`.
|
|
55
|
+
#
|
|
56
|
+
# @return [Future] a reference to `self`
|
|
57
|
+
#
|
|
58
|
+
# @example Instance and execute in separate steps
|
|
59
|
+
# future = Garcon::Future.new{ sleep(1); 42 }
|
|
60
|
+
# future.state #=> :unscheduled
|
|
61
|
+
# future.execute
|
|
62
|
+
# future.state #=> :pending
|
|
63
|
+
#
|
|
64
|
+
# @example Instance and execute in one line
|
|
65
|
+
# future = Garcon::Future.new{ sleep(1); 42 }.execute
|
|
66
|
+
# future.state #=> :pending
|
|
67
|
+
def execute
|
|
68
|
+
if compare_and_set_state(:pending, :unscheduled)
|
|
69
|
+
@executor.post(@args){ work }
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Create a new `Future` object with the given block, execute it, and return
|
|
75
|
+
# the `:pending` object.
|
|
76
|
+
#
|
|
77
|
+
# @example
|
|
78
|
+
# future = Garcon::Future.execute{ sleep(1); 42 }
|
|
79
|
+
# future.state #=> :pending
|
|
80
|
+
#
|
|
81
|
+
# @yield the asynchronous operation to perform.
|
|
82
|
+
#
|
|
83
|
+
# @!macro executor_and_deref_options.
|
|
84
|
+
#
|
|
85
|
+
# @option opts [object, Array] :args
|
|
86
|
+
# Zero or more arguments to be passed the task block on execution.
|
|
87
|
+
#
|
|
88
|
+
# @raise [ArgumentError] if no block is given.
|
|
89
|
+
#
|
|
90
|
+
# @return [Future]
|
|
91
|
+
# The newly created `Future` in the `:pending` state.
|
|
92
|
+
#
|
|
93
|
+
def self.execute(opts = {}, &block)
|
|
94
|
+
Future.new(opts, &block).execute
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
protected :set, :fail, :complete
|
|
98
|
+
|
|
99
|
+
private # P R O P R I E T À P R I V A T A Vietato L'accesso
|
|
100
|
+
|
|
101
|
+
# @!visibility private
|
|
102
|
+
def work
|
|
103
|
+
success, val, reason = SafeTaskExecutor.new(@task).execute(*@args)
|
|
104
|
+
complete(success, val, reason)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require_relative 'event'
|
|
21
|
+
require_relative 'executor'
|
|
22
|
+
|
|
23
|
+
module Garcon
|
|
24
|
+
|
|
25
|
+
# An executor service which runs all operations on the current thread,
|
|
26
|
+
# blocking as necessary. Operations are performed in the order they are
|
|
27
|
+
# received and no two operations can be performed simultaneously.
|
|
28
|
+
#
|
|
29
|
+
# This executor service exists mainly for testing an debugging. When used
|
|
30
|
+
# it immediately runs every `#post` operation on the current thread, blocking
|
|
31
|
+
# that thread until the operation is complete. This can be very beneficial
|
|
32
|
+
# during testing because it makes all operations deterministic.
|
|
33
|
+
#
|
|
34
|
+
# @note Intended for use primarily in testing and debugging.
|
|
35
|
+
class ImmediateExecutor
|
|
36
|
+
include SerialExecutor
|
|
37
|
+
|
|
38
|
+
# Creates a new executor
|
|
39
|
+
def initialize
|
|
40
|
+
@stopped = Garcon::Event.new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @!macro executor_method_post
|
|
44
|
+
def post(*args, &task)
|
|
45
|
+
raise ArgumentError, 'no block given' unless block_given?
|
|
46
|
+
return false unless running?
|
|
47
|
+
task.call(*args)
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @!macro executor_method_left_shift
|
|
52
|
+
def <<(task)
|
|
53
|
+
post(&task)
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @!macro executor_method_running_question
|
|
58
|
+
def running?
|
|
59
|
+
! shutdown?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @!macro executor_method_shuttingdown_question
|
|
63
|
+
def shuttingdown?
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @!macro executor_method_shutdown_question
|
|
68
|
+
def shutdown?
|
|
69
|
+
@stopped.set?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @!macro executor_method_shutdown
|
|
73
|
+
def shutdown
|
|
74
|
+
@stopped.set
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
alias_method :kill, :shutdown
|
|
78
|
+
|
|
79
|
+
# @!macro executor_method_wait_for_termination
|
|
80
|
+
def wait_for_termination(timeout = nil)
|
|
81
|
+
@stopped.wait(timeout)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require 'thread'
|
|
21
|
+
|
|
22
|
+
require_relative '../exceptions'
|
|
23
|
+
require_relative 'obligation'
|
|
24
|
+
require_relative 'observable'
|
|
25
|
+
|
|
26
|
+
module Garcon
|
|
27
|
+
|
|
28
|
+
# An `IVar` is like a future that you can assign. As a future is a value that
|
|
29
|
+
# is being computed that you can wait on, an `IVar` is a value that is waiting
|
|
30
|
+
# to be assigned, that you can wait on. `IVars` are single assignment and
|
|
31
|
+
# deterministic.
|
|
32
|
+
#
|
|
33
|
+
# Then, express futures as an asynchronous computation that assigns an `IVar`.
|
|
34
|
+
# The `IVar` becomes the primitive on which [futures](Future) and
|
|
35
|
+
# [dataflow](Dataflow) are built.
|
|
36
|
+
#
|
|
37
|
+
# An `IVar` is a single-element container that is normally created empty, and
|
|
38
|
+
# can only be set once. The I in `IVar` stands for immutable. Reading an
|
|
39
|
+
# `IVar` normally blocks until it is set. It is safe to set and read an `IVar`
|
|
40
|
+
# from different threads.
|
|
41
|
+
#
|
|
42
|
+
# If you want to have some parallel task set the value in an `IVar`, you want
|
|
43
|
+
# a `Future`. If you want to create a graph of parallel tasks all executed
|
|
44
|
+
# when the values they depend on are ready you want `dataflow`. `IVar` is
|
|
45
|
+
# generally a low-level primitive.
|
|
46
|
+
#
|
|
47
|
+
# @example Create, set and get an `IVar`
|
|
48
|
+
# ivar = Garcon::IVar.new
|
|
49
|
+
# ivar.set 14
|
|
50
|
+
# ivar.get #=> 14
|
|
51
|
+
# ivar.set 2 # would now be an error
|
|
52
|
+
#
|
|
53
|
+
class IVar
|
|
54
|
+
include Obligation
|
|
55
|
+
include Observable
|
|
56
|
+
|
|
57
|
+
# @!visibility private
|
|
58
|
+
NO_VALUE = Object.new
|
|
59
|
+
|
|
60
|
+
# Create a new `IVar` in the `:pending` state with the (optional) initial
|
|
61
|
+
# value.
|
|
62
|
+
#
|
|
63
|
+
# @param [Object] value
|
|
64
|
+
# The initial value.
|
|
65
|
+
#
|
|
66
|
+
# @param [Hash] opts the options to create a message with.
|
|
67
|
+
#
|
|
68
|
+
# @option opts [String] :dup_on_deref (false)
|
|
69
|
+
# Call `#dup` before returning the data.
|
|
70
|
+
#
|
|
71
|
+
# @option opts [String] :freeze_on_deref (false)
|
|
72
|
+
# Call `#freeze` before returning the data.
|
|
73
|
+
#
|
|
74
|
+
# @option opts [String] :copy_on_deref (nil)
|
|
75
|
+
# Cll the given `Proc` passing the internal value and returning the value
|
|
76
|
+
# returned from the proc.
|
|
77
|
+
#
|
|
78
|
+
def initialize(value = NO_VALUE, opts = {})
|
|
79
|
+
init_obligation
|
|
80
|
+
self.observers = CopyOnWriteObserverSet.new
|
|
81
|
+
set_deref_options(opts)
|
|
82
|
+
|
|
83
|
+
if value == NO_VALUE
|
|
84
|
+
@state = :pending
|
|
85
|
+
else
|
|
86
|
+
set(value)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Add an observer on this object that will receive notification on update.
|
|
91
|
+
#
|
|
92
|
+
# Upon completion the `IVar` will notify all observers in a thread-safe way.
|
|
93
|
+
# The `func` method of the observer will be called with three arguments: the
|
|
94
|
+
# `Time` at which the `Future` completed the asynchronous operation, the
|
|
95
|
+
# final `value` (or `nil` on rejection), and the final `reason` (or `nil` on
|
|
96
|
+
# fulfillment).
|
|
97
|
+
#
|
|
98
|
+
# @param [Object] observer
|
|
99
|
+
# The object that will be notified of changes.
|
|
100
|
+
#
|
|
101
|
+
# @param [Symbol] func
|
|
102
|
+
# Symbol naming the method to call when the `Observable` has changes`
|
|
103
|
+
#
|
|
104
|
+
def add_observer(bsrver = nil, func = :update, &block)
|
|
105
|
+
if observer && block
|
|
106
|
+
raise ArgumentError, 'cannot provide both an observer and a block'
|
|
107
|
+
end
|
|
108
|
+
direct_notification = false
|
|
109
|
+
|
|
110
|
+
if block
|
|
111
|
+
observer = block
|
|
112
|
+
func = :call
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
mutex.synchronize do
|
|
116
|
+
if event.set?
|
|
117
|
+
direct_notification = true
|
|
118
|
+
else
|
|
119
|
+
observers.add_observer(observer, func)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
observer.send(func, Time.now, self.value, reason) if direct_notification
|
|
124
|
+
observer
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Set the `IVar` to a value and wake or notify all threads waiting on it.
|
|
128
|
+
#
|
|
129
|
+
# @param [Object] value
|
|
130
|
+
# The value to store in the `IVar`.
|
|
131
|
+
#
|
|
132
|
+
# @raise [Garcon::MultipleAssignmentError]
|
|
133
|
+
# If the `IVar` has already been set or otherwise completed.
|
|
134
|
+
#
|
|
135
|
+
# @return [IVar] self
|
|
136
|
+
#
|
|
137
|
+
def set(value)
|
|
138
|
+
complete(true, value, nil)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Set the `IVar` to failed due to some error and wake or notify all threads
|
|
142
|
+
# waiting on it.
|
|
143
|
+
#
|
|
144
|
+
# @param [Object] reason
|
|
145
|
+
# For the failure.
|
|
146
|
+
#
|
|
147
|
+
# @raise [Garcon::MultipleAssignmentError]
|
|
148
|
+
# If the `IVar` has already been set or otherwise completed.
|
|
149
|
+
#
|
|
150
|
+
# @return [IVar] self
|
|
151
|
+
#
|
|
152
|
+
def fail(reason = StandardError.new)
|
|
153
|
+
complete(false, nil, reason)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @!visibility private
|
|
157
|
+
def complete(success, value, reason)
|
|
158
|
+
mutex.synchronize do
|
|
159
|
+
if [:fulfilled, :rejected].include? @state
|
|
160
|
+
raise MultipleAssignmentError, 'multiple assignment'
|
|
161
|
+
end
|
|
162
|
+
set_state(success, value, reason)
|
|
163
|
+
event.set
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
time = Time.now
|
|
167
|
+
observers.notify_and_delete_observers{ [time, self.value, reason] }
|
|
168
|
+
self
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
module Garcon
|
|
21
|
+
|
|
22
|
+
# Lazy evaluation of a block yielding an immutable result. Useful for
|
|
23
|
+
# expensive operations that may never be needed. `LazyReference` is a simpler,
|
|
24
|
+
# blocking version of `Delay` and has an API similar to `AtomicReference`.
|
|
25
|
+
# The first time `#value` is called the caller will block until the
|
|
26
|
+
# block given at construction is executed. Once the result has been
|
|
27
|
+
# computed the value will be immutably set. Any exceptions thrown during
|
|
28
|
+
# computation will be suppressed.
|
|
29
|
+
#
|
|
30
|
+
class LazyReference
|
|
31
|
+
|
|
32
|
+
# Creates a new unfulfilled object.
|
|
33
|
+
#
|
|
34
|
+
# @yield the delayed operation to perform
|
|
35
|
+
#
|
|
36
|
+
# @param [Object] default
|
|
37
|
+
# The default value for the object when the block raises an exception.
|
|
38
|
+
#
|
|
39
|
+
# @raise [ArgumentError] if no block is given
|
|
40
|
+
#
|
|
41
|
+
def initialize(default = nil, &block)
|
|
42
|
+
raise ArgumentError, 'no block given' unless block_given?
|
|
43
|
+
@default = default
|
|
44
|
+
@task = block
|
|
45
|
+
@mutex = Mutex.new
|
|
46
|
+
@value = nil
|
|
47
|
+
@fulfilled = false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The calculated value of the object or the default value if one was given
|
|
51
|
+
# at construction. This first time this method is called it will block
|
|
52
|
+
# indefinitely while the block is processed. Subsequent calls will not
|
|
53
|
+
# block.
|
|
54
|
+
#
|
|
55
|
+
# @return [Object] the calculated value
|
|
56
|
+
#
|
|
57
|
+
def value
|
|
58
|
+
return @value if @fulfilled
|
|
59
|
+
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
unless @fulfilled
|
|
62
|
+
begin
|
|
63
|
+
@value = @task.call
|
|
64
|
+
rescue
|
|
65
|
+
@value = @default
|
|
66
|
+
ensure
|
|
67
|
+
@fulfilled = true
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
return @value
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
module Garcon
|
|
21
|
+
|
|
22
|
+
# Clock that cannot be set and represents monotonic time since
|
|
23
|
+
# some unspecified starting point.
|
|
24
|
+
# @!visibility private
|
|
25
|
+
GLOBAL_MONOTONIC_CLOCK = Class.new {
|
|
26
|
+
|
|
27
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
|
28
|
+
# @!visibility private
|
|
29
|
+
def get_time
|
|
30
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
|
|
34
|
+
require 'thread'
|
|
35
|
+
|
|
36
|
+
# @!visibility private
|
|
37
|
+
def initialize
|
|
38
|
+
@mutex = Mutex.new
|
|
39
|
+
@last_time = Time.now.to_f
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @!visibility private
|
|
43
|
+
def get_time
|
|
44
|
+
@mutex.synchronize do
|
|
45
|
+
now = Time.now.to_f
|
|
46
|
+
if @last_time < now
|
|
47
|
+
@last_time = now
|
|
48
|
+
else # clock has moved back in time
|
|
49
|
+
@last_time += 0.000_001
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
}.new
|
|
55
|
+
private_constant :GLOBAL_MONOTONIC_CLOCK
|
|
56
|
+
|
|
57
|
+
# @!macro [attach] monotonic_get_time
|
|
58
|
+
#
|
|
59
|
+
# Returns the current time a tracked by the application monotonic clock.
|
|
60
|
+
#
|
|
61
|
+
# @return [Float] The current monotonic time when `since` not given else
|
|
62
|
+
# the elapsed monotonic time between `since` and the current time
|
|
63
|
+
#
|
|
64
|
+
# @!macro monotonic_clock_warning
|
|
65
|
+
def monotonic_time
|
|
66
|
+
GLOBAL_MONOTONIC_CLOCK.get_time
|
|
67
|
+
end
|
|
68
|
+
module_function :monotonic_time
|
|
69
|
+
end
|