cztop 1.0.0 → 1.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,16 +1,18 @@
1
- module CZTop
1
+ # frozen_string_literal: true
2
2
 
3
+ module CZTop
3
4
  # Authentication for ZeroMQ security mechanisms.
4
5
  #
5
6
  # This is implemented using an {Actor}.
6
7
  #
7
8
  # @see http://api.zeromq.org/czmq3-0:zauth
8
9
  class Authenticator
10
+
9
11
  include ::CZMQ::FFI
10
12
 
11
13
  # function pointer to the +zauth()+ function
12
14
  ZAUTH_FPTR = ::CZMQ::FFI.ffi_libraries.each do |dl|
13
- fptr = dl.find_function("zauth")
15
+ fptr = dl.find_function('zauth')
14
16
  break fptr if fptr
15
17
  end
16
18
  raise LoadError, "couldn't find zauth()" if ZAUTH_FPTR.nil?
@@ -23,6 +25,7 @@ module CZTop
23
25
  def initialize(cert_store = nil)
24
26
  if cert_store
25
27
  raise ArgumentError unless cert_store.is_a?(CertStore)
28
+
26
29
  cert_store = cert_store.ffi_delegate
27
30
  cert_store.__undef_finalizer # native object is now owned by zauth() actor
28
31
  end
@@ -38,13 +41,15 @@ module CZTop
38
41
  @actor.terminate
39
42
  end
40
43
 
44
+
41
45
  # Enable verbose logging of commands and activity.
42
46
  # @return [void]
43
47
  def verbose!
44
- @actor << "VERBOSE"
48
+ @actor << 'VERBOSE'
45
49
  @actor.wait
46
50
  end
47
51
 
52
+
48
53
  # Add a list of IP addresses to the whitelist. For _NULL_, all clients
49
54
  # from these addresses will be accepted. For _PLAIN_ and _CURVE_, they
50
55
  # will be allowed to continue with authentication.
@@ -52,10 +57,11 @@ module CZTop
52
57
  # @param addrs [String] IP address(es) to allow
53
58
  # @return [void]
54
59
  def allow(*addrs)
55
- @actor << ["ALLOW", *addrs]
60
+ @actor << ['ALLOW', *addrs]
56
61
  @actor.wait
57
62
  end
58
63
 
64
+
59
65
  # Add a list of IP addresses to the blacklist. For all security
60
66
  # mechanisms, this rejects the connection without any further
61
67
  # authentication. Use either a whitelist, or a blacklist, not not both. If
@@ -65,22 +71,23 @@ module CZTop
65
71
  # @param addrs [String] IP address(es) to deny
66
72
  # @return [void]
67
73
  def deny(*addrs)
68
- @actor << ["DENY", *addrs]
74
+ @actor << ['DENY', *addrs]
69
75
  @actor.wait
70
76
  end
71
77
 
78
+
72
79
  # Configure PLAIN security mechanism using a plain-text password file. The
73
80
  # password file will be reloaded automatically if modified externally.
74
81
  #
75
82
  # @param filename [String] path to the password file
76
83
  # @return [void]
77
84
  def plain(filename)
78
- @actor << ["PLAIN", *filename]
85
+ @actor << ['PLAIN', *filename]
79
86
  @actor.wait
80
87
  end
81
88
 
82
89
  # used to allow any CURVE client
83
- ALLOW_ANY = "*"
90
+ ALLOW_ANY = '*'
84
91
 
85
92
  # Configure CURVE authentication, using a directory that holds all public
86
93
  # client certificates, i.e. their public keys. The certificates must have been
@@ -90,15 +97,17 @@ module CZTop
90
97
  # @param directory [String] the directory to take the keys from
91
98
  # @return [void]
92
99
  def curve(directory = ALLOW_ANY)
93
- @actor << ["CURVE", directory]
100
+ @actor << ['CURVE', directory]
94
101
  @actor.wait
95
102
  end
96
103
 
104
+
97
105
  # Configure GSSAPI authentication.
98
106
  # @return [void]
99
107
  def gssapi
100
- @actor << "GSSAPI"
108
+ @actor << 'GSSAPI'
101
109
  @actor.wait
