Class: Cod::Pipe

Inherits:
Channel show all
Defined in:
lib/cod/pipe.rb

Overview

A cod channel based on IO.pipe.

Note that if you embed Cod::Pipe channels into your messages, Cod will insert the object id of that channel into the byte stream that is transmitted. On receiving such an object id (a machine pointer), Cod will try to reconstruct the channel that was at the origin of the id. This can obviously only work if you have such an object in your address space. There are multiple ways to construct such a situation. Say you want to send a pipe channel to one of your (forked) childs: This will work if you create the channel before forking the child, since master and child will share all objects that were available before the fork.

Defined Under Namespace

Modules: SplitMethods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Channel

#interact

Constructor Details

#initialize(serializer = nil, pipe_pair = nil) ⇒ Pipe

Creates a Cod::Pipe.



36
37
38
39
40
# File 'lib/cod/pipe.rb', line 36

def initialize(serializer=nil, pipe_pair=nil)
  super()
  @serializer = serializer || SimpleSerializer.new
  @pipe = IOPair.new(*pipe_pair)
end

Instance Attribute Details

#pipeObject (readonly)

The underlying IOPair.



18
19
20
# File 'lib/cod/pipe.rb', line 18

def pipe
  @pipe
end

#serializerObject (readonly)

The serializer for this pipe.



21
22
23
# File 'lib/cod/pipe.rb', line 21

def serializer
  @serializer
end

Class Method Details

._load(string) ⇒ Object



211
212
213
# File 'lib/cod/pipe.rb', line 211

def self._load(string) # :nodoc:
  ObjectSpace._id2ref(Integer(string))
end

Instance Method Details

#_dump(depth) ⇒ Object



206
207
208
# File 'lib/cod/pipe.rb', line 206

def _dump(depth) # :nodoc:
  object_id.to_s
end

#can_read?Boolean

Returns true if you can read from this pipe.

Returns:

  • (Boolean)


154
155
156
# File 'lib/cod/pipe.rb', line 154

def can_read?
  not r.nil?
end

#can_write?Boolean

Returns true if you can write to this pipe.

Returns:

  • (Boolean)


160
161
162
# File 'lib/cod/pipe.rb', line 160

def can_write?
  not pipe.w.nil?
end

#client(answers_to) ⇒ Cod::Service::Client

Produces a service client. Requests are sent to this channel, and answers are routed back to answers_to.

Parameters:

  • answers_to (Cod::Channel)

    Where answers should be addressed to.

Returns:



199
200
201
# File 'lib/cod/pipe.rb', line 199

def client(answers_to)
  Service::Client.new(self, answers_to)
end

#closevoid

This method returns an undefined value.

Closes the pipe completely. All active ends are closed. Note that you can call this function on a closed pipe without getting an error raised.



135
136
137
# File 'lib/cod/pipe.rb', line 135

def close
  pipe.close
end

#get(opts = {}) ⇒ Object

Using #get on a pipe instance will close the other pipe end. Subsequent #put will receive a Cod::InvalidOperation.

Examples:

pipe.get # => obj


119
120
121
122
123
124
125
126
127
128
# File 'lib/cod/pipe.rb', line 119

def get(opts={})
  raise Cod::WriteOnlyChannel unless can_read?
  pipe.close_w
  
  return deserialize_one
rescue EOFError
  raise Cod::ConnectionLost, 
    "All pipe ends seem to be closed. Reading from this pipe will not "+
    "return any data."
end

#initialize_copy(other) ⇒ Object

Creates a copy of this pipe channel. This performs a shallow #dup except for the file descriptors stored in the pipe, so that a #close affects only one copy.

Examples:

pipe.dup  # => anotherpipe


49
50
51
52
53
# File 'lib/cod/pipe.rb', line 49

def initialize_copy(other)
  super
  @serializer = other.serializer
  @pipe = other.pipe.dup
end

#put(obj) ⇒ void

This method returns an undefined value.

Using #put on a pipe instance will close the other pipe end. Subsequent #get will raise a Cod::InvalidOperation.

Examples:

pipe.put [:a, :message]

Parameters:

  • obj (Object)

    message to send to the channel

Raises:



105
106
107
108
109
110
111
# File 'lib/cod/pipe.rb', line 105

def put(obj)
  raise Cod::ReadOnlyChannel unless can_write?
  pipe.close_r
  
  pipe.write(
    serializer.en(obj))
end

#rObject

Returns the read end of the pipe



170
171
172
# File 'lib/cod/pipe.rb', line 170

def r
  pipe.r
end

#readonlyObject

Makes this pipe readonly. Calls to #put will error out. This closes the write end permanently and provokes end of file on the read end once all processes that posses a link to the write end do so.

Returns self so that you can write for example:

read_end = pipe.dup.readonly


64
65
66
67
# File 'lib/cod/pipe.rb', line 64

def readonly
  pipe.close_w
  self
end

#select(timeout = nil) ⇒ Object

Returns if this pipe is ready for reading.



141
142
143
144
# File 'lib/cod/pipe.rb', line 141

def select(timeout=nil)
  result = Cod.select(timeout, self)
  not result.nil?
end

#serviceCod::Service

Produces a service using this pipe as service channel.

Returns:

See Also:



189
190
191
# File 'lib/cod/pipe.rb', line 189

def service
  Service.new(self)
end

#splitArray<Cod::Channel>

Actively splits this pipe into two ends, a read end and a write end. The original pipe is closed, leaving only the two ends to work with. The read end can only be read from (#get) and the write end can only be written to (#put).

Returns:



88
89
90
91
92
93
94
# File 'lib/cod/pipe.rb', line 88

def split
  [self.dup.readonly, self.dup.writeonly].tap { |split|
    self.close
    
    split.extend(SplitMethods)
  }
end

#to_read_fdsObject



148
149
150
# File 'lib/cod/pipe.rb', line 148

def to_read_fds
  [r]
end

#wObject

Returns the write end of the pipe



178
179
180
# File 'lib/cod/pipe.rb', line 178

def w
  pipe.w
end

#writeonlyObject

Makes this pipe writeonly. Calls to #get will error out. See #readonly.

Returns self so that you can write for example:

write_end = pipe.dup.writeonly


76
77
78
79
# File 'lib/cod/pipe.rb', line 76

def writeonly
  pipe.close_r
  self
end