interop 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '084751018d90a52509edf5a1c67f864ee9990b95970ef3a5018617c21406fe8f'
4
- data.tar.gz: 31de67481b086a640eb322088cd06d908813ba1e495de10fbbf122e8596ee59a
3
+ metadata.gz: 3354d110f9c8fd23ec9681841e3403ec92b57d1d8247b2b856795f52344cc387
4
+ data.tar.gz: a9ecc3aaa1428509a120c7cfba1582ff28a237abbe86898ab0a31b034e8dfd76
5
5
  SHA512:
6
- metadata.gz: ae2e8597f69cc61b6a341f95ddcff5547fd99055070ed8ae991975a71f8ebdc555e37a7f4f6503572dfd8840fdad101d44f3739da57ed5c288e7d272b576862e
7
- data.tar.gz: fbb8c6666a20fed2de479ed56b7db5885a526117c6ba2801c3cdff2d89e30c861ae735d6f0bed0b5c8285bbeedec26fe321388305ee7a6f646c8e2404a956450
6
+ metadata.gz: 238204d49f14974ee72c8ece083866204a187788e55f3f3ad9047bf697f085480561d6f632cd183914c923605ca190cbdd6ac31b51d5cc0e9179bec149c556a3
7
+ data.tar.gz: 1aa9d43425c0f37a5671947a88448289c9d9bf3775a261e7d8fbf0bca99e34909c0364bb1148fcbf47b3d6643abe75dc7558bde358be6f4906973f0b4a579cff
data/lib/interop.rb CHANGED
@@ -8,6 +8,7 @@ require 'interop/interceptor'
8
8
  require 'interop/middleware'
9
9
  require 'interop/rpc/client'
10
10
  require 'interop/rpc/server'
11
+ require 'interop/content_type'
11
12
 
12
13
  module Hx
13
14
  module Interop
@@ -0,0 +1,53 @@
1
+ require 'json'
2
+ require 'interop/marshaler'
3
+ require 'interop/content_types'
4
+
5
+ module Hx
6
+ module Interop
7
+ # A marshaler that corresponds to a content-type string.
8
+ class ContentType
9
+ attr_reader :name
10
+
11
+ def initialize(name, marshaler)
12
+ name.is_a? String or
13
+ raise ArgumentError, 'Expected name to be a string'
14
+
15
+ %i[load dump].all?(&marshaler.method(:respond_to?)) or
16
+ raise ArgumentError, 'Expected marshaler to respond to :load and :dump'
17
+
18
+ @name = -name
19
+ @marshaler = marshaler
20
+ end
21
+
22
+ def load(str)
23
+ @marshaler.load str
24
+ end
25
+
26
+ def dump(obj)
27
+ @marshaler.dump obj
28
+ end
29
+
30
+ def decode(message)
31
+ load message.body
32
+ end
33
+
34
+ def encode(obj)
35
+ Message.new.tap { |m| encode_to obj, m }
36
+ end
37
+
38
+ def encode_to(obj, message)
39
+ body = dump(obj)
40
+ message.body = body
41
+ message.headers.merge!(
42
+ Headers::CONTENT_TYPE => name,
43
+ Headers::CONTENT_LENGTH => body.bytesize
44
+ )
45
+ end
46
+
47
+ STANDARD = ContentTypes.new
48
+ JSON = STANDARD.register('application/json', ::JSON)
49
+ BINARY = STANDARD.register('application/octet-stream', Marshaler::NULL)
50
+ STANDARD.freeze
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,47 @@
1
+ module Hx
2
+ module Interop
3
+ # A collection of marshalers, with content-type strings, for decoding messages by content type.
4
+ class ContentTypes < Hash
5
+ def register(content_type, marshaler = nil)
6
+ content_type = ContentType.new(content_type, marshaler) unless content_type.is_a? ContentType
7
+ self << content_type
8
+ content_type
9
+ end
10
+
11
+ def <<(content_type)
12
+ content_type.is_a? ContentType or
13
+ raise ArgumentError, "Expected an instance of #{ContentType}"
14
+ key? content_type.name and
15
+ raise ArgumentError, "Content type #{content_type.name} is already registered"
16
+ self[content_type.name] = content_type
17
+ self
18
+ end
19
+
20
+ def decode(message)
21
+ delegate message[Headers::CONTENT_TYPE], :decode, message
22
+ end
23
+
24
+ # @!method load(content_type, str)
25
+ # @!method dump(content_type, obj)
26
+ # @!method encode(content_type, obj)
27
+ # @!method encode_to(content_type, obj, message)
28
+ %i[load dump encode encode_to].each do |name|
29
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
30
+ def #{name}(content_type, *args) # def load(content_type, *args)
31
+ delegate content_type, :#{name}, *args # delegate content_type, :load, *args
32
+ end # end
33
+ RUBY
34
+ end
35
+
36
+ def to_s
37
+ keys.join ', '
38
+ end
39
+
40
+ private
41
+
42
+ def delegate(content_type, *args)
43
+ fetch(content_type) { raise Error::UnrecognisedContentType, 'Unrecognised content type' }.__send__ *args
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/interop/error.rb CHANGED
@@ -10,7 +10,7 @@ module Hx
10
10
  class Unexpected < Fatal
