Module: Tina4::Container
- Defined in:
- lib/tina4/container.rb
Overview
Lightweight dependency injection container.
Tina4::Container.register(:mailer) { MailService.new } # transient — new instance each resolve
Tina4::Container.singleton(:db) { Database.new(ENV["DB_URL"]) } # singleton — memoised
Tina4::Container.register(:cache, RedisCacheInstance) # concrete instance (always same)
Tina4::Container.resolve(:db) # => Database instance
Class Method Summary collapse
-
.clear! ⇒ Object
Remove all registrations (useful in tests).
-
.register(name, instance = nil, &factory) ⇒ Object
Register a service by name.
-
.registered?(name) ⇒ Boolean
Check if a service is registered.
- .registry ⇒ Object
-
.resolve(name) ⇒ Object
Resolve a service by name.
-
.singleton(name, &factory) ⇒ Object
Register a singleton factory by name.
Class Method Details
.clear! ⇒ Object
Remove all registrations (useful in tests).
69 70 71 |
# File 'lib/tina4/container.rb', line 69 def clear! @registry = {} end |
.register(name, instance = nil, &factory) ⇒ Object
Register a service by name. Pass a concrete instance directly, or a block for transient instantiation. Blocks are called on every resolve() — use singleton() for memoised factories.
20 21 22 23 24 25 26 27 28 29 |
# File 'lib/tina4/container.rb', line 20 def register(name, instance = nil, &factory) raise ArgumentError, "provide an instance or a block, not both" if instance && factory raise ArgumentError, "provide an instance or a block" unless instance || factory registry[name.to_sym] = if factory { factory: factory, singleton: false, instance: nil } else { factory: nil, singleton: false, instance: instance } end end |
.registered?(name) ⇒ Boolean
Check if a service is registered.
64 65 66 |
# File 'lib/tina4/container.rb', line 64 def registered?(name) registry.key?(name.to_sym) end |
.registry ⇒ Object
13 14 15 |
# File 'lib/tina4/container.rb', line 13 def registry @registry ||= {} end |
.resolve(name) ⇒ Object
Resolve a service by name. Singletons and concrete instances return the same object each time. Transient factories (register with block) return a new object each time.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/tina4/container.rb', line 42 def resolve(name) entry = registry[name.to_sym] raise KeyError, "service not registered: #{name}" unless entry # Concrete instance (register with value) return entry[:instance] if entry[:instance] && entry[:factory].nil? if entry[:factory] if entry[:singleton] # Singleton — call once, memoize entry[:instance] ||= entry[:factory].call entry[:instance] else # Transient — call every time entry[:factory].call end else entry[:instance] end end |
.singleton(name, &factory) ⇒ Object
Register a singleton factory by name. The block is called once on first resolve() and the result is memoised.
33 34 35 36 37 |
# File 'lib/tina4/container.rb', line 33 def singleton(name, &factory) raise ArgumentError, "singleton requires a block" unless factory registry[name.to_sym] = { factory: factory, singleton: true, instance: nil } end |