thunderchunk 0.2.0

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +3 -0
  3. data/lib/rubocop/cop/thunderchunk/restricted_access.rb +38 -0
  4. data/lib/thunderchunk/chunk.rb +123 -0
  5. data/lib/thunderchunk/configuration.rb +127 -0
  6. data/lib/thunderchunk/database.rb +64 -0
  7. data/lib/thunderchunk/default_configuration.rb +29 -0
  8. data/lib/thunderchunk/dependency.rb +6 -0
  9. data/lib/thunderchunk/dependency_injector.rb +51 -0
  10. data/lib/thunderchunk/event.rb +40 -0
  11. data/lib/thunderchunk/exporter.rb +55 -0
  12. data/lib/thunderchunk/exporters/base.rb +88 -0
  13. data/lib/thunderchunk/exporters/events.rb +24 -0
  14. data/lib/thunderchunk/exporters/operations.rb +30 -0
  15. data/lib/thunderchunk/external_importer.rb +51 -0
  16. data/lib/thunderchunk/external_importers/base.rb +91 -0
  17. data/lib/thunderchunk/external_importers/events.rb +58 -0
  18. data/lib/thunderchunk/external_importers/operations.rb +28 -0
  19. data/lib/thunderchunk/loader/load.rb +62 -0
  20. data/lib/thunderchunk/loader/namespace.rb +47 -0
  21. data/lib/thunderchunk/loader.rb +66 -0
  22. data/lib/thunderchunk/model.rb +67 -0
  23. data/lib/thunderchunk/operation.rb +0 -0
  24. data/lib/thunderchunk/operations/adapters/use_dependecy.rb +42 -0
  25. data/lib/thunderchunk/operations/base.rb +12 -0
  26. data/lib/thunderchunk/operations/external.rb +7 -0
  27. data/lib/thunderchunk/operations/internal.rb +6 -0
  28. data/lib/thunderchunk/operations/remote.rb +50 -0
  29. data/lib/thunderchunk/operations/subscriber.rb +12 -0
  30. data/lib/thunderchunk/outbox.rb +10 -0
  31. data/lib/thunderchunk/registries/base.rb +76 -0
  32. data/lib/thunderchunk/registries/models.rb +26 -0
  33. data/lib/thunderchunk/registries/operations.rb +17 -0
  34. data/lib/thunderchunk/registry.rb +55 -0
  35. data/lib/thunderchunk/rubocop.rb +6 -0
  36. data/lib/thunderchunk/sender_dock.rb +49 -0
  37. data/lib/thunderchunk/type_names.rb +35 -0
  38. data/lib/thunderchunk/usage_importer/kinds/model.rb +14 -0
  39. data/lib/thunderchunk/usage_importer/use.rb +13 -0
  40. data/lib/thunderchunk/version.rb +5 -0
  41. data/lib/thunderchunk.rb +61 -0
  42. metadata +132 -0
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ class Registries
5
+ class Base
6
+ def self.kind(value = nil)
7
+ return @kind = value if value
8
+
9
+ @kind || raise(NotImplementedError, "#{name} must declare `kind`")
10
+ end
11
+
12
+ def self.path(value = nil)
13
+ return @path = value if value
14
+
15
+ @path || @kind.to_s.pluralize || raise(NotImplementedError, "#{name} must declare `kind` or `path`")
16
+ end
17
+
18
+ def initialize(chunk)
19
+ @chunk = chunk
20
+ @items = {}
21
+ @loader = Loader.new(@chunk.name, @chunk.root_path)
22
+ end
23
+
24
+ attr_reader :items
25
+
26
+ def add_constant(constant)
27
+ return false unless constant.is_a?(Class)
28
+
29
+ key = key_for(constant)
30
+ return false unless key
31
+
32
+ add(key, constant)
33
+ true
34
+ end
35
+
36
+ def key_for(_constant)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def add(path, object)
41
+ @items[path] = object
42
+ end
43
+
44
+ def get(path)
45
+ @items[path]
46
+ end
47
+
48
+ def clear
49
+ @items.clear
50
+ end
51
+
52
+ def load
53
+ @items = {}
54
+
55
+ @loader.load(["app/internal/#{self.class.path}"])
56
+
57
+ @loader.each do |_parent, _name, constant|
58
+ add_constant(constant)
59
+ end
60
+
61
+ @loader.unload
62
+ end
63
+
64
+ private
65
+
66
+ def key_from_name(constant, *namespace)
67
+ segments = constant.name.split('::')
68
+ index = segments.each_index.find { |i| segments[i, namespace.size] == namespace }
69
+ return unless index
70
+
71
+ rest = segments.drop(index + namespace.size)
72
+ rest.map(&:underscore).join('.') unless rest.empty?
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ class Registries
5
+ class Models < Base
6
+ kind :model
7
+
8
+ def key_for(constant)
9
+ key_from_name(constant, 'Internal', 'Models')&.tap do |key|
10
+ unless constant < ThunderChunk::Model
11
+ raise RegistryRequirementError, "#{constant.name} must inherit from ThunderChunk::Model"
12
+ end
13
+ end
14
+ end
15
+
16
+ def add(path, object)
17
+ object.chunk_key = path
18
+ object.chunk_registry = self
19
+
20
+ # WARN: Test checkin that when is not a model class (dont respond to chunk key),
21
+ # raise error and dont save in registry
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ class Registries
5
+ class Operations < Base
6
+ kind :operation
7
+
8
+ def key_for(constant)
9
+ key_from_name(constant, 'Internal', 'Operations')&.tap do |key|
10
+ unless constant < ThunderChunk::Operations::Internal
11
+ raise RegistryRequirementError, "#{constant.name} must inherit from ThunderChunk::Operations::Internal"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ class Registry
5
+ def initialize(chunk = nil)
6
+ @chunk = chunk
7
+ @registries = chunk.configuration['boot.registries'].to_h do |klass|
8
+ [klass.kind, klass.new(chunk)]
9
+ end
10
+ end
11
+
12
+ def load
13
+ @registries.each_value(&:load)
14
+ end
15
+
16
+ def unload
17
+ @registries.each_value(&:unload)
18
+ end
19
+
20
+ def hash
21
+ @registries.transform_values(&:items)
22
+ end
23
+
24
+ def get(kind, path)
25
+ @registries[kind.to_sym]&.get(path.to_s)
26
+ end
27
+
28
+ def get!(kind, path)
29
+ get(kind, path) || raise(Error, "#{kind} #{path} is not registered")
30
+ end
31
+
32
+ def each_constant(*, &)
33
+ hash.each_value do |items|
34
+ items.each_value(*, &)
35
+ end
36
+ end
37
+
38
+ def clear
39
+ @registries.each_value(&:clear)
40
+ end
41
+
42
+ def create_kind(registry)
43
+ kind = registry.class.kind
44
+
45
+ raise ArgumentError, 'This registry already has a kind' if @registries.has_value?(registry)
46
+ raise ArgumentError, 'This kind already has a registry' if @registries.has_key?(kind)
47
+
48
+ @registries[kind] = registry
49
+ end
50
+
51
+ def [](value)
52
+ hash[value]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Entry point for `require: thunderchunk/rubocop` in a chunk's .rubocop.yml.
4
+ require 'rubocop'
5
+
6
+ require_relative '../rubocop/cop/thunderchunk/restricted_access'
@@ -0,0 +1,49 @@
1
+ module ThunderChunk
2
+ class SenderDock
3
+ # WARN: AI MADE
4
+ class << self
5
+ attr_accessor :resolver
6
+ end
7
+ # WARN: ---
8
+
9
+ def initialize(chunk)
10
+ @chunk = chunk
11
+ @senders = Hash.new { |a, k| a[k] = {} }
12
+ end
13
+
14
+ def sender_for(chunk_identifier, wire)
15
+ get(chunk_identifier, wire) || begin
16
+ remote = "remotes.chunk.#{chunk_identifier}.external_import.#{wire}"
17
+ url = @chunk.config["#{remote}.url"]
18
+
19
+ raise(Error, "Remote #{chunk_identifier} does not set a configured url") if url.blank?
20
+
21
+ protocol = @chunk.config["#{remote}.protocol"] || :http
22
+ sender_class = load_class(wire, protocol)
23
+
24
+ set(chunk_identifier, wire, sender_class.new(chunk_identifier, url))
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def get(chunk_identifier, wire)
31
+ @senders.dig(
32
+ wire.to_s.underscore.to_sym,
33
+ chunk_identifier.to_s.underscore.to_sym
34
+ )
35
+ end
36
+
37
+ def set(chunk_identifier, wire, sender)
38
+ @senders[wire.to_s.underscore.to_sym][chunk_identifier.to_s.underscore.to_sym] = sender
39
+ end
40
+
41
+ # WARN: AI MADE
42
+ def load_class(wire, protocol)
43
+ resolver = self.class.resolver || raise(Error, "no sender for #{protocol} #{wire}: require 'thunderwire'")
44
+
45
+ resolver.call(protocol, wire)
46
+ end
47
+ # WARN: ---
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # WARN: AI MADE
4
+ module ThunderChunk
5
+ # Types written by name in params and returns (`param :supplier, 'Models::Supplier'`), resolved at boot to the
6
+ # models the chunk registered: a class body cannot reach a model by constant before `use` injects it, and a name
7
+ # keeps the class the registry holds. 'Models::Supplier::Relation' is the class of Supplier.all.
8
+ module TypeNames
9
+ module_function
10
+
11
+ def resolve(chunk, klass)
12
+ parameters = [
13
+ (klass.base_parameter if klass.respond_to?(:base_parameter)),
14
+ (klass.returns if klass.respond_to?(:returns))
15
+ ]
16
+ parameters.grep(ThunderOperation::Parameters::Base).each do |parameter|
17
+ parameter.resolve_types! { |name| model_for(chunk, klass, name) }
18
+ end
19
+ end
20
+
21
+ def model_for(chunk, klass, name)
22
+ segments = name.delete_prefix('::').split('::')
23
+ relation = segments.last == 'Relation' && segments.size > 2 && segments.pop
24
+ unless segments.first == 'Models' && segments.size > 1
25
+ raise Error, "#{klass.name}: type '#{name}' must name a model of the chunk, as 'Models::Supplier'"
26
+ end
27
+
28
+ key = segments.drop(1).map(&:underscore).join('.')
29
+ model = chunk.registry.get(:model, key) ||
30
+ raise(Error, "#{klass.name}: type '#{name}' names no model; chunk #{chunk.identifier} has no model #{key}")
31
+
32
+ relation ? model.relation_delegate_class(ActiveRecord::Relation) : model
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ module ThunderChunk
5
+ module UsageImporter
6
+ module Kinds
7
+ class Model
8
+ def self.use(klass, path, options = {})
9
+ klass.
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ module UsageImporter
5
+ module Use
6
+ module_function
7
+
8
+ def use(kind, key, options = {})
9
+ "UsageImporter::Kinds::#{kind.classify}".constantize.use(self)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThunderChunk
4
+ VERSION = '0.2.0'
5
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'active_support/all'
5
+ require 'active_record'
6
+ # WARN: AI MADE
7
+ require 'console'
8
+ # WARN: ---
9
+ require 'thunderoperation'
10
+
11
+ require_relative 'thunderchunk/version'
12
+
13
+ # Manages a single chunk. Depends on thunderfoundation, never on thunderbolt.
14
+ module ThunderChunk
15
+ class Error < StandardError; end
16
+
17
+ # A class sits in the folder of a registry but does not meet what that registry requires.
18
+ class RegistryRequirementError < Error; end
19
+
20
+ # A chunk file does not define the constant its path names.
21
+ class FileConstantMismatchError < Error; end
22
+ end
23
+
24
+ require_relative 'thunderchunk/configuration'
25
+ require_relative 'thunderchunk/loader'
26
+ require_relative 'thunderchunk/loader/namespace'
27
+ require_relative 'thunderchunk/loader/load'
28
+ require_relative 'thunderchunk/model'
29
+ require_relative 'thunderchunk/outbox'
30
+ require_relative 'thunderchunk/dependency'
31
+ require_relative 'thunderchunk/dependency_injector'
32
+ require_relative 'thunderchunk/operations/adapters/use_dependecy'
33
+ require_relative 'thunderchunk/operations/base'
34
+ require_relative 'thunderchunk/operations/internal'
35
+ require_relative 'thunderchunk/operations/external'
36
+ require_relative 'thunderchunk/operations/subscriber'
37
+ require_relative 'thunderchunk/operation'
38
+ require_relative 'thunderchunk/chunk'
39
+ # WARN: AI MADE
40
+ require_relative 'thunderchunk/type_names'
41
+ require_relative 'thunderchunk/registries/base'
42
+ require_relative 'thunderchunk/registries/models'
43
+ require_relative 'thunderchunk/registries/operations'
44
+ require_relative 'thunderchunk/registry'
45
+ require_relative 'thunderchunk/database'
46
+ require_relative 'thunderchunk/exporter'
47
+ require_relative 'thunderchunk/exporters/base'
48
+ require_relative 'thunderchunk/operations/remote'
49
+ require_relative 'thunderchunk/event'
50
+ require_relative 'thunderchunk/sender_dock'
51
+ require_relative 'thunderchunk/external_importer'
52
+ require_relative 'thunderchunk/external_importers/base'
53
+ require_relative 'thunderchunk/external_importers/operations'
54
+ require_relative 'thunderchunk/external_importers/events'
55
+
56
+
57
+ ThunderOperation.config.transaction = lambda do |&block|
58
+ next block.call if ActiveRecord::Base.connection_handler.connection_pool_list.empty?
59
+
60
+ ActiveRecord::Base.transaction(&block)
61
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thunderchunk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Albert Alef
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '8.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '8.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activesupport
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '8.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: console
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.29'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.29'
54
+ - !ruby/object:Gem::Dependency
55
+ name: thunderoperation
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 0.2.0
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.2.0
68
+ executables: []
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - README.md
73
+ - lib/rubocop/cop/thunderchunk/restricted_access.rb
74
+ - lib/thunderchunk.rb
75
+ - lib/thunderchunk/chunk.rb
76
+ - lib/thunderchunk/configuration.rb
77
+ - lib/thunderchunk/database.rb
78
+ - lib/thunderchunk/default_configuration.rb
79
+ - lib/thunderchunk/dependency.rb
80
+ - lib/thunderchunk/dependency_injector.rb
81
+ - lib/thunderchunk/event.rb
82
+ - lib/thunderchunk/exporter.rb
83
+ - lib/thunderchunk/exporters/base.rb
84
+ - lib/thunderchunk/exporters/events.rb
85
+ - lib/thunderchunk/exporters/operations.rb
86
+ - lib/thunderchunk/external_importer.rb
87
+ - lib/thunderchunk/external_importers/base.rb
88
+ - lib/thunderchunk/external_importers/events.rb
89
+ - lib/thunderchunk/external_importers/operations.rb
90
+ - lib/thunderchunk/loader.rb
91
+ - lib/thunderchunk/loader/load.rb
92
+ - lib/thunderchunk/loader/namespace.rb
93
+ - lib/thunderchunk/model.rb
94
+ - lib/thunderchunk/operation.rb
95
+ - lib/thunderchunk/operations/adapters/use_dependecy.rb
96
+ - lib/thunderchunk/operations/base.rb
97
+ - lib/thunderchunk/operations/external.rb
98
+ - lib/thunderchunk/operations/internal.rb
99
+ - lib/thunderchunk/operations/remote.rb
100
+ - lib/thunderchunk/operations/subscriber.rb
101
+ - lib/thunderchunk/outbox.rb
102
+ - lib/thunderchunk/registries/base.rb
103
+ - lib/thunderchunk/registries/models.rb
104
+ - lib/thunderchunk/registries/operations.rb
105
+ - lib/thunderchunk/registry.rb
106
+ - lib/thunderchunk/rubocop.rb
107
+ - lib/thunderchunk/sender_dock.rb
108
+ - lib/thunderchunk/type_names.rb
109
+ - lib/thunderchunk/usage_importer/kinds/model.rb
110
+ - lib/thunderchunk/usage_importer/use.rb
111
+ - lib/thunderchunk/version.rb
112
+ licenses: []
113
+ metadata:
114
+ rubygems_mfa_required: 'true'
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '3.4'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.6.9
130
+ specification_version: 4
131
+ summary: 'Manages a chunk: operations engine, surfaces, schema and migrations'
132
+ test_files: []