11
11
  end
12
12
 
13
- class NotDecodable < self
13
+ class UnrecognisedContentType < self
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,16 @@
1
+ module Hx
2
+ module Interop
3
+ # Base class for message content marshalers.
4
+ class Marshaler
5
+ NULL = new
6
+
7
+ def load(str)
8
+ str
9
+ end
10
+
11
+ def dump(str)
12
+ str
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,21 +1,10 @@
1
- require 'json'
2
-
3
1
  require 'interop/headers'
4
2
 
5
3
  module Hx
6
4
  module Interop
7
5
  # Represents a single interop message, with headers and a body.
8
6
  class Message
9
- module Types
10
- JSON = 'application/json'.freeze
11
- BINARY = 'application/octet-stream'.freeze
12
- end
13
-
14
7
  class << self
15
- def json_parse_options
16
- @json_parse_options ||= {}
17
- end
18
-
19
8
  def build(*args)
20
9
  return args.first if args.one? && args.first.is_a?(Message)
21
10
 
@@ -26,10 +15,6 @@ module Hx
26
15
  end
27
16
  end
28
17
 
29
- def json(object, *args)
30
- build JSON.generate(object) << "\n", {Headers::CONTENT_TYPE => Types::JSON}, *args
31
- end
32
-
33
18
  private
34
19
 
35
20
  def assign_build_arg(message, arg)
@@ -67,12 +52,9 @@ module Hx
67
52
  @body = value.to_s
68
53
  end
69
54
 
70
- def decode
71
- case @headers[Headers::CONTENT_TYPE]
72
- when Types::JSON
73
- return JSON.parse @body, self.class.json_parse_options
74
- end
75
- raise Error::NotDecodable, 'Message is not in a decodable format'
55
+ # @param [ContentType, ContentTypes] decoder
56
+ def decode(decoder)
57
+ decoder.decode self
76
58
  end
77
59
 
78
60
  def dup
@@ -11,7 +11,7 @@ module Hx
11
11
  @connection = Connection.build(reader, writer)
12
12
  @dispatcher = Dispatcher.new
13
13
  yield self if block_given?
14
- @io_thread = Thread.new do
14
+ @io_thread = Thread.new do
15
15
  run
16
16
  rescue StandardError => e
17
17
  @error = e
@@ -37,10 +37,6 @@ module Hx
37
37
 
38
38
  alias [] call
39
39
 
40
- def call_json(message_class, unencoded_body, *args)
41
- call message_class, Message.json(unencoded_body, *args)
42
- end
43
-
44
40
  def magic(&block)
45
41
  Magic.new self, :call, &block
46
42
  end
@@ -1,5 +1,5 @@
1
1
  module Hx
2
2
  module Interop
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil E. Pearson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-10 00:00:00.000000000 Z
11
+ date: 2021-08-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby implementation of hx/interop cross-language interop abstraction
14
14
  email:
@@ -20,12 +20,15 @@ files:
20
20
  - lib/interop.rb
21
21
  - lib/interop/channel.rb
22
22
  - lib/interop/connection.rb
23
+ - lib/interop/content_type.rb
24
+ - lib/interop/content_types.rb
23
25
  - lib/interop/error.rb
24
26
  - lib/interop/headers.rb
25
27
  - lib/interop/interceptor.rb
26
28
  - lib/interop/interceptor/base.rb
27
29
  - lib/interop/interceptor/read.rb
28
30
  - lib/interop/interceptor/write.rb
31
+ - lib/interop/marshaler.rb
29
32
  - lib/interop/message.rb
30
33
  - lib/interop/middleware.rb
31
34
  - lib/interop/pipe.rb