Class: Torikago::Gateway
- Inherits:
-
Object
- Object
- Torikago::Gateway
- Defined in:
- lib/torikago/gateway.rb,
sig/torikago.rbs
Overview
Runtime entrypoint for all cross-module calls. It validates the package API manifest before dispatching into the target module container.
Instance Attribute Summary collapse
-
#configuration ⇒ Configuration
readonly
Returns the value of attribute configuration.
-
#manifest_loader ⇒ Object
readonly
Returns the value of attribute manifest_loader.
-
#manifests ⇒ Hash[Symbol, Hash[String, untyped]]
readonly
Returns the value of attribute manifests.
-
#registry ⇒ Registry
readonly
Returns the value of attribute registry.
Class Method Summary collapse
Instance Method Summary collapse
- #allowed_callers(public_api_entry) ⇒ Array[untyped]
- #build(public_api_class_name, *constructor_args, **constructor_kwargs) ⇒ Invocation
- #dependency_allowed?(public_api_entry, caller_name) ⇒ Boolean
-
#dispatch(public_api_class_name:, method_name:, constructor_args:, constructor_kwargs:, method_args:, method_kwargs:) ⇒ Object
Internal interface used by Invocation.
- #exported_methods(public_api_entry) ⇒ Array[String]
- #exported_package_apis(manifest) ⇒ Hash[String, untyped]
- #infer_target_module(public_api_class_name) ⇒ Symbol
-
#initialize(registry:, configuration:, manifest_loader: nil) ⇒ Gateway
constructor
A new instance of Gateway.
- #invoke(public_api_class_name, method_name, *method_args, **method_kwargs) ⇒ Object
- #load_manifest(definition) ⇒ Hash[String, untyped]
- #package_api_manifest_path(definition) ⇒ Pathname
- #validate_public_api!(target_module, public_api_class_name, method_name, caller_module) ⇒ nil
Constructor Details
#initialize(registry:, configuration:, manifest_loader: nil) ⇒ Gateway
Returns a new instance of Gateway.
18 19 20 21 22 23 |
# File 'lib/torikago/gateway.rb', line 18 def initialize(registry:, configuration:, manifest_loader: nil) @registry = registry @configuration = configuration @manifest_loader = manifest_loader || method(:load_manifest) @manifests = Hash.new end |
Instance Attribute Details
#configuration ⇒ Configuration (readonly)
Returns the value of attribute configuration.
64 65 66 |
# File 'lib/torikago/gateway.rb', line 64 def configuration @configuration end |
#manifest_loader ⇒ Object (readonly)
Returns the value of attribute manifest_loader.
64 65 66 |
# File 'lib/torikago/gateway.rb', line 64 def manifest_loader @manifest_loader end |
#manifests ⇒ Hash[Symbol, Hash[String, untyped]] (readonly)
Returns the value of attribute manifests.
64 65 66 |
# File 'lib/torikago/gateway.rb', line 64 def manifests @manifests end |
#registry ⇒ Registry (readonly)
Returns the value of attribute registry.
64 65 66 |
# File 'lib/torikago/gateway.rb', line 64 def registry @registry end |
Class Method Details
.build ⇒ Invocation
9 10 11 |
# File 'lib/torikago/gateway.rb', line 9 def build(...) Torikago.gateway.build(...) end |
Instance Method Details
#allowed_callers(public_api_entry) ⇒ Array[untyped]
138 139 140 141 142 143 144 145 |
# File 'lib/torikago/gateway.rb', line 138 def allowed_callers(public_api_entry) return Array.new unless public_api_entry.is_a?(Hash) allowed = public_api_entry["allowed_callers"] return allowed if allowed.is_a?(Array) Array.new end |
#build(public_api_class_name, *constructor_args, **constructor_kwargs) ⇒ Invocation
25 26 27 28 29 30 31 32 |
# File 'lib/torikago/gateway.rb', line 25 def build(public_api_class_name, *constructor_args, **constructor_kwargs) Invocation.new( gateway: self, public_api_class_name: public_api_class_name, constructor_args: constructor_args, constructor_kwargs: constructor_kwargs ) end |
#dependency_allowed?(public_api_entry, caller_name) ⇒ Boolean
125 126 127 |
# File 'lib/torikago/gateway.rb', line 125 def dependency_allowed?(public_api_entry, caller_name) allowed_callers(public_api_entry).map { |caller| caller.to_sym }.include?(caller_name) end |
#dispatch(public_api_class_name:, method_name:, constructor_args:, constructor_kwargs:, method_args:, method_kwargs:) ⇒ Object
Internal interface used by Invocation. Validation deliberately precedes Registry resolution so rejected calls cannot boot the target Box.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/torikago/gateway.rb', line 47 def dispatch(public_api_class_name:, method_name:, constructor_args:, constructor_kwargs:, method_args:, method_kwargs:) target_module = infer_target_module(public_api_class_name) caller_module = CurrentExecution.current_box validate_public_api!(target_module, public_api_class_name, method_name, caller_module) registry.resolve(target_module).invoke( public_api_class_name, method_name, constructor_args: constructor_args, constructor_kwargs: constructor_kwargs, method_args: method_args, method_kwargs: method_kwargs ) end |
#exported_methods(public_api_entry) ⇒ Array[String]
129 130 131 132 133 134 135 136 |
# File 'lib/torikago/gateway.rb', line 129 def exported_methods(public_api_entry) return Array.new unless public_api_entry.is_a?(Hash) methods = public_api_entry["methods"] return methods.map(&:to_s) if methods.is_a?(Array) Array.new end |
#exported_package_apis(manifest) ⇒ Hash[String, untyped]
121 122 123 |
# File 'lib/torikago/gateway.rb', line 121 def exported_package_apis(manifest) manifest.fetch("exports") { manifest.fetch("public_api", Hash.new) } end |
#infer_target_module(public_api_class_name) ⇒ Symbol
117 118 119 |
# File 'lib/torikago/gateway.rb', line 117 def infer_target_module(public_api_class_name) public_api_class_name.split("::").first.downcase.to_sym end |
#invoke(public_api_class_name, method_name, *method_args, **method_kwargs) ⇒ Object
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/torikago/gateway.rb', line 34 def invoke(public_api_class_name, method_name, *method_args, **method_kwargs) dispatch( public_api_class_name: public_api_class_name, method_name: method_name, constructor_args: Array.new, constructor_kwargs: Hash.new, method_args: method_args, method_kwargs: method_kwargs ) end |
#load_manifest(definition) ⇒ Hash[String, untyped]
102 103 104 105 106 107 108 109 110 111 |
# File 'lib/torikago/gateway.rb', line 102 def load_manifest(definition) manifest_path = package_api_manifest_path(definition) unless manifest_path.exist? raise DependencyError, "package_api manifest not found for #{definition.name}: #{manifest_path}" end YAML.safe_load(manifest_path.read, permitted_classes: Array.new, aliases: false) || Hash.new end |
#package_api_manifest_path(definition) ⇒ Pathname
113 114 115 |
# File 'lib/torikago/gateway.rb', line 113 def package_api_manifest_path(definition) Pathname(definition.root).join("package_api.yml") end |
#validate_public_api!(target_module, public_api_class_name, method_name, caller_module) ⇒ nil
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/torikago/gateway.rb', line 66 def validate_public_api!(target_module, public_api_class_name, method_name, caller_module) target_name = target_module.to_sym definition = configuration.fetch(target_name) manifest = manifests.fetch(target_name) do manifests[target_name] = manifest_loader.call(definition) end public_api_entry = exported_package_apis(manifest).fetch(public_api_class_name, nil) if public_api_entry.nil? raise PublicApiError, "package api export not declared for #{target_name}: #{public_api_class_name}##{method_name}" end methods = exported_methods(public_api_entry) if methods.empty? raise PublicApiError, "package api methods are not configured: #{public_api_class_name}##{method_name}" end unless methods.include?(method_name.to_s) raise PublicApiError, "package api method is not exported: #{public_api_class_name}##{method_name}" end return if caller_module.nil? caller_name = caller_module.to_sym # A module may always call its own public API; allowed_callers only governs # calls crossing from one module box into another. return if caller_name == target_name return if dependency_allowed?(public_api_entry, caller_name) raise DependencyError, "module dependency not allowed: #{caller_name} -> #{target_name}##{public_api_class_name}##{method_name}" end |