ichannel 5.2.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -9,5 +9,8 @@ env:
9
9
  - SERIALIZER=Marshal
10
10
  - SERIALIZER=JSON
11
11
 
12
+ services:
13
+ - redis-server
14
+
12
15
  notifications:
13
16
  email: true
data/ChangeLog.txt CHANGED
@@ -1,50 +1,65 @@
1
+ == v0.6.0
2
+ - IChannel::UNIXSocket can now be serialized by Marshal.
3
+ IChannel::UNIXSocket can be serialized by Marshal but there's a gotcha: it
4
+ only really works on the same machine between one or more Ruby processes.
5
+ The UNIXSocket#marshal_dump method is implemented to dump the FDs in an array,
6
+ so this feature won't fair well across different machines or time but I've
7
+ found this feature useful nonetheless.
8
+
9
+ - add IChannel.unix(…)
10
+ Returns an instance of IChannel::UNIXSocket.
11
+
12
+ - add IChannel::UNIXSocket
13
+ rename IChannel as IChannel::UNIXSocket in preparation for multiple
14
+ backends(UNIXSocket, Redis, …).
15
+
1
16
  == v5.2.0
2
- * add IChannel#last_msg.
17
+ - add IChannel#last_msg.
3
18
  Reads the last message written to the channel by reading until the channel
4
19
  is empty. The last message is cached and reset to nil on call to #close.
5
20
 
6
21
  == v5.1.1.1, v5.1.1.2, v5.1.1.3, v5.1.1.4, v5.1.1.5
7
- * doc improvements
22
+ - doc improvements
8
23
  a set of releases that improved the README & api docs.
9
24
 
10
25
  == v5.1.1
11
- * Change socket type to use TCP.
26
+ - Change socket type to use TCP.
12
27
  The use of UDP could result in bugs because of its unordered nature.
13
28
 
14
29
  == v5.1.0
15
- * Remove restriction on size of message.
30
+ - Remove restriction on size of message.
16
31
  IChannel#get can read a message of any size(before hand it was limited to
17
32
  1MB in size). Thanks to @quezacoatl.
18
33
 
19
- * IChannel#readable? no longer blocks.
34
+ - IChannel#readable? no longer blocks.
20
35
  IChannel#readable? no longer blocks for 0.1 seconds on IO.select call.
