realm-core 0.7.1 → 0.7.3

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