xchan.rb 0.17.0 → 0.17.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf2db46e92eb29ed0182377c209a8ff7511460d22a73225616c719cd05372884
4
- data.tar.gz: 05b70d50483d354f79e29f9219628c44cb6f4b25e63cbd5aee7e0c0a14da8865
3
+ metadata.gz: 5509107cf1cda5e847f3c15e19c81ba9323c2dbb524a7ef808eeb820d5bcdeb9
4
+ data.tar.gz: 43deff543ee38ace3ca8a083a043eb1c6bbedec9143bd2c8e17de50f13127031
5
5
  SHA512:
6
- metadata.gz: f8fb7b0f73b09c4593dfa7892fd3e0061dce37242c0e9bebab0edd204cda399dd16c8fdbadce2ee6a5fac1fc6c1d583ad60eadd85c7ece4a145fdb18358aff0a
7
- data.tar.gz: ef454d2422ae0a719a19b7fad3bf670a3cc4b46154ea6e87786a4c6404bbe9f7af5437e81b3ed8651fa9e1f438ee7f43c38d10497ca9b50facd3aea3ededc7f0
6
+ metadata.gz: d5455dd6c714bc4060ec1f563b46d8a9eaee32e5aa58c2a2508de99f53fc29e346d07ac04e719822bc394b66ac6ba6ddf5585bf7958c606a0f1f375c113b4310
7
+ data.tar.gz: '09bd28506d18a63e8e917ad1189c708cc6643b852707508ee0edf563064bd3618d3ae251d85e06f618672c414537b4da3db0538b61e4c11c2a6c64fff3394f38'
@@ -12,7 +12,7 @@ jobs:
12
12
  fail-fast: false
13
13
  matrix:
14
14
  os: [ubuntu-latest, macos-latest]
15
- ruby: [3.1, 3.2]
15
+ ruby: [3.1, 3.2, 3.3]
16
16
  runs-on: ${{ matrix.os }}
17
17
  steps:
18
18
  - uses: actions/checkout@v2
@@ -23,4 +23,4 @@ jobs:
23
23
  - run: SERIALIZER=marshal bundle exec rake
24
24
  - run: SERIALIZER=json bundle exec rake
25
25
  - run: SERIALIZER=yaml bundle exec rake
26
- - run: SERIALIZER=plain bundle exec rake
26
+ - run: SERIALIZER=pure bundle exec rake
data/.gitlab-ci.yml CHANGED
@@ -9,4 +9,4 @@ test-ruby32:
9
9
  - SERIALIZER=marshal bundle exec rake
10
10
  - SERIALIZER=json bundle exec rake
11
11
  - SERIALIZER=yaml bundle exec rake
12
- - SERIALIZER=plain bundle exec rake
12
+ - SERIALIZER=pure bundle exec rake
data/lib/xchan/bytes.rb CHANGED
@@ -1,39 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ##
4
- # The {Chan::Bytes Chan::Bytes} class is similar
5
- # to an array, where each element represents the
6
- # number of bytes used to store an object on a
7
- # channel. When an object is written to a channel,
8
- # the array increases in size, and when an object
9
- # is read from a channel, the array decreases in
10
- # size.
4
+ # {Chan::Bytes Chan::Bytes} represents a collection
5
+ # of byte counts for each object stored on a channel.
6
+ # When an object is written to a channel, the collection
7
+ # increases in size, and when an object is read from
8
+ # a channel, the collection decreases in size.
11
9
  class Chan::Bytes
12
10
  require "json"
13
- require_relative "stat"
14
-
15
- ##
16
- # @return [Chan::Stat]
17
- attr_reader :stat
11
+ require_relative "counter"
18
12
 
19
13
  ##
20
14
  # @param [String] tmpdir
21
- # Path to a directory where temporary files will be stored.
15
+ # Directory where temporary files are stored
22
16
  #
23
17
  # @return [Chan::Bytes]
24
18
  def initialize(tmpdir)
25
- @serializer = JSON
26
19
  @io = Chan.temporary_file("xchan.bytes", tmpdir:)
27
20
  @io.sync = true
