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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/coverage.yml +20 -0
  3. data/.github/workflows/draft_api.yml +27 -0
  4. data/.github/workflows/{main.yml → stable_api.yml} +6 -6
  5. data/.rubocop.yml +175 -0
  6. data/CHANGES.md +8 -1
  7. data/Gemfile +5 -0
  8. data/README.md +3 -1
  9. data/ci/install-libczmq +22 -0
  10. data/ci/install-libzmq +22 -0
  11. data/cztop.gemspec +3 -2
  12. data/lib/cztop/actor.rb +55 -26
  13. data/lib/cztop/authenticator.rb +18 -9
  14. data/lib/cztop/beacon.rb +22 -10
  15. data/lib/cztop/cert_store.rb +8 -2
  16. data/lib/cztop/certificate.rb +47 -18
  17. data/lib/cztop/config/comments.rb +14 -3
  18. data/lib/cztop/config/serialization.rb +25 -5
  19. data/lib/cztop/config/traversing.rb +44 -13
  20. data/lib/cztop/config.rb +23 -9
  21. data/lib/cztop/frame.rb +23 -10
  22. data/lib/cztop/has_ffi_delegate.rb +11 -1
  23. data/lib/cztop/message/frames.rb +16 -2
  24. data/lib/cztop/message.rb +36 -22
  25. data/lib/cztop/metadata.rb +35 -24
  26. data/lib/cztop/monitor.rb +14 -5
  27. data/lib/cztop/poller/aggregated.rb +31 -15
  28. data/lib/cztop/poller/zmq.rb +25 -22
  29. data/lib/cztop/poller/zpoller.rb +18 -6
  30. data/lib/cztop/poller.rb +43 -18
  31. data/lib/cztop/polymorphic_zsock_methods.rb +6 -1
  32. data/lib/cztop/proxy.rb +34 -19
  33. data/lib/cztop/send_receive_methods.rb +5 -1
  34. data/lib/cztop/socket/types.rb +128 -22
  35. data/lib/cztop/socket.rb +23 -18
  36. data/lib/cztop/version.rb +5 -1
  37. data/lib/cztop/z85/padded.rb +12 -3
  38. data/lib/cztop/z85/pipe.rb +40 -17
  39. data/lib/cztop/z85.rb +17 -6
  40. data/lib/cztop/zap.rb +57 -32
  41. data/lib/cztop/zsock_options.rb +155 -122
  42. data/lib/cztop.rb +2 -1
  43. metadata +28 -10
  44. data/.ruby-version +0 -1
data/lib/cztop/message.rb CHANGED
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # Represents a CZMQ::FFI::Zmsg.
3
5
  class Message
6
+
4
7
  include HasFFIDelegate
5
8
  extend CZTop::HasFFIDelegate::ClassMethods
6
9
  include ::CZMQ::FFI
@@ -12,14 +15,15 @@ module CZTop
12
15
  def self.coerce(msg)
13
16
  case msg
14
17
  when Message
15
- return msg
18
+ msg
16
19
  when String, Frame, Array
17
- return new(msg)
20
+ new(msg)
18
21
  else
19
- raise ArgumentError, "cannot coerce message: %p" % msg
22
+ raise ArgumentError, format('cannot coerce message: %p', msg)
20
23
  end
21
24
  end
22
25
 
26
+
23
27
  # @param parts [String, Frame, Array<String>, Array<Frame>] initial parts
24
28
  # of the message
25
29
  def initialize(parts = nil)
@@ -27,11 +31,13 @@ module CZTop
27
31
  Array(parts).each { |part| self << part } if parts
28
32
  end
29
33
 
34
+
30
35
  # @return [Boolean] if this message is empty or not
31
36
  def empty?
32
37
  content_size.zero?
33
38
  end
34
39
 
40
+
35
41
  # Send {Message} to a {Socket} or {Actor}.
36
42
  #
37
43
  # @note Do NOT use this {Message} anymore afterwards. Its native
@@ -56,12 +62,14 @@ module CZTop
56
62
  #
57
63
  def send_to(destination)
58
64
  rc = Zmsg.send(ffi_delegate, destination)
59
- return if rc == 0
65
+ return if rc.zero?
66
+
60
67
  raise_zmq_err
61
68
  rescue Errno::EAGAIN
62
69
  raise IO::EAGAINWaitWritable
63
70
  end
64
71
 
72
+
65
73
  # Receive a {Message} from a {Socket} or {Actor}.
66
74
  # @param source [Socket, Actor]
