revactor 0.1.0 → 0.1.1

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.
@@ -0,0 +1,46 @@
1
+ #--
2
+ # Copyright (C)2007 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ require File.dirname(__FILE__) + '/../lib/revactor'
8
+
9
+ describe Actor::Delegator do
10
+ before :each do
11
+ @obj = mock(:obj)
12
+ @delegator = Actor::Delegator.new(@obj)
13
+ end
14
+
15
+ it "delegates calls to the given object" do
16
+ @obj.should_receive(:foo).with(1)
17
+ @obj.should_receive(:bar).with(2)
18
+ @obj.should_receive(:baz).with(3)
19
+
20
+ @delegator.foo(1)
21
+ @delegator.bar(2)
22
+ @delegator.baz(3)
23
+ end
24
+
25
+ it "returns the value from calls to the delegate object" do
26
+ input_value = 42
27
+ output_value = 420
28
+
29
+ @obj.should_receive(:spiffy).with(input_value).and_return(input_value * 10)
30
+ @delegator.spiffy(input_value).should == output_value
31
+ end
32
+
33
+ it "captures exceptions in the delegate and raises them for the caller" do
34
+ ex = "crash!"
35
+
36
+ @obj.should_receive(:crashy_method).and_raise(ex)
37
+ proc { @delegator.crashy_method }.should raise_error(ex)
38
+ end
39
+
40
+ it "passes blocks along to the delegate" do
41
+ prc = proc { "yay" }
42
+
43
+ @obj.should_receive(:blocky).with(&prc)
44
+ @delegator.blocky(&prc)
45
+ end
46
+ end
@@ -22,63 +22,43 @@ describe Revactor::TCP do
22
22
  end
23
23
 
24
24
  it "connects to remote servers" do
25
- Actor.start do
26
- sock = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
27
- sock.should be_an_instance_of(Revactor::TCP::Socket)
28
- @server.accept.should be_an_instance_of(TCPSocket)
29
-
30
- sock.close
31
- @actor_run = true
32
- end
25
+ sock = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
26
+ sock.should be_an_instance_of(Revactor::TCP::Socket)
27
+ @server.accept.should be_an_instance_of(TCPSocket)
33
28
 
34
- @actor_run.should be_true
29
+ sock.close
35
30
  end
36
31
 
37
32
  it "listens for remote connections" do
38
- @server.close # Don't use it for this one...
33
+ @server.close # Don't use their server for this one...
39
34
 
40
- Actor.start do
41
- server = Revactor::TCP.listen(TEST_HOST, RANDOM_PORT)
42
- server.should be_an_instance_of(Revactor::TCP::Listener)
43
-
44
- s1 = TCPSocket.open(TEST_HOST, RANDOM_PORT)
45
- s2 = server.accept
46
-
47
- server.close
48
- s2.close
49
- @actor_run = true
50
- end
35
+ server = Revactor::TCP.listen(TEST_HOST, RANDOM_PORT)
36
+ server.should be_an_instance_of(Revactor::TCP::Listener)
51
37
 
52
- @actor_run.should be_true
38
+ s1 = TCPSocket.open(TEST_HOST, RANDOM_PORT)
39
+ s2 = server.accept
40
+
41
+ server.close
42
+ s2.close
53
43
  end
54
44
 
55
45
  it "reads data" do
56
- Actor.start do
57
- s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
58
- s2 = @server.accept
59
-
60
- s2.write 'foobar'
61
- s1.read(6).should == 'foobar'
62
-
63
- s1.close
64
- @actor_run = true
65
- end
46
+ s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
47
+ s2 = @server.accept
66
48
 
67
- @actor_run.should be_true
49
+ s2.write 'foobar'
50
+ s1.read(6).should == 'foobar'
51
+
52
+ s1.close
68
53
  end
69
54
 
70
55
  it "writes data" do
71
- Actor.start do
72
- s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
73
- s2 = @server.accept
74
-
75
- s1.write 'foobar'
76
- s2.read(6).should == 'foobar'
77
-
78
- s1.close
79
- @actor_run = true
80
- end
56
+ s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
57
+ s2 = @server.accept
58
+
59
+ s1.write 'foobar'
60
+ s2.read(6).should == 'foobar'
81
61
 
82
- @actor_run.should be_true
62
+ s1.close
83
63
  end
84
64
  end
@@ -6,24 +6,22 @@ begin_time = Time.now
6
6
 
7
7
  puts "#{begin_time.strftime('%H:%M:%S')} -- Sending #{NTIMES} messages"
8
8
 
9
- Actor.start do
10
- parent = Actor.current
11
- child = Actor.spawn do
12
- (NTIMES / 2).times do
13
- Actor.receive do |f|
14
- f.when(:foo) { parent << :bar }
15
- end
16
- end
17
- end
18
-
19
- child << :foo
9
+ parent = Actor.current
10
+ child = Actor.spawn do
20
11
  (NTIMES / 2).times do
21
12
  Actor.receive do |f|
22
- f.when(:bar) { child << :foo }
13
+ f.when(:foo) { parent << :bar }
23
14
  end
24
15
  end
25
16
  end