28
- @stat = Chan::Stat.new(tmpdir)
29
21
  write(@io, [])
30
22
  end
31
23
 
32
24
  ##
33
- # Insert a byte count at the head of the array
25
+ # Adds a count to the start of the collection
34
26
  #
35
27
  # @param [Integer] len
36
- # Number of bytes
28
+ # The bytesize of an object
37
29
  #
38
30
  # @return [void]
39
31
  def unshift(len)
@@ -41,15 +33,14 @@ class Chan::Bytes
41
33
  bytes = read(@io)
42
34
  bytes.unshift(len)
43
35
  write(@io, bytes)
44
- @stat.store(bytes_written: len)
45
36
  len
46
37
  end
47
38
 
48
39
  ##
49
- # Insert a byte count at the tail of the array
40
+ # Adds a count to the end of the collection
50
41
  #
51
42
  # @param [Integer] len
52
- # Number of bytes
43
+ # The bytesize of an object
53
44
  #
54
45
  # @return [void]
55
46
  def push(len)
@@ -57,25 +48,25 @@ class Chan::Bytes
57
48
  bytes = read(@io)
58
49
  bytes.push(len)
59
50
  write(@io, bytes)
60
- @stat.store(bytes_written: len)
61
51
  len
62
52
  end
63
53
 
64
54
  ##
55
+ # Removes a count from the start of the collection
56
+ #
65
57
  # @return [Integer]
66
- # Returns (and removes) a byte count from the head of the array
58
+ # Returns the removed byte count
67
59
  def shift
68
60
  bytes = read(@io)
69
61
  return 0 if bytes.size.zero?
70
62
  len = bytes.shift
71
63
  write(@io, bytes)
72
- @stat.store(bytes_read: len)
73
64
  len
74
65
  end
75
66
 
76
67
  ##
77
68
  # @return [Integer]
78
- # Returns the size of the array
69
+ # Returns the number of objects in the collection
79
70
  def size
80
71
  read(@io).size
81
72
  end
@@ -100,10 +91,10 @@ class Chan::Bytes
100
91
  end
101
92
 
102
93
  def serialize(bytes)
103
- @serializer.dump(bytes)
94
+ JSON.dump(bytes)
104
95
  end
105
96
 
106
97
  def deserialize(bytes)
107
- @serializer.load(bytes)
98
+ JSON.load(bytes)
108
99
  end
109
100
  end
@@ -1,33 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ##
4
- # The {Chan::Stat Chan::Stat} class provides statistics
5
- # (eg number of bytes read, number of bytes written) for
6
- # a given channel.
7
- class Chan::Stat
4
+ # {Chan::Counter Chan::Counter} provides a counter
5
+ # for the number of written and received bytes on a
6
+ # given channel.
7
+ class Chan::Counter
8
8
  require "json"
9
9
 
10
10
  ##
11
11
  # @param [String] tmpdir
12
- # Path to a directory where temporary files will be stored.
12
+ # Directory where temporary files are stored
13
13
  #
14
- # @return [Chan::Stat]
14
+ # @return [Chan::Counter]
15
15
  def initialize(tmpdir)
16
- @serializer = JSON
17
- @io = Chan.temporary_file("xchan.stat", tmpdir:)
16
+ @io = Chan.temporary_file("xchan.counter", tmpdir:)
18
17
  write(@io, {"bytes_read" => 0, "bytes_written" => 0})
19
18
  end
20
19
 
21
20
  ##
22
21
  # @return [Integer]
23
- # Returns the number of bytes written to a channel.
22
+ # Returns the number of bytes written to a channel
24
23
  def bytes_written
25
24
  read(@io).fetch("bytes_written")
26
25
  end
27
26
 
28
27
  ##
29
28
  # @return [Integer]
30
- # Returns the number of bytes read from a channel.
29
+ # Returns the number of bytes read from a channel
31
30
  def bytes_read
32
31
  read(@io).fetch("bytes_read")
33
32
  end
@@ -36,7 +35,7 @@ class Chan::Stat
36
35
  # @param [Hash] new_stat
37
36
  # @return [void]
38
37
  # @private
39
- def store(new_stat)
38
+ def increment!(new_stat)
40
39
  stat = read(@io)
