realm-core 0.7.1 → 0.7.3

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -0
  3. data/Rakefile +19 -0
  4. metadata +25 -44
  5. data/lib/realm-core.rb +0 -6
  6. data/lib/realm.rb +0 -22
  7. data/lib/realm/action_handler.rb +0 -84
  8. data/lib/realm/action_handler/result.rb +0 -32
  9. data/lib/realm/builder.rb +0 -93
  10. data/lib/realm/command_handler.rb +0 -23
  11. data/lib/realm/config.rb +0 -57
  12. data/lib/realm/container.rb +0 -68
  13. data/lib/realm/context.rb +0 -37
  14. data/lib/realm/dependency.rb +0 -24
  15. data/lib/realm/dispatcher.rb +0 -74
  16. data/lib/realm/domain_resolver.rb +0 -59
  17. data/lib/realm/error.rb +0 -62
  18. data/lib/realm/event.rb +0 -56
  19. data/lib/realm/event_factory.rb +0 -53
  20. data/lib/realm/event_handler.rb +0 -102
  21. data/lib/realm/event_router.rb +0 -100
  22. data/lib/realm/event_router/gateway.rb +0 -50
  23. data/lib/realm/event_router/internal_loop_gateway.rb +0 -50
  24. data/lib/realm/health_status.rb +0 -46
  25. data/lib/realm/mixins/aggregate_member.rb +0 -25
  26. data/lib/realm/mixins/context_injection.rb +0 -49
  27. data/lib/realm/mixins/controller.rb +0 -53
  28. data/lib/realm/mixins/decorator.rb +0 -33
  29. data/lib/realm/mixins/dependency_injection.rb +0 -52
  30. data/lib/realm/mixins/reactive.rb +0 -32
  31. data/lib/realm/mixins/repository_helper.rb +0 -43
  32. data/lib/realm/multi_worker.rb +0 -30
  33. data/lib/realm/persistence.rb +0 -54
  34. data/lib/realm/persistence/repository_query_handler_adapter.rb +0 -24
  35. data/lib/realm/plugin.rb +0 -20
  36. data/lib/realm/query_handler.rb +0 -8
  37. data/lib/realm/runtime.rb +0 -61
  38. data/lib/realm/runtime/session.rb +0 -33
  39. data/lib/realm/types.rb +0 -9
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'realm/error'
4
- require 'realm/event'
5
-
6
- module Realm
7
- class EventFactory
8
- def initialize(events_module)
9
- @events_module = events_module
10
- @event_class_map = collect_event_classes(events_module)
11
- end
12
-
13
- def create_event(event_type, correlate: nil, cause: nil, **attributes)
14
- head = enhance_head(attributes.fetch(:head, {}), correlate: correlate, cause: cause)
15
- body = attributes.fetch(:body, attributes.except(:head))
16
-
17
- event_class_for(event_type).new(head: head, body: body)
18
- end
19
-
20
- def event_class_for(event_type)
21
- return event_type if event_type.respond_to?(:new)
22
-
23
- @event_class_map.fetch(event_type.to_s) do
24
- raise EventClassMissing.new(event_type, @events_module)
25
- end
26
- end
27
-
28
- private
29
-
30
- def collect_event_classes(root_module)
31
- root_module_str = root_module.to_s
32
- root_module.constants.each_with_object({}) do |const_sym, all|
33
- const = root_module.const_get(const_sym)
34
- if !(const < Event) && const.to_s.start_with?(root_module_str)
35
- all.merge!(collect_event_classes(const))
36
- elsif const < Event
37
- all[const.type] = const
38
- end
39
- end
40
- end
41
-
42
- def enhance_head(head, correlate:, cause:)
43
- head[:correlation_id] = correlate.head.correlation_id if correlate
44
- if cause.is_a?(Event)
45
- head[:cause_event_id] = cause.head.id
46
- head[:correlation_id] ||= cause.head.correlation_id
47
- elsif cause
48
- head[:cause] = cause
49
- end
50
- head
51
- end
52
- end
53
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/string'
4
- require 'realm/persistence'
5
- require 'realm/mixins/context_injection'
6
- require 'realm/mixins/reactive'
7
- require 'realm/mixins/repository_helper'
8
- require 'realm/mixins/aggregate_member'
9
-
10
- module Realm
11
- class EventHandler
12
- extend Mixins::ContextInjection::ClassMethods
13
- include Mixins::AggregateMember
14
- include Mixins::Reactive
15
- include Mixins::RepositoryHelper
16
-
17
- class RuntimeBound
18
- delegate :identifier, :event_types, to: :@handler_class
19
-
20
- def initialize(handler_class, runtime)
21
- @handler_class = handler_class
22
- @runtime = runtime
23
- end
24
-
25
- def call(event)
26
- @handler_class.(event, runtime: @runtime.session(cause: event))
27
- end
28
- end
29
-
30
- class << self
31
- attr_reader :trigger_mapping, :event_namespace
32
-
33
- def bind_runtime(runtime)
34
- RuntimeBound.new(self, runtime)
35
- end
36
-
37
- def call(event, runtime:)
38
- new(runtime: runtime).(event)
39
- end
40
-
41
- def identifier(value = :undefined)
42
- if value == :undefined
43
- defined?(@identifier) ? @identifier : name.gsub(/(Domain|(Event)?Handlers?)/, '').underscore.gsub(%r{/+}, '-')
44
- else
45
- @identifier = value
46
- end
47
- end
48
-
49
- def event_types
50
- defined?(@trigger_mapping) ? @trigger_mapping.keys.uniq : []
51
- end
52
-
53
- protected
54
-
55
- def namespace(value)
56
- @event_namespace = value
57
- end
58
-
59
- def on(*triggers, run: nil, **options, &block)
60
- @method_triggers = triggers
61
- @method_trigger_options = options # TODO: store and pass to gateway
62
- return unless run || block
63
-
64
- block = ->(event) { self.run(run, event.body) } if run
65
- define_method("handle_#{triggers.join('_or_')}", &block)
66
- end
67
-
68
- def method_added(method_name)
69
- super
70
- return unless defined?(@method_triggers)
71
-
72
- @trigger_mapping ||= {}
73
- @method_triggers.each do |trigger|
74
- (@trigger_mapping[trigger.to_sym] ||= []) << method_name
75
- end
76
- remove_instance_variable(:@method_triggers)
77
- end
78
- end
79
-
80
- def initialize(runtime: nil)
81
- @runtime = runtime
82
- end
83
-
84
- def call(event)
85
- event_to_methods(event).each do |method_name|
86
- send(method_name, event)
87
- rescue Realm::Persistence::Conflict => e
88
- context[:logger]&.warn(e.full_message)
89
- end
90
- end
91
-
92
- protected
93
-
94
- delegate :context, to: :@runtime
95
-
96
- private
97
-
98
- def event_to_methods(event)
99
- self.class.trigger_mapping.fetch_values(event.type.to_sym, :any) { [] }.flatten
100
- end
101
- end
102
- end
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/string'
4
- require 'active_support/core_ext/hash'
5
- require 'realm/error'
6
- require 'realm/domain_resolver'
7
- require 'realm/event_handler'
8
- require 'realm/event_factory'
9
- require 'realm/mixins/dependency_injection'
10
- require_relative 'event_router/internal_loop_gateway'
11
-
12
- module Realm
13
- class EventRouter
14
- include Mixins::DependencyInjection
15
- inject DomainResolver
16
- inject 'Realm::Runtime', lazy: true
17
-
18
- def initialize(gateways_spec, prefix: nil)
19
- @prefix = prefix
20
- @auto_registered = false
21
- @default_namespace = nil
22
- init_gateways(gateways_spec)
23
- end
24
-
25
- def register(handler_class)
26
- gateway_for(handler_class.try(:event_namespace)).register(handler_class)
27
- end
28
-
29
- def add_listener(event_type, listener, namespace: nil)
30
- gateway_for(namespace).add_listener(event_type, listener)
31
- end
32
-
33
- def trigger(identifier, attributes = {})
34
- namespace, event_type = identifier.to_s.include?('/') ? identifier.split('/') : [nil, identifier]
35
- gateway_for(namespace).trigger(event_type, attributes)
36
- end
37
-
38
- def workers(*namespaces, **options)
39
- auto_register_handlers
40
- @gateways.filter_map do |(namespace, gateway)|
41
- gateway.worker(**options) if namespaces.empty? || namespaces.include?(namespace)
42
- end
43
- end
44
-
45
- def active_queues
46
- auto_register_handlers
47
- @gateways.values.reduce([]) do |queues, gateway|
48
- queues + gateway.queues
49
- end
50
- end
51
-
52
- private
53
-
54
- def init_gateways(gateways_spec)
55
- auto_register_on_init = false
56
- @gateways = gateways_spec.each_with_object({}) do |(namespace, config), gateways|
57
- gateway_class = gateway_class(config.fetch(:type))
58
- auto_register_on_init ||= gateway_class.auto_register_on_init
59
- gateways[namespace] = instantiate_gateway(namespace, gateway_class, config)
60
- @default_namespace = namespace if config[:default]
61
- end
62
- auto_register_handlers if auto_register_on_init
63
- end
64
-
65
- def gateway_class(type)
66
- return InternalLoopGateway if type.to_s == 'internal_loop'
67
-
68
- runtime.container.resolve("event_router.gateway_classes.#{type}")
69
- end
70
-
71
- def instantiate_gateway(namespace, klass, config)
72
- klass.new(
73
- namespace: namespace,
74
- queue_prefix: @prefix,
75
- event_factory: EventFactory.new(config.fetch(:events_module)),
76
- runtime: runtime,
77
- **config.except(:type, :default, :events_module),
78
- )
79
- end
80
-
81
- def auto_register_handlers
82
- return if @auto_registered || !domain_resolver
83
-
84
- @auto_registered = true
85
- domain_resolver.all_event_handlers.each { |klass| register(klass) }
86
- end
87
-
88
- def gateway_for(namespace)
89
- @gateways.fetch(namespace.try(:to_sym) || default_namespace) do
90
- raise "No event gateway for #{namespace || 'default'} namespace" # TODO: extract error class
91
- end
92
- end
93
-
94
- def default_namespace
95
- return @default_namespace if @default_namespace
96
-
97
- @gateways.keys[0] if @gateways.keys.size == 1
98
- end
99
- end
100
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Realm
4
- class EventRouter
5
- class Gateway
6
- def self.auto_register_on_init
7
- false
8
- end
9
-
10
- def initialize(event_factory:, namespace: :default, runtime: nil, **)
11
- @namespace = namespace
12
- @event_factory = event_factory
13
- @runtime = runtime
14
- end
15
-
16
- def register(handler_class)
17
- # TODO: validate event_types for existence of matching class
18
- handler_class.event_types.each do |event_type|
19
- add_listener(event_type, handler_class.bind_runtime(@runtime))
20
- end
21
- end
22
-
23
- def add_listener(event_type, listener)
24
- raise NotImplementedError
25
- end
26
-
27
- def trigger(event_type, attributes = {})
28
- raise NotImplementedError
29
- end
30
-
31
- def worker(*)
32
- nil
33
- end
34
-
35
- def cleanup
36
- # do nothing
37
- end
38
-
39
- def queues
40
- []
41
- end
42
-
43
- protected
44
-
45
- def create_event(event_type, attributes = {})
46
- @event_factory.create_event(event_type, **attributes)
47
- end
48
- end
49
- end
50
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './gateway'
4
-
5
- module Realm
6
- class EventRouter
7
- class InternalLoopGateway < Gateway
8
- def self.auto_register_on_init
9
- true
10
- end
11
-
12
- def initialize(isolated: false, **)
13
- super
14
- @listener_map = {}
15
- @isolated = isolated
16
- gateways << self
17
- end
18
-
19
- def add_listener(event_type, listener)
20
- (@listener_map[event_type.to_sym] ||= []) << listener
21
- end
22
-
23
- def trigger(event_type, attributes = {})
24
- create_event(event_type, attributes).tap do |event|
25
- gateways.each { |gateway| gateway.handle(event_type, event) }
26
- end
27
- end
28
-
29
- def purge!
30
- gateways.clear
31
- end
32
-
33
- protected
34
-
35
- def handle(event_type, event)
36
- find_listeners(event_type).each { |listener| listener.(event) }
37
- end
38
-
39
- private
40
-
41
- def find_listeners(event_type)
42
- @listener_map.fetch_values(event_type.to_sym, :any) { [] }.flatten
43
- end
44
-
45
- def gateways
46
- @isolated ? (@gateways ||= []) : (@@gateways ||= []) # rubocop:disable Style/ClassVars
47
- end
48
- end
49
- end
50
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/object/blank'
4
-
5
- module Realm
6
- class HealthStatus
7
- CODES = %i[green yellow red].freeze
8
- attr_reader :code, :issues
9
-
10
- class << self
11
- def [](code, *issues)
12
- new(code, issues.flatten)
13
- end
14
-
15
- def from_issues(issues)
16
- new(issues.blank? ? :green : :red, issues)
17
- end
18
-
19
- def combine(component_map)
20
- code_index = component_map.values.map { |i| CODES.index(i.code) }.max
21
- new(CODES[code_index || 0], [], component_map)
22
- end
23
- end
24
-
25
- def for_component(*names)
26
- @component_map.dig(*names)
27
- end
28
-
29
- def to_h
30
- hash = { status: @code }
31
- hash[:issues] = @issues if @issues.present?
32
- hash[:components] = @component_map.transform_values(&:to_h) if @component_map.present?
33
- hash
34
- end
35
-
36
- private
37
-
38
- def initialize(code, issues = [], component_map = {})
39
- raise ArgumentError, "Invalid status code #{code}" unless CODES.include?(code)
40
-
41
- @code = code
42
- @issues = issues.freeze
43
- @component_map = component_map.freeze
44
- end
45
- end
46
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Realm
4
- module Mixins
5
- module AggregateMember
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- def aggregate
11
- self.class.aggregate
12
- end
13
-
14
- module ClassMethods
15
- def aggregate
16
- @aggregate ||= begin
17
- module_chain = name.split('::')
18
- domain_index = module_chain.index('Domain')
19
- domain_index && module_chain[domain_index + 1].underscore.to_sym
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'realm/error'
4
-
5
- module Realm
6
- module Mixins
7
- module ContextInjection
8
- def self.included(base)
9
- base.extend(ClassMethods)
10
- base.prepend(Initializer)
11
- end
12
-
13
- module ClassMethods
14
- def inject(*names, &block)
15
- names.each do |name|
16
- define_method(name) do
17
- raise Realm::DependencyMissing, name unless context.key?(name)
18
-
19
- return context[name] unless block
20
-
21
- var = "@#{name}"
22
- return instance_variable_get(var) if instance_variable_defined?(var)
23
-
24
- instance_variable_set(var, block.(context[name]))
25
- end
26
- end
27
- end
28
- end
29
-
30
- module Initializer
31
- def initialize(*args, context: nil, **kwargs)
32
- @context = context || context_from_root_module || {}
33
- super(*args, **kwargs)
34
- end
35
-
36
- private
37
-
38
- def context_from_root_module
39
- root_module = self.class.module_parents[-2]
40
- root_module.realm.context if root_module.respond_to?(:realm)
41
- end
42
- end
43
-
44
- protected
45
-
46
- attr_reader :context
47
- end
48
- end
49
- end