asterism 0.5.0 → 0.7.0

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.
data/mrblib/future.rb CHANGED
@@ -48,16 +48,22 @@ module Asterism
48
48
  @finished
49
49
  end
50
50
 
51
+ # The answer: {"value" => v} gives v, {"error" => {"kind", "class",
52
+ # "message"}} raises RemoteError; anything else is a malformed answer.
51
53
  def value
52
54
  raw = raw_value
53
- unless raw.is_a?(Array) && (raw[0] == "ok" || raw[0] == "error")
54
- raise ::Asterism::Error, "malformed answer from #{@path}"
55
+ raise ::Asterism::Error, "malformed answer from #{@path}" unless raw.is_a?(Hash)
56
+ if raw.key?("error")
57
+ e = raw["error"]
58
+ raise ::Asterism::Error, "malformed answer from #{@path}" unless e.is_a?(Hash)
59
+ kind = e["kind"]
60
+ raise ::Asterism::RemoteError.new(e["class"], e["message"], kind.is_a?(String) ? kind : nil)
55
61
  end
56
- raise ::Asterism::RemoteError.new(raw[1], raw[2]) if raw[0] == "error"
57
- raw[1]
62
+ raise ::Asterism::Error, "malformed answer from #{@path}" unless raw.key?("value")
63
+ raw["value"]
58
64
  end
59
65
 
60
- # The decoded answer (meta replies are not ["ok", value] pairs).
66
+ # The decoded answer (meta and profile replies are not value maps).
61
67
  def raw_value
62
68
  ::Asterism.wait_until { done? } unless done?
63
69
  if @reply.nil?
data/mrblib/profile.rb CHANGED
@@ -7,11 +7,14 @@
7
7
  #
8
8
  # Key: asterism/<node>/@profile (a queryable of every application connected
9
9
  # as that node). The reply is a MessagePack Hash:
10
+ # "protocol" the wire protocol the node speaks (Asterism::PROTOCOL, 1);
11
+ # a node without it speaks protocol 0
10
12
  # "kind" what Ruby runs the node: "family_mruby", "picoruby",
11
13
  # "cruby", "console" (others are allowed)
12
14
  # "host" where it runs, optional ("atoms3r", "tab5", "sim", ...)
13
15
  # "name" a display name, optional
14
- # "icon" PNG bytes, optional (8 KB and 256x256 at most)
16
+ # "icon" PNG bytes as a MessagePack bin, optional (8 KB and
17
+ # 256x256 at most)
15
18
  # "icon_hash" the icon's summary (Profile.png_info): a reader that has
16
19
  # that icon already asks again with the parameter icon=0 and
17
20
  # gets the rest without it
@@ -87,6 +90,13 @@ module Asterism
87
90
  nil
88
91
  end
89
92
 
93
+ # The bytes as a binary String (String#b), so that they are sent as a
94
+ # MessagePack bin; as they are where String#b is missing.
95
+ # @api private
96
+ def self.binary(s)
97
+ s.respond_to?(:b) ? s.b : s
98
+ end
99
+
90
100
  # @api private
91
101
  def self.type?(b, pos, c0, c1, c2, c3)
92
102
  b.getbyte(pos + 4) == c0 && b.getbyte(pos + 5) == c1 && b.getbyte(pos + 6) == c2 && b.getbyte(pos + 7) == c3
@@ -107,6 +117,8 @@ module Asterism
107
117
  kind = h["kind"]
108
118
  return nil unless kind.is_a?(String) && kind?(kind)
109
119
  out = { "kind" => kind }
120
+ pr = h["protocol"]
121
+ out["protocol"] = pr if pr.is_a?(Integer) && pr >= 0
110
122
  host = h["host"]
111
123
  out["host"] = host if host.is_a?(String) && !host.empty? && host.bytesize <= HOST_MAX
112
124
  name = h["name"]
@@ -301,7 +313,7 @@ module Asterism
301
313
  # @api private
302
314
  def self.profile_hash(with_icon)
303
315
  set = @profile_set || {}
304
- h = { "kind" => set["kind"] || default_profile_kind }
316
+ h = { "protocol" => PROTOCOL, "kind" => set["kind"] || default_profile_kind }
305
317
  h["host"] = set["host"] if set["host"]
306
318
  h["name"] = set["name"] if set["name"]
