cztop 1.0.0 → 1.1.0.pre1
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 +4 -4
- data/.github/workflows/coverage.yml +20 -0
- data/.github/workflows/draft_api.yml +27 -0
- data/.github/workflows/{main.yml → stable_api.yml} +6 -6
- data/.rubocop.yml +175 -0
- data/CHANGES.md +8 -1
- data/Gemfile +5 -0
- data/README.md +3 -1
- data/ci/install-libczmq +22 -0
- data/ci/install-libzmq +22 -0
- data/cztop.gemspec +3 -2
- data/lib/cztop/actor.rb +55 -26
- data/lib/cztop/authenticator.rb +18 -9
- data/lib/cztop/beacon.rb +22 -10
- data/lib/cztop/cert_store.rb +8 -2
- data/lib/cztop/certificate.rb +47 -18
- data/lib/cztop/config/comments.rb +14 -3
- data/lib/cztop/config/serialization.rb +25 -5
- data/lib/cztop/config/traversing.rb +44 -13
- data/lib/cztop/config.rb +23 -9
- data/lib/cztop/frame.rb +23 -10
- data/lib/cztop/has_ffi_delegate.rb +11 -1
- data/lib/cztop/message/frames.rb +16 -2
- data/lib/cztop/message.rb +36 -22
- data/lib/cztop/metadata.rb +35 -24
- data/lib/cztop/monitor.rb +14 -5
- data/lib/cztop/poller/aggregated.rb +31 -15
- data/lib/cztop/poller/zmq.rb +25 -22
- data/lib/cztop/poller/zpoller.rb +18 -6
- data/lib/cztop/poller.rb +43 -18
- data/lib/cztop/polymorphic_zsock_methods.rb +6 -1
- data/lib/cztop/proxy.rb +34 -19
- data/lib/cztop/send_receive_methods.rb +5 -1
- data/lib/cztop/socket/types.rb +128 -22
- data/lib/cztop/socket.rb +23 -18
- data/lib/cztop/version.rb +5 -1
- data/lib/cztop/z85/padded.rb +12 -3
- data/lib/cztop/z85/pipe.rb +40 -17
- data/lib/cztop/z85.rb +17 -6
- data/lib/cztop/zap.rb +57 -32
- data/lib/cztop/zsock_options.rb +155 -122
- data/lib/cztop.rb +2 -1
- metadata +28 -10
- data/.ruby-version +0 -1
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Methods used to traverse a {CZTop::Config} tree.
|
2
4
|
module CZTop::Config::Traversing
|
3
5
|
|
@@ -12,24 +14,25 @@ module CZTop::Config::Traversing
|
|
12
14
|
# @raise [Exception] the block's exception, in case it raises (it won't
|
13
15
|
# call the block any more after that)
|
14
16
|
def execute
|
15
|
-
raise ArgumentError,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
raise ArgumentError, 'no block given' unless block_given?
|
18
|
+
|
19
|
+
exception = nil
|
20
|
+
block_value = nil
|
21
|
+
ret = nil
|
22
|
+
callback = CZMQ::FFI::Zconfig.fct do |zconfig, _arg, level|
|
20
23
|
begin
|
21
24
|
# NOTE: work around JRuby and Rubinius bug, where it'd keep calling
|
22
25
|
# this FFI::Function, even when the block `break`ed
|
23
26
|
if ret != -1
|
24
|
-
config
|
27
|
+
config = from_ffi_delegate(zconfig)
|
25
28
|
block_value = yield config, level
|
26
|
-
ret
|
29
|
+
ret = 0 # report success to keep zconfig_execute() going
|
27
30
|
end
|
28
|
-
rescue
|
31
|
+
rescue StandardError
|
29
32
|
# remember exception, so we can raise it later to the ruby code
|
30
33
|
# (it can't be raised now, as we have to report failure to
|
31
34
|
# zconfig_execute())
|
32
|
-
exception =
|
35
|
+
exception = $ERROR_INFO
|
33
36
|
|
34
37
|
ret = -1 # report failure to stop zconfig_execute() immediately
|
35
38
|
ensure
|
@@ -39,15 +42,18 @@ module CZTop::Config::Traversing
|
|
39
42
|
end
|
40
43
|
ffi_delegate.execute(callback, _arg = nil)
|
41
44
|
raise exception if exception
|
42
|
-
|
45
|
+
|
46
|
+
block_value
|
43
47
|
end
|
44
48
|
|
49
|
+
|
45
50
|
# Access to this config item's direct children.
|
46
51
|
# @return [ChildrenAccessor]
|
47
52
|
def children
|
48
53
|
ChildrenAccessor.new(self)
|
49
54
|
end
|
50
55
|
|
56
|
+
|
51
57
|
# Access to this config item's siblings.
|
52
58
|
# @note Only the "younger" (later in the ZPL file) config items are
|
53
59
|
# considered.
|
@@ -56,9 +62,11 @@ module CZTop::Config::Traversing
|
|
56
62
|
SiblingsAccessor.new(self)
|
57
63
|
end
|
58
64
|
|
65
|
+
|
59
66
|
# Used to give access to a {Config} item's children or siblings.
|
60
67
|
# @abstract
|
61
68
|
class FamilyAccessor
|
69
|
+
|
62
70
|
include Enumerable
|
63
71
|
|
64
72
|
# @param config [Config] the relative starting point (either parent or
|
@@ -67,25 +75,30 @@ module CZTop::Config::Traversing
|
|
67
75
|
@config = config
|
68
76
|
end
|
69
77
|
|
78
|
+
|
70
79
|
# This is supposed to return the first relevant config item.
|
71
80
|
# @abstract
|
72
81
|
# @return [Config, nil]
|
73
82
|
def first; end
|
74
83
|
|
84
|
+
|
75
85
|
# Yields all direct children/younger siblings. Starts with {#first}, if
|
76
86
|
# set.
|
77
87
|
# @yieldparam config [Config]
|
78
88
|
def each
|
79
|
-
current = first
|
89
|
+
current = first
|
80
90
|
return if current.nil?
|
91
|
+
|
81
92
|
yield current
|
82
|
-
current_delegate
|
93
|
+
current_delegate = current.ffi_delegate
|
83
94
|
while current_delegate = current_delegate.next
|
84
95
|
break if current_delegate.null?
|
96
|
+
|
85
97
|
yield CZTop::Config.from_ffi_delegate(current_delegate)
|
86
98
|
end
|
87
99
|
end
|
88
100
|
|
101
|
+
|
89
102
|
# Recursively compares these config items with the ones of the other.
|
90
103
|
# @param other [FamilyAccessor]
|
91
104
|
def ==(other)
|
@@ -94,30 +107,39 @@ module CZTop::Config::Traversing
|
|
94
107
|
these.size == those.size && these.zip(those) do |this, that|
|
95
108
|
this.tree_equal?(that) or return false
|
96
109
|
end
|
97
|
-
|
110
|
+
true
|
98
111
|
end
|
112
|
+
|
99
113
|
end
|
100
114
|
|
115
|
+
|
101
116
|
# Accesses the younger siblings of a given {Config} item.
|
102
117
|
class SiblingsAccessor < FamilyAccessor
|
118
|
+
|
103
119
|
# Returns the first sibling.
|
104
120
|
# @return [Config]
|
105
121
|
# @return [nil] if no younger siblings
|
106
122
|
def first
|
107
123
|
ptr = @config.ffi_delegate.next
|
108
124
|
return nil if ptr.null?
|
125
|
+
|
109
126
|
CZTop::Config.from_ffi_delegate(ptr)
|
110
127
|
end
|
128
|
+
|
111
129
|
end
|
112
130
|
|
131
|
+
|
113
132
|
# Accesses the direct children of a given {Config} item.
|
114
133
|
class ChildrenAccessor < FamilyAccessor
|
134
|
+
|
115
135
|
def first
|
116
136
|
ptr = @config.ffi_delegate.child
|
117
137
|
return nil if ptr.null?
|
138
|
+
|
118
139
|
CZTop::Config.from_ffi_delegate(ptr)
|
119
140
|
end
|
120
141
|
|
142
|
+
|
121
143
|
# Adds a new Config item and yields it, so it can be configured in
|
122
144
|
# a block.
|
123
145
|
# @param name [String] name for new config item
|
@@ -129,8 +151,10 @@ module CZTop::Config::Traversing
|
|
129
151
|
yield config if block_given?
|
130
152
|
config
|
131
153
|
end
|
154
|
+
|
132
155
|
end
|
133
156
|
|
157
|
+
|
134
158
|
# Finds a config item along a path, relative to the current item.
|
135
159
|
# @param path [String] path (leading slash is optional and will be
|
136
160
|
# ignored)
|
@@ -139,19 +163,26 @@ module CZTop::Config::Traversing
|
|
139
163
|
def locate(path)
|
140
164
|
ptr = ffi_delegate.locate(path)
|
141
165
|
return nil if ptr.null?
|
166
|
+
|
142
167
|
from_ffi_delegate(ptr)
|
143
168
|
end
|
144
169
|
|
170
|
+
|
145
171
|
# Finds last item at given level (0 = root).
|
146
172
|
# @return [Config] the last config item at given level
|
147
173
|
# @return [nil] if there's no config item at given level
|
148
174
|
def last_at_depth(level)
|
149
175
|
ptr = ffi_delegate.at_depth(level)
|
150
176
|
return nil if ptr.null?
|
177
|
+
|
151
178
|
from_ffi_delegate(ptr)
|
152
179
|
end
|
180
|
+
|
153
181
|
end
|
154
182
|
|
183
|
+
|
155
184
|
class CZTop::Config
|
185
|
+
|
156
186
|
include Traversing
|
187
|
+
|
157
188
|
end
|
data/lib/cztop/config.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CZTop
|
3
4
|
# Represents a CZMQ::FFI::Zconfig item.
|
4
5
|
# @see http://rfc.zeromq.org/spec:4/ZPL
|
5
6
|
class Config
|
7
|
+
|
6
8
|
include HasFFIDelegate
|
7
9
|
extend CZTop::HasFFIDelegate::ClassMethods
|
8
10
|
|
11
|
+
|
9
12
|
# Initializes a new {Config} item. Takes an optional block to initialize
|
10
13
|
# the item further.
|
11
14
|
# @param name [String] config item name
|
@@ -17,7 +20,7 @@ module CZTop
|
|
17
20
|
# {Config} object is garbage collected).
|
18
21
|
def initialize(name = nil, value = nil, parent: nil)
|
19
22
|
if parent
|
20
|
-
parent
|
23
|
+
parent = parent.ffi_delegate if parent.is_a?(Config)
|
21
24
|
delegate = ::CZMQ::FFI::Zconfig.new(name, parent)
|
22
25
|
attach_ffi_delegate(delegate)
|
23
26
|
|
@@ -42,9 +45,11 @@ module CZTop
|
|
42
45
|
def name
|
43
46
|
ptr = ffi_delegate.name
|
44
47
|
return nil if ptr.null? # NOTE: for unnamed elements
|
48
|
+
|
45
49
|
ptr.read_string
|
46
50
|
end
|
47
51
|
|
52
|
+
|
48
53
|
# Sets a new name.
|
49
54
|
# @param new_name [String, #to_s]
|
50
55
|
# @return [new_name]
|
@@ -52,28 +57,33 @@ module CZTop
|
|
52
57
|
ffi_delegate.set_name(new_name.to_s)
|
53
58
|
end
|
54
59
|
|
60
|
+
|
55
61
|
# Get the value of the config item.
|
56
62
|
# @return [String]
|
57
63
|
# @note This returns an empty string if the value is unset.
|
58
64
|
def value
|
59
65
|
ptr = ffi_delegate.value
|
60
|
-
return
|
66
|
+
return '' if ptr.null? # NOTE: for root elements
|
67
|
+
|
61
68
|
ptr.read_string
|
62
69
|
end
|
63
70
|
|
71
|
+
|
64
72
|
# Set or update the value of the config item.
|
65
73
|
# @param new_value [String, #to_s]
|
66
74
|
# @return [new_value]
|
67
75
|
def value=(new_value)
|
68
|
-
ffi_delegate.set_value(
|
76
|
+
ffi_delegate.set_value('%s', :string, new_value.to_s)
|
69
77
|
end
|
70
78
|
|
79
|
+
|
71
80
|
# Inspects this {Config} item.
|
72
81
|
# @return [String] shows class, name, and value
|
73
82
|
def inspect
|
74
83
|
"#<#{self.class.name}: name=#{name.inspect} value=#{value.inspect}>"
|
75
84
|
end
|
76
85
|
|
86
|
+
|
77
87
|
# Update the value of a config item by path.
|
78
88
|
# @param path [String, #to_s] path to config item
|
79
89
|
# @param value [String, #to_s] path to config item
|
@@ -81,7 +91,7 @@ module CZTop
|
|
81
91
|
def []=(path, value)
|
82
92
|
ffi_delegate.put(path.to_s, value.to_s)
|
83
93
|
end
|
84
|
-
|
94
|
+
alias put []=
|
85
95
|
|
86
96
|
# Get the value of the current config item.
|
87
97
|
# @param path [String, #to_s] path to config item
|
@@ -92,30 +102,34 @@ module CZTop
|
|
92
102
|
# @note The default value is not returned when the config item exists but
|
93
103
|
# just doesn't have a value. In that case, it'll return the empty
|
94
104
|
# string.
|
95
|
-
def [](path, default =
|
105
|
+
def [](path, default = '')
|
96
106
|
ptr = ffi_delegate.get(path, default)
|
97
107
|
return nil if ptr.null?
|
108
|
+
|
98
109
|
ptr.read_string
|
99
110
|
end
|
100
|
-
|
111
|
+
alias get []
|
101
112
|
|
102
113
|
# @!endgroup
|
103
114
|
|
115
|
+
|
104
116
|
# Compares this config item to another. Only the name and value are
|
105
117
|
# considered. If you need to compare a config tree, use {#tree_equal?}.
|
106
118
|
# @param other [Config] the other config item
|
107
119
|
# @return [Boolean] whether they're equal
|
108
120
|
def ==(other)
|
109
121
|
name == other.name &&
|
110
|
-
|
122
|
+
value == other.value
|
111
123
|
end
|
112
124
|
|
125
|
+
|
113
126
|
# Compares this config tree to another tree or subtree. Names, values, and
|
114
127
|
# children are considered.
|
115
128
|
# @param other [Config] the other config tree
|
116
129
|
# @return [Boolean] whether they're equal
|
117
130
|
def tree_equal?(other)
|
118
|
-
self == other &&
|
131
|
+
self == other && children == other.children
|
119
132
|
end
|
133
|
+
|
120
134
|
end
|
121
135
|
end
|
data/lib/cztop/frame.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
# Represents a CZMQ::FFI::Zframe, a part of a message.
|
3
5
|
#
|
@@ -8,6 +10,7 @@ module CZTop
|
|
8
10
|
#
|
9
11
|
# @see http://api.zeromq.org/czmq3-0:zframe
|
10
12
|
class Frame
|
13
|
+
|
11
14
|
include HasFFIDelegate
|
12
15
|
extend CZTop::HasFFIDelegate::ClassMethods
|
13
16
|
|
@@ -18,8 +21,8 @@ module CZTop
|
|
18
21
|
self.content = content if content
|
19
22
|
end
|
20
23
|
|
21
|
-
FLAG_MORE
|
22
|
-
FLAG_REUSE
|
24
|
+
FLAG_MORE = 1
|
25
|
+
FLAG_REUSE = 2
|
23
26
|
FLAG_DONTWAIT = 4
|
24
27
|
|
25
28
|
# Send {Message} to a {Socket}/{Actor}.
|
@@ -39,14 +42,14 @@ module CZTop
|
|
39
42
|
# @raise [SystemCallError] if there was some error. In that case, the
|
40
43
|
# native counterpart still exists and this {Frame} can be reused.
|
41
44
|
def send_to(destination, more: false, reuse: false, dontwait: false)
|
42
|
-
flags
|
45
|
+
flags = 0
|
43
46
|
flags |= FLAG_MORE if more
|
44
47
|
flags |= FLAG_REUSE if reuse
|
45
48
|
flags |= FLAG_DONTWAIT if dontwait
|
46
49
|
|
47
50
|
# remember pointer, in case the zframe_t won't be destroyed
|
48
51
|
zframe_ptr = ffi_delegate.to_ptr
|
49
|
-
ret
|
52
|
+
ret = CZMQ::FFI::Zframe.send(ffi_delegate, destination, flags)
|
50
53
|
|
51
54
|
if reuse || ret == -1
|
52
55
|
# zframe_t hasn't been destroyed yet: avoid memory leak.
|
@@ -55,14 +58,13 @@ module CZTop
|
|
55
58
|
end
|
56
59
|
|
57
60
|
if ret == -1
|
58
|
-
if dontwait && FFI.errno == Errno::EAGAIN::Errno
|
59
|
-
raise IO::EAGAINWaitWritable
|
60
|
-
end
|
61
|
+
raise IO::EAGAINWaitWritable if dontwait && FFI.errno == Errno::EAGAIN::Errno
|
61
62
|
|
62
63
|
raise_zmq_err
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
67
|
+
|
66
68
|
# Receive {Frame} from a {Socket}/{Actor}.
|
67
69
|
# @note This is low-level. Consider just receiving a {Message}.
|
68
70
|
# @return [Frame]
|
@@ -70,18 +72,20 @@ module CZTop
|
|
70
72
|
from_ffi_delegate(CZMQ::FFI::Zframe.recv(source))
|
71
73
|
end
|
72
74
|
|
75
|
+
|
73
76
|
# @note This string is always binary. Use String#force_encoding if needed.
|
74
77
|
# @return [String] content as string (encoding = Encoding::BINARY)
|
75
78
|
def content
|
76
79
|
ffi_delegate.data.read_string(size)
|
77
80
|
end
|
78
|
-
|
81
|
+
alias to_s content
|
79
82
|
|
80
83
|
# @return [Boolean] if this {Frame} has zero-sized content
|
81
84
|
def empty?
|
82
85
|
size.zero?
|
83
86
|
end
|
84
87
|
|
88
|
+
|
85
89
|
# Sets new content of this {Frame}.
|
86
90
|
# @param new_content [String]
|
87
91
|
# @return [new_content]
|
@@ -92,12 +96,14 @@ module CZTop
|
|
92
96
|
# NOTE: FFI::MemoryPointer will autorelease
|
93
97
|
end
|
94
98
|
|
99
|
+
|
95
100
|
# Duplicates a frame.
|
96
101
|
# @return [Frame] new frame with same content
|
97
102
|
def dup
|
98
103
|
from_ffi_delegate(ffi_delegate.dup)
|
99
104
|
end
|
100
105
|
|
106
|
+
|
101
107
|
# @return [Boolean] if the MORE indicator is set
|
102
108
|
# @note This happens when reading a frame from a {Socket} or using
|
103
109
|
# {#more=}.
|
@@ -105,6 +111,7 @@ module CZTop
|
|
105
111
|
ffi_delegate.more == 1
|
106
112
|
end
|
107
113
|
|
114
|
+
|
108
115
|
# Sets the MORE indicator.
|
109
116
|
# @param indicator [Boolean]
|
110
117
|
# @note This is NOT used when sending frame to socket.
|
@@ -114,6 +121,7 @@ module CZTop
|
|
114
121
|
ffi_delegate.set_more(indicator ? 1 : 0)
|
115
122
|
end
|
116
123
|
|
124
|
+
|
117
125
|
# Compare to another frame.
|
118
126
|
# @param other [Frame]
|
119
127
|
# @return [Boolean] if this and the other frame have identical size and
|
@@ -151,10 +159,12 @@ module CZTop
|
|
151
159
|
def routing_id=(new_routing_id)
|
152
160
|
# need to raise manually, as FFI lacks this feature.
|
153
161
|
# @see https://github.com/ffi/ffi/issues/473
|
154
|
-
raise RangeError if new_routing_id
|
162
|
+
raise RangeError if new_routing_id.negative?
|
163
|
+
|
155
164
|
ffi_delegate.set_routing_id(new_routing_id)
|
156
165
|
end
|
157
166
|
|
167
|
+
|
158
168
|
# Gets the group (radio/dish pattern).
|
159
169
|
# @note This is only set when the frame has been read from
|
160
170
|
# a {CZTop::Socket::DISH} socket.
|
@@ -163,9 +173,11 @@ module CZTop
|
|
163
173
|
def group
|
164
174
|
group = ffi_delegate.group
|
165
175
|
return nil if group.nil? || group.empty?
|
176
|
+
|
166
177
|
group
|
167
178
|
end
|
168
179
|
|
180
|
+
|
169
181
|
# Sets a new group (radio/dish pattern).
|
170
182
|
# @note This is used when the frame is sent via a {CZTop::Socket::RADIO}
|
171
183
|
# socket.
|
@@ -174,7 +186,8 @@ module CZTop
|
|
174
186
|
# @return [new_group]
|
175
187
|
def group=(new_group)
|
176
188
|
rc = ffi_delegate.set_group(new_group)
|
177
|
-
raise_zmq_err(
|
189
|
+
raise_zmq_err(format('unable to set group to %p', new_group)) if rc == -1
|
178
190
|
end
|
191
|
+
|
179
192
|
end
|
180
193
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
require 'socket' # for SocketError
|
3
5
|
|
4
6
|
# This module is used to attach the low-level objects of classes within the
|
5
7
|
# CZMQ::FFI namespace (coming from the _czmq-ffi-gen_ gem) as delegates.
|
6
8
|
module CZTop::HasFFIDelegate
|
9
|
+
|
7
10
|
# @return [CZMQ::FFI::*] the attached delegate
|
8
11
|
attr_reader :ffi_delegate
|
9
12
|
|
@@ -12,6 +15,7 @@ module CZTop::HasFFIDelegate
|
|
12
15
|
@ffi_delegate.to_ptr
|
13
16
|
end
|
14
17
|
|
18
|
+
|
15
19
|
# Attaches an FFI delegate to the current (probably new) {CZTop} object.
|
16
20
|
# @param ffi_delegate an instance of the corresponding class in the
|
17
21
|
# CZMQ::FFI namespace
|
@@ -27,6 +31,7 @@ module CZTop::HasFFIDelegate
|
|
27
31
|
@ffi_delegate = ffi_delegate
|
28
32
|
end
|
29
33
|
|
34
|
+
|
30
35
|
# Same as the counterpart in {ClassMethods}, but usable from within an
|
31
36
|
# instance.
|
32
37
|
# @see CZTop::FFIDelegate::ClassMethods#from_ffi_delegate
|
@@ -60,8 +65,10 @@ module CZTop::HasFFIDelegate
|
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
68
|
+
|
63
69
|
# Some class methods related to FFI delegates.
|
64
70
|
module ClassMethods
|
71
|
+
|
65
72
|
include Forwardable
|
66
73
|
|
67
74
|
# Delegate specified instance method to the registered FFI delegate.
|
@@ -73,6 +80,7 @@ module CZTop::HasFFIDelegate
|
|
73
80
|
def_delegator(:@ffi_delegate, method)
|
74
81
|
end
|
75
82
|
|
83
|
+
|
76
84
|
# Allocates a new instance and attaches the FFI delegate to it. This is
|
77
85
|
# useful if you already have an FFI delegate and need to attach it to a
|
78
86
|
# fresh high-level object.
|
@@ -84,7 +92,9 @@ module CZTop::HasFFIDelegate
|
|
84
92
|
def from_ffi_delegate(ffi_delegate)
|
85
93
|
obj = allocate
|
86
94
|
obj.attach_ffi_delegate(ffi_delegate)
|
87
|
-
|
95
|
+
obj
|
88
96
|
end
|
97
|
+
|
89
98
|
end
|
99
|
+
|
90
100
|
end
|
data/lib/cztop/message/frames.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
class Message
|
3
5
|
|
@@ -7,14 +9,17 @@ module CZTop
|
|
7
9
|
frames.count
|
8
10
|
end
|
9
11
|
|
12
|
+
|
10
13
|
# Access to this {Message}'s {Frame}s.
|
11
14
|
# @return [FramesAccessor]
|
12
15
|
def frames
|
13
16
|
FramesAccessor.new(self)
|
14
17
|
end
|
15
18
|
|
19
|
+
|
16
20
|
# Used to access a {Message}'s {Frame}s.
|
17
21
|
class FramesAccessor
|
22
|
+
|
18
23
|
include Enumerable
|
19
24
|
|
20
25
|
# @param message [Message]
|
@@ -22,24 +27,29 @@ module CZTop
|
|
22
27
|
@message = message
|
23
28
|
end
|
24
29
|
|
30
|
+
|
25
31
|
# Returns the last frame of this message.
|
26
32
|
# @return [Frame] first frame of Message
|
27
33
|
# @return [nil] if there are no frames
|
28
34
|
def first
|
29
35
|
first = @message.ffi_delegate.first
|
30
36
|
return nil if first.null?
|
37
|
+
|
31
38
|
Frame.from_ffi_delegate(first)
|
32
39
|
end
|
33
40
|
|
41
|
+
|
34
42
|
# Returns the last frame of this message.
|
35
43
|
# @return [Frame] last {Frame} of {Message}
|
36
44
|
# @return [nil] if there are no frames
|
37
45
|
def last
|
38
46
|
last = @message.ffi_delegate.last
|
39
47
|
return nil if last.null?
|
48
|
+
|
40
49
|
Frame.from_ffi_delegate(last)
|
41
50
|
end
|
42
51
|
|
52
|
+
|
43
53
|
# Index access to a frame/frames of this message, just like with an
|
44
54
|
# array.
|
45
55
|
# @overload [](index)
|
@@ -56,6 +66,7 @@ module CZTop
|
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
69
|
+
|
59
70
|
# Yields all frames for this message to the given block.
|
60
71
|
# @note Not thread safe.
|
61
72
|
# @yieldparam frame [Frame]
|
@@ -63,12 +74,15 @@ module CZTop
|
|
63
74
|
def each
|
64
75
|
first = first()
|
65
76
|
return unless first
|
77
|
+
|
66
78
|
yield first
|
67
|
-
while frame = @message.ffi_delegate.next
|
79
|
+
while (frame = @message.ffi_delegate.next) && !frame.null?
|
68
80
|
yield Frame.from_ffi_delegate(frame)
|
69
81
|
end
|
70
|
-
|
82
|
+
self
|
71
83
|
end
|
84
|
+
|
72
85
|
end
|
86
|
+
|
73
87
|
end
|
74
88
|
end
|