interfacets 0.1.0 → 0.9.9
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 +4 -4
- data/.rubocop.yml +173 -1
- data/LICENSE +21 -0
- data/Rakefile +4 -6
- data/lib/interfacets/client/actor.rb +20 -0
- data/lib/interfacets/client/assets.rb +209 -0
- data/lib/interfacets/client/bus.rb +69 -0
- data/lib/interfacets/client/channels/api.rb +95 -0
- data/lib/interfacets/client/channels/audio.rb +101 -0
- data/lib/interfacets/client/channels/base.rb +28 -0
- data/lib/interfacets/client/channels/page_visibility.rb +21 -0
- data/lib/interfacets/client/channels/react/builder.rb +203 -0
- data/lib/interfacets/client/channels/react/channel.rb +61 -0
- data/lib/interfacets/client/channels/react/dom.rb +91 -0
- data/lib/interfacets/client/channels/react/evaluator.rb +33 -0
- data/lib/interfacets/client/channels/speech_to_text.rb +100 -0
- data/lib/interfacets/client/channels/timer.rb +51 -0
- data/lib/interfacets/client/channels/url.rb +52 -0
- data/lib/interfacets/client/config.rb +22 -0
- data/lib/interfacets/client/delegator.rb +37 -0
- data/lib/interfacets/client/facet.rb +26 -0
- data/lib/interfacets/client/facet2.rb +15 -0
- data/lib/interfacets/client/facets/attributes/accessor.rb +28 -0
- data/lib/interfacets/client/facets/attributes/association.rb +50 -0
- data/lib/interfacets/client/facets/attributes/bind.rb +25 -0
- data/lib/interfacets/client/facets/attributes/collection.rb +47 -0
- data/lib/interfacets/client/facets/attributes/readonly.rb +19 -0
- data/lib/interfacets/client/facets/deserializer.rb +30 -0
- data/lib/interfacets/client/facets/schema/deserializer.rb +63 -0
- data/lib/interfacets/client/facets/schema.rb +63 -0
- data/lib/interfacets/client/facets/serializer.rb +18 -0
- data/lib/interfacets/client/registry.rb +84 -0
- data/lib/interfacets/client/system.rb +88 -0
- data/lib/interfacets/client/utils/active_support_concern.rb +220 -0
- data/lib/interfacets/client/utils/mruby_patches.rb +81 -0
- data/lib/interfacets/client/utils/open_struct.rb +102 -0
- data/lib/interfacets/client/utils/securerandom.rb +69 -0
- data/lib/interfacets/client/view.rb +47 -0
- data/lib/interfacets/client.rb +13 -0
- data/lib/interfacets/mruby/build.dockerfile +66 -0
- data/lib/interfacets/mruby/build_config.rb +20 -0
- data/lib/interfacets/mruby/entrypoint.rb +23 -0
- data/lib/interfacets/mruby/init.c +66 -0
- data/lib/interfacets/server/api.rb +64 -0
- data/lib/interfacets/server/assets/facet.rb +61 -0
- data/lib/interfacets/server/assets.rb +210 -0
- data/lib/interfacets/server/basic_routable.rb +40 -0
- data/lib/interfacets/server/basic_router.rb +74 -0
- data/lib/interfacets/server/bus.rb +39 -0
- data/lib/interfacets/server/config.rb +87 -0
- data/lib/interfacets/server/facet.rb +51 -0
- data/lib/interfacets/server/facets/deserializer.rb +25 -0
- data/lib/interfacets/server/facets/schema/serializer.rb +54 -0
- data/lib/interfacets/server/facets/serializer.rb +50 -0
- data/lib/interfacets/server/registry.rb +212 -0
- data/lib/interfacets/shared/entities/bus.rb +218 -0
- data/lib/interfacets/shared/entities/collection_proxy.rb +190 -0
- data/lib/interfacets/shared/entities/specs/handlers.rb +117 -0
- data/lib/interfacets/shared/entities/specs.rb +124 -0
- data/lib/interfacets/shared/entity.rb +178 -0
- data/lib/interfacets/shared/entity_collection.rb +88 -0
- data/lib/interfacets/shared/generated_store.rb +145 -0
- data/lib/interfacets/shared/utils.rb +54 -0
- data/lib/interfacets/shared/validations.rb +71 -0
- data/lib/interfacets/test/browser.rb +63 -0
- data/lib/interfacets/test/js/inline_bus.rb +91 -0
- data/lib/interfacets/test/js/nodo_bus.rb +81 -0
- data/lib/interfacets/test/js/receivers/api.rb +37 -0
- data/lib/interfacets/test/js/receivers/react/node.rb +167 -0
- data/lib/interfacets/test/js/receivers/react.rb +31 -0
- data/lib/interfacets/test/js/receivers/url.rb +55 -0
- data/lib/interfacets/test.rb +17 -0
- data/lib/interfacets/version.rb +1 -1
- data/lib/interfacets.rb +26 -2
- metadata +103 -6
- data/README.md +0 -35
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Channels
|
|
6
|
+
class Url
|
|
7
|
+
include Channels::Base
|
|
8
|
+
|
|
9
|
+
type("interfacets:url")
|
|
10
|
+
|
|
11
|
+
class Builder
|
|
12
|
+
attr_reader :state
|
|
13
|
+
def initialize
|
|
14
|
+
@state = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def path(path, query: {})
|
|
18
|
+
state[:urlSpec] = {
|
|
19
|
+
url: (
|
|
20
|
+
System
|
|
21
|
+
.current_bus
|
|
22
|
+
.url_for(path)
|
|
23
|
+
),
|
|
24
|
+
queryParams: query,
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def redirect(url, query: {})
|
|
29
|
+
@redirected = true
|
|
30
|
+
state[:redirectUrlSpec] = { url:, query: }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def redirected?
|
|
34
|
+
@redirected
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def prepare(entity)
|
|
39
|
+
@builder ||= Builder.new
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def builder(stream = "default")
|
|
43
|
+
@builder
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def result
|
|
47
|
+
{ streams: { default: @builder.state } }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
class Config
|
|
6
|
+
attr_accessor(
|
|
7
|
+
:mount_point,
|
|
8
|
+
:root_url
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
def url_for(path:)
|
|
12
|
+
[
|
|
13
|
+
root_url,
|
|
14
|
+
mount_point,
|
|
15
|
+
path,
|
|
16
|
+
]
|
|
17
|
+
.map { _1.sub(%r{/$}, "").sub(%r{^/}, "") }
|
|
18
|
+
.join("/")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
# alias: CrappyDelegator
|
|
6
|
+
class Delegator
|
|
7
|
+
def initialize(obj)
|
|
8
|
+
@__obj__ = obj
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def __getobj__
|
|
12
|
+
@__obj__
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def respond_to_missing?(...)
|
|
16
|
+
@__obj__.send(:respond_to_missing?, ...)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def method_missing(method, *a, **p, &)
|
|
20
|
+
@__obj__.send(method, *a, **p, &)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# delegation helpers
|
|
24
|
+
def inspect
|
|
25
|
+
[self.class.name, __getobj__.inspect].join(" -> ")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
inspect
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def presence
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
class Facet
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor(
|
|
8
|
+
:shared,
|
|
9
|
+
:entity,
|
|
10
|
+
:view,
|
|
11
|
+
:store,
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :entity, :view
|
|
16
|
+
def initialize(entity)
|
|
17
|
+
@entity = entity
|
|
18
|
+
@view = self.class.view.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render(channels)
|
|
22
|
+
view.render(entity:, channels:)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Attributes
|
|
7
|
+
class Accessor
|
|
8
|
+
attr_reader :send_if
|
|
9
|
+
def initialize(send_if:)
|
|
10
|
+
@send_if = send_if
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def coerce(val, **)
|
|
14
|
+
val
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def serialize(val)
|
|
18
|
+
val
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def should_send?(facet)
|
|
22
|
+
facet.instance_exec(&send_if)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Attributes
|
|
7
|
+
class Association
|
|
8
|
+
attr_reader :nested, :anonymous, :config, :bind_map
|
|
9
|
+
|
|
10
|
+
def initialize(nested:, anonymous:, config:, bind_map:)
|
|
11
|
+
@nested = nested
|
|
12
|
+
@anonymous = anonymous
|
|
13
|
+
@config = config
|
|
14
|
+
@bind_map = bind_map
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def coerce(val, parent:)
|
|
18
|
+
return if val.nil?
|
|
19
|
+
|
|
20
|
+
facet.build(
|
|
21
|
+
attrs: val,
|
|
22
|
+
binds: bind_map.transform_values { |v| Bind.new(name: v, facet: parent) },
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build(attrs:, parent:)
|
|
27
|
+
facet.build(
|
|
28
|
+
attrs:,
|
|
29
|
+
binds: bind_map.transform_values { |v| Bind.new(name: v, facet: parent) },
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def serialize(val)
|
|
34
|
+
val&.serialize
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def facet
|
|
38
|
+
@facet ||= (
|
|
39
|
+
if anonymous
|
|
40
|
+
@nested
|
|
41
|
+
else
|
|
42
|
+
config.schema(@nested.fetch("name"))
|
|
43
|
+
end
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Attributes
|
|
7
|
+
class Bind
|
|
8
|
+
attr_reader :name, :facet
|
|
9
|
+
def initialize(name:, facet:)
|
|
10
|
+
@name = name
|
|
11
|
+
@facet = facet
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get
|
|
15
|
+
facet.public_send(name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def set(v)
|
|
19
|
+
facet.public_send("#{name}=", v)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Attributes
|
|
7
|
+
class Collection
|
|
8
|
+
attr_reader :nested, :anonymous, :config, :bind_map
|
|
9
|
+
|
|
10
|
+
def initialize(nested:, anonymous:, config:, bind_map:)
|
|
11
|
+
@nested = nested
|
|
12
|
+
@anonymous = anonymous
|
|
13
|
+
@config = config
|
|
14
|
+
@bind_map = bind_map
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def coerce(val, parent:)
|
|
18
|
+
return [] if val.nil?
|
|
19
|
+
|
|
20
|
+
val.map { build(attrs: _1, parent:) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build(attrs:, parent:)
|
|
24
|
+
facet.build(
|
|
25
|
+
attrs:,
|
|
26
|
+
binds: bind_map.transform_values { |v| Bind.new(name: v, facet: parent) },
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def serialize(val)
|
|
31
|
+
val.map(&:serialize)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def facet
|
|
35
|
+
@facet ||= (
|
|
36
|
+
if anonymous
|
|
37
|
+
@nested
|
|
38
|
+
else
|
|
39
|
+
config.schema(@nested.fetch("name"))
|
|
40
|
+
end
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
class Deserializer
|
|
7
|
+
def self.call(data:, config: Client.system.config)
|
|
8
|
+
Logger.main.debug("deserializing facet: #{data.fetch("facet_class")}")
|
|
9
|
+
|
|
10
|
+
klass = Object.const_get(data.fetch("facet_class"))
|
|
11
|
+
|
|
12
|
+
Logger.main.debug("constructing: #{klass.client.name}")
|
|
13
|
+
|
|
14
|
+
facet = klass.new
|
|
15
|
+
|
|
16
|
+
entity = (
|
|
17
|
+
klass
|
|
18
|
+
.client
|
|
19
|
+
.build(data.fetch("attributes"), parent: nil, facet:)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
Logger.main.debug("entity constructed")
|
|
23
|
+
|
|
24
|
+
facet.entity = entity
|
|
25
|
+
facet
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Schema
|
|
7
|
+
class Deserializer
|
|
8
|
+
def self.call(...)
|
|
9
|
+
new(...).call
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attr_reader :schema, :results
|
|
13
|
+
def initialize(schema:)
|
|
14
|
+
@schema = schema
|
|
15
|
+
@results = { views: {}, entities: {}, apis: {} }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
schema.fetch("views").each do |view_type, view_json|
|
|
20
|
+
block = view_json.fetch("body")
|
|
21
|
+
|
|
22
|
+
results[:views][view_type] = View.new(
|
|
23
|
+
block: eval(block),
|
|
24
|
+
name: view_type,
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
schema.fetch("apis").each do |api_type, entity_json|
|
|
29
|
+
block = entity_json.fetch("body")
|
|
30
|
+
|
|
31
|
+
results[:apis][api_type] =
|
|
32
|
+
Module.new do
|
|
33
|
+
extend ActiveSupport::Concern
|
|
34
|
+
define_singleton_method(:name) { api_type }
|
|
35
|
+
|
|
36
|
+
included do
|
|
37
|
+
class_exec(&eval(block))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
schema.fetch("entities").each do |entity_type, client_json|
|
|
43
|
+
block = client_json.fetch("body")
|
|
44
|
+
api_type = client_json.fetch("api_type")
|
|
45
|
+
|
|
46
|
+
api_mod = results[:apis].fetch(api_type)
|
|
47
|
+
|
|
48
|
+
results[:entities][entity_type] =
|
|
49
|
+
Class.new(Entity) do
|
|
50
|
+
define_singleton_method(:name) { entity_type }
|
|
51
|
+
include api_mod
|
|
52
|
+
|
|
53
|
+
class_exec(&eval(block))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
results
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
module Schema
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
class_methods do
|
|
9
|
+
def view_spec(&block)
|
|
10
|
+
@view_spec = block
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def view
|
|
14
|
+
# TODO: change this to just inherit from view
|
|
15
|
+
@view ||= View.new(
|
|
16
|
+
block: @view_spec,
|
|
17
|
+
name: "#{self.name}::View",
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def client_spec(&block)
|
|
22
|
+
@client_spec = block
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def client
|
|
26
|
+
# scoping
|
|
27
|
+
client_name = "#{self.name}::Client"
|
|
28
|
+
client_spec = @client_spec
|
|
29
|
+
entity = self.entity
|
|
30
|
+
|
|
31
|
+
@client ||=
|
|
32
|
+
Class.new(Entity) do
|
|
33
|
+
define_singleton_method(:name) { client_name }
|
|
34
|
+
extend_entity { include entity }
|
|
35
|
+
|
|
36
|
+
class_exec(&client_spec)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def entity_spec(&block)
|
|
41
|
+
@entity_spec = block
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def entity
|
|
45
|
+
# scoping
|
|
46
|
+
entity_name = "#{self.name}::Entity"
|
|
47
|
+
entity_spec = @entity_spec
|
|
48
|
+
|
|
49
|
+
@entity ||=
|
|
50
|
+
Module.new do
|
|
51
|
+
extend ActiveSupport::Concern
|
|
52
|
+
define_singleton_method(:name) { entity_name }
|
|
53
|
+
|
|
54
|
+
included do
|
|
55
|
+
class_exec(&entity_spec)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Facets
|
|
6
|
+
class Serializer
|
|
7
|
+
class << self
|
|
8
|
+
def call(facet)
|
|
9
|
+
{
|
|
10
|
+
facet_class: facet.class.name,
|
|
11
|
+
attributes: facet.entity.serialize,
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
class Registry
|
|
6
|
+
def build(name)
|
|
7
|
+
entity = Object.const_get("#{name}::Client::Entity")
|
|
8
|
+
|
|
9
|
+
entity.new(
|
|
10
|
+
store: entity.store.new,
|
|
11
|
+
parent: nil,
|
|
12
|
+
nesting: ["root"]
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def register(schema, namespace: "Things")
|
|
17
|
+
schema.each do |name, schema|
|
|
18
|
+
next if registry.key?(name)
|
|
19
|
+
|
|
20
|
+
shared = Class.new(Shared::Entity) do
|
|
21
|
+
schema.fetch("shared").each { class_exec(&eval(_1)) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
view = Class.new(View) do
|
|
25
|
+
schema.fetch("view").each { view(&eval(_1)) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
entity = Class.new(Shared::Entity) do
|
|
29
|
+
define_singleton_method(:view) { view }
|
|
30
|
+
self.manifest = shared
|
|
31
|
+
|
|
32
|
+
schema.fetch("shared").each { class_exec(&eval(_1)) }
|
|
33
|
+
schema.fetch("client").each { class_exec(&eval(_1)) }
|
|
34
|
+
|
|
35
|
+
actions.each do |name, spec|
|
|
36
|
+
if name.start_with?("after_")
|
|
37
|
+
define_method(name) {}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
store = Shared::GeneratedStore.construct(entity)
|
|
43
|
+
|
|
44
|
+
mod = set_const(
|
|
45
|
+
[
|
|
46
|
+
namespace,
|
|
47
|
+
name.split("::"),
|
|
48
|
+
].flatten,
|
|
49
|
+
Module.new
|
|
50
|
+
)
|
|
51
|
+
entity.define_singleton_method(:facet_name) { name }
|
|
52
|
+
mod.const_set("Entity", entity)
|
|
53
|
+
entity.const_set("Shared", shared)
|
|
54
|
+
entity.const_set("View", view)
|
|
55
|
+
|
|
56
|
+
registry[name] = { entity:, store: }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def set_const(mods, klass)
|
|
63
|
+
|
|
64
|
+
namespace = Object
|
|
65
|
+
|
|
66
|
+
mods[0..-1].each do |mod|
|
|
67
|
+
namespace = (
|
|
68
|
+
if namespace.const_defined?(mod, false)
|
|
69
|
+
namespace.const_get(mod)
|
|
70
|
+
else
|
|
71
|
+
namespace.const_set(mod, Module.new)
|
|
72
|
+
end
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
namespace.const_set(mods.last, klass)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def registry
|
|
80
|
+
@registry ||= {}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
class System
|
|
6
|
+
module Transmit
|
|
7
|
+
def self.call(data)
|
|
8
|
+
Kernel.js_eval("self.rubyEvent(#{data.to_json})")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor(
|
|
14
|
+
:current_bus,
|
|
15
|
+
:logger,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def logger
|
|
19
|
+
@logger ||= InterfacetsLogger.main
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start(transmit: Transmit)
|
|
23
|
+
@instance = new(transmit)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attr_accessor :transmit
|
|
28
|
+
def initialize(transmit)
|
|
29
|
+
@transmit = transmit
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def handle(event)
|
|
33
|
+
if event.fetch("type") == "interfacets:system:create_bus"
|
|
34
|
+
create_bus(event.fetch("payload"))
|
|
35
|
+
else
|
|
36
|
+
bus_id = event.dig("destination", "bus")
|
|
37
|
+
raise("unknown event: #{event.inspect}") unless bus_id
|
|
38
|
+
|
|
39
|
+
System.current_bus = bus_registry.fetch(bus_id)
|
|
40
|
+
payload = System.current_bus.handle(event)
|
|
41
|
+
|
|
42
|
+
transmit.(
|
|
43
|
+
{
|
|
44
|
+
type: "interfacets:system:render",
|
|
45
|
+
payload:,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
ensure
|
|
50
|
+
GC.start
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# private
|
|
54
|
+
|
|
55
|
+
def config
|
|
56
|
+
@config ||= Config.new
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def create_bus(payload)
|
|
60
|
+
id = payload.fetch("id")
|
|
61
|
+
hydration_event = payload.fetch("hydration")
|
|
62
|
+
|
|
63
|
+
channel_ids = payload.fetch("channel_ids")
|
|
64
|
+
|
|
65
|
+
Bus.new(
|
|
66
|
+
id:,
|
|
67
|
+
channels: [
|
|
68
|
+
Channels::Api.new(id: "interfacets:api"),
|
|
69
|
+
Channels::React::Channel.new(id: "dom"),
|
|
70
|
+
Channels::Url.new(id: "url"),
|
|
71
|
+
(Channels::SpeechToText.new(id: "speechToText") if channel_ids.include?("speechToText")),
|
|
72
|
+
(Channels::Timer.new(id: "timer") if channel_ids.include?("timer")),
|
|
73
|
+
(Channels::Audio.new(id: "audio") if channel_ids.include?("audio")),
|
|
74
|
+
].compact,
|
|
75
|
+
root_url: payload.fetch("config").fetch("root_url"),
|
|
76
|
+
).tap do
|
|
77
|
+
bus_registry[id] = _1
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
handle(hydration_event)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def bus_registry
|
|
84
|
+
@bus_registry ||= {}
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|