102
110
  end
111
+
103
112
  end
104
113
  end
data/lib/cztop/beacon.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # Used for LAN discovery and presence.
3
5
  #
@@ -5,11 +7,12 @@ module CZTop
5
7
  #
6
8
  # @see http://api.zeromq.org/czmq3-0:zbeacon
7
9
  class Beacon
10
+
8
11
  include ::CZMQ::FFI
9
12
 
10
13
  # function pointer to the +zbeacon()+ function
11
14
  ZBEACON_FPTR = ::CZMQ::FFI.ffi_libraries.each do |dl|
12
- fptr = dl.find_function("zbeacon")
15
+ fptr = dl.find_function('zbeacon')
13
16
  break fptr if fptr
14
17
  end
15
18
  raise LoadError, "couldn't find zbeacon()" if ZBEACON_FPTR.nil?
@@ -28,12 +31,14 @@ module CZTop
28
31
  @actor.terminate
29
32
  end
30
33
 
34
+
31
35
  # Enable verbose logging of commands and activity.
32
36
  # @return [void]
33
37
  def verbose!
34
- @actor << "VERBOSE"
38
+ @actor << 'VERBOSE'
35
39
  end
36
40
 
41
+
37
42
  # Run the beacon on the specified UDP port.
38
43
  #
39
44
  # @param port [Integer] port number to
@@ -43,7 +48,7 @@ module CZTop
43
48
  # interrupted
44
49
  # @raise [NotImplementedError] if the system doesn't support UDP broadcasts
45
50
  def configure(port)
46
- @actor.send_picture("si", :string, "CONFIGURE", :int, port)
51
+ @actor.send_picture('si', :string, 'CONFIGURE', :int, port)
47
52
  ptr = Zstr.recv(@actor)
48
53
 
49
54
  # NULL if context terminated or interrupted
@@ -64,42 +69,49 @@ module CZTop
64
69
  # @raise [ArgumentError] if data is longer than {MAX_BEACON_DATA} bytes
65
70
  # @return [void]
66
71
  def publish(data, interval)
67
- raise ArgumentError, "data too long" if data.bytesize > MAX_BEACON_DATA
68
- @actor.send_picture("sbi", :string, "PUBLISH", :string, data,
69
- :int, data.bytesize, :int, interval)
72
+ raise ArgumentError, 'data too long' if data.bytesize > MAX_BEACON_DATA
73
+
74
+ @actor.send_picture('sbi', :string, 'PUBLISH', :string, data,
75
+ :int, data.bytesize, :int, interval)
70
76
  end
71
77
 
78
+
72
79
  # Stop broadcasting the beacon.
73
80
  # @return [void]
74
81
  def silence
75
- @actor << "SILENCE"
82
+ @actor << 'SILENCE'
76
83
  end
77
84
 
85
+
78
86
  # Start listening to beacons from peers.
79
87
  # @param filter [String] do a prefix match on received beacons
80
88
  # @return [void]
81
89
  def subscribe(filter)