67
75
  # @return [Message] the newly received message
@@ -73,11 +81,13 @@ module CZTop
73
81
  def self.receive_from(source)
74
82
  delegate = Zmsg.recv(source)
75
83
  return from_ffi_delegate(delegate) unless delegate.null?
84
+
76
85
  HasFFIDelegate.raise_zmq_err
77
86
  rescue Errno::EAGAIN
78
87
  raise IO::EAGAINWaitReadable
79
88
  end
80
89
 
90
+
81
91
  # Append a frame to this message.
82
92
  # @param frame [String, Frame] what to append
83
93
  # @raise [ArgumentError] if frame has an invalid type
@@ -90,16 +100,17 @@ module CZTop
90
100
  when String
91
101
  # NOTE: can't use addstr because the data might be binary
92
102
  mem = FFI::MemoryPointer.from_string(frame)
93
- rc = ffi_delegate.addmem(mem, mem.size - 1) # without NULL byte
103
+ rc = ffi_delegate.addmem(mem, mem.size - 1) # without NULL byte
94
104
  when Frame
95
105
  rc = ffi_delegate.append(frame.ffi_delegate)
96
106
  else
97
- raise ArgumentError, "invalid frame: %p" % frame
107
+ raise ArgumentError, format('invalid frame: %p', frame)
98
108
  end
99
- raise_zmq_err unless rc == 0
109
+ raise_zmq_err unless rc.zero?
100
110
  self
101
111
  end
102
112
 
113
+
103
114
  # Prepend a frame to this message.
104
115
  # @param frame [String, Frame] what to prepend
105
116
  # @raise [ArgumentError] if frame has an invalid type
@@ -112,30 +123,34 @@ module CZTop
112
123
  when String
113
124
  # NOTE: can't use pushstr because the data might be binary
114
125
  mem = FFI::MemoryPointer.from_string(frame)
115
- rc = ffi_delegate.pushmem(mem, mem.size - 1) # without NULL byte
126
+ rc = ffi_delegate.pushmem(mem, mem.size - 1) # without NULL byte
116
127
  when Frame
117
128
  rc = ffi_delegate.prepend(frame.ffi_delegate)
118
129
  else
119
- raise ArgumentError, "invalid frame: %p" % frame
130
+ raise ArgumentError, format('invalid frame: %p', frame)
120
131
  end
121
- raise_zmq_err unless rc == 0
132
+ raise_zmq_err unless rc.zero?
122
133
  end
123
134
 
135
+
124
136
  # Removes first part from message and returns it as a string.
125
137
  # @return [String, nil] first part, if any, or nil
126
138
  def pop
127
139
  # NOTE: can't use popstr because the data might be binary
128
140
  ptr = ffi_delegate.pop
129
141
  return nil if ptr.null?
142
+
130
143
  Frame.from_ffi_delegate(ptr).to_s
131
144
  end
132
145
 
146
+
133
147
  # @return [Integer] size of this message in bytes
134
148
  # @see size
135
149
  def content_size
136
150
  ffi_delegate.content_size
137
151
  end
138
152
 
153
+
139
154
  # Returns all frames as strings in an array. This is useful if for quick
140
155
  # inspection of the message.
141
156
  # @note It'll read all frames in the message and turn them into Ruby
@@ -143,30 +158,27 @@ module CZTop
143
158
  # @return [Array<String>] all frames
144
159
  def to_a
145
160
  ffi_delegate = ffi_delegate()
146
- frame = ffi_delegate.first
161
+ frame = ffi_delegate.first
147
162
  return [] if frame.null?
148
163
 
149
- arr = [ frame.data.read_bytes(frame.size) ]
150
- while frame = ffi_delegate.next and not frame.null?
164
+ arr = [frame.data.read_bytes(frame.size)]
165
+ while (frame = ffi_delegate.next) && !frame.null?
151
166
  arr << frame.data.read_bytes(frame.size)
152
167
  end
153
168
 
154
- return arr
169
+ arr
155
170
  end
156
171
 
172
+
157
173
  # Inspects this {Message}.
158
174
  # @return [String] shows class, number of frames, content size, and
159
175
  # content (only if it's up to 200 bytes)
160
176
  def inspect
161
- "#<%s:0x%x frames=%i content_size=%i content=%s>" % [
162
- self.class,
163
- to_ptr.address,
164
- size,
165
- content_size,
166
- content_size <= 500 ? to_a.inspect : "[...]"
167
- ]
177
+ format('#<%s:0x%x frames=%i content_size=%i content=%s>', self.class, to_ptr.address, size, content_size,
178
+ content_size <= 500 ? to_a.inspect : '[...]')
168
179
  end
