aux 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7ab27a48b02884baff3dedd1a770d02a71be57471b40aaabfd1213068dfd317
4
- data.tar.gz: 1e38945b37770dc63d2280c1b000cff18b96d06b6544430480c815ab571213ac
3
+ metadata.gz: 1cf122c1dc9b99cf9e0b875586c740617087f7d59c06b50e31a9b9f632874dcc
4
+ data.tar.gz: 185dd787c6d3ee866e9c67c8ffc4135a28565eb63167bd19f85c1e63e9bb397f
5
5
  SHA512:
6
- metadata.gz: 05c2d14e99306c482ca584ca330e0808e653bab12082c5726dfd8495370f1109646afa0a7985c948d180715ce4aa074d4c0eb9cb8f58d409dab30305fb2fcdc3
7
- data.tar.gz: 116352323a5886ac2e2c8eeafe0a55687bd5e6e37d29e4eb66b4b4c76eb7ad5e7ba5eefbdaec0a7c25cc6afe77318713cef01fcab95aeee957dbc3726b15c986
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.5'
17
- specification.add_development_dependency 'rubocop', '~> 1.36.0'
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 [TrueClass, Symbol, String, nil]
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 [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, initialization_block, namespace: scope, private: private, as: as)
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 [Dry::Container]
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 [Boolean] whether the subject requires initialization before use
22
- # @param memoization_required [Boolean] whether the subject should be memoized
23
- # @param namespace [Symbol] the namespace to register the subject
24
- # @param code [Symbol] an alternate name
25
- def register(initialization_required: nil, memoization_required: nil, namespace: nil, code: nil)
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 initialization_block [Proc] an optional block used to initialize the dependency
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
- # rubocop:disable Layout/LineLength, Metrics/AbcSize, Metrics/MethodLength
45
- def resolve(code, initialization_block = nil, namespace: true, private: true, as: nil)
46
- cipher = Utilities.dependency_cipher(@subject.name, scope: namespace, code: code)
47
- load_class(cipher) unless @registry.key?(cipher)
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), initialization_block, pointer: as || code, private: private)
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 Layout/LineLength, Metrics/AbcSize, Metrics/MethodLength
59
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
66
60
 
67
61
  private
68
62
 
69
- # @param initialization_required [TrueClass, FalseClass, nil]
70
- # @param memoization_required [TrueClass, FalseClass, nil]
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: nil, memoization_required: nil, namespace: nil, code: nil)
74
- @cipher = Utilities.dependency_cipher(@subject.name, scope: namespace, code: code)
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
- namespace.const_get(class_name.split('_').map(&:capitalize).join)
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 :pointer, :target, :private
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
- def initialize(target, initialization_block = nil, pointer:, private:)
20
- @target = initialization_block ? initialization_block.call(target) : target
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 [ClassName]
12
- # @param scope [TrueClass, Symbol, String, nil]
13
- # @param code [TrueClass, Symbol, String, nil]
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: nil, code: nil)
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 = scope == true ? native_cipher_partitions.first : scope
19
- code = code.nil? ? native_cipher_partitions.last : 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 [ClassName]
25
+ # @param subject [String]
25
26
  # @return [String]
26
27
  def self.dependency_native_cipher(subject)
27
- subject.dup.gsub(/::/, '.').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
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
- # @param registry [Dry::Container]
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 [Dry::Container]
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aux
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
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.1.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: 2023-05-13 00:00:00.000000000 Z
11
+ date: 2024-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activemodel
14
+ name: concurrent-ruby
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.1'
20
- - - "<"
19
+ version: '1.2'
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: '8'
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: '6.1'
30
- - - "<"
29
+ version: '1.2'
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '8'
32
+ version: 1.2.3
33
33
  - !ruby/object:Gem::Dependency
34
- name: dry-container
34
+ name: activemodel
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.9.0
40
- - - "<="
39
+ version: '6.1'
40
+ - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '0.11'
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: 0.9.0
50
- - - "<="
49
+ version: '6.1'
50
+ - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '0.11'
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.5'
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.5'
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.36.0
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.36.0
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