41
40
  new_stat.each { stat[_1.to_s] += _2 }
42
41
  write(@io, stat)
@@ -54,10 +53,10 @@ class Chan::Stat
54
53
  end
55
54
 
56
55
  def serialize(bytes)
57
- @serializer.dump(bytes)
56
+ JSON.dump(bytes)
58
57
  end
59
58
 
60
59
  def deserialize(bytes)
61
- @serializer.load(bytes)
60
+ JSON.load(bytes)
62
61
  end
63
62
  end
@@ -39,25 +39,26 @@ class Chan::UNIXSocket
39
39
  @serializer = Chan.serializers[serializer]&.call || serializer
40
40
  @r, @w = ::UNIXSocket.pair(sock_type)
41
41
  @bytes = Chan::Bytes.new(tmpdir)
42
+ @counter = Chan::Counter.new(tmpdir)
42
43
  @lock = LockFile.new Chan.temporary_file("xchan.lock", tmpdir:)
43
44
  end
44
45
 
45
46
  ##
46
47
  # @return [<#dump, #load>]
47
- # Returns the serializer used by the channel.
48
+ # Returns the serializer used by the channel
48
49
  def serializer
49
50
  @serializer
50
51
  end
51
52
 
52
53
  ##
53
54
  # @return [Boolean]
54
- # Returns true when the channel is closed.
55
+ # Returns true when the channel is closed
55
56
  def closed?
56
57
  @r.closed? and @w.closed?
57
58
  end
58
59
 
59
60
  ##
60
- # Closes the channel.
61
+ # Closes the channel
61
62
  #
62
63
  # @raise [IOError]
63
64
  # When the channel is closed.
@@ -79,13 +80,13 @@ class Chan::UNIXSocket
79
80
  # Performs a blocking write
80
81
  #
81
82
  # @param [Object] object
82
- # An object to write to the channel.
83
+ # An object
83
84
  #
84
85
  # @raise [IOError]
85
- # When the channel is closed.
86
+ # When the channel is closed
86
87
  #
87
88
  # @return [Object]
88
- # Returns the number of bytes written to the channel.
89
+ # Returns the number of bytes written to the channel
89
90
  def send(object)
90
91
  send_nonblock(object)
91
92
  rescue Chan::WaitWritable, Chan::WaitLockable
@@ -97,24 +98,25 @@ class Chan::UNIXSocket
97
98
  # Performs a non-blocking write
98
99
  #
99
100
  # @param [Object] object
100
- # An object to write to the channel.
101
+ # An object
101
102
  #
102
103
  # @raise [IOError]
103
- # When the channel is closed.
104
+ # When the channel is closed
104
105
  #
105
106
  # @raise [Chan::WaitWritable]
106
- # When a write to the underlying IO blocks.
107
+ # When a write to {#w} blocks
107
108
  #
108
109
  # @raise [Chan::WaitLockable]
109
- # When a write blocks because of a lock held by another process.
110
+ # When a write blocks because of a lock held by another process
110
111
  #
111
112
  # @return [Integer, nil]
112
- # Returns the number of bytes written to the channel.
113
+ # Returns the number of bytes written to the channel
113
114
  def send_nonblock(object)
114
115
  @lock.lock_nonblock
115
116
  raise IOError, "channel closed" if closed?
116
117
  len = @w.write_nonblock(serialize(object))
117
118
  @bytes.push(len)
119
+ @counter.increment!(bytes_written: len)
118
120
  len.tap { @lock.release }
119
121
  rescue IOError, IO::WaitWritable, Errno::ENOBUFS => ex
120
122
  @lock.release
@@ -134,10 +136,10 @@ class Chan::UNIXSocket
134
136
  # Performs a blocking read
135
137
  #
136
138
  # @raise [IOError]
137
- # When the channel is closed.
139
+ # When the channel is closed
138
140
  #
139
141
  # @return [Object]
140
- # Returns an object from the channel.
142
+ # Returns an object from the channel
141
143
  def recv
142
144
  recv_nonblock
143
145
  rescue Chan::WaitReadable