169
180
 
181
+
170
182
  # Return a frame's content.
171
183
  # @return [String] the frame's content, if it exists
172
184
  # @return [nil] if frame doesn't exist at given index
@@ -193,8 +205,10 @@ module CZTop
193
205
 
194
206
  # need to raise manually, as FFI lacks this feature.
195
207
  # @see https://github.com/ffi/ffi/issues/473
196
- raise RangeError if new_routing_id < 0
208
+ raise RangeError if new_routing_id.negative?
209
+
197
210
  ffi_delegate.set_routing_id(new_routing_id)
198
211
  end
212
+
199
213
  end
200
214
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module CZTop
@@ -13,12 +15,15 @@ module CZTop
13
15
  #
14
16
  # @see https://rfc.zeromq.org/spec:23/ZMTP
15
17
  class Metadata
16
- VALUE_MAXLEN = 2**31-1
18
+
19
+ VALUE_MAXLEN = (2**31) - 1
20
+
17
21
 
18
22
  # Raised when decoding malformed metadata.
19
23
  class InvalidData < StandardError
20
24
  end
21
25
 
26
+
22
27
  # regular expression used to validate property names
23
28
  NAME_REGEX = /\A[[:alnum:]_.+-]{1,255}\Z/.freeze
24
29
 
@@ -29,47 +34,49 @@ module CZTop
29
34
  # @return [String]
30
35
  def self.dump(metadata)
31
36
  ic_names = Set.new
37
+
32
38
  metadata.map do |k, v|
33
39
  ic_name = k.to_sym.downcase
34
- if ic_names.include?(ic_name)
35
- raise ArgumentError, "property #{k.inspect}: duplicate name"
36
- else
37
- ic_names << ic_name
38
- end
40
+ raise ArgumentError, "property #{k.inspect}: duplicate name" if ic_names.include? ic_name
41
+
42
+ ic_names << ic_name
43
+
39
44
  name = k.to_s
40
- if NAME_REGEX !~ name
41
- raise ArgumentError, "property #{k.inspect}: invalid name"
42
- end
45
+ raise ArgumentError, "property #{k.inspect}: invalid name" if NAME_REGEX !~ name
46
+
43
47
  value = v.to_s
44
- if value.bytesize > VALUE_MAXLEN
45
- raise ArgumentError, "property #{k.inspect}: value too long"
46
- end
47
- [name.size, name, value.bytesize, value].pack("CA*NA*")
48
+ raise ArgumentError, "property #{k.inspect}: value too long" if value.bytesize > VALUE_MAXLEN
49
+
50
+ [name.size, name, value.bytesize, value].pack('CA*NA*')
48
51
  end.join
49
52
  end
50
53
 
54
+
51
55
  # @param data [String, Frame, #to_s] the data representing the metadata
52
56
  # @return [Hash]
53
57
  def self.load(data)
54
58
  properties = {}
55
- consumed = 0
59
+ consumed = 0
60
+
56
61
  while consumed < data.bytesize # while there are bytes to read
57
62
  # read property name
58
- name_length = data.byteslice(consumed).unpack("C").first # never nil
59
- raise InvalidData, "zero-length property name" if name_length.zero?
63
+ name_length = data.byteslice(consumed).unpack1('C') # never nil
64
+ raise InvalidData, 'zero-length property name' if name_length.zero?
65
+
60
66
  name = data.byteslice(consumed + 1, name_length)
61
- raise InvalidData, "incomplete name" if name.bytesize != name_length
67
+ raise InvalidData, 'incomplete name' if name.bytesize != name_length
68
+
62
69
  name_sym = name.to_sym.downcase
63
- if properties.has_key?(name_sym)
64
- raise InvalidData, "property #{name.inspect}: duplicate name"
65
- end
70
+ raise InvalidData, "property #{name.inspect}: duplicate name" if properties.key?(name_sym)
71
+
66
72
  consumed += 1 + name.bytesize
67
73
 
68
74
  # read property value
69
- value_length = data.byteslice(consumed, 4).unpack("N").first or
70
- raise InvalidData, "incomplete length"
71
- value = data.byteslice(consumed + 4, value_length)
72
- raise InvalidData, "incomplete value" if value.bytesize != value_length
75
+ value_length = data.byteslice(consumed, 4).unpack1('N') or
76
+ raise InvalidData, 'incomplete length'
77
+ value = data.byteslice(consumed + 4, value_length)
78
+ raise InvalidData, 'incomplete value' if value.bytesize != value_length
79
+
73
80
  consumed += 4 + value.bytesize