26
17
 
18
+ child << :foo
19
+ (NTIMES / 2).times do
20
+ Actor.receive do |f|
21
+ f.when(:bar) { child << :foo }
22
+ end
23
+ end
24
+
27
25
  end_time = Time.now
28
26
  duration = end_time - begin_time
29
27
  throughput = NTIMES / duration
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: revactor
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2008-01-15 00:00:00 -07:00
6
+ version: 0.1.1
7
+ date: 2008-01-28 00:00:00 -07:00
8
8
  summary: Revactor is an Actor implementation for writing high performance concurrent programs
9
9
  require_paths:
10
10
  - lib
@@ -31,13 +31,13 @@ authors:
31
31
  files:
32
32
  - lib/revactor
33
33
  - lib/revactor/actor.rb
34
- - lib/revactor/behaviors
35
- - lib/revactor/behaviors/server.rb
34
+ - lib/revactor/delegator.rb
36
35
  - lib/revactor/filters
37
36
  - lib/revactor/filters/line.rb
38
37
  - lib/revactor/filters/packet.rb
38
+ - lib/revactor/mailbox.rb
39
39
  - lib/revactor/mongrel.rb
40
- - lib/revactor/server.rb
40
+ - lib/revactor/scheduler.rb
41
41
  - lib/revactor/tcp.rb
42
42
  - lib/revactor.rb
43
43
  - examples/echo_server.rb
@@ -45,6 +45,7 @@ files:
45
45
  - examples/mongrel.rb
46
46
  - tools/messaging_throughput.rb
47
47
  - spec/actor_spec.rb
48
+ - spec/delegator_spec.rb
48
49
  - spec/line_filter_spec.rb
49
50
  - spec/packet_filter_spec.rb
50
51
  - spec/tcp_spec.rb
@@ -79,7 +80,7 @@ dependencies:
79
80
  requirements:
80
81
  - - ">="
81
82
  - !ruby/object:Gem::Version
82
- version: 0.1.3
83
+ version: 0.1.4
83
84
  version:
84
85
  - !ruby/object:Gem::Dependency
85
86
  name: case
@@ -88,5 +89,5 @@ dependencies:
88
89
  requirements:
89
90
  - - ">="
90
91
  - !ruby/object:Gem::Version
91
- version: "0.3"
92
+ version: "0.4"
92
93
  version:
