bps 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5de5e6e993f0b96c93224163f85fc0cd3ef5a9ecf7d03487df35315ee3bd153b
4
+ data.tar.gz: cfaa3b821549d70bee5094321553123493d9e66fca4cf15fa50ccdb0f4c5a04d
5
+ SHA512:
6
+ metadata.gz: c4d068aa91b285af2a124a258a13207298c3c0f9202fe39f197e21a9fd49a53f433de12cf4817b78b265b2920deeaa402a014cba0fe74da3b258570688b8fb1e
7
+ data.tar.gz: 4b7f0fa9bf89e079e05312e4d202af107b102c51079166704ca4641146942a0b3a692a0605d52bf0e46bbb8d8847b0969a8c8c20e763308d160988cff1c7d9c5
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bps'
3
+ s.version = File.read(File.expand_path('../../.version', __dir__)).strip
4
+ s.platform = Gem::Platform::RUBY
5
+
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = 'Multi-platform pubsub adapter'
8
+ s.description = 'Minimalist abstraction for publish-subscribe'
9
+
10
+ s.authors = ['Black Square Media']
11
+ s.email = 'info@blacksquaremedia.com'
12
+ s.homepage = 'https://github.com/bsm/bps'
13
+
14
+ s.executables = []
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib']
18
+ s.required_ruby_version = '>= 2.6.0'
19
+ end
@@ -0,0 +1,52 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+
4
+ module BPS
5
+ autoload :Coercer, 'bps/coercer'
6
+
7
+ module Publisher
8
+ autoload :Abstract, 'bps/publisher/abstract'
9
+
10
+ def self.register(*schemes, &resolver)
11
+ @registry ||= {}
12
+ schemes.each do |scheme|
13
+ @registry[scheme] = resolver
14
+ end
15
+ end
16
+
17
+ def self.resolve(url)
18
+ url = url.is_a?(::URI) ? url.dup : URI.parse(url)
19
+ rsl = @registry[url.scheme]
20
+ raise ArgumentError, "Unable to resolve publisher #{url}, scheme #{url.scheme} is not registered" unless rsl
21
+
22
+ opts = {}
23
+ CGI.parse(url.query.to_s).each do |key, values|
24
+ opts[key.to_sym] = values.first
25
+ end
26
+ rsl.call(url, opts)
27
+ end
28
+ end
29
+
30
+ module Subscriber
31
+ autoload :Abstract, 'bps/subscriber/abstract'
32
+
33
+ def self.register(*schemes, &resolver)
34
+ @registry ||= {}
35
+ schemes.each do |scheme|
36
+ @registry[scheme] = resolver
37
+ end
38
+ end
39
+
40
+ def self.resolve(url)
41
+ url = url.is_a?(::URI) ? url.dup : URI.parse(url)
42
+ rsl = @registry[url.scheme]
43
+ raise ArgumentError, "Unable to resolve subscriber #{url}, scheme #{url.scheme} is not registered" unless rsl
44
+
45
+ opts = {}
46
+ CGI.parse(url.query.to_s).each do |key, values|
47
+ opts[key.to_sym] = values.first
48
+ end
49
+ rsl.call(url, opts)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,64 @@
1
+ require 'set'
2
+
3
+ module BPS
4
+ class Coercer
5
+ TRUE_VALUES = [true, 'TRUE', 'true', 'T', 't', 1, '1'].to_set
6
+
7
+ attr_reader :schema
8
+
9
+ def initialize(schema)
10
+ validate!(schema)
11
+ @schema = schema
12
+ end
13
+
14
+ def coerce(hash)
15
+ coerce_with(@schema, hash)
16
+ end
17
+
18
+ private
19
+
20
+ def validate!(schema)
21
+ schema.each do |key, type|
22
+ case type
23
+ when :string, :symbol, :int, :float, :bool
24
+ # OK
25
+ when Hash
26
+ validate!(type)
27
+ when Array
28
+ raise ArgumentError, "Array types must have exactly one entry, but was (#{key} => #{type.inspect})" unless type.size == 1
29
+ else
30
+ raise ArgumentError, "Unknown type #{type.inspect}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def coerce_with(schema, hash)
36
+ clone = {}
37
+ schema.each do |key, type|
38
+ next unless hash.key?(key)
39
+
40
+ clone[key] = coerce_value(type, hash[key])
41
+ end
42
+ clone
43
+ end
44
+
45
+ def coerce_value(type, val)
46
+ case type
47
+ when :string
48
+ val&.to_s
49
+ when :symbol
50
+ val&.to_sym
51
+ when :int
52
+ val&.to_i
53
+ when :float
54
+ val&.to_f
55
+ when :bool
56
+ val.nil? ? nil : TRUE_VALUES.include?(val)
57
+ when Hash
58
+ val.is_a?(Hash) ? coerce_with(type, val) : nil
59
+ when Array
60
+ Array(val).map {|v| coerce_value(type[0], v) }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ module BPS
2
+ module Publisher
3
+ class Abstract
4
+ class Topic
5
+ # Publish a message.
6
+ def publish(_message, **_opts)
7
+ raise 'not implemented'
8
+ end
9
+
10
+ # Flush any remaining buffer.
11
+ def flush(**); end
12
+ end
13
+
14
+ # Retrieve a topic handle.
15
+ # @params [String] name the topic name.
16
+ def topic(_name)
17
+ raise 'not implemented'
18
+ end
19
+
20
+ # Close the publisher.
21
+ def close; end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module BPS
2
+ module Subscriber
3
+ class Abstract
4
+ # Subscribe to a topic
5
+ # @params [String] topic the topic name.
6
+ def subscribe(_topic, **)
7
+ raise 'not implemented'
8
+ end
9
+
10
+ # Close the subscriber.
11
+ def close; end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe BPS::Coercer do
4
+ subject do
5
+ described_class.new(
6
+ name: :string,
7
+ codec: :symbol,
8
+ retries: :int,
9
+ backoff: :float,
10
+ idempotent: :bool,
11
+ tags: [:string],
12
+ )
13
+ end
14
+
15
+ let :options do
16
+ {
17
+ name: 123,
18
+ codec: 'snappy',
19
+ retries: '4',
20
+ backoff: '10',
21
+ idempotent: '1',
22
+ tags: [:foo, 33],
23
+ extra: 'foo',
24
+ }
25
+ end
26
+
27
+ it 'should validate' do
28
+ expect { described_class.new(name: :unknown) }.to raise_error(ArgumentError, /Unknown type :unknown/)
29
+ expect { described_class.new(bad: []) }.to raise_error(ArgumentError, /Array types must have exactly one entry/)
30
+ end
31
+
32
+ it 'should coerce options' do
33
+ expect(subject.coerce(options)).to eq(
34
+ name: '123',
35
+ codec: :snappy,
36
+ retries: 4,
37
+ backoff: 10.0,
38
+ idempotent: true,
39
+ tags: %w[foo 33],
40
+ )
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Black Square Media
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Minimalist abstraction for publish-subscribe
14
+ email: info@blacksquaremedia.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - bps.gemspec
20
+ - lib/bps.rb
21
+ - lib/bps/coercer.rb
22
+ - lib/bps/publisher/abstract.rb
23
+ - lib/bps/subscriber/abstract.rb
24
+ - spec/bps/coercer_spec.rb
25
+ homepage: https://github.com/bsm/bps
26
+ licenses:
27
+ - Apache-2.0
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 2.6.0
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.1.4
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Multi-platform pubsub adapter
48
+ test_files:
49
+ - spec/bps/coercer_spec.rb