interop 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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