Class: Syskit::DependencyInjectionContext
- Defined in:
- lib/syskit/dependency_injection_context.rb
Overview
Representation of a selection context, as a stack of DependencyInjection objects
This represents a prioritized set of selections (as DependencyInjection objects). It is mainly used during instanciation to find what should be instanciated.
In the stack, the latest selection added with #push takes priority over everything that has been added before it. During resolution, if nothing is found at a certain level, then the previous levels will be queried.
Use #selection_for and #candidates_for to query the selection. Use #save, #restore and #push to manage the stack
Defined Under Namespace
Classes: StackLevel
Instance Attribute Summary collapse
-
#savepoints ⇒ Object
readonly
The list of savepoints.
-
#stack ⇒ Object
readonly
The stack of StackLevel objects added with #push.
-
#state ⇒ Object
readonly
The resolved selections.
Instance Method Summary collapse
-
#concat(context) ⇒ Object
Push all DI information in the given context at the top of the stack of this context.
-
#current_state ⇒ Object
Returns the resolved state of the selection stack, as a DependencyInjection object.
- #empty? ⇒ Boolean
-
#has_selection_for?(name) ⇒ Boolean
True if there is an explicit selection for the given name.
-
#initialize(base = nil) ⇒ DependencyInjectionContext
constructor
Creates a new dependency injection context.
- #initialize_copy(obj) ⇒ Object
-
#instance_selection_for(name, requirements) ⇒ Object
Returns a non-ambiguous selection for the given criteria.
-
#pop ⇒ StackLevel?
Removes the last dependency injection context stored on the stack, and returns it.
- #pretty_print(pp) ⇒ Object
-
#push(spec) ⇒ Object
Adds a new dependency injection context on the stack.
- #push_mask(mask) ⇒ Object
-
#restore ⇒ Object
The opposite of #save.
-
#save ⇒ void
Pushes the current state of the context on the save stack.
-
#selection_for(name, requirements) ⇒ Object
Returns all the candidates that match
criteria
in the current state of this context. -
#top ⇒ StackLevel
Returns the StackLevel object representing the last added level on the stack.
Constructor Details
#initialize(base = nil) ⇒ DependencyInjectionContext
Creates a new dependency injection context
base
is the root selection context (can be nil). It can either
be a hash or a DependencyInjection object. In the first case, it is
interpreted as a selection hash usable in DependencyInjection#use, and is
converted to the corresponding DependencyInjection object this way.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/syskit/dependency_injection_context.rb', line 38 def initialize(base = nil) @stack = [] @state = [] @savepoints = [] # Add a guard on the stack, so that #push does not have to care stack << StackLevel.new(DependencyInjection.new, DependencyInjection.new) case base when Hash deps = DependencyInjection.new(base) push(deps) when DependencyInjection push(base) when NilClass else raise ArgumentError, "expected either a selection hash or a DependencyInjection object as base selection, got #{base}" end end |
Instance Attribute Details
#savepoints ⇒ Object (readonly)
The list of savepoints
They are stored as sizes of stack
. I.e. #restore simply
resizes stack
and state
to the size stored in
save.last
29 30 31 |
# File 'lib/syskit/dependency_injection_context.rb', line 29 def savepoints @savepoints end |
#stack ⇒ Object (readonly)
The stack of StackLevel objects added with #push
20 21 22 |
# File 'lib/syskit/dependency_injection_context.rb', line 20 def stack @stack end |
#state ⇒ Object (readonly)
The resolved selections. When a query is made at a certain level of the stack, it gets resolved into one single explicit selection hash, to optimize repeated queries.
24 25 26 |
# File 'lib/syskit/dependency_injection_context.rb', line 24 def state @state end |
Instance Method Details
#concat(context) ⇒ Object
Push all DI information in the given context at the top of the stack of this context
70 71 72 73 74 |
# File 'lib/syskit/dependency_injection_context.rb', line 70 def concat(context) context.stack.each do |di| push(di.added_info.dup) end end |
#current_state ⇒ Object
Returns the resolved state of the selection stack, as a DependencyInjection object.
Calling #candidates_for and #selection_for on the resolved object is equivalent to resolving the complete stack
115 116 117 |
# File 'lib/syskit/dependency_injection_context.rb', line 115 def current_state stack.last.resolver end |
#empty? ⇒ Boolean
172 173 174 |
# File 'lib/syskit/dependency_injection_context.rb', line 172 def empty? stack.size == 1 end |
#has_selection_for?(name) ⇒ Boolean
True if there is an explicit selection for the given name
143 144 145 |
# File 'lib/syskit/dependency_injection_context.rb', line 143 def has_selection_for?(name) current_state.has_selection_for?(name) end |
#initialize_copy(obj) ⇒ Object
58 59 60 61 62 |
# File 'lib/syskit/dependency_injection_context.rb', line 58 def initialize_copy(obj) @stack = obj.stack.dup @state = obj.state.dup @savepoints = obj.savepoints.dup end |
#instance_selection_for(name, requirements) ⇒ Object
Returns a non-ambiguous selection for the given criteria
Returns nil if no selection is defined, or if there is an ambiguity (i.e. multiple candidates exist)
See DependencyInjection#candidates_for for the format of
criteria
See also #candidates_for
156 157 158 |
# File 'lib/syskit/dependency_injection_context.rb', line 156 def instance_selection_for(name, requirements) current_state.instance_selection_for(name, requirements) end |
#pop ⇒ StackLevel?
Removes the last dependency injection context stored on the stack, and returns it.
Will stop at the last saved context (saved with #save). Returns nil in this case
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/syskit/dependency_injection_context.rb', line 215 def pop if stack.size == 1 return StackLevel.new(DependencyInjection.new, DependencyInjection.new) end expected_size = @savepoints.last if expected_size && expected_size == stack.size return end result = stack.pop if state.size > stack.size @state = state[0, stack.size] end result end |
#pretty_print(pp) ⇒ Object
64 65 66 |
# File 'lib/syskit/dependency_injection_context.rb', line 64 def pretty_print(pp) current_state.pretty_print(pp) end |
#push(spec) ⇒ Object
Adds a new dependency injection context on the stack
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/syskit/dependency_injection_context.rb', line 177 def push(spec) if spec.empty? stack << StackLevel.new(stack.last.resolver, DependencyInjection.new) return end spec = DependencyInjection.new(spec) new_state = stack.last.resolver.dup # Resolve all names unresolved = spec.resolve_names(new_state.explicit) if !unresolved.empty? raise NameResolutionError.new(unresolved), "could not resolve names while pushing #{spec} on #{self}" end # Resolve recursive selection, and default selections spec.resolve_default_selections # Finally, add it to the new state new_state.add(spec) new_state.resolve! # ... and to the stack stack << StackLevel.new(new_state, spec) end |
#push_mask(mask) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/syskit/dependency_injection_context.rb', line 160 def push_mask(mask) if mask.empty? stack << StackLevel.new(stack.last.resolver, DependencyInjection.new) return end spec = DependencyInjection.new spec.add_mask(mask) new_state = stack.last.resolver.dup new_state.add_mask(mask) stack << StackLevel.new(new_state, spec) end |
#restore ⇒ Object
The opposite of #save
Save and restore calls are paired. See #save for more information.
122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/syskit/dependency_injection_context.rb', line 122 def restore expected_size = @savepoints.pop if !expected_size raise ArgumentError, "save/restore stack is empty" end @stack = stack[0, expected_size] if state.size > expected_size @state = state[0, expected_size] end end |
#save ⇒ void #save ⇒ void
This method returns an undefined value.
Pushes the current state of the context on the save stack. #restore will go back to this exact state, regardless of the number of #push calls, and #pop will stop at the last savepoint
The save/restore mechanism is stack-based, so when doing
save
save
restore
restore
The first restore returns to the state in the second save and the second restore returns to the state in thef first save.
97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/syskit/dependency_injection_context.rb', line 97 def save if !block_given? @savepoints << stack.size else save begin yield ensure restore end end end |
#selection_for(name, requirements) ⇒ Object
Returns all the candidates that match criteria
in the current
state of this context
(see DependencyInjection#selection_for)
138 139 140 |
# File 'lib/syskit/dependency_injection_context.rb', line 138 def selection_for(name, requirements) current_state.selection_for(name, requirements) end |
#top ⇒ StackLevel
Returns the StackLevel object representing the last added level on the stack
204 205 206 |
# File 'lib/syskit/dependency_injection_context.rb', line 204 def top stack.last end |