21
36
  Thanks to quezacoatl(https://github.com/quezacoatl) for the initial
22
37
  implementation.
23
38
 
24
39
  == v5.0.0
25
- * Remove IChannel#empty?
40
+ - Remove IChannel#empty?
26
41
  I think the #readable? method is all you need, and is a much more
27
42
  accurate description of what the method is asking. We cannot determine
28
43
  if the channel is really empty, but we can ask if it is readable at the
29
44
  time you ask.
30
45
 
31
46
  == v4.1.0
32
- * Add IChannel#readable?
47
+ - Add IChannel#readable?
33
48
  A method that can tell you whether or not a read would block.
34
49
  When it returns true, a read shouldn't block, on the other hand
35
50
  if it were false it'd likely block by the time you call #get.
36
51
 
37
52
  == v4.0.0
38
- * Modify IChannel#empty?
53
+ - Modify IChannel#empty?
39
54
  It now returns true in case the underlying UNIXSocket being used as a
40
55
  reader is closed.
41
56
 
42
57
  == v3.1.0
43
- * Add IChannel#empty?.
58
+ - Add IChannel#empty?.
44
59
  IChannel#empty? returns true when the channel is empty(nothing to read).
45
60
 
46
- * Micro speed improvement on #write!, & #recv! operations.
61
+ - Micro speed improvement on #write!, & #recv! operations.
47
62
  By passing nil instead of creating two empty arrays for every read/write
48
63
  operation we should see a very small improvement in their performance.
49
64
 
50
- * Add ChangeLog.txt
65
+ - Add ChangeLog.txt
data/README.md CHANGED
@@ -32,7 +32,7 @@ A demo of how to pass ruby objects through a channel and also between processes.
32
32
  in this example:
33
33
 
34
34
  ```ruby
35
- channel = IChannel.new Marshal
35
+ channel = IChannel.unix Marshal
36
36
  pid = fork do
37
37
  channel.put Process.pid
38
38
  channel.put 'Hello!'
@@ -48,7 +48,7 @@ Knowing when a channel is readable can be useful so that you can avoid a
48
48
  blocking read. This (bad) example demonstrates how to do that:
49
49
 
50
50
  ```ruby
51
- channel = IChannel.new Marshal
51
+ channel = IChannel.unix Marshal
52
52
  pid = fork do
53
53
  sleep 3
54
54
  channel.put 42
@@ -75,7 +75,7 @@ module MyMessagePack
75
75
  MessagePack.unpack(msg)
76
76
  end
77
77
  end
78
- channel = IChannel.new MyMessagePack
78
+ channel = IChannel.unix MyMessagePack
79
79
  ```
80
80
 
81
81
  __PLATFORM SUPPORT__
@@ -0,0 +1,174 @@
1
+ require 'socket'
2
+ class IChannel
3
+ class UNIXSocket
4
+ SEP = '_$_'
5
+ if respond_to? :private_constant
6
+ private_constant :SEP
7
+ end
8
+
9
+ #
10
+ # @param [#dump,#load] serializer
11
+ # Any object that implements dump, & load.
12
+ #
13
+ def initialize(serializer = Marshal, adapter_options)
14
+ @serializer = serializer
15
+ @last_msg = nil
16
+ @reader, @writer = ::UNIXSocket.pair :STREAM
17
+ end
18
+
19
+ #
20
+ # @return [Boolean]
21
+ # Returns true when the channel is closed.
22
+ #
23
+ def closed?
24
+ @reader.closed? && @writer.closed?
25
+ end
26
+
27
+ #
28
+ # Close the channel.
29
+ #
30
+ # @return [Boolean]
31
+ # Returns true when the channel has been closed.
32
+ #
33
+ def close
34
+ unless closed?
35
+ @reader.close
36
+ @writer.close
37
+ @last_msg = nil
38
+ true
39
+ end
40
+ end
41
+
42
+ #
43
+ # Add an object to the channel.
44
+ #
45
+ # @raise [IOError]
46
+ # When the channel is closed.
47
+ #
48
+ # @param [Object] object
49
+ # An object to add to the channel.
50
+ #
51
+ def write(object)
52
+ write!(object, nil)
53
+ end
54
+ alias_method :put, :write
55
+
56
+ #
57
+ # Add an object to the channel.
58
+ #
59
+ # Unlike {#write}, which waits indefinitely until the channel becomes writable,
60
+ # this method will raise an IOError when _timeout_ seconds elapse and
61
+ # the channel remains unwritable.
62
+ #
63
+ # @param
64
+ # (see IChannel#write)
65
+ #
66
+ # @param [Numeric] timeout
67
+ # The number of seconds to wait for the channel to become writable.
68
+ #
69
+ # @raise (see IChannel#write)
70
+ #
71
+ # @raise [IOError]
72
+ # When _timeout_ seconds elapse & the channel remains unwritable.
73
+ #
74
+ def write!(object, timeout = 0.1)
75
+ if @writer.closed?
76
+ raise IOError, 'The channel cannot be written to (closed).'
77
+ end
78
+ _, writable, _ = IO.select nil, [@writer], nil, timeout
79
+ if writable
80
+ msg = @serializer.dump(object)
81
+ writable[0].syswrite "#{msg}#{SEP}"
82
+ else
83
+ raise IOError, 'The channel cannot be written to.'
84
+ end
85
+ end
86
+ alias_method :put!, :write!
87
+
88
+ #
89
+ # Reads the last message written to the channel by reading until the channel
90
+ # is empty. The last message is cached and reset to nil on call to {#close}.
91
+ #
92
+ # @return [Object]
93
+ # Returns the last message to be written to the channel.
94
+ #
95
+ def last_msg
96
+ while readable?
97
+ @last_msg = get
98
+ end
99
+ @last_msg
100
+ end
101
+
102
+ #
103
+ # Receive an object from the channel.
104
+ #
105
+ # @raise [IOError]
106
+ # When the channel is closed.
107
+ #
108
+ # @return [Object]
109
+ # The object read from the channel.
110
+ #
111
+ def recv
112
+ recv!(nil)
113
+ end
114
+ alias_method :get, :recv
115
+
116
+ #
117
+ # Receive an object from the channel.
118
+ #
119
+ # Unlike {#recv}, which waits indefinitely until the channel becomes readable,
120
+ # this method will raise an IOError when _timeout_ seconds elapse and the
121
+ # channel remains unreadable.
122
+ #
123
+ # @param [Numeric] timeout
124
+ # The number of seconds to wait for the channel to become readable.
125
+ #
126
+ # @raise [IOError]
127
+ # (see IChannel#recv)
128
+ #
129
+ # @raise [IOError]
130
+ # When _timeout_ seconds elapse & the channel remains unreadable.
131
+ #
132
+ # @return [Object]
133
+ # The object read from the channel.
134
+ #
135
+ def recv!(timeout = 0.1)
136
+ if @reader.closed?
137
+ raise IOError, 'The channel cannot be read from (closed).'
138
+ end
139
+ readable, _ = IO.select [@reader], nil, nil, timeout
140
+ if readable
141
+ msg = readable[0].readline(SEP).chomp SEP
142
+ @serializer.load msg
143
+ else
144
+ raise IOError, 'The channel cannot be read from.'
145
+ end
146
+ end
147
+ alias_method :get!, :recv!
148
+
149
+ #
150
+ # @return [Boolean]
151
+ # Returns true when the channel is readable.
152
+ #
153
+ def readable?
154
+ if closed?
155
+ false
156
+ else
157
+ readable, _ = IO.select [@reader], nil, nil, 0
158
+ !! readable
159
+ end
160
+ end
161
+
162
+ # @api private
163
+ def marshal_load(array)
164
+ @serializer, reader, writer, @last_msg = array
165
+ @reader = ::UNIXSocket.for_fd(reader)
166
+ @writer = ::UNIXSocket.for_fd(writer)
167
+ end
168
+
169
+ # @api private
170
+ def marshal_dump
171
+ [@serializer, @reader.to_i, @writer.to_i, @last_msg]
172
+ end
173
+ end
174
+ end
@@ -1,3 +1,3 @@
1
1
  class IChannel
2
- VERSION = "5.2.0"
2
+ VERSION = "6.0.0"
3
3
  end
data/lib/ichannel.rb CHANGED
@@ -1,159 +1,11 @@
1
- require 'socket'
2
1
  class IChannel
3
- SEP = '_$_'
4
- if respond_to? :private_constant
5
- private_constant :SEP
6
- end
7
- #
8
- # @param [#dump,#load] serializer
9
- # Any object that implements dump, & load.
10
- #
11
- def initialize(serializer)
12
- @reader, @writer = UNIXSocket.pair :STREAM
13
- @serializer = serializer
14
- @last_msg = nil
15
- end
16
-
17
- #
18
- # @return [Boolean]
19
- # Returns true when the channel is closed.
20
- #
21
- def closed?
22
- @reader.closed? && @writer.closed?
23
- end
24
-
25
- #
26
- # Close the channel.
27
- #
28
- # @return [Boolean]
29
- # Returns true when the channel has been closed.
30
- #
31
- def close
32
- unless closed?
33
- @reader.close
34
- @writer.close
35
- @last_msg = nil
36
- true
37
- end
38
- end
39
-
40
- #
41
- # Add an object to the channel.
42
- #
43
- # @raise [IOError]
44
- # When the channel is closed.
45
- #
46
- # @param [Object] object
47
- # An object to add to the channel.
48
- #
49
- def write(object)
50
- write!(object, nil)
51
- end
52
- alias_method :put, :write
53
-
54
- #
55
- # Add an object to the channel.
56
- #
57
- # Unlike {#write}, which waits indefinitely until the channel becomes writable,
58
- # this method will raise an IOError when _timeout_ seconds elapse and
59
- # the channel remains unwritable.
60
- #
61
- # @param
62
- # (see IChannel#write)
63
- #
64
- # @param [Numeric] timeout
65
- # The number of seconds to wait for the channel to become writable.
66
- #
67
- # @raise (see IChannel#write)
68
- #
69
- # @raise [IOError]
70
- # When _timeout_ seconds elapse & the channel remains unwritable.
71
- #
72
- def write!(object, timeout = 0.1)
73
- if @writer.closed?
74
- raise IOError, 'The channel cannot be written to (closed).'
75
- end
76
- _, writable, _ = IO.select nil, [@writer], nil, timeout
77
- if writable
78
- msg = @serializer.dump(object)
79
- writable[0].syswrite "#{msg}#{SEP}"
80
- else
81
- raise IOError, 'The channel cannot be written to.'
82
- end
83
- end
84
- alias_method :put!, :write!
85
-
86
- #
87
- # Reads the last message written to the channel by reading until the channel
88
- # is empty. The last message is cached and reset to nil on call to {#close}.
89
- #
90
- # @return [Object]
91
- # Returns the last message to be written to the channel.
92
- #
93
- def last_msg
94
- while readable?
95
- @last_msg = get
96
- end
97
- @last_msg
98
- end
99
-
100
- #
101
- # Receive an object from the channel.
102
- #
103
- # @raise [IOError]
104
- # When the channel is closed.
105
- #
106
- # @return [Object]
107
- # The object read from the channel.
108
- #
109
- def recv
110
- recv!(nil)
111
- end
112
- alias_method :get, :recv
2
+ require_relative "ichannel/unix_socket"
113
3
 
114
- #
115
- # Receive an object from the channel.
116
- #
117
- # Unlike {#recv}, which waits indefinitely until the channel becomes readable,
118
- # this method will raise an IOError when _timeout_ seconds elapse and the
119
- # channel remains unreadable.
120
- #
121
- # @param [Numeric] timeout
122
- # The number of seconds to wait for the channel to become readable.
123
- #
124
- # @raise [IOError]
125
- # (see IChannel#recv)
126
- #
127
- # @raise [IOError]
128
- # When _timeout_ seconds elapse & the channel remains unreadable.
129
- #
130
- # @return [Object]
131
- # The object read from the channel.
132
- #
133
- def recv!(timeout = 0.1)
134
- if @reader.closed?
135
- raise IOError, 'The channel cannot be read from (closed).'
136
- end
137
- readable, _ = IO.select [@reader], nil, nil, timeout
138
- if readable
139
- msg = readable[0].readline(SEP).chomp SEP
140
- @serializer.load msg
141
- else
142
- raise IOError, 'The channel cannot be read from.'
143
- end
4
+ def self.unix(options)
5
+ UNIXSocket.new(options)
144
6
  end
145
- alias_method :get!, :recv!
146
7
 
147
- #
148
- # @return [Boolean]
149
- # Returns true when the channel is readable.
150
- #
151
- def readable?
152
- if closed?
153
- false
154
- else
155
- readable, _ = IO.select [@reader], nil, nil, 0
156
- !! readable
157
- end
8
+ def self.redis(options)
9
+ raise NotImplementedError
158
10
  end
159
11
  end
@@ -2,13 +2,36 @@ require_relative 'setup'
2
2
  class IChannelTest < Test::Unit::TestCase
3
3
  def setup
4
4
  serializer = Object.const_get ENV["SERIALIZER"] || "Marshal"
5
- @channel = IChannel.new serializer
5
+ @channel = IChannel.unix serializer
6
6
  end
7
7
 
8
8
  def teardown
9
9
  @channel.close
10
10
  end
11
11
 
12
+ def test_interface
13
+ %w(write
14
+ write!
15
+ get
16
+ get!
17
+ close
18
+ closed?
19
+ readable?
20
+ last_msg
21
+ put
22
+ put!
23
+ recv
24
+ recv!).each do |method|
25
+ assert @channel.respond_to? method
26
+ end
27
+ end
28
+
29
+ def test_serialization
30
+ @channel.put 42
31
+ dump = Marshal.dump @channel
32
+ assert_equal 42, Marshal.load(dump).get
33
+ end
34
+
12
35
  def test_last_msg
13
36
  @channel.put %w(a)
14
37
  @channel.put %w(b)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ichannel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 6.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-05 00:00:00.000000000 Z
12
+ date: 2013-04-20 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! "A modern and easy-to-use interprocess communication \n primitive."
15
15
  email:
@@ -29,6 +29,7 @@ files:
29
29
  - Rakefile
30
30
  - ichannel.gemspec
31
31
  - lib/ichannel.rb
32
+ - lib/ichannel/unix_socket.rb
32
33
  - lib/ichannel/version.rb
33
34
  - test/ichannel_class_test.rb
34
35
  - test/setup.rb
@@ -46,7 +47,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
47
  version: '0'
47
48
  segments:
48
49
  - 0
49
- hash: 1696570348195705541
50
+ hash: -4148613930352415051
50
51
  required_rubygems_version: !ruby/object:Gem::Requirement
51
52
  none: false
52
53
  requirements:
@@ -55,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
56
  version: '0'
56
57
  segments:
57
58
  - 0
58
- hash: 1696570348195705541
59
+ hash: -4148613930352415051
59
60
  requirements: []
60
61
  rubyforge_project:
61
62
  rubygems_version: 1.8.23