aux 0.1.0 → 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.
- checksums.yaml +4 -4
- data/aux.gemspec +3 -3
- data/lib/aux/pluggable/class_methods.rb +4 -9
- data/lib/aux/pluggable/connector.rb +27 -29
- data/lib/aux/pluggable/dependency.rb +5 -4
- data/lib/aux/pluggable/utilities.rb +9 -8
- data/lib/aux/pluggable.rb +12 -2
- data/lib/aux/registry/entry.rb +27 -0
- data/lib/aux/registry.rb +32 -0
- data/lib/aux/version.rb +1 -1
- metadata +36 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cf122c1dc9b99cf9e0b875586c740617087f7d59c06b50e31a9b9f632874dcc
|
4
|
+
data.tar.gz: 185dd787c6d3ee866e9c67c8ffc4135a28565eb63167bd19f85c1e63e9bb397f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a393a2f312dfc8dc83bfe74ac4e8b77d0525158d6d7a34e2a9889aae8d269478fa2c16c0e44ecfefc236408696e5ceaa007944d4f486e7c2d39595b23f63e67a
|
7
|
+
data.tar.gz: '00679c6c77e2a668f7ee39accb292e19495ffaae3118232f1dd122bc3c31f3250d8517b66cbd863603cbd490b9a35cf292b66181a95de6069e071a0bf6503b28'
|
data/aux.gemspec
CHANGED
@@ -10,11 +10,11 @@ Gem::Specification.new do |specification|
|
|
10
10
|
specification.email = ['eboyko@eboyko.ru']
|
11
11
|
specification.homepage = 'https://github.com/eboyko/aux'
|
12
12
|
|
13
|
+
specification.add_dependency 'concurrent-ruby', '~> 1.2', '>= 1.2.3'
|
13
14
|
specification.add_dependency 'activemodel', '>= 6.1', '< 8'
|
14
|
-
specification.add_dependency 'dry-container', '>= 0.9.0', '<= 0.11'
|
15
15
|
|
16
|
-
specification.add_development_dependency 'zeitwerk', '~> 2.
|
17
|
-
specification.add_development_dependency 'rubocop', '~> 1.
|
16
|
+
specification.add_development_dependency 'zeitwerk', '~> 2.6', '>= 2.6.13'
|
17
|
+
specification.add_development_dependency 'rubocop', '~> 1.62', '>= 1.62.1'
|
18
18
|
|
19
19
|
specification.required_ruby_version = '>= 2.7.1'
|
20
20
|
specification.metadata['rubygems_mfa_required'] = 'true'
|
@@ -52,24 +52,19 @@ module Aux
|
|
52
52
|
|
53
53
|
# @param initialize [TrueClass, FalseClass]
|
54
54
|
# @param memoize [TrueClass, FalseClass]
|
55
|
-
# @param scope [
|
55
|
+
# @param scope [Symbol, String, TrueClass, nil]
|
56
56
|
# @param as [Symbol, String, nil]
|
57
57
|
def register(initialize: false, memoize: false, scope: true, as: nil)
|
58
|
-
@_pluggable.register(
|
59
|
-
initialization_required: initialize,
|
60
|
-
memoization_required: memoize,
|
61
|
-
namespace: scope,
|
62
|
-
code: as
|
63
|
-
)
|
58
|
+
@_pluggable.register(initialize, memoize, scope, as)
|
64
59
|
end
|
65
60
|
|
66
61
|
# @param code [Symbol, String]
|
67
|
-
# @param initialization_block [
|
62
|
+
# @param initialization_block [Proc, nil]
|
68
63
|
# @param scope [TrueClass, Symbol, String, nil]
|
69
64
|
# @param private [TrueClass, FalseClass]
|
70
65
|
# @param as [Symbol, String, nil]
|
71
66
|
def resolve(code, initialization_block = nil, scope: true, private: true, as: nil)
|
72
|
-
@_pluggable.resolve(code,
|
67
|
+
@_pluggable.resolve(code, scope, private, as, initialization_block)
|
73
68
|
end
|
74
69
|
end
|
75
70
|
end
|
@@ -3,32 +3,26 @@
|
|
3
3
|
module Aux
|
4
4
|
module Pluggable
|
5
5
|
# Describes the bridge between a pluggable class and the registry
|
6
|
+
# @!visibility private
|
6
7
|
class Connector
|
7
8
|
# @!attribute [r] dependencies
|
8
9
|
# @return [Array<Dependency>]
|
9
10
|
attr_reader :dependencies
|
10
11
|
|
11
12
|
# @param subject [Class]
|
12
|
-
# @param registry [
|
13
|
+
# @param registry [Aux::Registry]
|
13
14
|
def initialize(subject, registry)
|
14
15
|
@subject = subject
|
15
16
|
@registry = registry
|
16
17
|
@dependencies = []
|
17
|
-
|
18
|
-
configure
|
19
18
|
end
|
20
19
|
|
21
|
-
# @param initialization_required [
|
22
|
-
# @param memoization_required [
|
23
|
-
# @param namespace [Symbol] the namespace to register the subject
|
24
|
-
# @param code [Symbol] an alternate name
|
25
|
-
def register(initialization_required
|
26
|
-
configure(
|
27
|
-
initialization_required: initialization_required,
|
28
|
-
memoization_required: memoization_required,
|
29
|
-
namespace: namespace,
|
30
|
-
code: code
|
31
|
-
)
|
20
|
+
# @param initialization_required [TrueClass, FalseClass] whether the subject requires initialization before use
|
21
|
+
# @param memoization_required [TrueClass, FalseClass] whether the subject should be memoized
|
22
|
+
# @param namespace [Symbol, String, TrueClass, nil] the namespace to register the subject
|
23
|
+
# @param code [Symbol, String, nil] an alternate name
|
24
|
+
def register(initialization_required, memoization_required, namespace, code)
|
25
|
+
configure(initialization_required, memoization_required, namespace, code)
|
32
26
|
|
33
27
|
# Register the subject in the registry using the provided options
|
34
28
|
@registry.register(@cipher, memoize: @memoization_required) do
|
@@ -37,16 +31,16 @@ module Aux
|
|
37
31
|
end
|
38
32
|
|
39
33
|
# @param code [Symbol, String] the name of the dependency
|
40
|
-
# @param
|
41
|
-
# @param namespace [TrueClass, Symbol, String, nil] whether to resolve the dependency in the same namespace
|
34
|
+
# @param namespace [Symbol, String, TrueClass, nil] whether to resolve the dependency in the same namespace
|
42
35
|
# @param private [TrueClass, FalseClass] whether to make the dependency private
|
43
|
-
# @param as [Symbol] an internal alias name for the dependency
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
|
36
|
+
# @param as [Symbol, String, nil] an internal alias name for the dependency
|
37
|
+
# @param initialization_block [Proc, nil] an optional block used to initialize the dependency
|
38
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
39
|
+
def resolve(code, namespace, private, as, initialization_block = nil)
|
40
|
+
cipher = Utilities.dependency_cipher(@subject.name, namespace, code)
|
41
|
+
load_class(cipher)
|
48
42
|
|
49
|
-
dependency = Dependency.new(@registry.resolve(cipher),
|
43
|
+
dependency = Dependency.new(@registry.resolve(cipher), as || code, private, initialization_block)
|
50
44
|
@dependencies.push(dependency)
|
51
45
|
|
52
46
|
if @initialization_required
|
@@ -62,16 +56,16 @@ module Aux
|
|
62
56
|
end
|
63
57
|
end
|
64
58
|
end
|
65
|
-
# rubocop:enable
|
59
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
66
60
|
|
67
61
|
private
|
68
62
|
|
69
|
-
# @param initialization_required [TrueClass, FalseClass
|
70
|
-
# @param memoization_required [TrueClass, FalseClass
|
71
|
-
# @param namespace [Symbol, String, nil]
|
63
|
+
# @param initialization_required [TrueClass, FalseClass]
|
64
|
+
# @param memoization_required [TrueClass, FalseClass]
|
65
|
+
# @param namespace [TrueClass, Symbol, String, nil]
|
72
66
|
# @param code [Symbol, String, nil]
|
73
|
-
def configure(initialization_required
|
74
|
-
@cipher = Utilities.dependency_cipher(@subject.name,
|
67
|
+
def configure(initialization_required, memoization_required, namespace, code)
|
68
|
+
@cipher = Utilities.dependency_cipher(@subject.name, namespace, code)
|
75
69
|
@initialization_required = initialization_required
|
76
70
|
@memoization_required = memoization_required
|
77
71
|
@namespace = namespace
|
@@ -85,7 +79,11 @@ module Aux
|
|
85
79
|
# @return [Class] the loaded class
|
86
80
|
def load_class(cipher)
|
87
81
|
cipher.split('.').reduce(Object) do |namespace, class_name|
|
88
|
-
|
82
|
+
if defined?(ActiveSupport::Inflector)
|
83
|
+
namespace.const_get(class_name.camelcase)
|
84
|
+
else
|
85
|
+
namespace.const_get(class_name.split('_').map(&:capitalize).join)
|
86
|
+
end
|
89
87
|
end
|
90
88
|
end
|
91
89
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Aux
|
4
4
|
module Pluggable
|
5
5
|
# Describes the dependency and its preferences
|
6
|
+
# @!visibility private
|
6
7
|
class Dependency
|
7
8
|
# @!attribute [r] target
|
8
9
|
# @return [Object]
|
@@ -10,14 +11,14 @@ module Aux
|
|
10
11
|
# @return [Symbol, String]
|
11
12
|
# @!attribute [r] private
|
12
13
|
# @return [Boolean]
|
13
|
-
attr_reader :
|
14
|
+
attr_reader :target, :pointer, :private
|
14
15
|
|
15
16
|
# @param target [Object]
|
16
|
-
# @param initialization_block [Proc, nil]
|
17
17
|
# @param pointer [Symbol, String]
|
18
18
|
# @param private [Boolean]
|
19
|
-
|
20
|
-
|
19
|
+
# @param initialization_block [Proc, nil]
|
20
|
+
def initialize(target, pointer, private, initialization_block = nil)
|
21
|
+
@target = initialization_block&.call(target) || target
|
21
22
|
@pointer = pointer
|
22
23
|
@private = private
|
23
24
|
end
|
@@ -3,28 +3,29 @@
|
|
3
3
|
module Aux
|
4
4
|
module Pluggable
|
5
5
|
# Random methods for internal usage
|
6
|
+
# @!visibility private
|
6
7
|
module Utilities
|
7
8
|
# First, we need to determine the appropriate namespace (also called the scope) in which to resolve something.
|
8
9
|
# By default, we assume that the developers want to resolve a dependency from the same namespace as the
|
9
10
|
# referencing class. Another approach is to allow developers to set the correct scope themselves.
|
10
11
|
#
|
11
|
-
# @param subject [
|
12
|
-
# @param scope [
|
13
|
-
# @param code [
|
12
|
+
# @param subject [String]
|
13
|
+
# @param scope [Symbol, String, TrueClass, nil]
|
14
|
+
# @param code [Symbol, String, nil]
|
14
15
|
# @return [String]
|
15
|
-
def self.dependency_cipher(subject, scope
|
16
|
+
def self.dependency_cipher(subject, scope, code)
|
16
17
|
native_cipher = dependency_native_cipher(subject)
|
17
18
|
native_cipher_partitions = native_cipher.rpartition('.')
|
18
|
-
scope =
|
19
|
-
code =
|
19
|
+
scope = native_cipher_partitions.first if scope == true
|
20
|
+
code = native_cipher_partitions.last if code.nil?
|
20
21
|
|
21
22
|
[scope, code].reject { |part| part.nil? || part.empty? }.join('.')
|
22
23
|
end
|
23
24
|
|
24
|
-
# @param subject [
|
25
|
+
# @param subject [String]
|
25
26
|
# @return [String]
|
26
27
|
def self.dependency_native_cipher(subject)
|
27
|
-
subject.dup.gsub(
|
28
|
+
subject.dup.gsub('::', '.').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
data/lib/aux/pluggable.rb
CHANGED
@@ -4,11 +4,14 @@ require 'aux/pluggable/class_methods'
|
|
4
4
|
require 'aux/pluggable/connector'
|
5
5
|
require 'aux/pluggable/dependency'
|
6
6
|
require 'aux/pluggable/utilities'
|
7
|
+
require 'aux/registry'
|
7
8
|
|
8
9
|
module Aux
|
9
10
|
# Describes interface that makes any class able to register itself as well as resolve dependencies
|
10
11
|
# rubocop:disable Style/ClassVars
|
11
12
|
module Pluggable
|
13
|
+
@@registry = Aux::Registry.new
|
14
|
+
|
12
15
|
# Extends the including class with ClassMethods and initializes a new Connector instance
|
13
16
|
# @param base [Class] the class that includes this module
|
14
17
|
def self.included(base)
|
@@ -19,12 +22,19 @@ module Aux
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
# @
|
25
|
+
# @yield configure the module
|
26
|
+
# @yieldparam pluggable [Module<Aux::Pluggable>]
|
27
|
+
# @yieldparam registry [Aux::Registry]
|
28
|
+
def self.configure
|
29
|
+
yield(self, @@registry) if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param registry [Aux::Registry]
|
23
33
|
def self.registry=(registry)
|
24
34
|
@@registry = registry
|
25
35
|
end
|
26
36
|
|
27
|
-
# @return [
|
37
|
+
# @return [Aux::Registry]
|
28
38
|
def self.registry
|
29
39
|
@@registry
|
30
40
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aux
|
4
|
+
class Registry
|
5
|
+
# Describes a registered dependency
|
6
|
+
# @!visibility private
|
7
|
+
class Entry
|
8
|
+
# @param constructor [Proc]
|
9
|
+
# @param memoization_required [TrueClass, FalseClass]
|
10
|
+
def initialize(constructor, memoization_required)
|
11
|
+
@constructor = constructor
|
12
|
+
@memoization_required = memoization_required
|
13
|
+
|
14
|
+
@mutex = Thread::Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Object]
|
18
|
+
def call
|
19
|
+
return @constructor.call unless @memoization_required
|
20
|
+
|
21
|
+
@call ||= @mutex.synchronize do
|
22
|
+
@constructor.call
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/aux/registry.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aux/registry/entry'
|
4
|
+
require 'concurrent/map'
|
5
|
+
|
6
|
+
module Aux
|
7
|
+
# Registry for dependency injection
|
8
|
+
class Registry
|
9
|
+
def initialize
|
10
|
+
@prototypes = ::Concurrent::Map.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param key [Symbol, String]
|
14
|
+
# @param memoize [TrueClass, FalseClass]
|
15
|
+
# @param constructor [Proc]
|
16
|
+
def register(key, memoize: false, &constructor)
|
17
|
+
@prototypes.put(key.to_s, Entry.new(constructor, memoize))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param key [Symbol, String]
|
21
|
+
# @return [Object]
|
22
|
+
def resolve(key)
|
23
|
+
@prototypes.fetch(key.to_s).call
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param key [Symbol, String]
|
27
|
+
# @return [TrueClass, FalseClass]
|
28
|
+
def key?(key)
|
29
|
+
@prototypes.key?(key.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/aux/version.rb
CHANGED
metadata
CHANGED
@@ -1,83 +1,95 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aux
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evgeny Boyko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: concurrent-ruby
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - "
|
19
|
+
version: '1.2'
|
20
|
+
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 1.2.3
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- - "
|
29
|
+
version: '1.2'
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 1.2.3
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: activemodel
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
40
|
-
- - "
|
39
|
+
version: '6.1'
|
40
|
+
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '8'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
50
|
-
- - "
|
49
|
+
version: '6.1'
|
50
|
+
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '8'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: zeitwerk
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '2.
|
59
|
+
version: '2.6'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.6.13
|
60
63
|
type: :development
|
61
64
|
prerelease: false
|
62
65
|
version_requirements: !ruby/object:Gem::Requirement
|
63
66
|
requirements:
|
64
67
|
- - "~>"
|
65
68
|
- !ruby/object:Gem::Version
|
66
|
-
version: '2.
|
69
|
+
version: '2.6'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.6.13
|
67
73
|
- !ruby/object:Gem::Dependency
|
68
74
|
name: rubocop
|
69
75
|
requirement: !ruby/object:Gem::Requirement
|
70
76
|
requirements:
|
71
77
|
- - "~>"
|
72
78
|
- !ruby/object:Gem::Version
|
73
|
-
version: 1.
|
79
|
+
version: '1.62'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.62.1
|
74
83
|
type: :development
|
75
84
|
prerelease: false
|
76
85
|
version_requirements: !ruby/object:Gem::Requirement
|
77
86
|
requirements:
|
78
87
|
- - "~>"
|
79
88
|
- !ruby/object:Gem::Version
|
80
|
-
version: 1.
|
89
|
+
version: '1.62'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.62.1
|
81
93
|
description:
|
82
94
|
email:
|
83
95
|
- eboyko@eboyko.ru
|
@@ -93,6 +105,8 @@ files:
|
|
93
105
|
- lib/aux/pluggable/connector.rb
|
94
106
|
- lib/aux/pluggable/dependency.rb
|
95
107
|
- lib/aux/pluggable/utilities.rb
|
108
|
+
- lib/aux/registry.rb
|
109
|
+
- lib/aux/registry/entry.rb
|
96
110
|
- lib/aux/validations.rb
|
97
111
|
- lib/aux/validations/error.rb
|
98
112
|
- lib/aux/validations/errors.rb
|