mailbox 0.1.2 → 0.1.3
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.
- data/.gitignore +5 -0
- data/README +5 -2
- data/Rakefile +6 -0
- data/VERSION.yml +1 -1
- data/example/channel_based_log_example.rb +28 -0
- data/example/i_can_has_cheese_burger_example.rb +42 -0
- data/example/log_example.rb +23 -0
- data/example/parallel_each_example.rb +30 -0
- data/example/ping_pong_example.rb +36 -0
- data/lib/mailbox.rb +61 -30
- data/lib/synchronized.rb +57 -0
- data/mailbox.gemspec +18 -5
- data/mailbox.iml +13 -0
- data/mailbox.ipr +254 -0
- data/test/mailbox_test.rb +64 -24
- data/test/synchronized_test.rb +88 -0
- data/test/test_helper.rb +9 -0
- metadata +15 -2
data/.gitignore
ADDED
data/README
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
== About Mailbox
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
"Unobtrusive concurrency for a multicore world"
|
4
|
+
|
5
|
+
Mailbox is a JRuby mixin that simplifies JVM thread backed message passing concurrency.
|
6
|
+
|
7
|
+
Mailbox is Alpha software under active development. Future releases may include backward compatibility breaking changes.
|
5
8
|
|
6
9
|
* jretlang gem is required to use mailbox
|
7
10
|
|
data/Rakefile
CHANGED
@@ -11,6 +11,12 @@ Rake::TestTask.new do |t|
|
|
11
11
|
t.verbose = true
|
12
12
|
end
|
13
13
|
|
14
|
+
Rake::TestTask.new("example") do |t|
|
15
|
+
t.libs << "example"
|
16
|
+
t.test_files = FileList['example/**/*_example.rb']
|
17
|
+
t.verbose = true
|
18
|
+
end
|
19
|
+
|
14
20
|
Jeweler::Tasks.new do |gemspec|
|
15
21
|
gemspec.name = "mailbox"
|
16
22
|
gemspec.summary = "Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads."
|
data/VERSION.yml
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
+
|
6
|
+
class ChannelBasedLogger
|
7
|
+
include Mailbox
|
8
|
+
|
9
|
+
def initialize(log_channel)
|
10
|
+
register_channel :log_channel, log_channel
|
11
|
+
end
|
12
|
+
|
13
|
+
mailslot :channel => :log_channel
|
14
|
+
def log(message)
|
15
|
+
p "Logging on Thread #{Thread.current.object_id} - #{message}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ChannelBasedLogExample < Test::Unit::TestCase
|
20
|
+
|
21
|
+
def test_log_example
|
22
|
+
channel = JRL::Channel.new
|
23
|
+
logger = ChannelBasedLogger.new channel
|
24
|
+
p "Current Thread is #{Thread.current.object_id}"
|
25
|
+
channel.publish "some log message"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
+
|
6
|
+
class ICanHasCheeseBurger
|
7
|
+
include Mailbox
|
8
|
+
|
9
|
+
def initialize(channel)
|
10
|
+
register_channel :request_channel, channel
|
11
|
+
end
|
12
|
+
|
13
|
+
mailslot :channel => :request_channel, :replyable => true
|
14
|
+
def can_you_has?
|
15
|
+
return "ya you can has!"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class ICanHasCheeseBurgerExample < Test::Unit::TestCase
|
21
|
+
|
22
|
+
def test_cheeseburgerz
|
23
|
+
i_can_has_channel = org.jetlang.channels.MemoryRequestChannel.new
|
24
|
+
i_can_has_cheeseburger = ICanHasCheeseBurger.new(i_can_has_channel)
|
25
|
+
|
26
|
+
sync_executor = org.jetlang.core.SynchronousDisposingExecutor.new
|
27
|
+
sync_fiber = org.jetlang.fibers.ThreadFiber.new(sync_executor, nil, false)
|
28
|
+
question = "can i has?"
|
29
|
+
puts question
|
30
|
+
|
31
|
+
latch = JRL::Concurrent::Latch.new(1)
|
32
|
+
answer = "no response!"
|
33
|
+
org.jetlang.channels.AsyncRequest.with_one_reply(sync_fiber, i_can_has_channel, question) do |message|
|
34
|
+
answer = message
|
35
|
+
latch.count_down
|
36
|
+
end
|
37
|
+
|
38
|
+
latch.await(1)
|
39
|
+
puts answer
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
+
|
6
|
+
class Logger
|
7
|
+
include Mailbox
|
8
|
+
|
9
|
+
mailslot
|
10
|
+
def log(message)
|
11
|
+
p "Logging on Thread #{Thread.current.object_id} - #{message}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class LogExample < Test::Unit::TestCase
|
16
|
+
|
17
|
+
def test_log_example
|
18
|
+
logger = Logger.new
|
19
|
+
p "Current Thread is #{Thread.current.object_id}"
|
20
|
+
logger.log "some log message"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
+
|
6
|
+
class DataProcessor
|
7
|
+
include Mailbox
|
8
|
+
|
9
|
+
mailslot
|
10
|
+
def process(data)
|
11
|
+
p "#{data} was processed by Thread# #{Thread.current.object_id}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class ParallelEachExample < Test::Unit::TestCase
|
17
|
+
|
18
|
+
def test_a_simple_parallel_each
|
19
|
+
|
20
|
+
items = ["item1", "item2", "item3", "item4", "item5"]
|
21
|
+
|
22
|
+
processors = [DataProcessor.new, DataProcessor.new, DataProcessor.new]
|
23
|
+
|
24
|
+
items.each_with_index do |item, index|
|
25
|
+
processors[index % processors.length].process item
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
+
|
6
|
+
class Player
|
7
|
+
include Mailbox
|
8
|
+
|
9
|
+
def initialize(sound, send_channel, recieve_channel)
|
10
|
+
@sound = sound
|
11
|
+
@send_channel = send_channel
|
12
|
+
register_channel :recieve_channel, recieve_channel
|
13
|
+
end
|
14
|
+
|
15
|
+
mailslot :channel => :recieve_channel
|
16
|
+
def play(last_move)
|
17
|
+
p "Thread [#{Thread.current.object_id}] - #{@sound} for #{last_move}"
|
18
|
+
@send_channel.publish @sound
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class PingPongExample < Test::Unit::TestCase
|
24
|
+
|
25
|
+
def test_ping_pong
|
26
|
+
ping_channel = JRL::Channel.new
|
27
|
+
pong_channel = JRL::Channel.new
|
28
|
+
|
29
|
+
pinger = Player.new "ping", ping_channel, pong_channel
|
30
|
+
ponger = Player.new "pong", pong_channel, ping_channel
|
31
|
+
|
32
|
+
ping_channel.publish "ping"
|
33
|
+
sleep 0.001
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/mailbox.rb
CHANGED
@@ -1,23 +1,37 @@
|
|
1
|
+
# Author:: Joel Friedman and Patrick Farley
|
2
|
+
#
|
3
|
+
# This module is used to simplify concurrency
|
4
|
+
# in your application. JVM threads and JRetlang are
|
5
|
+
# used to provide Actor model style asynchronous
|
6
|
+
# message passing via method calls. Named channel based
|
7
|
+
# message passing is also supported via +register_channel+ and
|
8
|
+
# the <tt>:channel</tt> parameter on +mailslot+.
|
9
|
+
|
1
10
|
require 'rubygems'
|
2
11
|
require 'jretlang'
|
3
12
|
|
4
|
-
|
13
|
+
require File.dirname(__FILE__) + '/synchronized'
|
5
14
|
|
6
|
-
# This module is used to simplify the using concurrency
|
7
|
-
# in your application. Using JVM threads as the backing
|
8
|
-
# a method can set to become an asynchronous method
|
9
|
-
# to be used in a actor-model method. Or a method
|
10
|
-
# can be set to be the backing of a named channel
|
11
|
-
# (jretlang channels are used here).
|
12
15
|
module Mailbox
|
16
|
+
include Synchronized
|
13
17
|
|
14
18
|
# Register your jretlang channel as a named channel
|
15
19
|
def register_channel(channel_name, channel)
|
16
20
|
channel_registry = self.class.__channel_registry__
|
17
|
-
channel_registry.
|
21
|
+
channel_registry.select { |k,v| v[:channel] == channel_name }.each do |k,v|
|
22
|
+
v[:replyable] ? __subscribe_with_single_reply__(channel, k) : __subscribe__(channel, k)
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
|
-
|
26
|
+
class << self
|
27
|
+
# Used to tell +Mailbox+ that all +mailslot+
|
28
|
+
# methods should be run on the calling thread.
|
29
|
+
#
|
30
|
+
# <b>*** Intended for synchronus unit testing of concurrent apps***</b>
|
31
|
+
attr_accessor :synchronous
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
21
35
|
|
22
36
|
def self.included(base)
|
23
37
|
base.extend(Mailbox::ClassMethods)
|
@@ -27,65 +41,82 @@ module Mailbox
|
|
27
41
|
channel.subscribe_on_fiber(__fiber__) { |*args| self.send(method, *args) }
|
28
42
|
end
|
29
43
|
|
44
|
+
def __subscribe_with_single_reply__(channel, method)
|
45
|
+
channel.subscribe(__fiber__) do |message|
|
46
|
+
message.reply(self.send(method))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def __synchronous_fiber__
|
51
|
+
executor = JRL::SynchronousDisposingExecutor.new
|
52
|
+
fiber = JRL::Fibers::ThreadFiber.new executor, "synchronous_thread", true
|
53
|
+
end
|
54
|
+
|
30
55
|
def __started_fiber__
|
31
|
-
fiber = JRL::
|
56
|
+
fiber = Mailbox.synchronous == true ? __synchronous_fiber__ : JRL::Fibers::ThreadFiber.new
|
32
57
|
fiber.start
|
33
58
|
fiber
|
34
59
|
end
|
35
60
|
|
36
61
|
def __fiber__
|
37
62
|
@fiber ||= __started_fiber__
|
38
|
-
end
|
39
|
-
|
40
|
-
module ClassMethods
|
41
|
-
|
42
|
-
|
63
|
+
end
|
64
|
+
|
65
|
+
module ClassMethods
|
66
|
+
include Synchronized::ClassMethods
|
67
|
+
|
68
|
+
# Used within +Mailbox+ module
|
69
|
+
attr_accessor :__channel_registry__
|
43
70
|
|
44
71
|
# Notifies Mailbox that the next method added
|
45
|
-
# will be a
|
46
|
-
#
|
72
|
+
# will be a +mailslot+. If <tt>:channel</tt> is provided
|
73
|
+
# the next method will become a subscriber on the channel.
|
74
|
+
# Channel based +mailslot+ methods are also made private
|
75
|
+
# to discourage direct invocation
|
47
76
|
def mailslot(params={})
|
48
77
|
@next_channel_name = params[:channel]
|
78
|
+
@replyable = params[:replyable]
|
49
79
|
@mailslot = true
|
50
80
|
end
|
51
81
|
|
52
82
|
private
|
53
83
|
|
54
84
|
def method_added(method_name, &block)
|
55
|
-
return
|
56
|
-
|
57
|
-
return unless @mailslot == true
|
58
|
-
|
85
|
+
return super unless @mailslot == true
|
59
86
|
@mailslot = false
|
60
87
|
|
61
88
|
if @next_channel_name.nil?
|
62
89
|
__setup_on_fiber__(method_name)
|
63
90
|
else
|
64
|
-
__setup_on_channel__(method_name)
|
91
|
+
__setup_on_channel__(method_name, @replyable)
|
65
92
|
end
|
93
|
+
|
94
|
+
super
|
66
95
|
|
67
96
|
end
|
68
97
|
|
69
98
|
def __setup_on_fiber__(method_name)
|
99
|
+
return super if @is_adding_mailbox_to_method
|
100
|
+
|
70
101
|
alias_method :"__#{method_name}__", method_name
|
102
|
+
@is_adding_mailbox_to_method = true
|
71
103
|
|
72
|
-
|
73
|
-
|
74
|
-
define_method( method_name, lambda do |*args|
|
75
|
-
__fiber__.execute { self.send(:"__#{method_name}__", *args ) }
|
104
|
+
define_method( method_name, lambda do |*args|
|
105
|
+
__fiber__.execute { self.send(:"__#{method_name}__", *args ) }
|
76
106
|
end )
|
77
107
|
|
78
|
-
@
|
108
|
+
@is_adding_mailbox_to_method = false
|
79
109
|
end
|
80
110
|
|
81
|
-
def __setup_on_channel__(method_name)
|
111
|
+
def __setup_on_channel__(method_name, replyable)
|
82
112
|
private method_name
|
83
113
|
@__channel_registry__ ||= {}
|
84
|
-
__channel_registry__[method_name] = @next_channel_name
|
114
|
+
__channel_registry__[method_name] = { :channel => @next_channel_name, :replyable => replyable }
|
115
|
+
@replyable = nil
|
85
116
|
@next_channel_name = nil
|
86
117
|
end
|
87
118
|
|
88
|
-
end
|
119
|
+
end
|
89
120
|
|
90
121
|
end
|
91
122
|
|
data/lib/synchronized.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Author:: Joel Friedman and Patrick Farley
|
2
|
+
#
|
3
|
+
# This module goes hand in hand with +Mailbox+.
|
4
|
+
# It simplifies concurrecncy within your
|
5
|
+
# JRuby applications.
|
6
|
+
module Synchronized
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def __mutex__
|
11
|
+
@mutex ||= Mutex.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.extend(Synchronized::ClassMethods)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
# Notify +Mailbox+ that the next method added
|
21
|
+
# will be +synchronized+.
|
22
|
+
#
|
23
|
+
# This guarentees:
|
24
|
+
# 1. Two invocations of this method will not interleave and
|
25
|
+
# 2. a happens-before relationship is established with any subsequent invocation.
|
26
|
+
# http://java.sun.com/docs/books/tutorial/essential/concurrency/syncmeth.html
|
27
|
+
def synchronized
|
28
|
+
@synchronized = true
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def method_added(method_name, &block)
|
34
|
+
return super unless @synchronized == true
|
35
|
+
@synchronized = false
|
36
|
+
__synchronize__(method_name)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def __synchronize__(method_name)
|
42
|
+
return super if @is_adding_synchronized_to_method
|
43
|
+
|
44
|
+
alias_method :"__#{method_name}__", method_name
|
45
|
+
@is_adding_synchronized_to_method = true
|
46
|
+
|
47
|
+
|
48
|
+
define_method( method_name, lambda do |*args|
|
49
|
+
__mutex__.synchronize { self.send(:"__#{method_name}__", *args ) }
|
50
|
+
end )
|
51
|
+
|
52
|
+
@is_adding_synchronized_to_method = false
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/mailbox.gemspec
CHANGED
@@ -5,23 +5,34 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mailbox}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joel Friedman", "Patrick Farley"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-11-04}
|
13
13
|
s.description = %q{Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads.}
|
14
14
|
s.email = %q{asher.friedman@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"README"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
|
-
"
|
19
|
+
".gitignore",
|
20
|
+
"README",
|
20
21
|
"Rakefile",
|
21
22
|
"VERSION.yml",
|
23
|
+
"example/channel_based_log_example.rb",
|
24
|
+
"example/i_can_has_cheese_burger_example.rb",
|
25
|
+
"example/log_example.rb",
|
26
|
+
"example/parallel_each_example.rb",
|
27
|
+
"example/ping_pong_example.rb",
|
22
28
|
"lib/mailbox.rb",
|
29
|
+
"lib/synchronized.rb",
|
23
30
|
"mailbox.gemspec",
|
24
|
-
"
|
31
|
+
"mailbox.iml",
|
32
|
+
"mailbox.ipr",
|
33
|
+
"test/mailbox_test.rb",
|
34
|
+
"test/synchronized_test.rb",
|
35
|
+
"test/test_helper.rb"
|
25
36
|
]
|
26
37
|
s.homepage = %q{http://joelash.github.com/mailbox}
|
27
38
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -30,7 +41,9 @@ Gem::Specification.new do |s|
|
|
30
41
|
s.rubygems_version = %q{1.3.3}
|
31
42
|
s.summary = %q{Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads.}
|
32
43
|
s.test_files = [
|
33
|
-
"test/mailbox_test.rb"
|
44
|
+
"test/mailbox_test.rb",
|
45
|
+
"test/synchronized_test.rb",
|
46
|
+
"test/test_helper.rb"
|
34
47
|
]
|
35
48
|
|
36
49
|
if s.respond_to? :specification_version then
|
data/mailbox.iml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module relativePaths="true" type="RUBY_MODULE" version="4">
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
4
|
+
<exclude-output />
|
5
|
+
<content url="file://$MODULE_DIR$" />
|
6
|
+
<orderEntry type="jdk" jdkName="JRuby SDK 1.3.1" jdkType="JRUBY_SDK" />
|
7
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
8
|
+
</component>
|
9
|
+
<component name="RModuleSettingsStorage">
|
10
|
+
<RMODULE_SETTINGS_STORAGE_ID NAME="NUMBER" VALUE="0" />
|
11
|
+
</component>
|
12
|
+
</module>
|
13
|
+
|
data/mailbox.ipr
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project relativePaths="false" version="4">
|
3
|
+
<component name="AntConfiguration">
|
4
|
+
<defaultAnt bundledAnt="true" />
|
5
|
+
</component>
|
6
|
+
<component name="BuildJarProjectSettings">
|
7
|
+
<option name="BUILD_JARS_ON_MAKE" value="false" />
|
8
|
+
</component>
|
9
|
+
<component name="CodeStyleSettingsManager">
|
10
|
+
<option name="PER_PROJECT_SETTINGS" />
|
11
|
+
<option name="USE_PER_PROJECT_SETTINGS" value="false" />
|
12
|
+
</component>
|
13
|
+
<component name="CompilerConfiguration">
|
14
|
+
<option name="DEFAULT_COMPILER" value="Javac" />
|
15
|
+
<option name="DEPLOY_AFTER_MAKE" value="0" />
|
16
|
+
<resourceExtensions>
|
17
|
+
<entry name=".+\.(properties|xml|html|dtd|tld)" />
|
18
|
+
<entry name=".+\.(gif|png|jpeg|jpg)" />
|
19
|
+
</resourceExtensions>
|
20
|
+
<wildcardResourcePatterns>
|
21
|
+
<entry name="?*.properties" />
|
22
|
+
<entry name="?*.xml" />
|
23
|
+
<entry name="?*.gif" />
|
24
|
+
<entry name="?*.png" />
|
25
|
+
<entry name="?*.jpeg" />
|
26
|
+
<entry name="?*.jpg" />
|
27
|
+
<entry name="?*.html" />
|
28
|
+
<entry name="?*.dtd" />
|
29
|
+
<entry name="?*.tld" />
|
30
|
+
<entry name="?*.ftl" />
|
31
|
+
</wildcardResourcePatterns>
|
32
|
+
</component>
|
33
|
+
<component name="CopyrightManager" default="">
|
34
|
+
<module2copyright />
|
35
|
+
</component>
|
36
|
+
<component name="DependencyValidationManager">
|
37
|
+
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
38
|
+
</component>
|
39
|
+
<component name="EclipseCompilerSettings">
|
40
|
+
<option name="DEBUGGING_INFO" value="true" />
|
41
|
+
<option name="GENERATE_NO_WARNINGS" value="true" />
|
42
|
+
<option name="DEPRECATION" value="false" />
|
43
|
+
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
|
44
|
+
<option name="MAXIMUM_HEAP_SIZE" value="128" />
|
45
|
+
</component>
|
46
|
+
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
47
|
+
<component name="IdProvider" IDEtalkID="2A4BC5ABDEB6DBFA33020D902AA1570C" />
|
48
|
+
<component name="InspectionProjectProfileManager">
|
49
|
+
<option name="PROJECT_PROFILE" value="Project Default" />
|
50
|
+
<option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
|
51
|
+
<scopes />
|
52
|
+
<profiles>
|
53
|
+
<profile version="1.0" is_locked="false">
|
54
|
+
<option name="myName" value="Project Default" />
|
55
|
+
<option name="myLocal" value="false" />
|
56
|
+
</profile>
|
57
|
+
</profiles>
|
58
|
+
<list size="0" />
|
59
|
+
</component>
|
60
|
+
<component name="JavacSettings">
|
61
|
+
<option name="DEBUGGING_INFO" value="true" />
|
62
|
+
<option name="GENERATE_NO_WARNINGS" value="false" />
|
63
|
+
<option name="DEPRECATION" value="true" />
|
64
|
+
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
|
65
|
+
<option name="MAXIMUM_HEAP_SIZE" value="128" />
|
66
|
+
</component>
|
67
|
+
<component name="JavadocGenerationManager">
|
68
|
+
<option name="OUTPUT_DIRECTORY" />
|
69
|
+
<option name="OPTION_SCOPE" value="protected" />
|
70
|
+
<option name="OPTION_HIERARCHY" value="true" />
|
71
|
+
<option name="OPTION_NAVIGATOR" value="true" />
|
72
|
+
<option name="OPTION_INDEX" value="true" />
|
73
|
+
<option name="OPTION_SEPARATE_INDEX" value="true" />
|
74
|
+
<option name="OPTION_DOCUMENT_TAG_USE" value="false" />
|
75
|
+
<option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
|
76
|
+
<option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
|
77
|
+
<option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
|
78
|
+
<option name="OPTION_DEPRECATED_LIST" value="true" />
|
79
|
+
<option name="OTHER_OPTIONS" value="" />
|
80
|
+
<option name="HEAP_SIZE" />
|
81
|
+
<option name="LOCALE" />
|
82
|
+
<option name="OPEN_IN_BROWSER" value="true" />
|
83
|
+
</component>
|
84
|
+
<component name="JikesSettings">
|
85
|
+
<option name="JIKES_PATH" value="" />
|
86
|
+
<option name="DEBUGGING_INFO" value="true" />
|
87
|
+
<option name="DEPRECATION" value="true" />
|
88
|
+
<option name="GENERATE_NO_WARNINGS" value="false" />
|
89
|
+
<option name="IS_EMACS_ERRORS_MODE" value="true" />
|
90
|
+
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
|
91
|
+
</component>
|
92
|
+
<component name="Palette2">
|
93
|
+
<group name="Swing">
|
94
|
+
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
95
|
+
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
96
|
+
</item>
|
97
|
+
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
98
|
+
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
99
|
+
</item>
|
100
|
+
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
101
|
+
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
102
|
+
</item>
|
103
|
+
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
104
|
+
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
105
|
+
</item>
|
106
|
+
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
107
|
+
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
108
|
+
<initial-values>
|
109
|
+
<property name="text" value="Button" />
|
110
|
+
</initial-values>
|
111
|
+
</item>
|
112
|
+
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
113
|
+
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
114
|
+
<initial-values>
|
115
|
+
<property name="text" value="RadioButton" />
|
116
|
+
</initial-values>
|
117
|
+
</item>
|
118
|
+
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
119
|
+
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
120
|
+
<initial-values>
|
121
|
+
<property name="text" value="CheckBox" />
|
122
|
+
</initial-values>
|
123
|
+
</item>
|
124
|
+
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
125
|
+
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
126
|
+
<initial-values>
|
127
|
+
<property name="text" value="Label" />
|
128
|
+
</initial-values>
|
129
|
+
</item>
|
130
|
+
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
131
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
132
|
+
<preferred-size width="150" height="-1" />
|
133
|
+
</default-constraints>
|
134
|
+
</item>
|
135
|
+
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
136
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
137
|
+
<preferred-size width="150" height="-1" />
|
138
|
+
</default-constraints>
|
139
|
+
</item>
|
140
|
+
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
141
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
142
|
+
<preferred-size width="150" height="-1" />
|
143
|
+
</default-constraints>
|
144
|
+
</item>
|
145
|
+
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
146
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
147
|
+
<preferred-size width="150" height="50" />
|
148
|
+
</default-constraints>
|
149
|
+
</item>
|
150
|
+
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
151
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
152
|
+
<preferred-size width="150" height="50" />
|
153
|
+
</default-constraints>
|
154
|
+
</item>
|
155
|
+
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
156
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
157
|
+
<preferred-size width="150" height="50" />
|
158
|
+
</default-constraints>
|
159
|
+
</item>
|
160
|
+
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
161
|
+
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
162
|
+
</item>
|
163
|
+
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
164
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
165
|
+
<preferred-size width="150" height="50" />
|
166
|
+
</default-constraints>
|
167
|
+
</item>
|
168
|
+
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
169
|
+
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
170
|
+
<preferred-size width="150" height="50" />
|
171
|
+
</default-constraints>
|
172
|
+
</item>
|
173
|
+
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
174
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
175
|
+
<preferred-size width="150" height="50" />
|
176
|
+
</default-constraints>
|
177
|
+
</item>
|
178
|
+
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
179
|
+
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
180
|
+
<preferred-size width="200" height="200" />
|
181
|
+
</default-constraints>
|
182
|
+
</item>
|
183
|
+
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
184
|
+
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
185
|
+
<preferred-size width="200" height="200" />
|
186
|
+
</default-constraints>
|
187
|
+
</item>
|
188
|
+
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
189
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
190
|
+
</item>
|
191
|
+
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
192
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
193
|
+
</item>
|
194
|
+
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
195
|
+
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
196
|
+
</item>
|
197
|
+
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
198
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
199
|
+
</item>
|
200
|
+
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
201
|
+
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
202
|
+
<preferred-size width="-1" height="20" />
|
203
|
+
</default-constraints>
|
204
|
+
</item>
|
205
|
+
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
206
|
+
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
207
|
+
</item>
|
208
|
+
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
209
|
+
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
210
|
+
</item>
|
211
|
+
</group>
|
212
|
+
</component>
|
213
|
+
<component name="ProjectDetails">
|
214
|
+
<option name="projectName" value="mailbox" />
|
215
|
+
</component>
|
216
|
+
<component name="ProjectFileVersion" converted="true">
|
217
|
+
<converter id="javaee-modules" />
|
218
|
+
<converter id="ror-modules" />
|
219
|
+
<converter id="SelenaRunConfToDiana" />
|
220
|
+
</component>
|
221
|
+
<component name="ProjectKey">
|
222
|
+
<option name="state" value="project:///Users/garethjones/sandbox/mailbox/mailbox.ipr" />
|
223
|
+
</component>
|
224
|
+
<component name="ProjectModuleManager">
|
225
|
+
<modules>
|
226
|
+
<module fileurl="file://$PROJECT_DIR$/mailbox.iml" filepath="$PROJECT_DIR$/mailbox.iml" />
|
227
|
+
</modules>
|
228
|
+
</component>
|
229
|
+
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="JRuby SDK 1.3.1" project-jdk-type="JRUBY_SDK">
|
230
|
+
<output url="file://$PROJECT_DIR$/out" />
|
231
|
+
</component>
|
232
|
+
<component name="ResourceManagerContainer">
|
233
|
+
<option name="myResourceBundles">
|
234
|
+
<value>
|
235
|
+
<list size="0" />
|
236
|
+
</value>
|
237
|
+
</option>
|
238
|
+
</component>
|
239
|
+
<component name="RmicSettings">
|
240
|
+
<option name="IS_EANABLED" value="false" />
|
241
|
+
<option name="DEBUGGING_INFO" value="true" />
|
242
|
+
<option name="GENERATE_NO_WARNINGS" value="false" />
|
243
|
+
<option name="GENERATE_IIOP_STUBS" value="false" />
|
244
|
+
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
|
245
|
+
</component>
|
246
|
+
<component name="SvnBranchConfigurationManager">
|
247
|
+
<option name="mySupportsUserInfoFilter" value="true" />
|
248
|
+
</component>
|
249
|
+
<component name="VcsDirectoryMappings">
|
250
|
+
<mapping directory="" vcs="Git" />
|
251
|
+
</component>
|
252
|
+
<component name="WebServicesPlugin" addRequiredLibraries="true" />
|
253
|
+
</project>
|
254
|
+
|
data/test/mailbox_test.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'test/unit'
|
3
|
-
|
4
|
-
require File.dirname(__FILE__) + "/../lib/mailbox"
|
5
|
-
|
6
|
-
module Latches
|
7
|
-
include_package 'java.util.concurrent'
|
8
|
-
end
|
1
|
+
require 'test_helper.rb'
|
9
2
|
|
10
3
|
class MailboxTest < Test::Unit::TestCase
|
11
4
|
|
@@ -15,36 +8,48 @@ class MailboxTest < Test::Unit::TestCase
|
|
15
8
|
include Mailbox
|
16
9
|
|
17
10
|
mailslot
|
18
|
-
def test_method(latch,
|
19
|
-
|
11
|
+
def test_method(latch, thread_info)
|
12
|
+
thread_info[:thread_id] = Thread.current.object_id
|
20
13
|
latch.count_down
|
21
14
|
end
|
22
15
|
end
|
23
16
|
|
24
|
-
|
17
|
+
thread_info = {}
|
25
18
|
latch = Latches::CountDownLatch.new( 1 )
|
26
|
-
klass.new.test_method(latch,
|
19
|
+
klass.new.test_method(latch, thread_info)
|
27
20
|
|
28
21
|
assert( latch.await( 1, Latches::TimeUnit::SECONDS ), "Timed out" )
|
29
|
-
assert_not_equal Thread.current.object_id,
|
22
|
+
assert_not_equal Thread.current.object_id, thread_info[:thread_id]
|
30
23
|
|
31
24
|
end
|
32
25
|
|
33
|
-
def
|
26
|
+
def test_default_is_run_asynchronously
|
27
|
+
assert Mailbox.synchronous == false, "Mailbox is defaulting to synchronous execution"
|
28
|
+
end
|
34
29
|
|
35
|
-
|
36
|
-
|
30
|
+
def test_can_set_mailslot_to_run_synchronously
|
31
|
+
begin
|
32
|
+
Mailbox.synchronous = true
|
33
|
+
klass = Class.new do
|
34
|
+
include Mailbox
|
35
|
+
|
36
|
+
mailslot
|
37
|
+
def test_method(thread_info)
|
38
|
+
thread_info[:thread_id] = Thread.current.object_id
|
39
|
+
end
|
37
40
|
|
38
|
-
def bar
|
39
|
-
"foo"
|
40
41
|
end
|
41
|
-
end
|
42
42
|
|
43
|
-
|
43
|
+
thread_info = {}
|
44
|
+
klass.new.test_method(thread_info)
|
45
|
+
assert_equal Thread.current.object_id, thread_info[:thread_id]
|
46
|
+
ensure
|
47
|
+
Mailbox.synchronous = false;
|
48
|
+
end
|
44
49
|
|
45
50
|
end
|
46
51
|
|
47
|
-
def
|
52
|
+
def test_should_support_channels
|
48
53
|
|
49
54
|
klass = Class.new do
|
50
55
|
include Mailbox
|
@@ -54,19 +59,54 @@ class MailboxTest < Test::Unit::TestCase
|
|
54
59
|
end
|
55
60
|
|
56
61
|
mailslot :channel => :test_channel
|
57
|
-
def test_method(
|
58
|
-
|
62
|
+
def test_method(message)
|
63
|
+
message[:thread_info][:thread_id] = Thread.current.object_id
|
64
|
+
message[:latch].count_down
|
59
65
|
end
|
60
66
|
end
|
61
67
|
|
68
|
+
thread_info = {}
|
62
69
|
latch = Latches::CountDownLatch.new 1
|
63
70
|
a_channel = JRL::Channel.new
|
64
71
|
|
65
72
|
klass.new(a_channel)
|
66
|
-
a_channel.publish latch
|
73
|
+
a_channel.publish :latch => latch, :thread_info => thread_info
|
67
74
|
|
68
75
|
assert latch.await( 1, Latches::TimeUnit::SECONDS ), "Timed out"
|
76
|
+
assert_not_equal Thread.current.object_id, thread_info[:thread_id]
|
69
77
|
|
70
78
|
end
|
71
79
|
|
80
|
+
def test_should_support_request_channels
|
81
|
+
|
82
|
+
klass = Class.new do
|
83
|
+
include Mailbox
|
84
|
+
|
85
|
+
def initialize(request_channel)
|
86
|
+
register_channel :test_channel, request_channel
|
87
|
+
end
|
88
|
+
|
89
|
+
mailslot :channel => :test_channel, :replyable => true
|
90
|
+
def test_method
|
91
|
+
return "ya_rly!"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
thread_info = {}
|
96
|
+
latch = Latches::CountDownLatch.new 1
|
97
|
+
request_channel = JRL::Channels::MemoryRequestChannel.new
|
98
|
+
|
99
|
+
klass.new(request_channel)
|
100
|
+
fiber = JRL::Fibers::ThreadFiber.new
|
101
|
+
fiber.start
|
102
|
+
|
103
|
+
response = "no response"
|
104
|
+
JRL::Channels::AsyncRequest.with_one_reply(fiber, request_channel, "orly?") do |message|
|
105
|
+
response = message
|
106
|
+
latch.count_down
|
107
|
+
end
|
108
|
+
|
109
|
+
assert latch.await(1, Latches::TimeUnit::SECONDS), "timed out"
|
110
|
+
assert_equal "ya_rly!", response
|
111
|
+
end
|
72
112
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'test_helper.rb'
|
2
|
+
|
3
|
+
class SynchronizedTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_supports_synchronized_access_of_methods_by_including_synchronized
|
6
|
+
|
7
|
+
klass = Class.new do
|
8
|
+
include Synchronized
|
9
|
+
|
10
|
+
attr_accessor :values
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@values = []
|
14
|
+
end
|
15
|
+
|
16
|
+
synchronized
|
17
|
+
def test_method( value )
|
18
|
+
@value = value
|
19
|
+
@values << @value
|
20
|
+
sleep 1
|
21
|
+
@values << @value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
clazz = klass.new
|
26
|
+
|
27
|
+
thread_1 = Thread.new do
|
28
|
+
clazz.test_method "thread 1"
|
29
|
+
end
|
30
|
+
|
31
|
+
sleep 0.3
|
32
|
+
|
33
|
+
thread_2 = Thread.new do
|
34
|
+
clazz.test_method "thread 2"
|
35
|
+
end
|
36
|
+
|
37
|
+
thread_1.join 1
|
38
|
+
thread_2.join 1
|
39
|
+
|
40
|
+
assert_equal "thread 1", clazz.values[0], "1st wrong"
|
41
|
+
assert_equal "thread 1", clazz.values[1], "2nd wrong"
|
42
|
+
assert_equal "thread 2", clazz.values[2], "3rd wrong"
|
43
|
+
assert_equal "thread 2", clazz.values[3], "4th wrong"
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_supports_synchronized_access_of_methods_by_including_mailbox
|
48
|
+
|
49
|
+
klass = Class.new do
|
50
|
+
include Mailbox
|
51
|
+
|
52
|
+
attr_accessor :values
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
@values = []
|
56
|
+
end
|
57
|
+
|
58
|
+
synchronized
|
59
|
+
def test_method( value )
|
60
|
+
@value = value
|
61
|
+
@values << @value
|
62
|
+
sleep 1
|
63
|
+
@values << @value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
clazz = klass.new
|
68
|
+
|
69
|
+
thread_1 = Thread.new do
|
70
|
+
clazz.test_method "thread 1"
|
71
|
+
end
|
72
|
+
|
73
|
+
sleep 0.3
|
74
|
+
|
75
|
+
thread_2 = Thread.new do
|
76
|
+
clazz.test_method "thread 2"
|
77
|
+
end
|
78
|
+
|
79
|
+
thread_1.join 1
|
80
|
+
thread_2.join 1
|
81
|
+
|
82
|
+
assert_equal "thread 1", clazz.values[0], "1st wrong"
|
83
|
+
assert_equal "thread 1", clazz.values[1], "2nd wrong"
|
84
|
+
assert_equal "thread 2", clazz.values[2], "3rd wrong"
|
85
|
+
assert_equal "thread 2", clazz.values[3], "4th wrong"
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -29,12 +29,23 @@ description: Mailbox is a JRuby module that simplifies concurrency and is backed
|
|
29
29
|
specification_version: 3
|
30
30
|
default_executable:
|
31
31
|
files:
|
32
|
+
- .gitignore
|
32
33
|
- README
|
33
34
|
- Rakefile
|
34
35
|
- VERSION.yml
|
36
|
+
- example/channel_based_log_example.rb
|
37
|
+
- example/i_can_has_cheese_burger_example.rb
|
38
|
+
- example/log_example.rb
|
39
|
+
- example/parallel_each_example.rb
|
40
|
+
- example/ping_pong_example.rb
|
35
41
|
- lib/mailbox.rb
|
42
|
+
- lib/synchronized.rb
|
36
43
|
- mailbox.gemspec
|
44
|
+
- mailbox.iml
|
45
|
+
- mailbox.ipr
|
37
46
|
- test/mailbox_test.rb
|
47
|
+
- test/synchronized_test.rb
|
48
|
+
- test/test_helper.rb
|
38
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
50
|
requirements:
|
40
51
|
- - '>='
|
@@ -49,12 +60,14 @@ requirements: []
|
|
49
60
|
authors:
|
50
61
|
- Joel Friedman
|
51
62
|
- Patrick Farley
|
52
|
-
date: 2009-
|
63
|
+
date: 2009-11-04 06:00:00 +00:00
|
53
64
|
platform: ruby
|
54
65
|
test_files:
|
55
66
|
- test/mailbox_test.rb
|
67
|
+
- test/synchronized_test.rb
|
68
|
+
- test/test_helper.rb
|
56
69
|
version: !ruby/object:Gem::Version
|
57
|
-
version: 0.1.
|
70
|
+
version: 0.1.3
|
58
71
|
require_paths:
|
59
72
|
- lib
|
60
73
|
dependencies:
|