74
81
 
75
82
  # remember
@@ -78,12 +85,14 @@ module CZTop
78
85
  new(properties)
79
86
  end
80
87
 
88
+
81
89
  # @param properties [Hash<Symbol, String>] the properties as loaded by
82
90
  # {load}
83
91
  def initialize(properties)
84
92
  @properties = properties
85
93
  end
86
94
 
95
+
87
96
  # Gets the value corresponding to a property name. The case of the name
88
97
  # is insignificant.
89
98
  # @param name [Symbol, String] the property name
@@ -92,9 +101,11 @@ module CZTop
92
101
  @properties[name.to_sym.downcase]
93
102
  end
94
103
 
104
+
95
105
  # @return [Hash<Symbol, String] all properties
96
106
  def to_h
97
107
  @properties
98
108
  end
109
+
99
110
  end
100
111
  end
data/lib/cztop/monitor.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # CZMQ monitor. Listen for socket events.
3
5
  #
@@ -8,11 +10,12 @@ module CZTop
8
10
  # @see http://api.zeromq.org/czmq3-0:zmonitor
9
11
  # @see http://api.zeromq.org/4-1:zmq-socket-monitor
10
12
  class Monitor
13
+
11
14
  include ::CZMQ::FFI
12
15
 
13
16
  # function pointer to the +zmonitor()+ function
14
17
  ZMONITOR_FPTR = ::CZMQ::FFI.ffi_libraries.each do |dl|
15
- fptr = dl.find_function("zmonitor")
18
+ fptr = dl.find_function('zmonitor')
16
19
  break fptr if fptr
17
20
  end
18
21
  raise LoadError, "couldn't find zmonitor()" if ZMONITOR_FPTR.nil?
@@ -31,10 +34,11 @@ module CZTop
31
34
  @actor.terminate
32
35
  end
33
36
 
37
+
34
38
  # Enable verbose logging of commands and activity.
35
39
  # @return [void]
36
40
  def verbose!
37
- @actor << "VERBOSE"
41
+ @actor << 'VERBOSE'
38
42
  end
39
43
 
40
44
  # @return [Array<String>] types of valid events
@@ -55,7 +59,7 @@ module CZTop
55
59
  HANDSHAKE_FAILED_NO_DETAIL
56
60
  HANDSHAKE_FAILED_PROTOCOL
57
61
  HANDSHAKE_FAILED_AUTH
58
- ]
62
+ ].freeze
59
63
 
60
64
  # Configure monitor to listen for specific events.
61
65
  # @param events [String] one or more events from {EVENTS}
@@ -65,16 +69,18 @@ module CZTop
65
69
  EVENTS.include?(event) or
66
70
  raise ArgumentError, "invalid event: #{event.inspect}"
67
71
  end
68
- @actor << [ "LISTEN", *events ]
72
+ @actor << ['LISTEN', *events]
69
73
  end
70
74
 
75
+
71
76
  # Start the monitor. After this, you can read events using {#next}.
72
77
  # @return [void]
73
78
  def start
74
- @actor << "START"
79
+ @actor << 'START'
75
80
  @actor.wait
76
81
  end
77
82
 
83
+
78
84
  # Useful for registration in an event-loop.
79
85
  # @return [Integer] the FD
80
86
  # @see ZsockOptions#fd
@@ -82,11 +88,13 @@ module CZTop
82
88
  @actor.fd
83
89
  end
84
90
 
91
+
85
92
  # @return [Boolean] whether there's at least one event available
86
93
  def readable?
87
94
  @actor.readable?
88
95
  end
89
96
 
97
+
90
98
  # Get next event. This blocks until the next event is available.
91
99
  # @example
92
100
  # socket = CZTop::Socket::ROUTER.new("tcp://127.0.0.1:5050")
@@ -112,5 +120,6 @@ module CZTop
112
120
  def next
113
121
  @actor.receive
114
122
  end
123
+
115
124
  end
116
125
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # This is a poller which is able to provide a list of readable and a list
3
5
  # of writable sockets. This is useful for when you need to process socket
@@ -37,31 +39,37 @@ module CZTop
37
39
  # @return [CZTop::Poller.new] the associated (regular) poller
38
40
  attr_reader :poller
39
41
 
42
+
40
43
  # @return [Array<CZTop::Socket>] readable sockets
