hoodie 0.5.5 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +19 -0
- data/Rakefile +8 -23
- data/hoodie.gemspec +0 -23
- data/lib/hoodie.rb +40 -48
- data/lib/hoodie/configuration.rb +39 -2
- data/lib/hoodie/core_ext/blank.rb +6 -6
- data/lib/hoodie/core_ext/hash.rb +108 -13
- data/lib/hoodie/core_ext/string.rb +5 -3
- data/lib/hoodie/core_ext/try.rb +4 -3
- data/lib/hoodie/inflections.rb +18 -0
- data/lib/hoodie/inflections/defaults.rb +17 -0
- data/lib/hoodie/inflections/inflections.rb +17 -0
- data/lib/hoodie/inflections/rules_collection.rb +17 -0
- data/lib/hoodie/logging.rb +22 -4
- data/lib/hoodie/stash.rb +83 -80
- data/lib/hoodie/stash/disk_store.rb +142 -118
- data/lib/hoodie/stash/mem_store.rb +10 -9
- data/lib/hoodie/stash/memoizable.rb +46 -0
- data/lib/hoodie/utils.rb +13 -183
- data/lib/hoodie/utils/ansi.rb +199 -0
- data/lib/hoodie/utils/crypto.rb +288 -0
- data/lib/hoodie/utils/equalizer.rb +146 -0
- data/lib/hoodie/utils/file_helper.rb +225 -0
- data/lib/hoodie/utils/konstruktor.rb +77 -0
- data/lib/hoodie/utils/machine.rb +83 -0
- data/lib/hoodie/utils/os.rb +56 -0
- data/lib/hoodie/utils/retry.rb +235 -0
- data/lib/hoodie/utils/timeout.rb +54 -0
- data/lib/hoodie/utils/url_helper.rb +104 -0
- data/lib/hoodie/version.rb +4 -4
- metadata +13 -234
- data/lib/hoodie/identity_map.rb +0 -96
- data/lib/hoodie/memoizable.rb +0 -43
- data/lib/hoodie/obfuscate.rb +0 -121
- data/lib/hoodie/observable.rb +0 -309
- data/lib/hoodie/os.rb +0 -43
- data/lib/hoodie/proxy.rb +0 -68
- data/lib/hoodie/rash.rb +0 -125
- data/lib/hoodie/timers.rb +0 -355
data/lib/hoodie/identity_map.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
-
#
|
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
|
16
|
-
# implied. See the License for the specific language governing
|
17
|
-
# permissions and limitations under the License.
|
18
|
-
#
|
19
|
-
|
20
|
-
module Hoodie
|
21
|
-
module IdentityMap
|
22
|
-
def self.enabled=(flag)
|
23
|
-
Thread.current[:identity_map_enabled] = flag
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.enabled
|
27
|
-
Thread.current[:identity_map_enabled]
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.enabled?
|
31
|
-
enabled == true
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.repository
|
35
|
-
Thread.current[:identity_map] ||= {}
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.clear
|
39
|
-
repository.clear
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.include?(object)
|
43
|
-
repository.keys.include?(object.id)
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.use
|
47
|
-
old, self.enabled = enabled, true
|
48
|
-
yield if block_given?
|
49
|
-
ensure
|
50
|
-
self.enabled = old
|
51
|
-
clear
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.without
|
55
|
-
old, self.enabled = enabled, false
|
56
|
-
yield if block_given?
|
57
|
-
ensure
|
58
|
-
self.enabled = old
|
59
|
-
end
|
60
|
-
|
61
|
-
module ClassMethods
|
62
|
-
def get(id, options = nil)
|
63
|
-
get_from_identity_map(id) || super
|
64
|
-
end
|
65
|
-
|
66
|
-
def get_from_identity_map(id)
|
67
|
-
IdentityMap.repository[id] if IdentityMap.enabled?
|
68
|
-
end
|
69
|
-
private :get_from_identity_map
|
70
|
-
|
71
|
-
def load(id, attrs)
|
72
|
-
if IdentityMap.enabled? && instance = IdentityMap.repository[id]
|
73
|
-
instance
|
74
|
-
else
|
75
|
-
super.tap { |doc| doc.add_to_identity_map }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def save(options={})
|
81
|
-
super.tap { |result| add_to_identity_map if result }
|
82
|
-
end
|
83
|
-
|
84
|
-
def delete
|
85
|
-
super.tap { remove_from_identity_map }
|
86
|
-
end
|
87
|
-
|
88
|
-
def add_to_identity_map
|
89
|
-
IdentityMap.repository[id] = self if IdentityMap.enabled?
|
90
|
-
end
|
91
|
-
|
92
|
-
def remove_from_identity_map
|
93
|
-
IdentityMap.repository.delete(id) if IdentityMap.enabled?
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
data/lib/hoodie/memoizable.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
-
#
|
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 'hoodie/stash' unless defined?(Stash)
|
21
|
-
|
22
|
-
# Memoization is an optimization that saves the return value of a
|
23
|
-
# method so it doesn't need to be re-computed every time that method
|
24
|
-
# is called.
|
25
|
-
module Memoizable
|
26
|
-
# Create a new memoized method. To use, extend class with Memoizable,
|
27
|
-
# then, in initialize, call memoize
|
28
|
-
#
|
29
|
-
# @return [undefined]
|
30
|
-
#
|
31
|
-
def memoize(methods, cache = nil)
|
32
|
-
cache ||= Stash.new
|
33
|
-
methods.each do |name|
|
34
|
-
uncached_name = "#{name}_uncached".to_sym
|
35
|
-
singleton_class.class_eval do
|
36
|
-
alias_method uncached_name, name
|
37
|
-
define_method(name) do |*a, &b|
|
38
|
-
cache.cache(name) { send uncached_name, *a, &b }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/hoodie/obfuscate.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
-
#
|
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 Hoodie
|
21
|
-
begin
|
22
|
-
require 'openssl'
|
23
|
-
INCOMPREHENSIBLE_ERROR = nil
|
24
|
-
rescue LoadError => err
|
25
|
-
raise unless err.to_s.include?('openssl')
|
26
|
-
warn 'Oea pieoYreb h wYoerh dl hwsnhoib r Lrbea tbte wbnaetvoouahe h rbe.'
|
27
|
-
warn "olorbvtelYShnSben irrSwoet eto eihSrLoS'do n See wLiape."
|
28
|
-
INCOMPREHENSIBLE_ERROR = err
|
29
|
-
end
|
30
|
-
|
31
|
-
require 'digest/sha2'
|
32
|
-
require 'base64'
|
33
|
-
|
34
|
-
# Befuddle and enlighten values in StashCache::Store
|
35
|
-
#
|
36
|
-
module Obfuscate
|
37
|
-
ESOTERIC_TYPE = 'aes-256-cbc' unless defined?(ESOTERIC_TYPE)
|
38
|
-
|
39
|
-
def self.check_platform_can_discombobulate!
|
40
|
-
return true unless INCOMPREHENSIBLE_ERROR
|
41
|
-
fail INCOMPREHENSIBLE_ERROR.class, "b0rked! #{INCOMPREHENSIBLE_ERROR}"
|
42
|
-
end
|
43
|
-
|
44
|
-
# Befuddle the given string
|
45
|
-
#
|
46
|
-
# @param plaintext the text to befuddle
|
47
|
-
# @param [String] befuddle_pass secret passphrase to befuddle with
|
48
|
-
#
|
49
|
-
# @return [String] befuddleed text, suitable for deciphering with
|
50
|
-
# Obfuscate#enlighten (decrypt)
|
51
|
-
#
|
52
|
-
def self.befuddle(plaintext, befuddle_pass, options = {})
|
53
|
-
cipher = new_cipher :befuddle, befuddle_pass, options
|
54
|
-
cipher.iv = iv = cipher.random_iv
|
55
|
-
ciphertext = cipher.update(plaintext)
|
56
|
-
ciphertext << cipher.final
|
57
|
-
Base64.encode64(combine_iv_and_ciphertext(iv, ciphertext))
|
58
|
-
end
|
59
|
-
|
60
|
-
# Enlighten the given string, using the key and id supplied
|
61
|
-
#
|
62
|
-
# @param ciphertext the text to enlighten, probably produced with
|
63
|
-
# Obfuscate#befuddle (encrypt)
|
64
|
-
# @param [String] befuddle_pass secret sauce to enlighten with
|
65
|
-
#
|
66
|
-
# @return [String] the enlightened plaintext
|
67
|
-
#
|
68
|
-
def self.enlighten(enc_ciphertext, befuddle_pass, options = {})
|
69
|
-
iv_and_ciphertext = Base64.decode64(enc_ciphertext)
|
70
|
-
cipher = new_cipher :enlighten, befuddle_pass, options
|
71
|
-
cipher.iv, ciphertext = separate_iv_and_ciphertext(cipher, iv_and_ciphertext)
|
72
|
-
plaintext = cipher.update(ciphertext)
|
73
|
-
plaintext << cipher.final
|
74
|
-
plaintext
|
75
|
-
end
|
76
|
-
|
77
|
-
protected # A T T E N Z I O N E A R E A P R O T E T T A
|
78
|
-
|
79
|
-
# Cipher create machine do, befuddle engage, enlighten. Dials set
|
80
|
-
# direction to infinity
|
81
|
-
#
|
82
|
-
# @param [:befuddle, :enlighten] to befuddle or enlighten
|
83
|
-
# @param [String] befuddle_pass secret sauce to enlighten with
|
84
|
-
#
|
85
|
-
def self.new_cipher(direction, befuddle_pass, options = {})
|
86
|
-
check_platform_can_discombobulate!
|
87
|
-
cipher = OpenSSL::Cipher::Cipher.new(ESOTERIC_TYPE)
|
88
|
-
case direction
|
89
|
-
when :befuddle
|
90
|
-
cipher.encrypt
|
91
|
-
when :enlighten
|
92
|
-
cipher.decrypt
|
93
|
-
else fail "Bad cipher direction #{direction}"
|
94
|
-
end
|
95
|
-
cipher.key = befuddle_key(befuddle_pass, options)
|
96
|
-
cipher
|
97
|
-
end
|
98
|
-
|
99
|
-
# vector inspect encoder serialize prepend initialization message
|
100
|
-
def self.combine_iv_and_ciphertext(iv, message)
|
101
|
-
message.force_encoding('BINARY') if message.respond_to?(:force_encoding)
|
102
|
-
iv.force_encoding('BINARY') if iv.respond_to?(:force_encoding)
|
103
|
-
iv + message
|
104
|
-
end
|
105
|
-
|
106
|
-
# front vector initialization, encoded pull message
|
107
|
-
def self.separate_iv_and_ciphertext(cipher, iv_and_ciphertext)
|
108
|
-
idx = cipher.iv_len
|
109
|
-
[iv_and_ciphertext[0..(idx - 1)], iv_and_ciphertext[idx..-1]]
|
110
|
-
end
|
111
|
-
|
112
|
-
# Convert the befuddle_pass passphrase into the key used for
|
113
|
-
# befuddletion
|
114
|
-
def self.befuddle_key(befuddle_pass, _options = {})
|
115
|
-
befuddle_pass = befuddle_pass.to_s
|
116
|
-
fail 'Missing befuddled password!' if befuddle_pass.empty?
|
117
|
-
# 256 beers on the wall, keys for cipher required of aes cbc
|
118
|
-
Digest::SHA256.digest(befuddle_pass)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
data/lib/hoodie/observable.rb
DELETED
@@ -1,309 +0,0 @@
|
|
1
|
-
|
2
|
-
module Garcon
|
3
|
-
module Observable
|
4
|
-
|
5
|
-
# @return [Object] the added observer
|
6
|
-
#
|
7
|
-
def add_observer(*args, &block)
|
8
|
-
observers.add_observer(*args, &block)
|
9
|
-
end
|
10
|
-
|
11
|
-
# as #add_observer but it can be used for chaining
|
12
|
-
#
|
13
|
-
# @return [Observable] self
|
14
|
-
#
|
15
|
-
def with_observer(*args, &block)
|
16
|
-
add_observer(*args, &block)
|
17
|
-
self
|
18
|
-
end
|
19
|
-
|
20
|
-
# @return [Object] the deleted observer
|
21
|
-
#
|
22
|
-
def delete_observer(*args)
|
23
|
-
observers.delete_observer(*args)
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [Observable] self
|
27
|
-
#
|
28
|
-
def delete_observers
|
29
|
-
observers.delete_observers
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [Integer] the observers count
|
34
|
-
#
|
35
|
-
def count_observers
|
36
|
-
observers.count_observers
|
37
|
-
end
|
38
|
-
|
39
|
-
protected # A T T E N Z I O N E A R E A P R O T E T T A
|
40
|
-
|
41
|
-
attr_accessor :observers
|
42
|
-
end
|
43
|
-
|
44
|
-
# A thread safe observer set implemented using copy-on-read approach.
|
45
|
-
# Observers are added and removed from a thread safe collection; every time
|
46
|
-
# a notification is required the internal data structure is copied to
|
47
|
-
# prevent concurrency issues
|
48
|
-
#
|
49
|
-
class CopyOnNotifyObserverSet
|
50
|
-
|
51
|
-
def initialize
|
52
|
-
@mutex = Mutex.new
|
53
|
-
@observers = {}
|
54
|
-
end
|
55
|
-
|
56
|
-
# Adds an observer to this set, if a block is passed, the observer will be
|
57
|
-
# created by this method and no other params should be passed.
|
58
|
-
#
|
59
|
-
# @param [Object] observer
|
60
|
-
# the observer to add
|
61
|
-
# @param [Symbol] func
|
62
|
-
# the function to call on the observer during notification.
|
63
|
-
# Default is :update
|
64
|
-
#
|
65
|
-
# @return [Object]
|
66
|
-
# the added observer
|
67
|
-
#
|
68
|
-
def add_observer(observer = nil, func = :update, &block)
|
69
|
-
if observer.nil? && block.nil?
|
70
|
-
raise ArgumentError, 'should pass observer as a first argument or block'
|
71
|
-
elsif observer && block
|
72
|
-
raise ArgumentError, 'cannot provide both an observer and a block'
|
73
|
-
end
|
74
|
-
|
75
|
-
if block
|
76
|
-
observer = block
|
77
|
-
func = :call
|
78
|
-
end
|
79
|
-
|
80
|
-
begin
|
81
|
-
@mutex.lock
|
82
|
-
@observers[observer] = func
|
83
|
-
ensure
|
84
|
-
@mutex.unlock
|
85
|
-
end
|
86
|
-
observer
|
87
|
-
end
|
88
|
-
|
89
|
-
# @param [Object] observer the observer to remove
|
90
|
-
#
|
91
|
-
# @return [Object] the deleted observer
|
92
|
-
#
|
93
|
-
def delete_observer(observer)
|
94
|
-
@mutex.lock
|
95
|
-
@observers.delete(observer)
|
96
|
-
@mutex.unlock
|
97
|
-
observer
|
98
|
-
end
|
99
|
-
|
100
|
-
# Deletes all observers
|
101
|
-
#
|
102
|
-
# @return [CopyOnWriteObserverSet] self
|
103
|
-
#
|
104
|
-
def delete_observers
|
105
|
-
@mutex.lock
|
106
|
-
@observers.clear
|
107
|
-
@mutex.unlock
|
108
|
-
self
|
109
|
-
end
|
110
|
-
|
111
|
-
# @return [Integer] the observers count
|
112
|
-
#
|
113
|
-
def count_observers
|
114
|
-
@mutex.lock
|
115
|
-
result = @observers.count
|
116
|
-
@mutex.unlock
|
117
|
-
result
|
118
|
-
end
|
119
|
-
|
120
|
-
# Notifies all registered observers with optional args.
|
121
|
-
#
|
122
|
-
# @param [Object] args
|
123
|
-
# arguments to be passed to each observer
|
124
|
-
#
|
125
|
-
# @return [CopyOnWriteObserverSet] self
|
126
|
-
#
|
127
|
-
def notify_observers(*args, &block)
|
128
|
-
observers = duplicate_observers
|
129
|
-
notify_to(observers, *args, &block)
|
130
|
-
self
|
131
|
-
end
|
132
|
-
|
133
|
-
# Notifies all registered observers with optional args and deletes them.
|
134
|
-
#
|
135
|
-
# @param [Object] args
|
136
|
-
# arguments to be passed to each observer
|
137
|
-
#
|
138
|
-
# @return [CopyOnWriteObserverSet] self
|
139
|
-
#
|
140
|
-
def notify_and_delete_observers(*args, &block)
|
141
|
-
observers = duplicate_and_clear_observers
|
142
|
-
notify_to(observers, *args, &block)
|
143
|
-
self
|
144
|
-
end
|
145
|
-
|
146
|
-
private # P R O P R I E T À P R I V A T A Vietato L'accesso
|
147
|
-
|
148
|
-
def duplicate_and_clear_observers
|
149
|
-
@mutex.lock
|
150
|
-
observers = @observers.dup
|
151
|
-
@observers.clear
|
152
|
-
@mutex.unlock
|
153
|
-
observers
|
154
|
-
end
|
155
|
-
|
156
|
-
def duplicate_observers
|
157
|
-
@mutex.lock
|
158
|
-
observers = @observers.dup
|
159
|
-
@mutex.unlock
|
160
|
-
observers
|
161
|
-
end
|
162
|
-
|
163
|
-
def notify_to(observers, *args)
|
164
|
-
if block_given? && !args.empty?
|
165
|
-
raise ArgumentError, 'cannot give arguments and a block'
|
166
|
-
end
|
167
|
-
observers.each do |observer, function|
|
168
|
-
args = yield if block_given?
|
169
|
-
observer.send(function, *args)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# A thread safe observer set implemented using copy-on-write approach. Every
|
175
|
-
# time an observer is added or removed the whole internal data structure is
|
176
|
-
# duplicated and replaced with a new one.
|
177
|
-
#
|
178
|
-
class CopyOnWriteObserverSet
|
179
|
-
|
180
|
-
def initialize
|
181
|
-
@mutex = Mutex.new
|
182
|
-
@observers = {}
|
183
|
-
end
|
184
|
-
|
185
|
-
# Adds an observer to this set, if a block is passed, the observer will be
|
186
|
-
# created by this method and no other params should be passed.
|
187
|
-
#
|
188
|
-
# @param [Object] observer
|
189
|
-
# the observer to add
|
190
|
-
# @param [Symbol] func
|
191
|
-
# the function to call on the observer during notification
|
192
|
-
# Default is :update
|
193
|
-
# @return [Object]
|
194
|
-
# the added observer
|
195
|
-
#
|
196
|
-
def add_observer(observer = nil, func = :update, &block)
|
197
|
-
if observer.nil? && block.nil?
|
198
|
-
raise ArgumentError, 'should pass observer as a first argument or block'
|
199
|
-
elsif observer && block
|
200
|
-
raise ArgumentError, 'cannot provide both an observer and a block'
|
201
|
-
end
|
202
|
-
|
203
|
-
if block
|
204
|
-
observer = block
|
205
|
-
func = :call
|
206
|
-
end
|
207
|
-
|
208
|
-
begin
|
209
|
-
@mutex.lock
|
210
|
-
new_observers = @observers.dup
|
211
|
-
new_observers[observer] = func
|
212
|
-
@observers = new_observers
|
213
|
-
observer
|
214
|
-
ensure
|
215
|
-
@mutex.unlock
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# @param [Object] observer the observer to remove
|
220
|
-
#
|
221
|
-
# @return [Object] the deleted observer
|
222
|
-
#
|
223
|
-
def delete_observer(observer)
|
224
|
-
@mutex.lock
|
225
|
-
new_observers = @observers.dup
|
226
|
-
new_observers.delete(observer)
|
227
|
-
@observers = new_observers
|
228
|
-
observer
|
229
|
-
ensure
|
230
|
-
@mutex.unlock
|
231
|
-
end
|
232
|
-
|
233
|
-
# Deletes all observers
|
234
|
-
#
|
235
|
-
# @return [CopyOnWriteObserverSet] self
|
236
|
-
#
|
237
|
-
def delete_observers
|
238
|
-
self.observers = {}
|
239
|
-
self
|
240
|
-
end
|
241
|
-
|
242
|
-
|
243
|
-
# @return [Integer] the observers count
|
244
|
-
#
|
245
|
-
def count_observers
|
246
|
-
observers.count
|
247
|
-
end
|
248
|
-
|
249
|
-
# Notifies all registered observers with optional args.
|
250
|
-
#
|
251
|
-
# @param [Object] args
|
252
|
-
# arguments to be passed to each observer
|
253
|
-
#
|
254
|
-
# @return [CopyOnWriteObserverSet] self
|
255
|
-
#
|
256
|
-
def notify_observers(*args, &block)
|
257
|
-
notify_to(observers, *args, &block)
|
258
|
-
self
|
259
|
-
end
|
260
|
-
|
261
|
-
# Notifies all registered observers with optional args and deletes them.
|
262
|
-
#
|
263
|
-
# @param [Object] args
|
264
|
-
# arguments to be passed to each observer
|
265
|
-
#
|
266
|
-
# @return [CopyOnWriteObserverSet] self
|
267
|
-
#
|
268
|
-
def notify_and_delete_observers(*args, &block)
|
269
|
-
old = clear_observers_and_return_old
|
270
|
-
notify_to(old, *args, &block)
|
271
|
-
self
|
272
|
-
end
|
273
|
-
|
274
|
-
private # P R O P R I E T À P R I V A T A Vietato L'accesso
|
275
|
-
|
276
|
-
def notify_to(observers, *args)
|
277
|
-
if block_given? && !args.empty?
|
278
|
-
raise ArgumentError, 'cannot give arguments and a block'
|
279
|
-
end
|
280
|
-
observers.each do |observer, function|
|
281
|
-
args = yield if block_given?
|
282
|
-
observer.send(function, *args)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
def observers
|
287
|
-
@mutex.lock
|
288
|
-
@observers
|
289
|
-
ensure
|
290
|
-
@mutex.unlock
|
291
|
-
end
|
292
|
-
|
293
|
-
def observers=(new_set)
|
294
|
-
@mutex.lock
|
295
|
-
@observers = new_set
|
296
|
-
ensure
|
297
|
-
@mutex.unlock
|
298
|
-
end
|
299
|
-
|
300
|
-
def clear_observers_and_return_old
|
301
|
-
@mutex.lock
|
302
|
-
old_observers = @observers
|
303
|
-
@observers = {}
|
304
|
-
old_observers
|
305
|
-
ensure
|
306
|
-
@mutex.unlock
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|