wirer 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,234 @@
1
+ # dependency :foo, Class, :features => [:feature, :feature], :optional => true
2
+ # dependency :foo, Class, :features => [:feature, :feature], :multiple => true
3
+ #
4
+ # dependency :foo, Class, :optional => true
5
+ # dependency :foo, :feature, :another_feature, :optional => true, :constructor => true
6
+
7
+ module Wirer
8
+
9
+ class Dependency
10
+ def self.new_from_args(*args)
11
+ new(normalise_args(*args))
12
+ end
13
+
14
+ def self.new_from_arg_or_args_list(arg_or_args_list)
15
+ new(normalise_arg_or_args_list(arg_or_args_list))
16
+ end
17
+
18
+ def self.normalise_arg_or_args_list(arg_or_args_list)
19
+ case arg_or_args_list
20
+ when Hash then arg_or_args_list
21
+ when Array then normalise_args(*arg_or_args_list)
22
+ else normalise_args(arg_or_args_list)
23
+ end
24
+ end
25
+
26
+ def self.normalise_args(*args)
27
+ options = args.last.is_a?(Hash) ? args.pop : {}
28
+ args.each do |requirement|
29
+ case requirement
30
+ when Module then options[:class] = requirement
31
+ else (options[:features] ||= []) << requirement
32
+ end
33
+ end
34
+ options
35
+ end
36
+
37
+ OPTION_NAMES = [:class, :module, :features, :prefer, :multiple, :optional, :factory]
38
+
39
+ # By default, dependencies will :prefer => :default.
40
+ # This means if you want to force one factory to be preferred over another
41
+ # in a given situation, you can just add (or wrap it with) a provided feature
42
+ # name of :default.
43
+ PREFER_DEFAULT = :default
44
+
45
+ def initialize(options = {})
46
+ required_class = options[:class] || options[:module]
47
+ case required_class
48
+ when Module
49
+ @required_class = required_class
50
+ when String
51
+ @required_class_name = required_class
52
+ when NilClass
53
+ @required_class = nil
54
+ else
55
+ raise ArgumentError, "required :class for a Dependency must be a Module or Class, or a String name of a Module or Class"
56
+ end
57
+ @required_features = options[:features] && [*options[:features]]
58
+ @multiple = options[:multiple] || false
59
+ @optional = options[:optional] || false
60
+ @factory = options[:factory] || false
61
+
62
+ if @multiple
63
+ raise ArgumentError, "preferred features don't make sense for a :multiple depedency" if options.has_key?(:prefer)
64
+ else
65
+ @preferred_features = [*options.fetch(:prefer, PREFER_DEFAULT) || []]
66
+ end
67
+ end
68
+
69
+ attr_reader :required_features, :preferred_features
70
+ def multiple?; @multiple; end
71
+ def optional?; @optional; end
72
+
73
+ # Specifying :factory => true on a dependency means that you won't be given an actual instance
74
+ # of the class you asked for, but rather you'll be given a simple factory wrapper which allows
75
+ # you to construct your own instance(s), with any dependencies pre-supplied.
76
+ # See Factory::CurriedDependencies
77
+ def factory?; @factory; end
78
+
79
+ # A string class name may be supplied as the :class arg to the constructor, in which case we only
80
+ # attempt to resolve the actual class from it the first time .required_class is requested.
81
+ #
82
+ # This helps avoid introducing undesired load order dependencies between classes using Wirer::Factory::ClassDSL.
83
+ def required_class
84
+ return @required_class if defined?(@required_class)
85
+ @required_class = @required_class_name.split("::").inject(Object, :const_get)
86
+ end
87
+
88
+ def requirements_to_s
89
+ [
90
+ begin
91
+ case required_class
92
+ when ::Class then "class #{@required_class}"
93
+ when ::Module then "module #{@required_class}"
94
+ end
95
+ rescue NameError
96
+ "class or module name #{@required_class_name} (not currently loaded!)"
97
+ end,
98
+ @required_features && "features #{@required_features.inspect}"
99
+ ].compact.join(" and ")
100
+ end
101
+
102
+ def inspect
103
+ description = [
104
+ @factory ? "factory for #{requirements_to_s}" : requirements_to_s,
105
+ ("optional" if @optional),
106
+ ("multiple" if @multiple),
107
+ ("preferring features #{@preferred_features.inspect}" if @preferred_features && !@preferred_features.empty?)
108
+ ].compact.join(', ')
109
+ "#<#{self.class} on #{description}>"
110
+ end
111
+
112
+ def match_factories(available_factories)
113
+ candidates = available_factories.select {|f| self === f}
114
+ if !@optional && candidates.length == 0
115
+ raise DependencyFindingError, "No available factories matching #{requirements_to_s}"
116
+ end
117
+ if @multiple
118
+ candidates.map! {|c| yield c} if block_given?; candidates
119
+ else
120
+ candidate = if candidates.length > 1
121
+ if @preferred_features.empty?
122
+ raise DependencyFindingError, "More than one factory available matching #{requirements_to_s}"
123
+ else
124
+ unique_preferred_factory(candidates)
125
+ end
126
+ else
127
+ candidates.first
128
+ end
129
+ if block_given?
130
+ yield candidate if candidate
131
+ else
132
+ candidate
133
+ end
134
+ end
135
+ end
136
+
137
+ def ===(factory)
138
+ factory.is_a?(Factory::Interface) && matches_required_class(factory) && matches_required_features(factory)
139
+ end
140
+
141
+ def check_argument(argument_name, argument, strict_type_checks=false)
142
+ if @multiple
143
+ raise ArgumentError, "expected Array for argument #{argument_name}" unless argument.is_a?(Array)
144
+ if argument.empty?
145
+ if @optional then return else
146
+ raise ArgumentError, "expected at least one value for argument #{argument_name}"
147
+ end
148
+ end
149
+ argument.each do |value|
150
+ if @factory
151
+ unless value.respond_to?(:new)
152
+ raise ArgumentError, "expected Array of factory-like objects which respond_to?(:new) for argument #{argument_name}"
153
+ end
154
+ elsif strict_type_checks && required_class && !value.is_a?(required_class)
155
+ raise ArgumentError, "expected Array of #{required_class} for argument #{argument_name}"
156
+ end
157
+ end
158
+ else
159
+ if argument.nil?
160
+ if @optional then return else
161
+ raise ArgumentError, "expected argument #{argument_name}"
162
+ end
163
+ end
164
+ if @factory
165
+ unless argument.respond_to?(:new)
166
+ raise ArgumentError, "expected factory-like object which respond_to?(:new) for argument #{argument_name}"
167
+ end
168
+ elsif strict_type_checks && required_class && !argument.is_a?(required_class)
169
+ raise ArgumentError, "expected #{required_class} for argument #{argument_name}"
170
+ end
171
+ end
172
+ end
173
+
174
+ # if the required_class can't be resolved (ie a class of that name doesn't even exist) then nothing will match.
175
+ def matches_required_class(factory)
176
+ begin
177
+ !required_class || factory.provides_class <= required_class
178
+ rescue NameError
179
+ false
180
+ end
181
+ end
182
+
183
+ def matches_required_features(factory)
184
+ !@required_features || @required_features.all? {|feature| factory.provides_features.include?(feature)}
185
+ end
186
+
187
+ def with_options(options)
188
+ new_options = {
189
+ :multiple => @multiple,
190
+ :optional => @optional,
191
+ :class => required_class,
192
+ :features => @required_features,
193
+ :prefer => @preferred_features
194
+ }
195
+ new_required_class = options[:class] and begin
196
+ if required_class && !(new_required_class <= required_class)
197
+ raise "Required class #{new_required_class} not compatible with existing requirement for #{required_class}"
198
+ end
199
+ new_options[:class] = new_required_class
200
+ end
201
+ new_required_features = options[:features] and begin
202
+ new_options[:features] ||= []
203
+ new_options[:features] |= [*new_required_features]
204
+ end
205
+ new_preferred_features = options[:prefer] and begin
206
+ new_options[:prefer] ||= []
207
+ new_options[:prefer] |= [*new_preferred_features]
208
+ end
209
+ self.class.new(new_options)
210
+ end
211
+
212
+ private
213
+
214
+ def unique_preferred_factory(candidates)
215
+ max_preferred_features_count = 0
216
+ winners = []
217
+ candidates.each do |candidate|
218
+ provided = candidate.provides_features
219
+ count = @preferred_features.count {|f| provided.include?(f)}
220
+ if count > max_preferred_features_count
221
+ max_preferred_features_count = count
222
+ winners = [candidate]
223
+ elsif count == max_preferred_features_count
224
+ winners << candidate
225
+ end
226
+ end
227
+ if winners.length > 1
228
+ raise DependencyFindingError,
229
+ "More than one factory available matching #{requirements_to_s}, and tie can't be resolved using preferred_features #{@preferred_features.inspect}"
230
+ end
231
+ winners.first
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,30 @@
1
+ module Wirer
2
+
3
+ # Thank you to http://rubyforge.org/projects/nestegg for the pattern
4
+ class Error < StandardError
5
+
6
+ attr_reader :cause
7
+ alias :wrapped_error :cause
8
+
9
+ def initialize(msg, cause=nil)
10
+ @cause = cause
11
+ super(msg)
12
+ end
13
+
14
+ def set_backtrace(bt)
15
+ if cause
16
+ bt << "cause: #{cause.class.name}: #{cause}"
17
+ bt.concat cause.backtrace
18
+ end
19
+ super(bt)
20
+ end
21
+
22
+ end
23
+
24
+ class DependencyFindingError < Error; end
25
+ class CyclicDependencyError < Error; end
26
+
27
+ # raised when a dependency could be found, but failed to be constructed.
28
+ class DependencyConstructionError < Error; end
29
+
30
+ end
@@ -0,0 +1,117 @@
1
+ module Wirer
2
+ # You can extend a Class instance directly with this if you want
3
+ # the class itself to be usable as a factory, exposing
4
+ # Wirer::Factory::Interface.
5
+ #
6
+ # By default, new_from_dependencies will call new on the class
7
+ # with the hash of dependencies as the last argument (or merged
8
+ # into the last argument where this is already a Hash). If you
9
+ # don't like this you may want to override the new_from_dependencies
10
+ # class method.
11
+ #
12
+ # You'll still probably want to override some of
13
+ # constructor_dependencies, provides_features, setter_dependencies;
14
+ # if you'd prefer to do this via a handy DSL, instead see
15
+ # See Wirer::Factory::ClassDSL.
16
+ module Factory::ClassMixin
17
+ include Factory::Interface
18
+
19
+ def provides_class; self; end
20
+
21
+ def new_from_dependencies(dependencies, *other_args, &block_arg)
22
+ if other_args.last.is_a?(Hash)
23
+ hash_arg = other_args.pop
24
+ other_args.push(hash_arg.merge(dependencies))
25
+ else
26
+ other_args.push(dependencies) unless dependencies.empty?
27
+ end
28
+ new(*other_args, &block_arg)
29
+ end
30
+ end
31
+
32
+ # A more convenient form of Wirer::Factory::ClassMixin, this additionally adds some
33
+ # private DSL methods which let you declare your constructor_dependencies,
34
+ # setter_dependencies and provides_features.
35
+ #
36
+ # The DSL works nicely with respect to subclassing, so you can add extra dependencies
37
+ # or features in a subclass.
38
+ module Factory::ClassDSL
39
+ include Factory::ClassMixin
40
+
41
+ def constructor_dependencies
42
+ @constructor_dependencies ||= (superclass.is_a?(Factory::Interface) ? superclass.constructor_dependencies.dup : {})
43
+ end
44
+
45
+ # the supplied implementation of setter_dependencies does not allow for them varying dependening on the
46
+ # instance passed; if you want to specify setter_dependencies on an instance-sensitive basis you'll need
47
+ # to override this yourself.
48
+ def setter_dependencies(instance=nil)
49
+ @setter_dependencies ||= (superclass.is_a?(Factory::Interface) ? superclass.setter_dependencies.dup : {})
50
+ end
51
+
52
+ def provides_features
53
+ @provides_features ||= (superclass.is_a?(Factory::Interface) ? superclass.provides_features.dup : [])
54
+ end
55
+
56
+ private
57
+
58
+ def provides_feature(*args)
59
+ provides_features.concat(args)
60
+ end
61
+
62
+ def add_dependency(type, arg_name, *dependency_args)
63
+ deps_hash = type == :setter ? setter_dependencies : constructor_dependencies
64
+ deps_hash[arg_name] = Dependency.new_from_args(*dependency_args)
65
+ end
66
+
67
+ # as a convenience, will additionally define an attr_reader for this dependency name
68
+ # unless you specify :getter => false. by default it will be private, but :getter => :public
69
+ # will make it public.
70
+ def constructor_dependency(name, *args)
71
+ getter = if args.last.is_a?(Hash) then args.last.delete(:getter) end
72
+ if getter != false
73
+ attr_reader(name)
74
+ getter == :public ? public(name) : private(name)
75
+ end
76
+ add_dependency(:constructor, name, *args)
77
+ end
78
+ alias :dependency :constructor_dependency
79
+
80
+ # sugar for dependency :foo, ..., :factory => true.
81
+ #
82
+ # for factory dependencies, you'll be given a factory instance responding to 'new'
83
+ # from which you can construct your own instances of the dependency -- as opposed
84
+ # to normal dependencies where the container will give you a pre-constructed instance.
85
+ def factory_dependency(name, *args)
86
+ args.push({}) unless args.last.is_a?(Hash)
87
+ args.last[:factory] = true
88
+ constructor_dependency(name, *args)
89
+ end
90
+
91
+ # will additionally define a attr_writer method of this name, unless :setter => false
92
+ # is specified. this is private by default but made public if you specify :setter => :public.
93
+ #
94
+ # and a corresponding public attr_reader too if :accessor => true if specified.
95
+ def setter_dependency(name, *args)
96
+ options = args.last.is_a?(Hash) ? args.last : {}
97
+ getter = options.delete(:getter)
98
+ setter = options.delete(:setter)
99
+ if setter != false
100
+ attr_writer(name)
101
+ setter == :public ? public(:"#{name}=") : private(:"#{name}=")
102
+ end
103
+ if getter != false
104
+ attr_reader(name)
105
+ getter == :public ? public(name) : private(name)
106
+ end
107
+
108
+ add_dependency(:setter, name, *args)
109
+ end
110
+ end
111
+ end
112
+
113
+ class Class
114
+ def wireable
115
+ extend Wirer::Factory::ClassDSL
116
+ end
117
+ end
@@ -0,0 +1,33 @@
1
+ module Wirer
2
+ # This doesn't implement the full Factory::Interface, rather it's a simple
3
+ # 'curried' wrapper around the new_from_dependencies method of a factory,
4
+ # where the dependency arguments are pre-supplied.
5
+ #
6
+ # You can use one of these pretty much the same as a class, in that it has a
7
+ # 'new' method, or it also implements a Proc-like interface ('call' and 'to_proc')
8
+ # so you can also treat it like a block which constructs things.
9
+ #
10
+ # Factory::Interface#curry_with_dependencies is used to make these, but you'd
11
+ # normally get one via a Wirer::Containerm by specifying a dependency with :factory => true;
12
+ # the container will then give you a curried factory from which you can construct
13
+ # your own instances, rather than supplying a single pre-constructed instance.
14
+ #
15
+ # Note: at present only constructor dependencies can be curried in this way.
16
+ class Factory::CurriedDependencies
17
+ def initialize(factory, dependencies)
18
+ @factory = factory
19
+ @dependencies = dependencies
20
+ end
21
+
22
+ def new(*args, &block_arg)
23
+ @factory.new_from_dependencies(@dependencies, *args, &block_arg)
24
+ end
25
+
26
+ alias :call :new
27
+
28
+ # this allows it to be implicitly converted into a block argument, eg: instances = args.map(&factory)
29
+ def to_proc
30
+ method(:new).to_proc
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,100 @@
1
+ module Wirer
2
+ # This is handy if you want to create a factory instance entirely from
3
+ # supplied arguments, in particular from a supplied constructor block.
4
+ #
5
+ # This saves you having to create your own Factory class in almost all
6
+ # cases.
7
+ #
8
+ # If you specify a :class, a default implementation will be supplied
9
+ # for constructing instances from it, whereby dependencies are passed
10
+ # as the last argument to the class's new method, after any other args.
11
+ # (if the last arg is already a Hash, the dependencies will be merged
12
+ # into it).
13
+ #
14
+ # Is also aliased for convenience from Factory.new.
15
+ #
16
+ # Factory.new(
17
+ # :class => Foo,
18
+ # :dependencies => {
19
+ # :logger => Logger,
20
+ # :bars => {:class => Bar, :multiple => true}
21
+ # }
22
+ # ) do |depedencies, *args, &block|
23
+ # Foo.new(*args, dependencies, &block)
24
+ # end
25
+ class Factory::FromArgs
26
+ include Factory::Interface
27
+
28
+ OPTION_NAMES = [:class, :module, :args, :features, :dependencies, :constructor_dependencies, :setter_dependencies].freeze
29
+
30
+ def initialize(options={}, &constructor_block)
31
+ @provides_class = options[:class] || options[:module]
32
+
33
+ @constructor_dependencies = {}
34
+ (options[:constructor_dependencies] || options[:dependencies] || {}).each do |name, args|
35
+ @constructor_dependencies[name] = Dependency.new_from_arg_or_args_list(args)
36
+ end
37
+ @setter_dependencies = {}
38
+ (options[:setter_dependencies] || {}).each do |name, args|
39
+ @setter_dependencies[name] = Dependency.new_from_arg_or_args_list(args)
40
+ end
41
+
42
+ @provides_features = options[:features] || []
43
+ @constructor_block = constructor_block if constructor_block
44
+
45
+ case @provides_class
46
+ when ::Class
47
+ @initial_args = options[:args] if options[:args]
48
+ when Module
49
+ unless @constructor_block
50
+ raise ArgumentError, "when a Module is specified you need to supply a constructor block"
51
+ end
52
+ when NilClass
53
+ @provides_class = Object
54
+ unless @constructor_block
55
+ raise ArgumentError, "expected a :class or a constructor block or both"
56
+ end
57
+ else
58
+ raise TypeError, ":class / :module options only accept a Class or Module"
59
+ end
60
+ end
61
+
62
+ attr_reader :constructor_dependencies, :provides_class,
63
+ :provides_features, :initial_args, :wrapped_class
64
+
65
+ # Factory::FromArgs doesn't allow you to do instance-sensitive setter-dependencies;
66
+ # subclass or make your own factory if you want these.
67
+ def setter_dependencies(instance=nil); @setter_dependencies; end
68
+
69
+ def new_from_dependencies(dependencies, *other_args, &block_arg)
70
+ if @constructor_block
71
+ @constructor_block.call(dependencies, *other_args, &block_arg)
72
+ else
73
+ # The only time it allows you not to specify a constructor_block
74
+ # is when an actual Class is supplied for provides_class.
75
+ #
76
+ # In this case we supply a default construction method whereby
77
+ # dependencies are merged into a last argument:
78
+ if other_args.last.is_a?(Hash)
79
+ hash_arg = other_args.pop
80
+ other_args.push(hash_arg.merge(dependencies))
81
+ else
82
+ other_args.push(dependencies) unless dependencies.empty?
83
+ end
84
+ case @initial_args
85
+ when NilClass # forgeddit
86
+ when Array then other_args.unshift(*@initial_args)
87
+ else other_args.unshift(@initial_args)
88
+ end
89
+ @provides_class.new(*other_args, &block_arg)
90
+ end
91
+ end
92
+ end
93
+
94
+ module Factory
95
+ # delegates to Factory::FromArgs.new
96
+ def self.new(options, &constructor_block)
97
+ FromArgs.new(options, &constructor_block)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,24 @@
1
+ module Wirer
2
+ # For when you have some pre-existing instance which you want to wrap as a singleton
3
+ # Factory.
4
+ # (You wouldn't normally need to do this yourself, but rather Container uses it
5
+ # under the hood if you add an existing instance to the container)
6
+ class Factory::FromInstance
7
+ include Factory::Interface
8
+
9
+ attr_reader :instance, :provides_features
10
+
11
+ def initialize(instance, *features)
12
+ @instance = instance
13
+ @provides_features = features
14
+ end
15
+
16
+ def provides_class
17
+ @instance.class
18
+ end
19
+
20
+ def new_from_dependencies(deps=nil)
21
+ @instance
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,114 @@
1
+ module Wirer
2
+ module Factory; end
3
+
4
+ # This is the basic Factory interface around which the whole framework is built.
5
+ #
6
+ # You won't normally need to implement this interface yourself, but it's useful
7
+ # in terms of understanding how Wirer works.
8
+ #
9
+ # A Factory is responsible for creating some kind of object, given some dependencies
10
+ # and possibly some additional arguments. so new_from_dependencies is the main
11
+ # method here.
12
+ #
13
+ # It also comes with an interface (constructor_dependencies) telling you what
14
+ # the required dependencies are; this is specified via a hash of symbol argument
15
+ # names to Dependency objects which specify the criterea that must be satisfied
16
+ # for the dependency argument of that name.
17
+ #
18
+ # Wirer::Container uses this metadata to find and pass in dependencies automatically
19
+ # when constructing things from Factories.
20
+ #
21
+ # == Two-phase initialisation
22
+ #
23
+ # Factory can also support cases where some dependencies need to be passed in
24
+ # after creation time, eg when you have cyclic dependencies.
25
+ #
26
+ # This is done via specifying setter_dependencies in the same way as
27
+ # constructor_dependencies; the expectation is that after constructing an instance
28
+ # with new_from_dependencies, you must additionally fetch any setter_dependencies
29
+ # and 'inject' them into the instance via calling inject_dependency on the factory
30
+ # with the instance, dependency name and the value for that dependency.
31
+ #
32
+ # (the default implementation of inject_dependency will just call a setter method
33
+ # on the instance, eg instance.logger = logger; this will work with a private setter
34
+ # if you prefer to make private these things which are only a part of initialization)
35
+ #
36
+ # After a whole set of objects have been created and their setter_dependencies injected, it
37
+ # can be handy for them to get a notification along the lines of "hey so your whole dependency
38
+ # graph is now all wired up any ready". Factory#post_initialize should send this notification
39
+ # to an object created from the factory, where it's supported by the objects you construct.
40
+ #
41
+ # (by default it will call a :post_initialize method on the instance, if this is present;
42
+ # again this can be a private method if you wish).
43
+ module Factory::Interface
44
+ # A Module or Class which all objects constructed by this factory are kind_of?.
45
+ # The more specific you are, the more use this will be when specifying requirements
46
+ # based on a Module or Class.
47
+ def provides_class
48
+ Object # not very informative by default :)
49
+ end
50
+
51
+ # List of arbitrary objects representing features provided by this factory,
52
+ # which may be compared against required features when looking for dependencies.
53
+ # Typically symbols are used.
54
+ def provides_features
55
+ []
56
+ end
57
+
58
+ # Hash of symbol argument names to Wirer::Dependency objects, representing
59
+ # dependencies that need to be passed as arguments to new_from_dependencies
60
+ def constructor_dependencies
61
+ {}
62
+ end
63
+
64
+ # Hash of symbol argument names to Wirer::Dependency objects, representing
65
+ # dependencies which need to be injected into instances *after* they have
66
+ # been constructed via new_from_dependencies
67
+ #
68
+ # if no instance is passed, should return a hash of any setter dependencies
69
+ # applying to all instances constructed from this factory. (which may be none)
70
+ #
71
+ # if an instance is passed, it may add to this hash any additional setter dependencies
72
+ # which are specific to this instance. This is useful when you have some extra set
73
+ # of dependencies which varies depending on the parameters to the constructor.
74
+ def setter_dependencies(instance=nil)
75
+ {}
76
+ end
77
+
78
+ # Will be passed a hash which has keys for all of the argument names specified
79
+ # in constructor_dependencies, together with values which are the constructed
80
+ # dependencies meeting the requirements of the corresponding Wirer::Depedency.
81
+ #
82
+ # May also be passed additional non-dependency arguments supplied directly
83
+ # to the factory.
84
+ #
85
+ # The following must hold:
86
+ # factory.new_from_dependencies(dependencies, ...).is_a?(factory.provides_class)
87
+ #
88
+ # however the following is not required to hold:
89
+ # factory.new_from_dependencies(dependencies, ...).instance_of?(factory.provides_class)
90
+ def new_from_dependencies(dependencies={}, *other_args, &block_arg)
91
+ raise NotImplementedError
92
+ end
93
+
94
+ # Supplies a wrapper around the factory with a set of pre-supplied dependencies.
95
+ # The wrapper can then be used to construct instances.
96
+ # See Factory::CurriedDependencies
97
+ def curry_with_dependencies(dependencies)
98
+ Factory::CurriedDependencies.new(self, dependencies)
99
+ end
100
+
101
+ def inject_dependency(instance, attr_name, dependency)
102
+ instance.send(:"#{attr_name}=", dependency)
103
+ end
104
+
105
+ def post_initialize(instance)
106
+ instance.send(:post_initialize) if instance.respond_to?(:post_initialize, true)
107
+ end
108
+
109
+ def wrapped_with(additional_options={}, &wrapped_constructor_block)
110
+ Factory::Wrapped.new(self, additional_options, &wrapped_constructor_block)
111
+ end
112
+ end
113
+
114
+ end