41
44
  attr_reader :readables
42
45
 
46
+
43
47
  # @return [Array<CZTop::Socket>] writable sockets
44
48
  attr_reader :writables
45
49
 
50
+
46
51
  extend Forwardable
52
+
47
53
  def_delegators :@poller,
48
- :add,
49
- :add_reader,
50
- :add_writer,
51
- :modify,
52
- :remove,
53
- :remove_reader,
54
- :remove_writer,
55
- :sockets
54
+ :add,
55
+ :add_reader,
56
+ :add_writer,
57
+ :modify,
58
+ :remove,
59
+ :remove_reader,
60
+ :remove_writer,
61
+ :sockets
62
+
56
63
 
57
64
  # Initializes the aggregated poller.
58
65
  # @param poller [CZTop::Poller] the wrapped poller
59
66
  def initialize(poller = CZTop::Poller.new)
60
67
  @readables = []
61
68
  @writables = []
62
- @poller = poller
69
+ @poller = poller
63
70
  end
64
71
 
72
+
65
73
  # Forgets all previous event information (which sockets are
66
74
  # readable/writable) and waits for events anew. After getting the first
67
75
  # event, {CZTop::Poller#wait} is called again with a zero-timeout to get
@@ -76,26 +84,29 @@ module CZTop
76
84
  # or -1 to wait indefinitely
77
85
  # @return [Boolean] whether there have been any events
78
86
  def wait(timeout = -1)
79
- @readables = []
80
- @writables = []
87
+ @readables = []
88
+ @writables = []
81
89
  @event_masks = {}
82
90
 
83
- if event = @poller.wait(timeout)
91
+ if (event = @poller.wait(timeout))
84
92
  extract(event)
85
93
 
86
94
  # get all other pending events, if any, but no more blocking
87
- while event = @poller.wait(0)
95
+ while (event = @poller.wait 0)
88
96
  extract(event)
89
97
  end
90
98
 
91
99
  restore_event_masks
92
100
  return true
93
101
  end
94
- return false
102
+
103
+ false
95
104
  end
96
105
 
106
+
97
107
  private
98
108
 
109
+
99
110
  # Extracts the event information, adds the socket to the correct list(s)
100
111
  # and modifies the socket's event mask for the socket to not turn up
101
112
  # again during the next call(s) to {CZTop::Poller#wait} within {#wait}.
@@ -103,24 +114,29 @@ module CZTop
103
114
  # @param event [CZTop::Poller::Event]
104
115
  # @return [void]
105
116
  def extract(event)
106
- event_mask = poller.event_mask_for_socket(event.socket)
117
+ event_mask = poller.event_mask_for_socket(event.socket)
107
118
  @event_masks[event.socket] = event_mask
119
+
108
120
  if event.readable?
109
121
  @readables << event.socket
110
122
  event_mask &= 0xFFFF ^ CZTop::Poller::ZMQ::POLLIN
111
123
  end
124
+
112
125
  if event.writable?
113
126
  @writables << event.socket
114
127
  event_mask &= 0xFFFF ^ CZTop::Poller::ZMQ::POLLOUT
115
128
  end
129
+
116
130
  poller.modify(event.socket, event_mask)
117
131
  end
118
132
 
133
+
119
134
  # Restores the event mask for all registered sockets to the state they
120
135
  # were before the call to {#wait}.
121
136
  # @return [void]
122
137
  def restore_event_masks
123
138
  @event_masks.each { |socket, mask| poller.modify(socket, mask) }
124
139
  end
140
+
125
141
  end
126
142
  end
@@ -1,5 +1,6 @@
1
- module CZTop
1
+ # frozen_string_literal: true
2
2
 
3
+ module CZTop
3
4
  # CZTop's interface to the low-level +zmq_poller_*()+ functions.
4
5
  module Poller::ZMQ
5
6
 
@@ -8,9 +9,9 @@ module CZTop
8
9
  POLLERR = 4
9
10
 
10
11
  extend ::FFI::Library
11
- lib_name = 'libzmq'
12
- lib_dirs = ['/usr/local/lib', '/opt/local/lib', '/usr/lib64']
13
- lib_dirs = [*ENV['LIBZMQ_PATH'].split(':'), *lib_dirs] if ENV['LIBZMQ_PATH']
12
+ lib_name = 'libzmq'
13
+ lib_dirs = ['/usr/local/lib', '/opt/local/lib', '/usr/lib64']
14
+ lib_dirs = [*ENV['LIBZMQ_PATH'].split(':'), *lib_dirs] if ENV['LIBZMQ_PATH']
14
15
  lib_paths = lib_dirs.map { |path| "#{path}/#{lib_name}.#{::FFI::Platform::LIBSUFFIX}" }
