Module: Diana
- Extended by:
- Config
- Defined in:
- lib/diana.rb,
lib/diana/config.rb,
lib/diana/version.rb
Overview
Dependency Injection DSL
This module offers a DSL designed for the lazy resolution of dependency injections. It facilitates efficient and deferred initialization of dependencies ensuring that resources are only allocated when necessary.
This approach optimizes performance of application.
Defined Under Namespace
Modules: Config
Constant Summary collapse
- VERSION =
Returns the version of the Diana gem.
File.read(File.join(File.dirname(__FILE__), "../../VERSION")).strip
Class Method Summary collapse
-
.dependencies(deps) ⇒ Module
(also: dependency)
Define dependencies for a class.
Methods included from Config
methods_visibility, methods_visibility=, resolve, resolver, resolver=
Class Method Details
.dependencies(deps) ⇒ Module Also known as: dependency
Define dependencies for a class.
param deps [Hash] A hash where keys are the names of the dependencies and
values are the dependencies themselves, resolved lazily.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/diana.rb', line 44 def dependencies(deps) Module.new do # Adds readable name to this anonymous module when showing `MyClass.ancestors` def self.inspect "<Diana.dependencies:#{object_id.to_s(16)}>" end class_mod = Module.new do # Adds readable name to this anonymous module when showing `MyClass.singleton_class.ancestors` def self.inspect "<Diana.inheritance:#{object_id.to_s(16)}>" end private def inherited(subclass) # When `inherited` is called for the first time, we add the parent's # `@_diana_dependencies`. To avoid adding dependencies from # ancestors in the `super` call, we check if `@_diana_dependencies` # is already defined. unless subclass.instance_variable_defined?(:@_diana_dependencies) subclass.include Diana.dependencies(@_diana_dependencies) end super end end define_singleton_method(:included) do |base| # Adds .inherited method base.extend(class_mod) # # Merging dependencies allows to add dependencies multiple times # # Example: # class MyClass # include Diana.dependencies(foo: 'foo') # include Diana.dependencies(bar: 'bar') # end # merged_deps = if base.instance_variable_defined?(:@_diana_dependencies) base.instance_variable_get(:@_diana_dependencies).merge!(deps) else base.instance_variable_set(:@_diana_dependencies, deps.dup) end # Add initialize method # Instance variables are set only for not-null dependencies. # Using class_eval is slower to define the method, yet it provides the # benefit of executing faster than if it were defined using define_method. class_eval(" def initialize(\#{merged_deps.each_key.map { |dependency| \"\#{dependency}: nil\" }.join(\", \")})\n \#{merged_deps.each_key.map { |dependency| \" @\#{dependency} = \#{dependency} if \#{dependency}\" }.join(\"\\n\")}\n end\n INITIALIZE\n end\n\n # Add dependencies attribute readers and set their visibility.\n # Using class_eval is slower to define the method, yet it provides the\n # benefit of executing faster than if it were defined using define_method.\n deps.each_key do |dependency|\n class_eval(<<~ATTR_READER, __FILE__, __LINE__ + 1)\n def \#{dependency}\n @\#{dependency} ||= Diana.resolve(self.class.instance_variable_get(:@_diana_dependencies)[:\#{dependency}])\n end\n\n \#{Diana.methods_visibility} :\#{dependency}\n ATTR_READER\n end\n end\nend\n", __FILE__, __LINE__ + 1) |