@@ -1,87 +0,0 @@
1
- #--
2
- # Copyright (C)2007 Tony Arcieri
3
- # You can redistribute this under the terms of the Ruby license
4
- # See file LICENSE for details
5
- #++
6
-
7
- module Revactor
8
- module Behavior
9
- # The Server behavior provides a callback-driven class which eases the
10
- # creation of standard synchronous "blocking" calls by abstracting away
11
- # inter-Actor communication and also providing baked-in state management.
12
- #
13
- # This behavior module provides the base set of callbacks necessary
14
- # to implement the behavior. It also provides descriptions for what
15
- # certain callback methods should do.
16
- #
17
- # When used properly, the server behavior can implement transactional
18
- # semantics, ensuring only successful calls mutate the previous state
19
- # and erroneous/exception-raising ones do not.
20
- #
21
- # The design is modeled off Erlang/OTP's gen_server
22
- module Server
23
- # Initialize the server state. Can return:
24
- #
25
- # start(*args)
26
- # -> [:ok, state]
27
- # -> [:ok, state, timeout]
28
- # -> [:stop, reason]
29
- #
30
- # The state variable allows you to provide a set of state whose mutation
31
- # can be controlled a lot more closely than is possible with standard
32
- # object oriented behavior. The latest version of state is passed
33
- # to all Revactor::Server callbacks and is only mutated upon a
34
- # successful return (unless an exception was raised)
35
- #
36
- def start(*args)
37
- return :ok
38
- end
39
-
40
- # Handle any calls made to a Reactor::Server object, which are captured
41
- # via method_missing and dispatched here. Calls provide synchronous
42
- # behavior: the callee will block until this method completss and a
43
- # reply is sent back to them. Can return:
44
- #
45
- # handle_call(message, from, state)
46
- # -> [:reply, reply, new_state]
47
- # -> [:reply, reply, new_state, timeout]
48
- # -> [:noreply, new_state]
49
- # -> [:noreply, new_state, timeout]
50
- # -> [:stop, reason, reply, new_state]
51
- #
52
- def handle_call(message, from, state)
53
- return :reply, :ok, state
54
- end
55
-
56
- # Handle calls without return values
57
- #
58
- # handle_cast(message, state)
59
- # -> [:noreply, new_state]
60
- # -> [:noreply, new_state, timeout]
61
- # -> [:stop, reason, new_state]
62
- #
63
- def handle_cast(message, state)
64
- return :noreply, state
65
- end
66
-
67
- # Handle any spontaneous messages to the server which are not calls
68
- # or casts made from Rev::Server. Can return:
69
- #
70
- # handle_info(info, state)
71
- # -> [:noreply, new_state]
72
- # -> [:noreply, new_state, timeout]
73
- # -> [:stop, reason, new_state]
74
- #
75
- def handle_info(info, state)
76
- return :noreply, state
77
- end
78
-
79
- # Method called when the server is about to terminate, for example when
80
- # any of the handle_* routines above return :stop. The return value of
81
- # terminate is discarded.
82
- #
83
- def terminate(reason, state)
84
- end
85
- end
86
- end
87
- end
@@ -1,153 +0,0 @@
1
- #--
2
- # Copyright (C)2007 Tony Arcieri
3
- # You can redistribute this under the terms of the Ruby license
4
- # See file LICENSE for details
5
- #++
6
-
7
- require File.dirname(__FILE__) + '/../revactor'
8
-
9
- module Revactor
10
- # Revactor::Server wraps an Actor's receive loop and issues callbacks to
11
- # a class which implements Revactor::Behaviors::Server. It eases the
12
- # creation of standard synchronous "blocking" calls by abstracting away
13
- # inter-Actor communication and also providing baked-in state management.
14
- #
15
- # When used properly, Revactor::Server can implement transactional
16
- # semantics, ensuring only successful calls mutate the previous state
17
- # and erroneous/exception-raising ones do not.
18
- #
19
- # The design is modeled off Erlang/OTP's gen_server
20
- class Server
21
- # How long to wait for a response to a call before timing out
22
- # This value also borrowed from Erlang. More cargo culting!
23
- DEFAULT_CALL_TIMEOUT = 5
24
-
25
- # Create a new server. Accepts the following options:
26
- #
27
- # register: Register the Actor in the Actor registry under
28
- # the given term
29
- #
30
- # Any options passed after the options hash are passed to the
31
- # start method of the given object.
32
- #
33
- def initialize(obj, options = {}, *args)
34
- @obj = obj
35
- @timeout = nil
36
- @state = obj.start(*args)
37
- @actor = Actor.new(&method(:start).to_proc)
38
-
39
- Actor[options[:register]] = @actor if options[:register]
40
- end
41
-
42
- # Call the server with the given message
43
- def call(message, options = {})
44
- options[:timeout] ||= DEFAULT_CALL_TIMEOUT
45
-
46
- @actor << T[:call, Actor.current, message]
47
- Actor.receive do |filter|
48
- filter.when(Case[:call_reply, @actor, Object]) { |_, _, reply| reply }
49
- filter.when(Case[:call_error, @actor, Object]) { |_, _, ex| raise ex }
50
- filter.after(options[:timeout]) { raise 'timeout' }
51
- end
52
- end
53
-
54
- # Send a cast to the server
55
- def cast(message)
56
- @actor << T[:cast, message]
57
- message
58
- end
59
-
60
- #########
61
- protected
62
- #########
63
-
64
- # Start the server
65
- def start
66
- @running = true
67
- while @running do
68
- Actor.receive do |filter|
69
- filter.when(Object) { |message| handle_message(message) }
70
- filter.after(@timeout) { stop(:timeout) } if @timeout
71
- end
72
- end
73
- end
74
-
75
- # Dispatch the incoming message to the appropriate handler
76
- def handle_message(message)
77
- case message.first
78
- when :call then handle_call(message)
79
- when :cast then handle_cast(message)
80
- else handle_info(message)
81
- end
82
- end
83
-
84
- # Wrapper for calling the provided object's handle_call method
85
- def handle_call(message)
86
- _, from, body = message
87
-
88
- begin
89
- result = @obj.handle_call(body, from, @state)
90
- case result.first
91
- when :reply
92
- _, reply, @state, @timeout = result
93
- from << T[:call_reply, Actor.current, reply]
94
- when :noreply
95
- _, @state, @timeout = result
96
- when :stop
97
- _, reason, @state = result
98
- stop(reason)
99
- end
100
- rescue Exception => ex
101
- log_exception(ex)
102
- from << T[:call_error, Actor.current, ex]
103
- end
104
- end
105
-
106
- # Wrapper for calling the provided object's handle_cast method
107
- def handle_cast(message)
108
- _, body = message
109
-
110
- begin
111
- result = @obj.handle_cast(body, @state)
112
- case result.first
113
- when :noreply
114
- _, @state, @timeout = result
115
- when :stop
116
- _, reason, @state = result
117
- stop(reason)
118
- end
119
- rescue Exception => e
120
- log_exception(e)
121
- end
122
- end
123
-
124
- # Wrapper for calling the provided object's handle_info method
125
- def handle_info(message)
126
- begin
127
- result = @obj.handle_info(message, @state)
128
- case result.first
129
- when :noreply
130
- _, @state, @timeout = result
131
- when :stop
132
- _, reason, @state = result
133
- stop(reason)
134
- end
135
- rescue Exception => e
136
- log_exception(e)
137
- end
138
- end
139
-
140
- # Stop the server
141
- def stop(reason)
142
- @running = false
143
- @obj.terminate(reason, @state)
144
- end
145
-
146
- # Log an exception
147
- def log_exception(exception)
148
- # FIXME this should really go to a logger, not STDERR
149
- STDERR.puts "Rev::Server exception: #{exception}"
150
- STDERR.puts exception.backtrace
151
- end
152
- end
153
- end