cod 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/HISTORY.txt +5 -1
- data/README +12 -13
- data/Rakefile +7 -1
- data/examples/{ping.rb → ping_pong/ping.rb} +1 -1
- data/examples/{pong.rb → ping_pong/pong.rb} +1 -1
- data/examples/{presence_client.rb → presence/client.rb} +0 -0
- data/examples/{presence_server.rb → presence/server.rb} +0 -0
- data/examples/queue/README +9 -0
- data/examples/queue/client.rb +31 -0
- data/examples/queue/queue.rb +51 -0
- data/examples/queue/send.rb +9 -0
- data/examples/service.rb +2 -2
- data/examples/tcp.rb +1 -1
- data/lib/cod.rb +47 -82
- data/lib/cod/beanstalk.rb +7 -0
- data/lib/cod/beanstalk/channel.rb +170 -0
- data/lib/cod/beanstalk/serializer.rb +80 -0
- data/lib/cod/beanstalk/service.rb +53 -0
- data/lib/cod/channel.rb +54 -12
- data/lib/cod/pipe.rb +188 -0
- data/lib/cod/select.rb +47 -0
- data/lib/cod/select_group.rb +87 -0
- data/lib/cod/service.rb +55 -42
- data/lib/cod/simple_serializer.rb +19 -0
- data/lib/cod/tcp_client.rb +202 -0
- data/lib/cod/tcp_server.rb +124 -0
- data/lib/cod/work_queue.rb +129 -0
- metadata +31 -45
- data/examples/pubsub/README +0 -12
- data/examples/pubsub/client.rb +0 -13
- data/examples/pubsub/directory.rb +0 -13
- data/examples/service_directory.rb +0 -32
- data/lib/cod/channel/base.rb +0 -185
- data/lib/cod/channel/beanstalk.rb +0 -69
- data/lib/cod/channel/pipe.rb +0 -137
- data/lib/cod/channel/tcp.rb +0 -16
- data/lib/cod/channel/tcpconnection.rb +0 -67
- data/lib/cod/channel/tcpserver.rb +0 -84
- data/lib/cod/client.rb +0 -81
- data/lib/cod/connection/beanstalk.rb +0 -77
- data/lib/cod/directory.rb +0 -98
- data/lib/cod/directory/countdown.rb +0 -31
- data/lib/cod/directory/subscription.rb +0 -59
- data/lib/cod/object_io.rb +0 -6
- data/lib/cod/objectio/connection.rb +0 -106
- data/lib/cod/objectio/reader.rb +0 -98
- data/lib/cod/objectio/serializer.rb +0 -26
- data/lib/cod/objectio/writer.rb +0 -27
- data/lib/cod/topic.rb +0 -95
@@ -0,0 +1,129 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Cod
|
4
|
+
# Describes a queue that stores work items given through #schedule and works
|
5
|
+
# through those items in order if #predicate is true.
|
6
|
+
#
|
7
|
+
# Synopsis:
|
8
|
+
# queue = WorkQueue.new
|
9
|
+
# queue.predicate { true }
|
10
|
+
# queue.schedule {
|
11
|
+
# # some work
|
12
|
+
# }
|
13
|
+
#
|
14
|
+
# # Will try to work through items right now.
|
15
|
+
# queue.try_work
|
16
|
+
#
|
17
|
+
# # Will cleanly shutdown background threads, but not finish work.
|
18
|
+
# queue.shutdown
|
19
|
+
#
|
20
|
+
class WorkQueue # :nodoc:
|
21
|
+
def initialize
|
22
|
+
# NOTE: This is an array that is protected by careful coding, rather
|
23
|
+
# than a mutex. Queue would be right, but Rubys GIL will interfere with
|
24
|
+
# that producing more deadlocks than I would like.
|
25
|
+
@queue = Array.new
|
26
|
+
|
27
|
+
@try_work_exclusive_section = ExclusiveSection.new
|
28
|
+
|
29
|
+
@thread = Thread.start(&method(:thread_main))
|
30
|
+
end
|
31
|
+
|
32
|
+
# The internal thread that is used to work on scheduled items in the
|
33
|
+
# background.
|
34
|
+
attr_reader :thread
|
35
|
+
|
36
|
+
def try_work
|
37
|
+
@try_work_exclusive_section.enter {
|
38
|
+
# NOTE if predicate is nil or not set, no work will be accomplished.
|
39
|
+
# This is the way I need it.
|
40
|
+
while !@queue.empty? && @predicate && @predicate.call
|
41
|
+
wi = @queue.shift
|
42
|
+
wi.call
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Before any kind of work is attempted, this predicate must evaluate to
|
48
|
+
# true. It is tested repeatedly.
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
# work_queue.predicate { connection.established? }
|
52
|
+
#
|
53
|
+
def predicate(&predicate)
|
54
|
+
@predicate = predicate
|
55
|
+
end
|
56
|
+
|
57
|
+
# Schedules a piece of work.
|
58
|
+
# Example:
|
59
|
+
# work_queue.schedule { a_piece_of_work }
|
60
|
+
#
|
61
|
+
def schedule(&work)
|
62
|
+
@queue << work
|
63
|
+
end
|
64
|
+
|
65
|
+
# Shuts down the queue properly, without waiting for work to be completed.
|
66
|
+
#
|
67
|
+
def shutdown
|
68
|
+
@shutdown_requested = true
|
69
|
+
@thread.join
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the size of the queue.
|
73
|
+
#
|
74
|
+
def size
|
75
|
+
@queue.size
|
76
|
+
end
|
77
|
+
|
78
|
+
def clear_thread_semaphore
|
79
|
+
@one_turn = false
|
80
|
+
end
|
81
|
+
def thread_semaphore_set?
|
82
|
+
@one_turn
|
83
|
+
end
|
84
|
+
private
|
85
|
+
def thread_main
|
86
|
+
Thread.current.abort_on_exception = true
|
87
|
+
|
88
|
+
loop do
|
89
|
+
sleep 0.01
|
90
|
+
|
91
|
+
try_work
|
92
|
+
|
93
|
+
# Signal the outside world that we've been around this loop once.
|
94
|
+
# See #clear_thread_semaphore and #thread_semaphore_set?
|
95
|
+
@one_turn = true
|
96
|
+
|
97
|
+
return if @shutdown_requested
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# A section of code that is entered only once. Instead of blocking threads
|
103
|
+
# that are waiting to enter, it just returns nil.
|
104
|
+
#
|
105
|
+
class ExclusiveSection # :nodoc:
|
106
|
+
def initialize
|
107
|
+
@mutex = Mutex.new
|
108
|
+
@threads_in_block = 0
|
109
|
+
end
|
110
|
+
|
111
|
+
# If no one is in the block given to #enter currently, this will yield
|
112
|
+
# to the block. If one thread is already executing that block, it will
|
113
|
+
# return nil.
|
114
|
+
#
|
115
|
+
def enter
|
116
|
+
@mutex.synchronize {
|
117
|
+
return if @threads_in_block > 0
|
118
|
+
@threads_in_block += 1 }
|
119
|
+
begin
|
120
|
+
yield
|
121
|
+
ensure
|
122
|
+
fail "Assert fails, #{@threads_in_block} threads in block" \
|
123
|
+
if @threads_in_block != 1
|
124
|
+
@mutex.synchronize {
|
125
|
+
@threads_in_block -= 1 }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-11-29 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: uuid
|
16
|
-
requirement: &70169583690420 !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '2'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: *70169583690420
|
25
14
|
- !ruby/object:Gem::Dependency
|
26
15
|
name: rspec
|
27
|
-
requirement: &
|
16
|
+
requirement: &70297088779060 !ruby/object:Gem::Requirement
|
28
17
|
none: false
|
29
18
|
requirements:
|
30
19
|
- - ! '>='
|
@@ -32,10 +21,10 @@ dependencies:
|
|
32
21
|
version: '0'
|
33
22
|
type: :development
|
34
23
|
prerelease: false
|
35
|
-
version_requirements: *
|
24
|
+
version_requirements: *70297088779060
|
36
25
|
- !ruby/object:Gem::Dependency
|
37
26
|
name: flexmock
|
38
|
-
requirement: &
|
27
|
+
requirement: &70297088777820 !ruby/object:Gem::Requirement
|
39
28
|
none: false
|
40
29
|
requirements:
|
41
30
|
- - ! '>='
|
@@ -43,10 +32,10 @@ dependencies:
|
|
43
32
|
version: '0'
|
44
33
|
type: :development
|
45
34
|
prerelease: false
|
46
|
-
version_requirements: *
|
35
|
+
version_requirements: *70297088777820
|
47
36
|
- !ruby/object:Gem::Dependency
|
48
37
|
name: sdoc
|
49
|
-
requirement: &
|
38
|
+
requirement: &70297088776720 !ruby/object:Gem::Requirement
|
50
39
|
none: false
|
51
40
|
requirements:
|
52
41
|
- - ! '>='
|
@@ -54,7 +43,7 @@ dependencies:
|
|
54
43
|
version: '0'
|
55
44
|
type: :development
|
56
45
|
prerelease: false
|
57
|
-
version_requirements: *
|
46
|
+
version_requirements: *70297088776720
|
58
47
|
description:
|
59
48
|
email: kaspar.schiess@absurd.li
|
60
49
|
executables: []
|
@@ -67,37 +56,31 @@ files:
|
|
67
56
|
- LICENSE
|
68
57
|
- Rakefile
|
69
58
|
- README
|
70
|
-
- lib/cod/channel
|
71
|
-
- lib/cod/
|
72
|
-
- lib/cod/
|
73
|
-
- lib/cod/
|
74
|
-
- lib/cod/channel/tcpconnection.rb
|
75
|
-
- lib/cod/channel/tcpserver.rb
|
59
|
+
- lib/cod/beanstalk/channel.rb
|
60
|
+
- lib/cod/beanstalk/serializer.rb
|
61
|
+
- lib/cod/beanstalk/service.rb
|
62
|
+
- lib/cod/beanstalk.rb
|
76
63
|
- lib/cod/channel.rb
|
77
|
-
- lib/cod/
|
78
|
-
- lib/cod/
|
79
|
-
- lib/cod/
|
80
|
-
- lib/cod/directory/subscription.rb
|
81
|
-
- lib/cod/directory.rb
|
82
|
-
- lib/cod/object_io.rb
|
83
|
-
- lib/cod/objectio/connection.rb
|
84
|
-
- lib/cod/objectio/reader.rb
|
85
|
-
- lib/cod/objectio/serializer.rb
|
86
|
-
- lib/cod/objectio/writer.rb
|
64
|
+
- lib/cod/pipe.rb
|
65
|
+
- lib/cod/select.rb
|
66
|
+
- lib/cod/select_group.rb
|
87
67
|
- lib/cod/service.rb
|
88
|
-
- lib/cod/
|
68
|
+
- lib/cod/simple_serializer.rb
|
69
|
+
- lib/cod/tcp_client.rb
|
70
|
+
- lib/cod/tcp_server.rb
|
71
|
+
- lib/cod/work_queue.rb
|
89
72
|
- lib/cod.rb
|
90
73
|
- examples/example_scaffold.rb
|
91
74
|
- examples/master_child.rb
|
92
|
-
- examples/ping.rb
|
93
|
-
- examples/pong.rb
|
94
|
-
- examples/
|
95
|
-
- examples/
|
96
|
-
- examples/
|
97
|
-
- examples/
|
98
|
-
- examples/
|
75
|
+
- examples/ping_pong/ping.rb
|
76
|
+
- examples/ping_pong/pong.rb
|
77
|
+
- examples/presence/client.rb
|
78
|
+
- examples/presence/server.rb
|
79
|
+
- examples/queue/client.rb
|
80
|
+
- examples/queue/queue.rb
|
81
|
+
- examples/queue/README
|
82
|
+
- examples/queue/send.rb
|
99
83
|
- examples/service.rb
|
100
|
-
- examples/service_directory.rb
|
101
84
|
- examples/tcp.rb
|
102
85
|
homepage: http://kschiess.github.com/cod
|
103
86
|
licenses: []
|
@@ -113,6 +96,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
96
|
- - ! '>='
|
114
97
|
- !ruby/object:Gem::Version
|
115
98
|
version: '0'
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
hash: -3574736004851783821
|
116
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
103
|
none: false
|
118
104
|
requirements:
|
@@ -121,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
107
|
version: '0'
|
122
108
|
requirements: []
|
123
109
|
rubyforge_project:
|
124
|
-
rubygems_version: 1.8.
|
110
|
+
rubygems_version: 1.8.10
|
125
111
|
signing_key:
|
126
112
|
specification_version: 3
|
127
113
|
summary: Really simple IPC.
|
data/examples/pubsub/README
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
|
2
|
-
This is an example of PUB/SUB style messaging. You should run one directory
|
3
|
-
and any number of clients. All clients should receive timestamps from the directory, once every second.
|
4
|
-
|
5
|
-
Experiments that can be made using this setup:
|
6
|
-
|
7
|
-
1) Disconnect a client, restart it. It should start receiving updates
|
8
|
-
immediately.
|
9
|
-
|
10
|
-
2) Disconnect the directory, restart it. It should start redistributing
|
11
|
-
updates to all clients within 5 seconds.
|
12
|
-
|
data/examples/pubsub/client.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
channels = Struct.new(:directory, :answers).new(
|
5
|
-
Cod.beanstalk('localhost:11300', 'directory'),
|
6
|
-
Cod.beanstalk('localhost:11300', 'directory.'+Cod.uuid))
|
7
|
-
|
8
|
-
topic = Cod::Topic.new('', channels.directory, channels.answers, :renew => 5)
|
9
|
-
|
10
|
-
loop do
|
11
|
-
puts topic.get
|
12
|
-
end
|
13
|
-
|
@@ -1,13 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
channels = Struct.new(:directory).new(
|
5
|
-
Cod.beanstalk('localhost:11300', 'directory'))
|
6
|
-
|
7
|
-
directory = Cod::Directory.new(channels.directory)
|
8
|
-
|
9
|
-
loop do
|
10
|
-
directory.publish '', Time.now
|
11
|
-
sleep 1
|
12
|
-
end
|
13
|
-
|
@@ -1,32 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
announce = Cod.pipe
|
5
|
-
directory = Cod::Directory.new(announce)
|
6
|
-
|
7
|
-
pipes = []
|
8
|
-
pids = ['foo.bar', /^foo\..+/].map { |match_expr|
|
9
|
-
# Creates a communication channel that both the parent and the child know
|
10
|
-
# about. After the fork, they will own unique ends to that channel.
|
11
|
-
pipes << pipe = Cod.pipe # store in pipes as well to prevent GC
|
12
|
-
|
13
|
-
# Create a child that will receive messages that match match_expr.
|
14
|
-
fork do
|
15
|
-
puts "Spawned child: #{Process.pid}"
|
16
|
-
topic = Cod::Topic.new(match_expr, announce, pipe)
|
17
|
-
|
18
|
-
sleep 0.1
|
19
|
-
loop do
|
20
|
-
message = topic.get
|
21
|
-
puts "#{Process.pid}: received #{message.inspect}."
|
22
|
-
|
23
|
-
break if message == :shutdown
|
24
|
-
end
|
25
|
-
end }
|
26
|
-
|
27
|
-
directory.publish 'foo.bar', 'Hi everyone!' # to both childs
|
28
|
-
directory.publish 'foo.baz', 'Hi you!' # only second child matches this
|
29
|
-
directory.publish 'no.one', 'echo?' # no one matches this
|
30
|
-
|
31
|
-
directory.publish 'foo.bar', :shutdown # shutdown children in orderly fashion
|
32
|
-
Process.waitall
|
data/lib/cod/channel/base.rb
DELETED
@@ -1,185 +0,0 @@
|
|
1
|
-
|
2
|
-
module Cod
|
3
|
-
# Channels are the communication primitives you've always wanted (secretly).
|
4
|
-
# They are simple to use, abstract most of the OS away and allow direct
|
5
|
-
# communication using language objects, not just strings. (Although you can
|
6
|
-
# fall back to just strings if you want to)
|
7
|
-
#
|
8
|
-
# == Construction
|
9
|
-
#
|
10
|
-
# The simplest way to obtain a new channel is through the Module Cod. It
|
11
|
-
# provides the following channel types:
|
12
|
-
#
|
13
|
-
# Cod.beanstalk(url, name) :: connects to beanstalkd daemon
|
14
|
-
# Cod.pipe :: abstracts IO.pipe
|
15
|
-
# Cod.tcp(url) :: connects to a tcp socket somewhere
|
16
|
-
# Cod.tcpserver(url) :: the counterpart to Cod.tcp
|
17
|
-
#
|
18
|
-
# Please refer to the documentation of these methods for more information.
|
19
|
-
#
|
20
|
-
# == Basic Interaction
|
21
|
-
#
|
22
|
-
# You can #put messages (Ruby objects) into a channel on one side:
|
23
|
-
#
|
24
|
-
# channel.put("some message")
|
25
|
-
#
|
26
|
-
# and #get messages on the other side:
|
27
|
-
#
|
28
|
-
# channel.get # => "some message"
|
29
|
-
#
|
30
|
-
# == Querying
|
31
|
-
#
|
32
|
-
# Are there messages waiting to be read from the channel? Use #waiting?:
|
33
|
-
#
|
34
|
-
# channel.waiting? # => true or false
|
35
|
-
#
|
36
|
-
# == Cleaning up
|
37
|
-
#
|
38
|
-
# Be sure to #close the channel once you're done with it.
|
39
|
-
#
|
40
|
-
# channel.close
|
41
|
-
#
|
42
|
-
class Channel::Base
|
43
|
-
def initialize(reader, writer)
|
44
|
-
@reader = reader
|
45
|
-
@writer = writer
|
46
|
-
end
|
47
|
-
|
48
|
-
# Writes a Ruby object (the 'message') to the channel. This object will
|
49
|
-
# be queued in the channel and become available for #get in a FIFO manner.
|
50
|
-
#
|
51
|
-
# Issuing a #put may also close the channel instance for subsequent #get's.
|
52
|
-
#
|
53
|
-
# Example:
|
54
|
-
# chan.put 'test'
|
55
|
-
# chan.put true
|
56
|
-
# chan.put :symbol
|
57
|
-
#
|
58
|
-
def put(message)
|
59
|
-
# TODO Errno::EPIPE raised after a while when the receiver goes away.
|
60
|
-
@writer.put(message)
|
61
|
-
end
|
62
|
-
|
63
|
-
# Reads a Ruby object (a message) from the channel. Some channels may not
|
64
|
-
# allow reading after you've written to it once. Options that work:
|
65
|
-
#
|
66
|
-
# <code>:timeout</code> :: Time to wait before throwing Cod::Channel::TimeoutError.
|
67
|
-
#
|
68
|
-
def get(opts={})
|
69
|
-
@reader.get(opts)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Returns true if there are messages waiting in the channel.
|
73
|
-
#
|
74
|
-
def waiting?
|
75
|
-
# TODO EOFError is thrown when the other end has gone away
|
76
|
-
@reader.waiting?
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns true if the channel is connected, and false if all hope must be
|
80
|
-
# given up of reconnecting this channel.
|
81
|
-
#
|
82
|
-
def connected?
|
83
|
-
not_implemented
|
84
|
-
end
|
85
|
-
|
86
|
-
# Closes reader and writer.
|
87
|
-
#
|
88
|
-
def close
|
89
|
-
@reader.close if @reader
|
90
|
-
@writer.close if @writer
|
91
|
-
|
92
|
-
@reader = @writer = nil
|
93
|
-
end
|
94
|
-
|
95
|
-
# Returns the Identifier class below the current channel class. This is
|
96
|
-
# a helper function that should only be used by subclasses.
|
97
|
-
#
|
98
|
-
def identifier_class # :nodoc:
|
99
|
-
self.class.const_get(:Identifier)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Something to put into the data stream that is transmitted through a
|
103
|
-
# channel that allows reconstitution of the channel at the other end.
|
104
|
-
# The invariant is this:
|
105
|
-
#
|
106
|
-
# # channel1 and channel2 are abstract channels that illustrate my
|
107
|
-
# # meaning
|
108
|
-
# channel1.put channel2
|
109
|
-
# channel2a = channel1.get
|
110
|
-
# channel2a.put 'foo'
|
111
|
-
# channel2.get # => 'foo'
|
112
|
-
#
|
113
|
-
# Note that this should also work if channel1 and channel2 are the same.
|
114
|
-
#
|
115
|
-
def identifier # :nodoc:
|
116
|
-
identifier_class.new(self)
|
117
|
-
end
|
118
|
-
|
119
|
-
# ------------------------------------------------------------ marshalling
|
120
|
-
|
121
|
-
# Makes sure that we don't marshal this object, but the memento object
|
122
|
-
# returned by identifier.
|
123
|
-
#
|
124
|
-
def _dump(d) # :nodoc:
|
125
|
-
wire_data = to_wire_data
|
126
|
-
Marshal.dump(wire_data)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Loads the object from string. This doesn't always return the same kind
|
130
|
-
# of object that was serialized.
|
131
|
-
#
|
132
|
-
def self._load(string) # :nodoc:
|
133
|
-
wire_data = Marshal.load(string)
|
134
|
-
from_wire_data(wire_data)
|
135
|
-
end
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
|
-
# Returns the objects that need to be transmitted in order to reconstruct
|
140
|
-
# this object after transmission through the wire.
|
141
|
-
#
|
142
|
-
# If you're using a serialisation method other than the Ruby built in
|
143
|
-
# one, use this to obtain something in lieu of a channel that can be sent
|
144
|
-
# through the wire and reinterpreted at the other end.
|
145
|
-
#
|
146
|
-
# Example:
|
147
|
-
#
|
148
|
-
# # this should work:
|
149
|
-
# obj = channel.to_wire_data
|
150
|
-
# channel_equiv = Cod::Channel::Base.from_wire_data(obj)
|
151
|
-
#
|
152
|
-
def to_wire_data
|
153
|
-
identifier
|
154
|
-
end
|
155
|
-
|
156
|
-
# Using an object previously returned by #to_wire_data, reconstitute the
|
157
|
-
# original channel or something that is alike it. What you send to this
|
158
|
-
# second channel (#put) you should be able to #get from this copy returned
|
159
|
-
# here.
|
160
|
-
#
|
161
|
-
def self.from_wire_data(obj)
|
162
|
-
obj.resolve
|
163
|
-
end
|
164
|
-
|
165
|
-
# ---------------------------------------------------------- error raising
|
166
|
-
|
167
|
-
def direction_error(msg)
|
168
|
-
raise Cod::Channel::DirectionError, msg
|
169
|
-
end
|
170
|
-
|
171
|
-
def communication_error(msg)
|
172
|
-
raise Cod::Channel::CommunicationError, msg
|
173
|
-
end
|
174
|
-
|
175
|
-
def not_implemented
|
176
|
-
trace = caller.reject {|l| l =~ %r{#{Regexp.escape(__FILE__)}}} # blatantly stolen from dependencies.rb in activesupport
|
177
|
-
exception = NotImplementedError.new(
|
178
|
-
"You called a method in Cod::Channel::Base. Missing implementation in "+
|
179
|
-
"the subclass #{self.class.name}!")
|
180
|
-
exception.set_backtrace trace
|
181
|
-
|
182
|
-
raise exception
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|