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



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

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

Instance Method Details

#_dump(depth) ⇒ Object



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

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

#can_read?Boolean

Returns true if you can read from this pipe.

Returns:

  • (Boolean)


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

def can_read?
  not r.nil?
end

#can_write?Boolean

Returns true if you can write to this pipe.

Returns:

  • (Boolean)


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

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:



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

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.



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

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


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

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
# File 'lib/cod/pipe.rb', line 105

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

#rObject

Returns the read end of the pipe



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

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.



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

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:



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

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



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

def to_read_fds
  r
end

#wObject

Returns the write end of the pipe



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

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