307
319
  icon = profile_icon
@@ -324,7 +336,8 @@ module Asterism
324
336
  bytes = path ? read_icon_file(path) : nil
325
337
  end
326
338
  info = bytes ? Profile.png_info(bytes) : nil
327
- @profile_icon = info ? [bytes, info[2]] : false
339
+ # A binary String: it goes as a MessagePack bin.
340
+ @profile_icon = info ? [Profile.binary(bytes), info[2]] : false
328
341
  end
329
342
  @profile_icon ? @profile_icon : nil
330
343
  end
@@ -342,7 +355,7 @@ module Asterism
342
355
  # @api private
343
356
  def self.answer_profile
344
357
  qa = @profile_queryable
345
- return unless qa
358
+ return unless qa && qa.pending > 0
346
359
  queries = qa.each_pending
347
360
  i = 0
348
361
  while i < queries.size
data/mrblib/proxy.rb CHANGED
@@ -3,9 +3,9 @@ module Asterism
3
3
  # Any method it does not have itself becomes a call that waits for the
4
4
  # answer. respond_to? and remote_methods come from the object's meta.
5
5
  #
6
- # Its own methods (not forwarded): async, asterism_path, asterism_meta,
7
- # asterism_refresh, remote_methods, respond_to?, methods, inspect, to_s
8
- # and those of Object.
6
+ # Its own methods (not forwarded): async, asterism_call, asterism_path,
7
+ # asterism_meta, asterism_refresh, remote_methods, respond_to?, methods,
8
+ # inspect, to_s and those of Object.
9
9
  class Proxy
10
10
  # Conversions Ruby asks for implicitly (puts, Array#flatten, ...): never
11
11
  # forwarded.
@@ -27,6 +27,15 @@ module Asterism
27
27
  ::Asterism.call(@path, name, args, kw, @timeout_ms)
28
28
  end
29
29
 
30
+ # Calls the remote method by its name (a String or Symbol): for the
31
+ # names the proxy cannot forward (those Object and Kernel define:
32
+ # display, hash, class, fail, ...) and for names that are not Ruby
33
+ # identifiers (from objects written in other languages).
34
+ def asterism_call(name, *args, **kw, &blk)
35
+ raise ::ArgumentError, "a block cannot be sent to #{@path}" if blk
36
+ ::Asterism.call(@path, name.to_s, args, kw, @timeout_ms)
37
+ end
38
+
30
39
  # In Ruby rather than through respond_to_missing?: Object#respond_to? is
31
40
  # C, and calling back into Ruby from it (which then waits for the meta)
32
41
  # costs another interpreter entry on the C stack.
@@ -52,7 +61,8 @@ module Asterism
52
61
  remote_methods
53
62
  end
54
63
 
55
- # The meta reply, fetched once: {"methods" => [[name, arity], ...]}.
64
+ # The meta reply, fetched once:
65
+ # {"methods" => [{"name" => name, "arity" => n}, ...]}.
56
66
  def asterism_meta
57
67
  @meta ||= ::Asterism.meta(@path, @timeout_ms)
58
68
  end
@@ -67,7 +77,9 @@ module Asterism
67
77
  def remote_names
68
78
  list = asterism_meta["methods"]
69
79
  return [] unless list.is_a?(Array)
70
- list.map { |pair| pair.is_a?(Array) ? pair[0].to_s : pair.to_s }
80
+ names = []
81
+ list.each { |m| names << m["name"].to_s if m.is_a?(Hash) && m["name"].is_a?(String) }
82
+ names
71
83
  end
72
84
 
73
85
  # The same object, calls that do not wait: each returns a Future.
@@ -100,6 +112,12 @@ module Asterism
100
112
  !::Asterism::Proxy::LOCAL_ONLY.include?(name.to_sym)
101
113
  end
102
114
 
115
+ # Proxy#asterism_call that does not wait: returns a Future.
116
+ def asterism_call(name, *args, **kw, &blk)
117
+ raise ::ArgumentError, "a block cannot be sent to #{@path}" if blk
118
+ ::Asterism.call_async(@path, name.to_s, args, kw, @timeout_ms)
119
+ end
120
+
103
121
  def inspect
104
122
  "#<Asterism::AsyncProxy #{@path}>"
105
123
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asterism
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuhiko Kageyama