rubysl-monitor 1.0.0
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/.gitignore +17 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/monitor.rb +1 -0
- data/lib/rubysl/monitor.rb +2 -0
- data/lib/rubysl/monitor/monitor.rb +341 -0
- data/lib/rubysl/monitor/version.rb +5 -0
- data/rubysl-monitor.gemspec +22 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0611fdd2b6a1443e13577664e38ea505b906bfab
|
4
|
+
data.tar.gz: fcf2eaf0f16be03c284b10166cc33c658922d93e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 942b331aab1098f3a7de9f8e3295bbec7e550507473f941861e37766ae2a699a428e25011a7aef8e51e52db7653a5d0bd9382315e1ec9e279990f8d93233e910
|
7
|
+
data.tar.gz: ad8e8567390e5a64d68ddeeeccad617e77a66cd540f13d33eb9a3aad4546da8d60aa2f5946bcd9b56e3c9d2fe2ec92db5185b8bb41ed1be632584123f6e226a9
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2013, Brian Shirai
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
3. Neither the name of the library nor the names of its contributors may be
|
13
|
+
used to endorse or promote products derived from this software without
|
14
|
+
specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
|
20
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
21
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
22
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
23
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
24
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
25
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rubysl::Monitor
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rubysl-monitor'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rubysl-monitor
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/monitor.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "rubysl/monitor"
|
@@ -0,0 +1,341 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= monitor.rb
|
4
|
+
|
5
|
+
Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
|
6
|
+
Copyright (C) 2008 MenTaLguY <mental@rydia.net>
|
7
|
+
|
8
|
+
This library is distributed under the terms of the Ruby license.
|
9
|
+
You can freely distribute/modify this library.
|
10
|
+
|
11
|
+
== example
|
12
|
+
|
13
|
+
This is a simple example.
|
14
|
+
|
15
|
+
require 'monitor.rb'
|
16
|
+
|
17
|
+
buf = []
|
18
|
+
buf.extend(MonitorMixin)
|
19
|
+
empty_cond = buf.new_cond
|
20
|
+
|
21
|
+
# consumer
|
22
|
+
Thread.start do
|
23
|
+
loop do
|
24
|
+
buf.synchronize do
|
25
|
+
empty_cond.wait_while { buf.empty? }
|
26
|
+
print buf.shift
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# producer
|
32
|
+
while line = ARGF.gets
|
33
|
+
buf.synchronize do
|
34
|
+
buf.push(line)
|
35
|
+
empty_cond.signal
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
The consumer thread waits for the producer thread to push a line
|
40
|
+
to buf while buf.empty?, and the producer thread (main thread)
|
41
|
+
reads a line from ARGF and push it to buf, then call
|
42
|
+
empty_cond.signal.
|
43
|
+
|
44
|
+
=end
|
45
|
+
|
46
|
+
require 'thread'
|
47
|
+
|
48
|
+
#
|
49
|
+
# Adds monitor functionality to an arbitrary object by mixing the module with
|
50
|
+
# +include+. For example:
|
51
|
+
#
|
52
|
+
# require 'monitor.rb'
|
53
|
+
#
|
54
|
+
# buf = []
|
55
|
+
# buf.extend(MonitorMixin)
|
56
|
+
# empty_cond = buf.new_cond
|
57
|
+
#
|
58
|
+
# # consumer
|
59
|
+
# Thread.start do
|
60
|
+
# loop do
|
61
|
+
# buf.synchronize do
|
62
|
+
# empty_cond.wait_while { buf.empty? }
|
63
|
+
# print buf.shift
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # producer
|
69
|
+
# while line = ARGF.gets
|
70
|
+
# buf.synchronize do
|
71
|
+
# buf.push(line)
|
72
|
+
# empty_cond.signal
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# The consumer thread waits for the producer thread to push a line
|
77
|
+
# to buf while buf.empty?, and the producer thread (main thread)
|
78
|
+
# reads a line from ARGF and push it to buf, then call
|
79
|
+
# empty_cond.signal.
|
80
|
+
#
|
81
|
+
module MonitorMixin
|
82
|
+
#
|
83
|
+
# FIXME: This isn't documented in Nutshell.
|
84
|
+
#
|
85
|
+
# Since MonitorMixin.new_cond returns a ConditionVariable, and the example
|
86
|
+
# above calls while_wait and signal, this class should be documented.
|
87
|
+
#
|
88
|
+
class ConditionVariable
|
89
|
+
# Create a new timer with the argument timeout, and add the
|
90
|
+
# current thread to the list of waiters. Then the thread is
|
91
|
+
# stopped. It will be resumed when a corresponding #signal
|
92
|
+
# occurs.
|
93
|
+
def wait(timeout = nil)
|
94
|
+
condition = @condition
|
95
|
+
@monitor.instance_eval { mon_wait_for_cond(condition, timeout) }
|
96
|
+
end
|
97
|
+
|
98
|
+
# call #wait while the supplied block returns +true+.
|
99
|
+
def wait_while
|
100
|
+
while yield
|
101
|
+
wait
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# call #wait until the supplied block returns +true+.
|
106
|
+
def wait_until
|
107
|
+
until yield
|
108
|
+
wait
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Wake up and run the next waiter
|
113
|
+
def signal
|
114
|
+
condition = @condition
|
115
|
+
@monitor.instance_eval { mon_signal_cond(condition) }
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
# Wake up all the waiters.
|
120
|
+
def broadcast
|
121
|
+
condition = @condition
|
122
|
+
@monitor.instance_eval { mon_broadcast_cond(condition) }
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def count_waiters
|
127
|
+
condition = @condition
|
128
|
+
@monitor.instance_eval { mon_count_cond_waiters(condition) }
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def initialize(monitor, condition)
|
134
|
+
@monitor = monitor
|
135
|
+
@condition = condition
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.extend_object(obj)
|
140
|
+
super(obj)
|
141
|
+
obj.instance_eval {mon_initialize()}
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Attempts to enter exclusive section. Returns +false+ if lock fails.
|
146
|
+
#
|
147
|
+
def mon_try_enter
|
148
|
+
@mon_mutex.synchronize do
|
149
|
+
@mon_owner = Thread.current unless @mon_owner
|
150
|
+
if @mon_owner == Thread.current
|
151
|
+
@mon_count += 1
|
152
|
+
true
|
153
|
+
else
|
154
|
+
false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
# For backward compatibility
|
159
|
+
alias try_mon_enter mon_try_enter
|
160
|
+
|
161
|
+
#
|
162
|
+
# Enters exclusive section.
|
163
|
+
#
|
164
|
+
def mon_enter
|
165
|
+
@mon_mutex.synchronize do
|
166
|
+
mon_acquire(@mon_entering_cond)
|
167
|
+
@mon_count += 1
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Leaves exclusive section.
|
173
|
+
#
|
174
|
+
def mon_exit
|
175
|
+
@mon_mutex.synchronize do
|
176
|
+
mon_check_owner
|
177
|
+
@mon_count -= 1
|
178
|
+
mon_release if @mon_count.zero?
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
# Enters exclusive section and executes the block. Leaves the exclusive
|
185
|
+
# section automatically when the block exits. See example under
|
186
|
+
# +MonitorMixin+.
|
187
|
+
#
|
188
|
+
def mon_synchronize
|
189
|
+
mon_enter
|
190
|
+
begin
|
191
|
+
yield
|
192
|
+
ensure
|
193
|
+
mon_exit
|
194
|
+
end
|
195
|
+
end
|
196
|
+
alias synchronize mon_synchronize
|
197
|
+
|
198
|
+
#
|
199
|
+
# FIXME: This isn't documented in Nutshell.
|
200
|
+
#
|
201
|
+
# Create a new condition variable for this monitor.
|
202
|
+
# This facilitates control of the monitor with #signal and #wait.
|
203
|
+
#
|
204
|
+
def new_cond
|
205
|
+
condition = ::ConditionVariable.new
|
206
|
+
condition.instance_eval { @mon_n_waiters = 0 }
|
207
|
+
return ConditionVariable.new(self, condition)
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def initialize(*args)
|
213
|
+
super
|
214
|
+
mon_initialize
|
215
|
+
end
|
216
|
+
|
217
|
+
# called by initialize method to set defaults for instance variables.
|
218
|
+
def mon_initialize
|
219
|
+
@mon_mutex = Mutex.new
|
220
|
+
@mon_owner = nil
|
221
|
+
@mon_count = 0
|
222
|
+
@mon_total_waiting = 0
|
223
|
+
@mon_entering_cond = ::ConditionVariable.new
|
224
|
+
@mon_waiting_cond = ::ConditionVariable.new
|
225
|
+
self
|
226
|
+
end
|
227
|
+
|
228
|
+
# Throw a ThreadError exception if the current thread
|
229
|
+
# does't own the monitor
|
230
|
+
def mon_check_owner
|
231
|
+
# called with @mon_mutex held
|
232
|
+
if @mon_owner != Thread.current
|
233
|
+
raise ThreadError, "current thread not owner"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def mon_acquire(condition)
|
238
|
+
# called with @mon_mutex held
|
239
|
+
while @mon_owner && @mon_owner != Thread.current
|
240
|
+
condition.wait @mon_mutex
|
241
|
+
end
|
242
|
+
@mon_owner = Thread.current
|
243
|
+
end
|
244
|
+
|
245
|
+
def mon_release
|
246
|
+
# called with @mon_mutex held
|
247
|
+
@mon_owner = nil
|
248
|
+
if @mon_total_waiting.nonzero?
|
249
|
+
@mon_waiting_cond.signal
|
250
|
+
else
|
251
|
+
@mon_entering_cond.signal
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def mon_wait_for_cond(condition, timeout)
|
256
|
+
@mon_mutex.synchronize do
|
257
|
+
mon_check_owner
|
258
|
+
count = @mon_count
|
259
|
+
@mon_count = 0
|
260
|
+
condition.instance_eval { @mon_n_waiters += 1 }
|
261
|
+
begin
|
262
|
+
mon_release
|
263
|
+
if timeout
|
264
|
+
condition.wait(@mon_mutex, timeout)
|
265
|
+
else
|
266
|
+
condition.wait(@mon_mutex)
|
267
|
+
true
|
268
|
+
end
|
269
|
+
ensure
|
270
|
+
@mon_total_waiting += 1
|
271
|
+
# TODO: not interrupt-safe
|
272
|
+
mon_acquire(@mon_waiting_cond)
|
273
|
+
@mon_total_waiting -= 1
|
274
|
+
@mon_count = count
|
275
|
+
condition.instance_eval { @mon_n_waiters -= 1 }
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def mon_signal_cond(condition)
|
281
|
+
@mon_mutex.synchronize do
|
282
|
+
mon_check_owner
|
283
|
+
condition.signal
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def mon_broadcast_cond(condition)
|
288
|
+
@mon_mutex.synchronize do
|
289
|
+
mon_check_owner
|
290
|
+
condition.broadcast
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def mon_count_cond_waiters(condition)
|
295
|
+
@mon_mutex.synchronize do
|
296
|
+
condition.instance_eval { @mon_n_waiters }
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Monitors provide means of mutual exclusion for Thread programming.
|
302
|
+
# A critical region is created by means of the synchronize method,
|
303
|
+
# which takes a block.
|
304
|
+
# The condition variables (created with #new_cond) may be used
|
305
|
+
# to control the execution of a monitor with #signal and #wait.
|
306
|
+
#
|
307
|
+
# the Monitor class wraps MonitorMixin, and provides aliases
|
308
|
+
# alias try_enter try_mon_enter
|
309
|
+
# alias enter mon_enter
|
310
|
+
# alias exit mon_exit
|
311
|
+
# to access its methods more concisely.
|
312
|
+
class Monitor
|
313
|
+
include MonitorMixin
|
314
|
+
alias try_enter try_mon_enter
|
315
|
+
alias enter mon_enter
|
316
|
+
alias exit mon_exit
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
# Documentation comments:
|
321
|
+
# - All documentation comes from Nutshell.
|
322
|
+
# - MonitorMixin.new_cond appears in the example, but is not documented in
|
323
|
+
# Nutshell.
|
324
|
+
# - All the internals (internal modules Accessible and Initializable, class
|
325
|
+
# ConditionVariable) appear in RDoc. It might be good to hide them, by
|
326
|
+
# making them private, or marking them :nodoc:, etc.
|
327
|
+
# - The entire example from the RD section at the top is replicated in the RDoc
|
328
|
+
# comment for MonitorMixin. Does the RD section need to remain?
|
329
|
+
# - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
|
330
|
+
# not synchronize.
|
331
|
+
# - mon_owner is in Nutshell, but appears as an accessor in a separate module
|
332
|
+
# here, so is hard/impossible to RDoc. Some other useful accessors
|
333
|
+
# (mon_count and some queue stuff) are also in this module, and don't appear
|
334
|
+
# directly in the RDoc output.
|
335
|
+
# - in short, it may be worth changing the code layout in this file to make the
|
336
|
+
# documentation easier
|
337
|
+
|
338
|
+
# Local variables:
|
339
|
+
# mode: Ruby
|
340
|
+
# tab-width: 8
|
341
|
+
# End:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require './lib/rubysl/monitor/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "rubysl-monitor"
|
6
|
+
spec.version = RubySL::Monitor::VERSION
|
7
|
+
spec.authors = ["Brian Shirai"]
|
8
|
+
spec.email = ["brixen@gmail.com"]
|
9
|
+
spec.description = %q{Ruby standard library Monitor.}
|
10
|
+
spec.summary = %q{Ruby standard library Monitor.}
|
11
|
+
spec.homepage = "https://github.com/rubysl/rubysl-monitor"
|
12
|
+
spec.license = "BSD"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
20
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
21
|
+
spec.add_development_dependency "mspec", "~> 1.5"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubysl-monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Shirai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
description: Ruby standard library Monitor.
|
56
|
+
email:
|
57
|
+
- brixen@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .travis.yml
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/monitor.rb
|
69
|
+
- lib/rubysl/monitor.rb
|
70
|
+
- lib/rubysl/monitor/monitor.rb
|
71
|
+
- lib/rubysl/monitor/version.rb
|
72
|
+
- rubysl-monitor.gemspec
|
73
|
+
homepage: https://github.com/rubysl/rubysl-monitor
|
74
|
+
licenses:
|
75
|
+
- BSD
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.0.7
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: Ruby standard library Monitor.
|
97
|
+
test_files: []
|