conject 0.0.4 → 0.0.5
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.
- data/TODO +15 -4
- data/TODO.txt +4 -0
- data/lib/conject/object_context.rb +38 -11
- data/lib/conject/object_factory.rb +23 -5
- data/lib/conject/version.rb +1 -1
- data/{spike → scratch}/arity_funny_business_in_different_ruby_versions.rb +0 -0
- data/scratch/class_singletons.rb +61 -0
- data/{spike → scratch}/depends_on_spike.rb +0 -0
- data/{spike → scratch}/donkey_fail.rb +0 -0
- data/{spike → scratch}/donkey_journey.rb +0 -0
- data/{spike → scratch}/go.rb +0 -0
- data/{spike → scratch}/metaid.rb +0 -0
- data/scratch/namespace_support.rb +3 -0
- data/{spike → scratch}/object_definition.rb +0 -0
- data/{spike → scratch}/sample.rb +0 -0
- data/scratch/special_construct.rb +6 -0
- data/spec/acceptance/regression/custom_constructor_spec.rb +56 -0
- data/spec/acceptance/regression/default_object_context_spec.rb +36 -0
- data/spec/acceptance/regression/inherited_dependencies_spec.rb +19 -4
- data/spec/acceptance/regression/non_singleton_spec.rb +62 -0
- data/spec/conject/object_context_spec.rb +30 -2
- data/spec/conject/object_factory_spec.rb +75 -25
- data/spec/test_data/basic_composition/wood.rb +3 -0
- data/spec/test_data/namespace/chart/model.rb +4 -0
- data/spec/test_data/namespace/chart/presenter.rb +7 -0
- data/spec/test_data/namespace/chart/view.rb +4 -0
- metadata +32 -16
data/TODO
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
-
|
1
|
+
Features:
|
2
|
+
customer construction lambda via configure_objects
|
3
|
+
|
4
|
+
Class singletons:
|
5
|
+
use_class_in_context
|
6
|
+
class_depends_on
|
7
|
+
|
8
|
+
context.configure( :use_class_singletons => true)
|
9
|
+
|
10
|
+
ObjectContext#no_cache? <- reimplement for recursive upward search of object configs
|
11
|
+
|
12
|
+
contexts can accept configurations targeted at named subcontext
|
13
|
+
|
14
|
+
Support classes namespaced to modules
|
15
|
+
|
2
16
|
|
3
17
|
Move / copy test data (loadable classes) into spec/acceptance/testdata
|
4
18
|
Make helpers for accessing that folder
|
5
19
|
Make helper to set load path for a specific test
|
6
20
|
|
7
|
-
Move basic object creation spec to regression
|
8
|
-
|
9
|
-
|
data/TODO.txt
ADDED
@@ -5,6 +5,7 @@ module Conject
|
|
5
5
|
|
6
6
|
def initialize
|
7
7
|
@cache = { :this_object_context => self }
|
8
|
+
@object_configs = Hash.new do |h,k| h[k] = {} end
|
8
9
|
end
|
9
10
|
|
10
11
|
# Inject a named object into this context
|
@@ -20,32 +21,31 @@ module Conject
|
|
20
21
|
# If the object exists nowhere in this or a super context: construct, cache and return a new instance of the requested object using the object factory.
|
21
22
|
def get(name)
|
22
23
|
name = name.to_sym
|
23
|
-
object = @cache[name]
|
24
24
|
return @cache[name] if @cache.keys.include?(name)
|
25
25
|
|
26
26
|
if parent_context and parent_context.has?(name)
|
27
27
|
return parent_context.get(name)
|
28
28
|
else
|
29
29
|
object = object_factory.construct_new(name,self)
|
30
|
-
@cache[name] = object
|
30
|
+
@cache[name] = object unless no_cache?(name)
|
31
31
|
return object
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
alias_method :[], :get
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def walk_up_contexts(&block)
|
38
|
+
yield self
|
39
|
+
parent_context.walk_up_contexts(&block) unless parent_context.nil?
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
return
|
44
|
-
else
|
45
|
-
# I don't have it, and neither do my ancestors.
|
46
|
-
return false
|
42
|
+
def has?(name)
|
43
|
+
walk_up_contexts do |context|
|
44
|
+
return true if context.directly_has?(name)
|
47
45
|
end
|
46
|
+
return false
|
48
47
|
end
|
48
|
+
|
49
49
|
|
50
50
|
# Indicates if this context has the requested object in its own personal cache.
|
51
51
|
# (Does not consult any parent contexts.)
|
@@ -53,9 +53,36 @@ module Conject
|
|
53
53
|
@cache.keys.include?(name.to_sym)
|
54
54
|
end
|
55
55
|
|
56
|
+
# Create and yield a new ObjectContext with this ObjectContext as its parent
|
56
57
|
def in_subcontext
|
57
58
|
yield Conject.create_object_context(self) if block_given?
|
58
59
|
end
|
59
60
|
|
61
|
+
|
62
|
+
#
|
63
|
+
# Allow configuration options to be set for named objects.
|
64
|
+
#
|
65
|
+
def configure_objects(conf={})
|
66
|
+
conf.each do |key,opts|
|
67
|
+
get_object_config(key).merge!(opts)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Get the object configuration options for the given name
|
73
|
+
#
|
74
|
+
def get_object_config(name)
|
75
|
+
@object_configs[name.to_sym]
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
#
|
81
|
+
# Returns true if an object has been specifically declared as non-cacheable.
|
82
|
+
#
|
83
|
+
def no_cache?(name)
|
84
|
+
get_object_config(name)[:cache] == false
|
85
|
+
end
|
86
|
+
|
60
87
|
end
|
61
88
|
end
|
@@ -4,13 +4,31 @@ module Conject
|
|
4
4
|
construct_with :class_finder, :dependency_resolver
|
5
5
|
|
6
6
|
def construct_new(name, object_context)
|
7
|
+
lambda_constructor = object_context.get_object_config(name)[:construct]
|
8
|
+
if lambda_constructor
|
9
|
+
case lambda_constructor.arity
|
10
|
+
when 0
|
11
|
+
return lambda_constructor[]
|
12
|
+
when 1
|
13
|
+
return lambda_constructor[object_context]
|
14
|
+
when 2
|
15
|
+
return lambda_constructor[name, object_context]
|
16
|
+
else
|
17
|
+
raise "Constructor lambda takes 0, 1 or 2 params; this lambda takes #{lambda_constructor.arity}"
|
18
|
+
end
|
19
|
+
else
|
20
|
+
return type_1_constructor(name, object_context)
|
21
|
+
end
|
22
|
+
end
|
7
23
|
|
8
|
-
|
9
|
-
# This implementation is what I'm loosely calling "type 1" or "regular" object creation:
|
10
|
-
# - Assume we're looking for a class to create an instance with
|
11
|
-
# - it may or may not have a declared list of named objects it needs to be constructed with
|
12
|
-
#
|
24
|
+
private
|
13
25
|
|
26
|
+
#
|
27
|
+
# This implementation is what I'm loosely calling "type 1" or "regular" object creation:
|
28
|
+
# - Assume we're looking for a class to create an instance with
|
29
|
+
# - it may or may not have a declared list of named objects it needs to be constructed with
|
30
|
+
#
|
31
|
+
def type_1_constructor(name, object_context)
|
14
32
|
klass = class_finder.find_class(name)
|
15
33
|
|
16
34
|
if klass.has_object_definition?
|
data/lib/conject/version.rb
CHANGED
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#
|
2
|
+
# Classes-as-objects can be a convenient way to build
|
3
|
+
# systems of objects that need to collaborate, but which
|
4
|
+
# have no other need for repeated instantiation, or implementation
|
5
|
+
# substitutions within the roles. (Ie, objects are what they are, and the
|
6
|
+
# system objects are more or less free of mutable state.)
|
7
|
+
#
|
8
|
+
# Ruby's classes, when declared "normally", are named objects available globally.
|
9
|
+
# So class S3, while a Class that could be used to generate instances, is also
|
10
|
+
# and _object_, a singleton named S3, and any other object can refer to this
|
11
|
+
# singleton by name. Implement your functionality as class methods and you're ready to go.
|
12
|
+
#
|
13
|
+
# Drawbacks:
|
14
|
+
#
|
15
|
+
# You have to be right about not needing subcontexts or impl.
|
16
|
+
# substitution; without this assumption, you're left with nothing.
|
17
|
+
#
|
18
|
+
# Code NOT written this way might have difficulty using Classes-as-objects code
|
19
|
+
#
|
20
|
+
# Classes-as-objects code cannot utilize systems that aren't written in the same way
|
21
|
+
#
|
22
|
+
# A classes-as-objects system, if during development is discovered to break these assumptions,
|
23
|
+
# they must be re-written.
|
24
|
+
#
|
25
|
+
# Observations:
|
26
|
+
# Classes-as-objects is a special case of contextual objects: all system objects are
|
27
|
+
# singletons, no implementation substitution is ever required, dependency injection
|
28
|
+
# is not required, and no construction-time behavior needs to be implemented.
|
29
|
+
# (No constructors. This isn't 100% off the table; there's always in-body configuration, eg,
|
30
|
+
# via metacoding.) All objects are at the top-most (global, or root) context in the application,
|
31
|
+
# and no subcontexts are ever needed.
|
32
|
+
#
|
33
|
+
# We could provide tooling to imply context for classes, and give them more abstract
|
34
|
+
# access to their constituents, in a way that can be modified orthogonally to their
|
35
|
+
# code. (Whereas you can't change what it means for S3 to refer to NameFormatter, you _could_
|
36
|
+
# change the way name_formatter is provided to the S3 class).
|
37
|
+
#
|
38
|
+
# NEEDS:
|
39
|
+
# - Let a class singleton declare itself to participate in a Context (root context by default)
|
40
|
+
# - withing class singleton, reference collaborator objects contextually
|
41
|
+
# - ObjectContext configuration: assume all objects are serviced by class singletons
|
42
|
+
# - ObjcetContext configuration: object-by-object config to indicate class singletons
|
43
|
+
|
44
|
+
|
45
|
+
class S3
|
46
|
+
use_class_in_context
|
47
|
+
class_depends_on :name_formatter
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
def store_file(name, data)
|
52
|
+
formatted_name = name_formatter.format(name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context.configure :use_class_singletons => true
|
58
|
+
|
59
|
+
context.configure_object :s3 => { :use_class_singleton => true }
|
60
|
+
# same as: context[:s3] = S3 ??
|
61
|
+
|
File without changes
|
File without changes
|
File without changes
|
data/{spike → scratch}/go.rb
RENAMED
File without changes
|
data/{spike → scratch}/metaid.rb
RENAMED
File without changes
|
File without changes
|
data/{spike → scratch}/sample.rb
RENAMED
File without changes
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe "configuring objects to be built with a lambda" do
|
4
|
+
subject { new_object_context }
|
5
|
+
|
6
|
+
before do
|
7
|
+
append_test_load_path "basic_composition"
|
8
|
+
require 'fence'
|
9
|
+
require 'wood'
|
10
|
+
require 'nails'
|
11
|
+
end
|
12
|
+
|
13
|
+
let :wood_substitute do
|
14
|
+
Class.new do
|
15
|
+
attr_reader :name, :object_context
|
16
|
+
|
17
|
+
def initialize(name,object_context)
|
18
|
+
@name = name
|
19
|
+
@object_context = object_context
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"MDF"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
restore_load_path
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
it "constructs and caches instances by running the given lamdba" do
|
34
|
+
wood_constructs = 0
|
35
|
+
|
36
|
+
subject.configure_objects(
|
37
|
+
:wood => {
|
38
|
+
:construct => lambda do |name,object_context|
|
39
|
+
wood_constructs += 1
|
40
|
+
wood_substitute.new name,object_context
|
41
|
+
end
|
42
|
+
}
|
43
|
+
)
|
44
|
+
|
45
|
+
fence = subject.get(:fence)
|
46
|
+
fence.wood.should be
|
47
|
+
fence.wood.to_s.should == "MDF"
|
48
|
+
fence.wood.name.should == :wood
|
49
|
+
fence.wood.object_context.should == subject
|
50
|
+
wood_constructs.should == 1
|
51
|
+
|
52
|
+
subject.get(:wood).should == fence.wood
|
53
|
+
wood_constructs.should == 1
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe "Conject" do
|
4
|
+
before do
|
5
|
+
append_test_load_path "basic_composition"
|
6
|
+
require 'fence'
|
7
|
+
require 'wood'
|
8
|
+
require 'nails'
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".default_object_context" do
|
12
|
+
it "provides an object context" do
|
13
|
+
context = Conject.default_object_context
|
14
|
+
context[:fence].should be
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it "provides the SAME object context on repeated use" do
|
19
|
+
context1 = Conject.default_object_context
|
20
|
+
context2 = Conject.default_object_context
|
21
|
+
|
22
|
+
context1.should be
|
23
|
+
context1.should == context2
|
24
|
+
context1[:fence].should == context2[:fence]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
restore_load_path
|
31
|
+
# Sneak in and reset default object context instance inside Conject:
|
32
|
+
Conject.instance_variable_set(:@default_object_context, nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -136,10 +136,6 @@ describe "basic inheritance" do
|
|
136
136
|
end
|
137
137
|
|
138
138
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
139
|
context "superclass has 1-arg #initialize" do
|
144
140
|
class Reptile
|
145
141
|
construct_with :scales
|
@@ -250,4 +246,23 @@ describe "basic inheritance" do
|
|
250
246
|
end
|
251
247
|
|
252
248
|
end
|
249
|
+
|
250
|
+
context "subclass not declaring deps, though its superclass DOES have deps" do
|
251
|
+
let(:parent) do
|
252
|
+
Class.new do
|
253
|
+
construct_with :home, :money
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
let(:child) do
|
258
|
+
Class.new(parent) do
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it "raises an error at init time" do
|
263
|
+
lambda do
|
264
|
+
child.new nil
|
265
|
+
end.should raise_error(/ancestor.*construct_with.*dependencies.*instantiate/)
|
266
|
+
end
|
267
|
+
end
|
253
268
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe "configuring objects to be non-cacheable" do
|
4
|
+
subject { new_object_context }
|
5
|
+
|
6
|
+
before do
|
7
|
+
append_test_load_path "basic_composition"
|
8
|
+
require 'fence'
|
9
|
+
require 'wood'
|
10
|
+
require 'nails'
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
restore_load_path
|
15
|
+
end
|
16
|
+
|
17
|
+
it "causes an object to be rebuilt with every request" do
|
18
|
+
subject.configure_objects(
|
19
|
+
:fence => { :cache => false },
|
20
|
+
:nails => { :cache => false },
|
21
|
+
)
|
22
|
+
|
23
|
+
f1 = subject.get(:fence)
|
24
|
+
f2 = subject.get(:fence)
|
25
|
+
|
26
|
+
# Show new fences built:
|
27
|
+
f1.should be
|
28
|
+
f2.should be
|
29
|
+
f1.should_not == f2
|
30
|
+
|
31
|
+
# nails should also be unique:
|
32
|
+
f1.nails.should_not == f2.nails
|
33
|
+
|
34
|
+
# context should not retain references to fence or nails:
|
35
|
+
subject.has?(:fence).should == false
|
36
|
+
subject.has?(:nails).should == false
|
37
|
+
|
38
|
+
# wood should remain cached as usual, and shared
|
39
|
+
f1.wood.should == f2.wood
|
40
|
+
subject.has?(:wood).should == true
|
41
|
+
subject.get(:wood).should == f1.wood
|
42
|
+
subject.get(:wood).should == f2.wood
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# other syntax ideas:
|
49
|
+
#
|
50
|
+
# subject.no_cache(:fence)
|
51
|
+
|
52
|
+
# subject.do_not_cache(:fence)
|
53
|
+
|
54
|
+
# subject.configure(:fence, :cache => false)
|
55
|
+
|
56
|
+
# subject.configure(:fence, :singleton => false)
|
57
|
+
|
58
|
+
# subject.configure do |config|
|
59
|
+
# config.object :fence, :cache => false
|
60
|
+
# end
|
61
|
+
|
62
|
+
# subject.configure.object :fence, :cache => false
|
@@ -119,10 +119,12 @@ describe Conject::ObjectContext do
|
|
119
119
|
|
120
120
|
describe "when there is a parent context" do
|
121
121
|
it "delegates the question to the parent context" do
|
122
|
-
parent_context.should_receive(:
|
123
|
-
|
122
|
+
parent_context.should_receive(:walk_up_contexts).and_yield(parent_context)
|
123
|
+
parent_context.should_receive(:directly_has?).with(:a_clue).and_return(true)
|
124
|
+
subject.has?(:a_clue).should == true
|
124
125
|
end
|
125
126
|
end
|
127
|
+
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
@@ -183,4 +185,30 @@ describe Conject::ObjectContext do
|
|
183
185
|
subsubcontext_executed.should be_true
|
184
186
|
end
|
185
187
|
end
|
188
|
+
|
189
|
+
describe "#configure_objects" do
|
190
|
+
describe ":cache => false" do
|
191
|
+
before do
|
192
|
+
parent_context.stub(:has?).and_return(false)
|
193
|
+
parent_context.should_not_receive(:get)
|
194
|
+
@first_burger = "first burger"
|
195
|
+
@second_burger = "second burger"
|
196
|
+
|
197
|
+
subject.configure_objects :cheezburger => { :cache => false }
|
198
|
+
end
|
199
|
+
|
200
|
+
it "causes the Context not to cache a constructed object, but to build new each time" do
|
201
|
+
object_factory.should_receive(:construct_new).with(:cheezburger, subject).and_return(@first_burger)
|
202
|
+
object_factory.should_receive(:construct_new).with(:cheezburger, subject).and_return(@second_burger)
|
203
|
+
|
204
|
+
subject[:cheezburger].should == @first_burger
|
205
|
+
subject[:cheezburger].should == @second_burger
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# describe "for already-cached objects" do
|
210
|
+
# it "raises an error"
|
211
|
+
# end
|
212
|
+
|
213
|
+
end
|
186
214
|
end
|
@@ -22,46 +22,96 @@ describe Conject::ObjectFactory do
|
|
22
22
|
let :my_objects_components do mock(:my_objects_components) end
|
23
23
|
|
24
24
|
describe "#construct_new" do
|
25
|
-
|
26
|
-
class_finder.should_receive(:find_class).with(my_object_name).and_return my_object_class
|
27
|
-
Conject::Utilities.stub(:has_zero_arg_constructor?).and_return true
|
28
|
-
end
|
29
|
-
|
30
|
-
describe "when target class has an object definition (implying composition dependencies)" do
|
25
|
+
describe "for Type 1 object construction" do
|
31
26
|
before do
|
32
|
-
|
27
|
+
object_context.stub(:get_object_config).and_return({})
|
28
|
+
|
29
|
+
class_finder.should_receive(:find_class).with(my_object_name).and_return my_object_class
|
30
|
+
Conject::Utilities.stub(:has_zero_arg_constructor?).and_return true
|
33
31
|
end
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
describe "when target class has an object definition (implying composition dependencies)" do
|
34
|
+
before do
|
35
|
+
my_object_class.should_receive(:has_object_definition?).and_return true
|
36
|
+
end
|
38
37
|
|
39
|
-
|
38
|
+
it "finds the object definition, pulls its deps, and instantiates a new instance" do
|
39
|
+
dependency_resolver.should_receive(:resolve_for_class).with(my_object_class, object_context).and_return my_objects_components
|
40
|
+
my_object_class.should_receive(:new).with(my_objects_components).and_return(my_object)
|
41
|
+
|
42
|
+
subject.construct_new(my_object_name, object_context).should == my_object
|
43
|
+
end
|
40
44
|
end
|
41
|
-
end
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
describe "when target class has no object definition" do
|
47
|
+
before do
|
48
|
+
my_object_class.should_receive(:has_object_definition?).and_return false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "creates a new instance of the class without any arguments" do
|
52
|
+
my_object_class.should_receive(:new).and_return(my_object)
|
53
|
+
subject.construct_new(my_object_name, object_context).should == my_object
|
54
|
+
end
|
46
55
|
end
|
47
56
|
|
48
|
-
|
49
|
-
|
50
|
-
|
57
|
+
describe "when target class has no object def, but also a non-default constructor" do
|
58
|
+
before do
|
59
|
+
my_object_class.should_receive(:has_object_definition?).and_return false
|
60
|
+
Conject::Utilities.stub(:has_zero_arg_constructor?).and_return false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "raises a CompositionError" do
|
64
|
+
lambda do
|
65
|
+
subject.construct_new(my_object_name, object_context)
|
66
|
+
end.should raise_error(ArgumentError)
|
67
|
+
end
|
51
68
|
end
|
52
69
|
end
|
53
70
|
|
54
|
-
describe "
|
71
|
+
describe "for custom lambda construction" do
|
72
|
+
let(:object_config) do { :construct => lambda do "The Object" end } end
|
73
|
+
let(:object_config2) do { :construct => lambda do |object_context| { :the_oc => object_context } end } end
|
74
|
+
let(:object_config3) do { :construct => lambda do |name, object_context| { :the_name => name, :the_oc => object_context } end } end
|
75
|
+
let(:object_config4) do { :construct => lambda do raise("the roof") end } end
|
76
|
+
let(:object_config5) do { :construct => lambda do |a,b,c| "whatev" end } end
|
77
|
+
|
55
78
|
before do
|
56
|
-
|
57
|
-
|
79
|
+
object_context.stub(:get_object_config).with(:the_object).and_return(object_config)
|
80
|
+
object_context.stub(:get_object_config).with(:the_other_object).and_return(object_config2)
|
81
|
+
object_context.stub(:get_object_config).with(:the_third_object).and_return(object_config3)
|
82
|
+
object_context.stub(:get_object_config).with(:the_fail_object).and_return(object_config4)
|
83
|
+
object_context.stub(:get_object_config).with(:the_two_many_params).and_return(object_config5)
|
58
84
|
end
|
59
85
|
|
60
|
-
it "
|
61
|
-
|
62
|
-
subject.construct_new(my_object_name, object_context)
|
63
|
-
end.should raise_error(ArgumentError)
|
86
|
+
it "invokes the configured lambda in order to build the object" do
|
87
|
+
subject.construct_new(:the_object, object_context).should == "The Object"
|
64
88
|
end
|
89
|
+
|
90
|
+
it "supplies object_context for lambdas with arity of 1" do
|
91
|
+
obj = subject.construct_new(:the_other_object, object_context)
|
92
|
+
obj.should be
|
93
|
+
obj[:the_oc].should == object_context
|
94
|
+
end
|
95
|
+
|
96
|
+
it "supplies name, object_context for lambdas with arity of 2" do
|
97
|
+
obj = subject.construct_new(:the_third_object, object_context)
|
98
|
+
obj.should be
|
99
|
+
obj[:the_name].should == :the_third_object
|
100
|
+
obj[:the_oc].should == object_context
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "when lambda has more than two args" do
|
104
|
+
it "raises an error" do
|
105
|
+
lambda do subject.construct_new(:the_fail_object, object_context) end.should raise_error(/the roof/)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "when lambda raises an error" do
|
110
|
+
it "raises an error" do
|
111
|
+
lambda do subject.construct_new(:the_two_many_params, object_context) end.should raise_error(/constructor lambda takes 0, 1 or 2 params/i)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
65
115
|
end
|
66
116
|
end
|
67
117
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conject
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152736840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152736840
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152736400 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152736400
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: simplecov
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152735900 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152735900
|
47
47
|
description: Enable Guice-like dependency injection and contextual object interactions.
|
48
48
|
email:
|
49
49
|
- david.crosby@atomicobject.com
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- README.md
|
60
60
|
- Rakefile
|
61
61
|
- TODO
|
62
|
+
- TODO.txt
|
62
63
|
- conject.gemspec
|
63
64
|
- doc/inheritance_woes.txt
|
64
65
|
- lib/conject.rb
|
@@ -74,13 +75,27 @@ files:
|
|
74
75
|
- lib/conject/utilities.rb
|
75
76
|
- lib/conject/version.rb
|
76
77
|
- rake_tasks/rspec.rake
|
78
|
+
- scratch/arity_funny_business_in_different_ruby_versions.rb
|
79
|
+
- scratch/class_singletons.rb
|
80
|
+
- scratch/depends_on_spike.rb
|
81
|
+
- scratch/donkey_fail.rb
|
82
|
+
- scratch/donkey_journey.rb
|
83
|
+
- scratch/go.rb
|
84
|
+
- scratch/metaid.rb
|
85
|
+
- scratch/namespace_support.rb
|
86
|
+
- scratch/object_definition.rb
|
87
|
+
- scratch/sample.rb
|
88
|
+
- scratch/special_construct.rb
|
77
89
|
- spec/acceptance/dev/README
|
78
90
|
- spec/acceptance/regression/README
|
79
91
|
- spec/acceptance/regression/basic_composition_spec.rb
|
80
92
|
- spec/acceptance/regression/basic_object_creation_spec.rb
|
93
|
+
- spec/acceptance/regression/custom_constructor_spec.rb
|
94
|
+
- spec/acceptance/regression/default_object_context_spec.rb
|
81
95
|
- spec/acceptance/regression/inherited_dependencies_spec.rb
|
82
96
|
- spec/acceptance/regression/inject_object_context_spec.rb
|
83
97
|
- spec/acceptance/regression/nested_contexts_spec.rb
|
98
|
+
- spec/acceptance/regression/non_singleton_spec.rb
|
84
99
|
- spec/conject/borrowed_active_support_inflector_spec.rb
|
85
100
|
- spec/conject/class_ext_construct_with_spec.rb
|
86
101
|
- spec/conject/class_finder_spec.rb
|
@@ -112,15 +127,10 @@ files:
|
|
112
127
|
- spec/test_data/inheritance/malibu.rb
|
113
128
|
- spec/test_data/inheritance/vehicle.rb
|
114
129
|
- spec/test_data/inheritance/wheel.rb
|
130
|
+
- spec/test_data/namespace/chart/model.rb
|
131
|
+
- spec/test_data/namespace/chart/presenter.rb
|
132
|
+
- spec/test_data/namespace/chart/view.rb
|
115
133
|
- spec/test_data/simple_stuff/some_random_class.rb
|
116
|
-
- spike/arity_funny_business_in_different_ruby_versions.rb
|
117
|
-
- spike/depends_on_spike.rb
|
118
|
-
- spike/donkey_fail.rb
|
119
|
-
- spike/donkey_journey.rb
|
120
|
-
- spike/go.rb
|
121
|
-
- spike/metaid.rb
|
122
|
-
- spike/object_definition.rb
|
123
|
-
- spike/sample.rb
|
124
134
|
- src/user_model.rb
|
125
135
|
- src/user_presenter.rb
|
126
136
|
- src/user_view.rb
|
@@ -153,9 +163,12 @@ test_files:
|
|
153
163
|
- spec/acceptance/regression/README
|
154
164
|
- spec/acceptance/regression/basic_composition_spec.rb
|
155
165
|
- spec/acceptance/regression/basic_object_creation_spec.rb
|
166
|
+
- spec/acceptance/regression/custom_constructor_spec.rb
|
167
|
+
- spec/acceptance/regression/default_object_context_spec.rb
|
156
168
|
- spec/acceptance/regression/inherited_dependencies_spec.rb
|
157
169
|
- spec/acceptance/regression/inject_object_context_spec.rb
|
158
170
|
- spec/acceptance/regression/nested_contexts_spec.rb
|
171
|
+
- spec/acceptance/regression/non_singleton_spec.rb
|
159
172
|
- spec/conject/borrowed_active_support_inflector_spec.rb
|
160
173
|
- spec/conject/class_ext_construct_with_spec.rb
|
161
174
|
- spec/conject/class_finder_spec.rb
|
@@ -187,4 +200,7 @@ test_files:
|
|
187
200
|
- spec/test_data/inheritance/malibu.rb
|
188
201
|
- spec/test_data/inheritance/vehicle.rb
|
189
202
|
- spec/test_data/inheritance/wheel.rb
|
203
|
+
- spec/test_data/namespace/chart/model.rb
|
204
|
+
- spec/test_data/namespace/chart/presenter.rb
|
205
|
+
- spec/test_data/namespace/chart/view.rb
|
190
206
|
- spec/test_data/simple_stuff/some_random_class.rb
|