82
- @actor.send_picture("sb", :string, "SUBSCRIBE",
90
+ @actor.send_picture('sb', :string, 'SUBSCRIBE',
83
91
  :string, filter, :int, filter.bytesize)
84
92
  end
85
93
 
94
+
86
95
  # Just like {#subscribe}, but subscribe to all peer beacons.
87
96
  # @return [void]
88
97
  def listen
89
- @actor.send_picture("sb", :string, "SUBSCRIBE",
98
+ @actor.send_picture('sb', :string, 'SUBSCRIBE',
90
99
  :string, nil, :int, 0)
91
100
  end
92
101
 
102
+
93
103
  # Stop listening to other peers.
94
104
  # @return [void]
95
105
  def unsubscribe
96
- @actor << "UNSUBSCRIBE"
106
+ @actor << 'UNSUBSCRIBE'
97
107
  end
98
108
 
109
+
99
110
  # Receive next beacon from a peer.
100
111
  # @return [Message] 2-frame message with ([ipaddr, data])
101
112
  def receive
102
113
  @actor.receive
103
114
  end
115
+
104
116
  end
105
117
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module CZTop
4
-
5
6
  # A store for CURVE security certificates, either backed by files on disk or
6
7
  # in-memory.
7
8
  #
8
9
  # @see http://api.zeromq.org/czmq3-0:zcertstore
9
10
  class CertStore
11
+
10
12
  include ::CZMQ::FFI
11
13
  include HasFFIDelegate
12
14
  extend CZTop::HasFFIDelegate::ClassMethods
@@ -21,6 +23,7 @@ module CZTop
21
23
  attach_ffi_delegate(Zcertstore.new(location))
22
24
  end
23
25
 
26
+
24
27
  # Looks up a certificate in the store by its public key.
25
28
  #
26
29
  # @param pubkey [String] the public key in question, in Z85 format
@@ -29,9 +32,11 @@ module CZTop
29
32
  def lookup(pubkey)
30
33
  ptr = ffi_delegate.lookup(pubkey)
31
34
  return nil if ptr.null?
35
+
32
36
  Certificate.from_ffi_delegate(ptr)
33
37
  end
34
38
 
39
+
35
40
  # Inserts a new certificate into the store.
36
41
  #
37
42
  # @note The same public key must not be inserted more than once.
@@ -43,11 +48,12 @@ module CZTop
43
48
  raise ArgumentError unless cert.is_a?(Certificate)
44
49
 
45
50
  @_inserted_pubkeys ||= Set.new
46
- pubkey = cert.public_key
51
+ pubkey = cert.public_key
47
52
  raise ArgumentError if @_inserted_pubkeys.include? pubkey
48
53
 
49
54
  ffi_delegate.insert(cert.ffi_delegate)
50
55
  @_inserted_pubkeys << pubkey
51
56
  end
57
+
52
58
  end
53
59
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # Represents a CZMQ::FFI::Zcert.
3
5
  class Certificate
6
+
4
7
  include HasFFIDelegate
5
8
  extend CZTop::HasFFIDelegate::ClassMethods
6
9
  include ::CZMQ::FFI
@@ -9,9 +12,11 @@ module CZTop
9
12
  # @return [void]
10
13
  def self.check_curve_availability
11
14
  return if Zsys.has_curve
15
+
12
16
  warn "CZTop: CURVE isn't available. Consider installing libsodium."
13
17
  end
14
18
 
19
+
15
20
  # Loads a certificate from a file.
16
21
  # @param filename [String, Pathname, #to_s] path to certificate file
17
22
  # @return [Certificate] the loaded certificate
@@ -20,6 +25,7 @@ module CZTop
20
25
  from_ffi_delegate(ptr)
21
26
  end
22
27
 
28
+
23
29
  # Creates a new certificate from the given keys (either binary or in Z85
24
30
  # format).
25
31
  # @param public_key [String] binary public key (32 or 40 bytes)
@@ -29,25 +35,28 @@ module CZTop
29
35
  # @raise [ArgumentError] if keys passed are invalid
30
36
  # @raise [SystemCallError] if this fails
31
37
  def self.new_from(public_key, secret_key = nil)
32
- raise ArgumentError, "no public key given" unless public_key
38
+ raise ArgumentError, 'no public key given' unless public_key
39
+
33
40
  secret_key ||= "\x00" * 32 # no secret key given, provide 32 null bytes
34
41
 
35
42
  # convert Z85 => binary
36
43
  public_key = Z85.decode(public_key) if public_key.bytesize == 40
37
44
  secret_key = Z85.decode(secret_key) if secret_key.bytesize == 40
38
45
 
39
- raise ArgumentError, "invalid public key size" if public_key.bytesize != 32
40
- raise ArgumentError, "invalid secret key size" if secret_key.bytesize != 32
46
+ raise ArgumentError, 'invalid public key size' if public_key.bytesize != 32
47
+ raise ArgumentError, 'invalid secret key size' if secret_key.bytesize != 32
41
48
 
42
49
  ptr = Zcert.new_from(public_key, secret_key)
43
50
  from_ffi_delegate(ptr)
44
51
  end
45
52
 
53
+
46
54
  # Initialize a new in-memory certificate with random keys.
47
55
  def initialize
48
56
  attach_ffi_delegate(Zcert.new)
49
57
  end
50
58
 
59
+
51
60
  # Returns the public key either as Z85-encoded ASCII string (default) or
52
61
  # binary string.
53
62
  # @param format [Symbol] +:z85+ for Z85, +:binary+ for binary
@@ -59,10 +68,11 @@ module CZTop
59
68
  when :binary
60
69
  ffi_delegate.public_key.read_string(32)
61
70
  else
62
- raise ArgumentError, "invalid format: %p" % format
71
+ raise ArgumentError, format('invalid format: %p', format)
63
72
  end
64
73
  end
65
74
 
75
+
66
76
  # Returns the secret key either as Z85-encoded ASCII string (default) or
67
77
  # binary string.
68
78
  # @param format [Symbol] +:z85+ for Z85, +:binary+ for binary
@@ -73,16 +83,17 @@ module CZTop
73
83
  case format
74
84
  when :z85
75
85
  key = ffi_delegate.secret_txt.force_encoding(Encoding::ASCII)
76
- return nil if key.count("0") == 40
86
+ return nil if key.count('0') == 40
77
87
  when :binary
78
88
  key = ffi_delegate.secret_key.read_string(32)
79
89
  return nil if key.count("\0") == 32
80
90
  else
81
- raise ArgumentError, "invalid format: %p" % format
91
+ raise ArgumentError, format('invalid format: %p', format)
82
92
  end
83
93
  key
84
94
  end
85
95
 
96
+
86
97
  # Get metadata.
87
98
  # @param key [String] metadata key
88
99
  # @return [String] value for meta key
@@ -90,32 +101,38 @@ module CZTop
90
101
  def [](key)
91
102
  ffi_delegate.meta(key)
92
103
  end
104
+
105
+
93
106
  # Set metadata.
94
107
  # @param key [String] metadata key
95
108
  # @param value [String] metadata value
96
109
  # @return [value]
97
110
  def []=(key, value)
98
111
  if value
99
- ffi_delegate.set_meta(key, "%s", :string, value)
112
+ ffi_delegate.set_meta(key, '%s', :string, value)
100
113
  else
101
114
  ffi_delegate.unset_meta(key)
102
115
  end
103
116
  end
104
117
 
118
+
105
119
  # Returns meta keys set.
106
120
  # @return [Array<String>]
107
121
  def meta_keys
108
- zlist = ffi_delegate.meta_keys
122
+ zlist = ffi_delegate.meta_keys
109
123
  first_key = zlist.first
110
124
  return [] if first_key.null?
125
+
111
126
  keys = [first_key.read_string]
112
- while key = zlist.next
127
+ while (key = zlist.next)
113
128
  break if key.null?
129
+
114
130
  keys << key.read_string
115
131
  end
116
132
  keys
117
133
  end
118
134
 
135
+
119
136
  # Save full certificate (public + secret) to files.
120
137
  # @param filename [String, #to_s] path/filename to public file
121
138
  # @return [void]
@@ -126,55 +143,67 @@ module CZTop
126
143
  def save(filename)
127
144
  # see https://github.com/zeromq/czmq/issues/1244
128
145
  raise ArgumentError, "filename can't be empty" if filename.to_s.empty?
146
+
129
147
  rc = ffi_delegate.save(filename.to_s)
130
- return if rc == 0
131
- raise_zmq_err("error while saving to file %p" % filename)
148
+ return if rc.zero?
149
+
150
+ raise_zmq_err(format('error while saving to file %p', filename))
132
151
  end
133
152
 
153
+
134
154
  # Saves the public key to file in ZPL ({Config}) format.
135
155
  # @param filename [String, #to_s] path/filename to public file
136
156
  # @return [void]
137
157
  # @raise [SystemCallError] if this fails
138
158
  def save_public(filename)
139
159
  rc = ffi_delegate.save_public(filename.to_s)
140
- return if rc == 0
141
- raise_zmq_err("error while saving to the file %p" % filename)
160
+ return if rc.zero?
161
+
162
+ raise_zmq_err(format('error while saving to the file %p', filename))
142
163
  end
143
164
 
165
+
144
166
  # Saves the secret key to file in ZPL ({Config}) format.
145
167
  # @param filename [String, #to_s] path/filename to secret file
146
168
  # @return [void]
147
169
  # @raise [SystemCallError] if this fails
148
170
  def save_secret(filename)
149
171
  rc = ffi_delegate.save_secret(filename.to_s)
150
- return if rc == 0
151
- raise_zmq_err("error while saving to the file %p" % filename)
172
+ return if rc.zero?
173
+
174
+ raise_zmq_err(format('error while saving to the file %p', filename))
152
175
  end
153
176
 
177
+
154
178
  # Applies this certificate on a {Socket} or {Actor}.
155
179
  # @param zocket [Socket, Actor] path/filename to secret file
156
180
  # @return [void]
157
181
  # @raise [SystemCallError] if secret key is undefined
158
182
  def apply(zocket)
159
- raise ArgumentError, "invalid zocket argument %p" % zocket unless zocket
183
+ raise ArgumentError, format('invalid zocket argument %p', zocket) unless zocket
160
184
  return ffi_delegate.apply(zocket) unless secret_key.nil?
161
- raise_zmq_err("secret key is undefined")
185
+
186
+ raise_zmq_err('secret key is undefined')
162
187
  end
163
188
 
189
+
164
190
  # Duplicates the certificate.
165
191
  # @return [Certificate]
166
192
  # @raise [SystemCallError] if this fails
167
193
  def dup
168
194
  ptr = ffi_delegate.dup
169
195
  return from_ffi_delegate(ptr) unless ptr.null?
170
- raise_zmq_err("unable to duplicate certificate")
196
+
197
+ raise_zmq_err('unable to duplicate certificate')
171
198
  end
172
199
 
200
+
173
201
  # Compares this certificate to another.
174
202
  # @param other [Cert] other certificate
175
203
  # @return [Boolean] whether they have the same keys
176
204
  def ==(other)
177
205
  ffi_delegate.eq(other.ffi_delegate)
178
206
  end
207
+
179
208
  end
180
209
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  class Config
3
5
 
@@ -7,11 +9,13 @@ module CZTop
7
9
  # are accessible.
8
10
  # @return [CommentsAccessor]
9
11
  def comments
10
- return CommentsAccessor.new(self)
12
+ CommentsAccessor.new(self)
11
13
  end
12
14
 
15
+
13
16
  # Used to access a {Config}'s comments.
14
17
  class CommentsAccessor
18
+
15
19
  include Enumerable
16
20
 
17
21
  # @param config [Config]
@@ -19,26 +23,30 @@ module CZTop
19
23
  @config = config
20
24
  end
21
25
 
26
+
22
27
  # Adds a new comment.
23
28
  # @param new_comment [String]
24
29
  # @return [self]
25
30
  def <<(new_comment)
26
- @config.ffi_delegate.set_comment("%s", :string, new_comment)
27
- return self
31
+ @config.ffi_delegate.set_comment('%s', :string, new_comment)
32
+ self
28
33
  end
29
34
 
35
+
30
36
  # Deletes all comments for this {Config} item.
31
37
  # @return [void]
32
38
  def delete_all
33
39
  @config.ffi_delegate.set_comment(nil)
34
40
  end
35
41
 
42
+
36
43
  # Yields all comments for this {Config} item.
37
44
  # @yieldparam comment [String]
38
45
  # @return [void]
39
46
  def each
40
47
  while comment = _zlist.next
41
48
  break if comment.null?
49
+
42
50
  yield comment.read_string
43
51
  end
44
52
  rescue CZMQ::FFI::Zlist::DestroyedError
@@ -46,6 +54,7 @@ module CZTop
46
54
  nil
47
55
  end
48
56
 
57
+
49
58
  # Returns the number of comments for this {Config} item.
50
59
  # @return [Integer] number of comments
51
60
  def size
@@ -61,6 +70,8 @@ module CZTop
61
70
  def _zlist
62
71
  @config.ffi_delegate.comments
63
72
  end
73
+
64
74
  end
75
+
65
76
  end
66
77
  end
@@ -1,19 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Methods used around serialization of {CZTop::Config} items.
2
4
  module CZTop::Config::Serialization
5
+
3
6
  # Serialize to a string in the ZPL format.
4
7
  # @return [String]
5
8
  def to_s
6
9
  ffi_delegate.str_save.read_string
7
10
  end
8
11
 
12
+
9
13
  # Returns the path/filename of the file this {Config} tree was loaded from.
10
14
  # @return [String]
11
15
  def filename
12
16
  ffi_delegate.filename
13
17
  end
14
18
 
19
+
15
20
  # Some class methods for {Config} related to serialization.
16
21
  module ClassMethods
22
+
17
23
  # Loads a {Config} tree from a string.
18
24
  # @param string [String] the tree
19
25
  # @return [Config]
@@ -21,6 +27,7 @@ module CZTop::Config::Serialization
21
27
  from_ffi_delegate CZMQ::FFI::Zconfig.str_load(string)
22
28
  end
23
29
 
30
+
24
31
  # Loads a {Config} tree from a file.
25
32
  # @param path [String, Pathname, #to_s] the path to the ZPL config file
26
33
  # @raise [SystemCallError] if this fails
@@ -28,10 +35,13 @@ module CZTop::Config::Serialization
28
35
  def load(path)
29
36
  ptr = CZMQ::FFI::Zconfig.load(path.to_s)
30
37
  return from_ffi_delegate(ptr) unless ptr.null?
38
+
31
39
  CZTop::HasFFIDelegate.raise_zmq_err(
32
- "error while reading the file %p" % path.to_s)
40
+ format('error while reading the file %p', path.to_s)
41
+ )
33
42
  end
34
43
 
44
+
35
45
  # Loads a {Config} tree from a marshalled string.
36
46
  # @note This method is automatically used by Marshal.load.
37
47
  # @param string [String] marshalled {Config}
@@ -39,18 +49,22 @@ module CZTop::Config::Serialization
39
49
  def _load(string)
40
50
  from_string(string)
41
51
  end
52
+
42
53
  end
43
54
 
55
+
44
56
  # Saves the Config tree to a file.
45
57
  # @param path [String, Pathname, #to_s] the path to the ZPL config file
46
58
  # @return [void]
47
59
  # @raise [SystemCallError] if this fails
48
60
  def save(path)
49
61
  rc = ffi_delegate.save(path.to_s)
50
- return if rc == 0
51
- raise_zmq_err("error while saving to the file %s" % path)
62
+ return if rc.zero?
63
+
64
+ raise_zmq_err(format('error while saving to the file %s', path))
52
65
  end
53
66
 
67
+
54
68
  # Reload config tree from same file that it was previously loaded from.
55
69
  # @raise [TypeError] if this is an in-memory config
56
70
  # @raise [SystemCallError] if this fails (no existing data will be
@@ -62,11 +76,13 @@ module CZTop::Config::Serialization
62
76
  # swap out the FFI delegate.
63
77
  filename = filename() or
64
78
  raise TypeError, "can't reload in-memory config"
65
- ptr = CZMQ::FFI::Zconfig.load(filename)
79
+ ptr = CZMQ::FFI::Zconfig.load(filename)
66
80
  return attach_ffi_delegate(ptr) unless ptr.null?
67
- raise_zmq_err("error while reloading from the file %p" % filename)
81
+
82
+ raise_zmq_err(format('error while reloading from the file %p', filename))
68
83
  end
69
84
 
85
+
70
86
  # Serialize (marshal) this Config and all its children.
71
87
  #
72
88
  # @note This method is automatically used by Marshal.dump.
@@ -74,9 +90,13 @@ module CZTop::Config::Serialization
74
90
  def _dump(_level)
75
91
  to_s
76
92
  end
93
+
77
94
  end
78
95
 
96
+
79
97
  class CZTop::Config
98
+
80
99
  include Serialization
81
100
  extend Serialization::ClassMethods
101
+
82
102
  end