@@ -152,21 +154,22 @@ class Chan::UNIXSocket
152
154
  # Performs a non-blocking read
153
155
  #
154
156
  # @raise [IOError]
155
- # When the channel is closed.
157
+ # When the channel is closed
156
158
  #
157
159
  # @raise [Chan::WaitReadable]
158
- # When a read from the underlying IO blocks.
160
+ # When a read from {#r} blocks
159
161
  #
160
162
  # @raise [Chan::WaitLockable]
161
- # When a read blocks because of a lock held by another process.
163
+ # When a read blocks because of a lock held by another process
162
164
  #
163
165
  # @return [Object]
164
- # Returns an object from the channel.
166
+ # Returns an object from the channel
165
167
  def recv_nonblock
166
168
  @lock.lock_nonblock
167
169
  raise IOError, "closed channel" if closed?
168
170
  len = @bytes.shift
169
171
  obj = deserialize(@r.read_nonblock(len.zero? ? 1 : len))
172
+ @counter.increment!(bytes_read: len)
170
173
  obj.tap { @lock.release }
171
174
  rescue IOError => ex
172
175
  @lock.release
@@ -190,7 +193,7 @@ class Chan::UNIXSocket
190
193
  # ch.to_a.last # => 4
191
194
  #
192
195
  # @return [Array<Object>]
193
- # Returns the consumed contents of the channel.
196
+ # Returns the contents of the channel
194
197
  def to_a
195
198
  lock do
196
199
  [].tap { _1.push(recv) until empty? }
@@ -199,7 +202,7 @@ class Chan::UNIXSocket
199
202
 
200
203
  ##
201
204
  # @return [Boolean]
202
- # Returns true when the channel is empty.
205
+ # Returns true when the channel is empty
203
206
  def empty?
204
207
  return true if closed?
205
208
  lock { size.zero? }
@@ -210,17 +213,17 @@ class Chan::UNIXSocket
210
213
 
211
214
  ##
212
215
  # @return [Integer]
213
- # Returns the total number of bytes written to the channel.
216
+ # Returns the total number of bytes written to the channel
214
217
  def bytes_sent
215
- lock { @bytes.stat.bytes_written }
218
+ lock { @counter.bytes_written }
216
219
  end
217
220
  alias_method :bytes_written, :bytes_sent
218
221
 
219
222
  ##
220
223
  # @return [Integer]
221
- # Returns the total number of bytes read from the channel.
224
+ # Returns the total number of bytes read from the channel
222
225
  def bytes_received
223
- lock { @bytes.stat.bytes_read }
226
+ lock { @counter.bytes_read }
224
227
  end
225
228
  alias_method :bytes_read, :bytes_received
226
229
 
data/lib/xchan/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chan
4
- VERSION = "0.17.0"
4
+ VERSION = "0.17.1"
5
5
  end
data/test/xchan_test.rb CHANGED
@@ -4,7 +4,7 @@ require_relative "setup"
4
4
 
5
5
  class Chan::Test < Test::Unit::TestCase
6
6
  def setup
7
- @ch = xchan ENV.fetch("SERIALIZER", "marshal").to_sym
7
+ @ch = xchan(serializer)
8
8
  end
9
9
 
10
10
  def teardown
@@ -17,9 +17,13 @@ class Chan::Test < Test::Unit::TestCase
17
17
  @ch
18
18
  end
19
19
 
20
+ def serializer
21
+ ENV.fetch("SERIALIZER", "pure").to_sym
22
+ end
23
+
20
24
  def object
21
- case ENV["SERIALIZER"]
22
- when "plain" then "xchan"
25
+ case serializer
26
+ when :pure then "xchan"
23
27
  else %w[xchan]
24
28
  end
25
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xchan.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'
@@ -127,7 +127,7 @@ files:
127
127
  - Rakefile.rb
128
128
  - lib/xchan.rb
129
129
  - lib/xchan/bytes.rb
130
- - lib/xchan/stat.rb
130
+ - lib/xchan/counter.rb
131
131
  - lib/xchan/tempfile.rb
132
132
  - lib/xchan/unix_socket.rb
133
133
  - lib/xchan/version.rb