15
16
  ffi_lib lib_paths + [lib_name]
16
17
 
@@ -24,6 +25,7 @@ module CZTop
24
25
  # short events;
25
26
  # } zmq_poller_event_t;
26
27
  class PollerEvent < FFI::Struct
28
+
27
29
  layout :socket, :pointer,
28
30
  :fd, :int,
29
31
  :user_data, :pointer,
@@ -31,21 +33,23 @@ module CZTop
31
33
 
32
34
  # @return [Boolean] whether the socket is readable
33
35
  def readable?
34
- (self[:events] & POLLIN) > 0
36
+ (self[:events] & POLLIN).positive?
35
37
  end
36
38
 
39
+
37
40
  # @return [Boolean] whether the socket is writable
38
41
  def writable?
39
- (self[:events] & POLLOUT) > 0
42
+ (self[:events] & POLLOUT).positive?
40
43
  end
44
+
41
45
  end
42
46
 
43
- #ZMQ_EXPORT void *zmq_poller_new (void);
44
- #ZMQ_EXPORT int zmq_poller_destroy (void **poller_p);
45
- #ZMQ_EXPORT int zmq_poller_add (void *poller, void *socket, void *user_data, short events);
46
- #ZMQ_EXPORT int zmq_poller_modify (void *poller, void *socket, short events);
47
- #ZMQ_EXPORT int zmq_poller_remove (void *poller, void *socket);
48
- #ZMQ_EXPORT int zmq_poller_wait (void *poller, zmq_poller_event_t *event, long timeout);
47
+ # ZMQ_EXPORT void *zmq_poller_new (void);
48
+ # ZMQ_EXPORT int zmq_poller_destroy (void **poller_p);
49
+ # ZMQ_EXPORT int zmq_poller_add (void *poller, void *socket, void *user_data, short events);
50
+ # ZMQ_EXPORT int zmq_poller_modify (void *poller, void *socket, short events);
51
+ # ZMQ_EXPORT int zmq_poller_remove (void *poller, void *socket);
52
+ # ZMQ_EXPORT int zmq_poller_wait (void *poller, zmq_poller_event_t *event, long timeout);
49
53
 
50
54
  # Gracefully attaches a function. If it's not available, this creates
51
55
  # a placeholder class method which, when called, simply raises
@@ -53,27 +57,26 @@ module CZTop
53
57
  def self.attach_function(function_nickname, function_name, *args)
54
58
  super
55
59
  rescue ::FFI::NotFoundError
56
- if $VERBOSE || $DEBUG
57
- warn "CZTop: The ZMQ function #{function_name}() is not available. Don't use CZTop::Poller."
58
- end
60
+ warn "CZTop: The ZMQ function #{function_name}() is not available. Don't use CZTop::Poller." if $VERBOSE || $DEBUG
59
61
  define_singleton_method(function_nickname) do |*|
60
- raise NotImplementedError, "compile ZMQ with --enable-drafts"
62
+ raise NotImplementedError, 'compile ZMQ with --enable-drafts'
61
63
  end
62
64
  end
63
65
 
64
66
  opts = {
65
- blocking: true # only necessary on MRI to deal with the GIL.
67
+ blocking: true # only necessary on MRI to deal with the GIL.
66
68
  }
67
69
  attach_function :poller_new, :zmq_poller_new, [], :pointer, **opts
68
70
  attach_function :poller_destroy, :zmq_poller_destroy,
69
- [:pointer], :int, **opts
71
+ [:pointer], :int, **opts
70
72
  attach_function :poller_add, :zmq_poller_add,
71
- [:pointer, :pointer, :pointer, :short], :int, **opts
73
+ %i[pointer pointer pointer short], :int, **opts
72
74
  attach_function :poller_modify, :zmq_poller_modify,
73
- [:pointer, :pointer, :short], :int, **opts
75
+ %i[pointer pointer short], :int, **opts
74
76
  attach_function :poller_remove, :zmq_poller_remove,
75
- [:pointer, :pointer], :int, **opts
77
+ %i[pointer pointer], :int, **opts
76
78
  attach_function :poller_wait, :zmq_poller_wait,
77
- [:pointer, :pointer, :long], :int, **opts
79
+ %i[pointer pointer long], :int, **opts
80
+
78
81
  end
79
82
  end