Class: Whoosh::DependencyInjection
- Inherits:
-
Object
- Object
- Whoosh::DependencyInjection
- Defined in:
- lib/whoosh/dependency_injection.rb
Instance Method Summary collapse
- #close_all ⇒ Object
-
#initialize ⇒ DependencyInjection
constructor
A new instance of DependencyInjection.
- #inject_for(names, request: nil) ⇒ Object
- #provide(name, scope: :singleton, &block) ⇒ Object
- #registered?(name) ⇒ Boolean
- #resolve(name, request: nil, resolving: []) ⇒ Object
- #validate! ⇒ Object
Constructor Details
#initialize ⇒ DependencyInjection
Returns a new instance of DependencyInjection.
5 6 7 8 9 |
# File 'lib/whoosh/dependency_injection.rb', line 5 def initialize @providers = {} @singletons = {} @mutex = Mutex.new end |
Instance Method Details
#close_all ⇒ Object
71 72 73 74 75 76 |
# File 'lib/whoosh/dependency_injection.rb', line 71 def close_all @singletons.each_value do |instance| instance.close if instance.respond_to?(:close) end @singletons.clear end |
#inject_for(names, request: nil) ⇒ Object
38 39 40 41 42 |
# File 'lib/whoosh/dependency_injection.rb', line 38 def inject_for(names, request: nil) names.each_with_object({}) do |name, hash| hash[name] = resolve(name, request: request) end end |
#provide(name, scope: :singleton, &block) ⇒ Object
11 12 13 14 |
# File 'lib/whoosh/dependency_injection.rb', line 11 def provide(name, scope: :singleton, &block) @providers[name] = { block: block, scope: scope } @singletons.delete(name) # Clear cached value on re-register end |
#registered?(name) ⇒ Boolean
67 68 69 |
# File 'lib/whoosh/dependency_injection.rb', line 67 def registered?(name) @providers.key?(name) end |
#resolve(name, request: nil, resolving: []) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/whoosh/dependency_injection.rb', line 16 def resolve(name, request: nil, resolving: []) provider = @providers[name] raise Errors::DependencyError, "Unknown dependency: #{name}" unless provider if resolving.include?(name) raise Errors::DependencyError, "Circular dependency detected: #{(resolving + [name]).join(' -> ')}" end case provider[:scope] when :singleton # Check cache without lock first (double-checked locking pattern) return @singletons[name] if @singletons.key?(name) # Compute outside the lock to allow recursive singleton resolution value = call_provider(provider[:block], request: request, resolving: resolving + [name]) @mutex.synchronize { @singletons[name] ||= value } @singletons[name] when :request call_provider(provider[:block], request: request, resolving: resolving + [name]) end end |
#validate! ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/whoosh/dependency_injection.rb', line 44 def validate! # Topological sort to detect circular deps and unknown refs at boot visited = {} sorted = [] visit = ->(name, path) do return if visited[name] == :done raise Errors::DependencyError, "Circular dependency detected: #{(path + [name]).join(' -> ')}" if visited[name] == :visiting provider = @providers[name] raise Errors::DependencyError, "Unknown dependency: #{name} (referenced by #{path.last})" unless provider visited[name] = :visiting deps = extract_deps(provider[:block]) deps.each { |dep| visit.call(dep, path + [name]) } visited[name] = :done sorted << name end @providers.each_key { |name| visit.call(name, []) unless visited[name] } sorted end |