diy 1.0.3 → 1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -0
- data/Manifest.txt +33 -0
- data/README.txt +11 -0
- data/Rakefile +9 -8
- data/TODO.txt +9 -0
- data/homepage/Notes.txt +27 -0
- data/homepage/Rakefile +14 -0
- data/homepage/diy_example.png +0 -0
- data/homepage/index.erb +36 -0
- data/homepage/index.html +45 -0
- data/homepage/objects_yml.png +0 -0
- data/homepage/page_header.graffle +0 -0
- data/homepage/page_header.html +9 -0
- data/homepage/page_header.png +0 -0
- data/lib/diy.rb +40 -12
- data/sample_code/car.rb +7 -0
- data/sample_code/chassis.rb +5 -0
- data/sample_code/diy_example.rb +26 -0
- data/sample_code/engine.rb +5 -0
- data/sample_code/objects.yml +10 -0
- data/test/constructor.rb +119 -0
- data/test/diy_test.rb +41 -3
- data/test/files/functions/invalid_method.yml +5 -0
- data/test/files/functions/nonsingleton_objects.yml +6 -0
- data/test/files/functions/objects.yml +5 -0
- data/test/files/functions/thing.rb +3 -0
- data/test/files/functions/thing_builder.rb +21 -0
- data/test/files/namespace/animal/bird.rb +5 -0
- data/test/files/namespace/animal/cat.rb +5 -0
- data/test/files/namespace/animal/reptile/hardshell/turtle.rb +8 -0
- data/test/files/namespace/animal/reptile/lizard.rb +7 -0
- data/test/files/namespace/bad_module_specified.yml +8 -0
- data/test/files/namespace/class_name_combine.yml +8 -0
- data/test/files/namespace/hello.txt +1 -0
- data/test/files/namespace/no_module_specified.yml +8 -0
- data/test/files/namespace/objects.yml +21 -0
- data/test/files/namespace/road.rb +2 -0
- data/test/files/namespace/sky.rb +2 -0
- data/test/files/namespace/subcontext.yml +22 -0
- metadata +41 -5
data/History.txt
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
== 1.1 / 2008-05-20
|
2
|
+
* Added 'method' directive for building a bounded method from an object defined in diy
|
3
|
+
|
1
4
|
== 1.0.3 / 2007-12-11
|
2
5
|
|
3
6
|
* The 1.0.1 release had a load-path search in it that resulted in requiring files with full path names (rooted in loadpath entries). This is unintuitive, and will almost always result in a double "require" if the application code ever requires a library. The "require" for library loading now relies implicitly on the load path (just like normal human-coded requires.)
|
data/Manifest.txt
CHANGED
@@ -2,7 +2,23 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
+
TODO.txt
|
6
|
+
homepage/Notes.txt
|
7
|
+
homepage/Rakefile
|
8
|
+
homepage/diy_example.png
|
9
|
+
homepage/index.erb
|
10
|
+
homepage/index.html
|
11
|
+
homepage/objects_yml.png
|
12
|
+
homepage/page_header.graffle
|
13
|
+
homepage/page_header.html
|
14
|
+
homepage/page_header.png
|
5
15
|
lib/diy.rb
|
16
|
+
sample_code/car.rb
|
17
|
+
sample_code/chassis.rb
|
18
|
+
sample_code/diy_example.rb
|
19
|
+
sample_code/engine.rb
|
20
|
+
sample_code/objects.yml
|
21
|
+
test/constructor.rb
|
6
22
|
test/diy_test.rb
|
7
23
|
test/files/broken_construction.yml
|
8
24
|
test/files/cat/cat.rb
|
@@ -20,6 +36,11 @@ test/files/donkey/foo.rb
|
|
20
36
|
test/files/donkey/foo/bar/qux.rb
|
21
37
|
test/files/fud/objects.yml
|
22
38
|
test/files/fud/toy.rb
|
39
|
+
test/files/functions/invalid_method.yml
|
40
|
+
test/files/functions/nonsingleton_objects.yml
|
41
|
+
test/files/functions/objects.yml
|
42
|
+
test/files/functions/thing.rb
|
43
|
+
test/files/functions/thing_builder.rb
|
23
44
|
test/files/gnu/objects.yml
|
24
45
|
test/files/gnu/thinger.rb
|
25
46
|
test/files/goat/base.rb
|
@@ -32,6 +53,18 @@ test/files/goat/shirt.rb
|
|
32
53
|
test/files/goat/wings.rb
|
33
54
|
test/files/horse/holder_thing.rb
|
34
55
|
test/files/horse/objects.yml
|
56
|
+
test/files/namespace/animal/bird.rb
|
57
|
+
test/files/namespace/animal/cat.rb
|
58
|
+
test/files/namespace/animal/reptile/hardshell/turtle.rb
|
59
|
+
test/files/namespace/animal/reptile/lizard.rb
|
60
|
+
test/files/namespace/bad_module_specified.yml
|
61
|
+
test/files/namespace/class_name_combine.yml
|
62
|
+
test/files/namespace/hello.txt
|
63
|
+
test/files/namespace/no_module_specified.yml
|
64
|
+
test/files/namespace/objects.yml
|
65
|
+
test/files/namespace/road.rb
|
66
|
+
test/files/namespace/sky.rb
|
67
|
+
test/files/namespace/subcontext.yml
|
35
68
|
test/files/non_singleton/air.rb
|
36
69
|
test/files/non_singleton/fat_cat.rb
|
37
70
|
test/files/non_singleton/objects.yml
|
data/README.txt
CHANGED
@@ -182,6 +182,17 @@ a per-object override (handled in the context YAML):
|
|
182
182
|
engine:
|
183
183
|
auto_require: false
|
184
184
|
|
185
|
+
=== Method Directive
|
186
|
+
This introduces the concept of first class methods. An object can now be constructed with a method bound to
|
187
|
+
a particular object in the diy context.
|
188
|
+
|
189
|
+
---
|
190
|
+
trinket_builder:
|
191
|
+
|
192
|
+
method build_trinket:
|
193
|
+
object: trinket_builder
|
194
|
+
method: build
|
195
|
+
|
185
196
|
== LICENSE:
|
186
197
|
|
187
198
|
(The MIT License)
|
data/Rakefile
CHANGED
@@ -16,13 +16,14 @@ Hoe.new('diy', DIY::VERSION) do |p|
|
|
16
16
|
p.extra_deps << ['constructor', '>= 1.0.0']
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
if File.exists?("../tools/")
|
20
|
+
load "../tools/tasks/homepage.rake"
|
21
|
+
load "../tools/tasks/release_tagging.rake"
|
22
|
+
ReleaseTagging.new do |t|
|
23
|
+
t.package = "diy"
|
24
|
+
t.version = DIY::VERSION
|
25
|
+
end
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
t.package = "diy"
|
24
|
-
t.version = DIY::VERSION
|
27
|
+
desc "Release package to Rubyforge, tag the release in svn, and publish documentation"
|
28
|
+
task :release_full => [ :release, :tag_release, :publish_docs ]
|
25
29
|
end
|
26
|
-
|
27
|
-
desc "Release package to Rubyforge, tag the release in svn, and publish documentation"
|
28
|
-
task :release_full => [ :release, :tag_release, :publish_docs ]
|
data/TODO.txt
ADDED
data/homepage/Notes.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Wed Nov 21 21:49:27 EST 2007
|
2
|
+
crosby
|
3
|
+
|
4
|
+
1. Edit page_header.graffle
|
5
|
+
2. Export as HTML imagemap
|
6
|
+
3. Open ../sample_code/synopsis.rb
|
7
|
+
4. Screen shot, save as sample_code.png
|
8
|
+
5. rake (rewrites index.html)
|
9
|
+
6. cd ..
|
10
|
+
7. rake publish_docs
|
11
|
+
|
12
|
+
page_header.graffle
|
13
|
+
Export-as-HTML-Imagemap
|
14
|
+
Use png
|
15
|
+
Use 125% scale
|
16
|
+
Remember to use the style inspector to assign actions to things that should be links.
|
17
|
+
|
18
|
+
rake index
|
19
|
+
Rewrites index.html using index.erb and page_header.html (and some values in the Rakefile)
|
20
|
+
|
21
|
+
The code sample screenshot:
|
22
|
+
Taken with Snapz Pro X (this is important, as Snapz is providing the
|
23
|
+
dropshadow and about 28 extra pixels widthwise)
|
24
|
+
|
25
|
+
Should be 650 px wide to line up with the page header.
|
26
|
+
|
27
|
+
Transparency: be conscious of WHAT'S IN THE BACKGROUND
|
data/homepage/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
desc "Rewrite index.html using index.erb and publisher_homepage.html"
|
2
|
+
task :index do
|
3
|
+
require 'erb'
|
4
|
+
@title = "DIY - atomicobject.rb"
|
5
|
+
@header_html = File.read("page_header.html")
|
6
|
+
html = ERB.new(File.read("index.erb")).result(binding)
|
7
|
+
fname = "index.html"
|
8
|
+
File.open(fname,"w") do |f|
|
9
|
+
f.print html
|
10
|
+
end
|
11
|
+
puts "Wrote #{fname}"
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :index
|
Binary file
|
data/homepage/index.erb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title><%= @title %></title>
|
4
|
+
<style>
|
5
|
+
.code_sample_title {
|
6
|
+
border-top: 1px solid grey;
|
7
|
+
width: 625px;
|
8
|
+
font: bold 12pt Trebuchet MS;
|
9
|
+
text-align:left;
|
10
|
+
margin: 5px;
|
11
|
+
padding-top: 5px;
|
12
|
+
}
|
13
|
+
</style>
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body>
|
17
|
+
|
18
|
+
<div align="center">
|
19
|
+
|
20
|
+
<%= @header_html %>
|
21
|
+
|
22
|
+
<div class="code_sample_title">
|
23
|
+
objects.yml:
|
24
|
+
</div>
|
25
|
+
<a href="rdoc/index.html"><img border="0" src="objects_yml.png"></a>
|
26
|
+
|
27
|
+
<div class="code_sample_title">
|
28
|
+
diy_example.rb:
|
29
|
+
</div>
|
30
|
+
<a href="rdoc/index.html"><img border="0" src="diy_example.png"></a>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
</body>
|
36
|
+
</html>
|
data/homepage/index.html
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>DIY - atomicobject.rb</title>
|
4
|
+
<style>
|
5
|
+
.code_sample_title {
|
6
|
+
border-top: 1px solid grey;
|
7
|
+
width: 625px;
|
8
|
+
font: bold 12pt Trebuchet MS;
|
9
|
+
text-align:left;
|
10
|
+
margin: 5px;
|
11
|
+
padding-top: 5px;
|
12
|
+
}
|
13
|
+
</style>
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body>
|
17
|
+
|
18
|
+
<div align="center">
|
19
|
+
|
20
|
+
<map name="GraffleExport">
|
21
|
+
<area shape=rect coords="486,91,635,108" href="http://atomicobjectrb.rubyforge.org/">
|
22
|
+
<area shape=rect coords="485,120,635,187" href="rdoc/index.html">
|
23
|
+
<area shape=rect coords="310,120,463,187" href="http://rubyforge.org/frs/?group_id=4897&release_id=16546">
|
24
|
+
<area shape=rect coords="14,91,206,108" href="http://atomicobject.com">
|
25
|
+
<area shape=rect coords="572,16,627,71" href="http://atomicobjectrb.rubyforge.org/">
|
26
|
+
<area shape=rect coords="21,13,83,75" href="http://atomicobject.com">
|
27
|
+
</map>
|
28
|
+
<img border=0 src="page_header.png" usemap="#GraffleExport">
|
29
|
+
|
30
|
+
|
31
|
+
<div class="code_sample_title">
|
32
|
+
objects.yml:
|
33
|
+
</div>
|
34
|
+
<a href="rdoc/index.html"><img border="0" src="objects_yml.png"></a>
|
35
|
+
|
36
|
+
<div class="code_sample_title">
|
37
|
+
diy_example.rb:
|
38
|
+
</div>
|
39
|
+
<a href="rdoc/index.html"><img border="0" src="diy_example.png"></a>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
</body>
|
45
|
+
</html>
|
Binary file
|
Binary file
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<map name="GraffleExport">
|
2
|
+
<area shape=rect coords="486,91,635,108" href="http://atomicobjectrb.rubyforge.org/">
|
3
|
+
<area shape=rect coords="485,120,635,187" href="rdoc/index.html">
|
4
|
+
<area shape=rect coords="310,120,463,187" href="http://rubyforge.org/frs/?group_id=4897&release_id=16546">
|
5
|
+
<area shape=rect coords="14,91,206,108" href="http://atomicobject.com">
|
6
|
+
<area shape=rect coords="572,16,627,71" href="http://atomicobjectrb.rubyforge.org/">
|
7
|
+
<area shape=rect coords="21,13,83,75" href="http://atomicobject.com">
|
8
|
+
</map>
|
9
|
+
<img border=0 src="page_header.png" usemap="#GraffleExport">
|
Binary file
|
data/lib/diy.rb
CHANGED
@@ -2,7 +2,7 @@ require 'yaml'
|
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
module DIY #:nodoc:#
|
5
|
-
VERSION = '1.
|
5
|
+
VERSION = '1.1'
|
6
6
|
class Context
|
7
7
|
|
8
8
|
class << self
|
@@ -24,7 +24,7 @@ module DIY #:nodoc:#
|
|
24
24
|
|
25
25
|
# store extra inputs
|
26
26
|
if extra_inputs.kind_of?(Hash)
|
27
|
-
@extra_inputs
|
27
|
+
@extra_inputs= {}
|
28
28
|
extra_inputs.each { |k,v| @extra_inputs[k.to_s] = v } # smooth out the names
|
29
29
|
else
|
30
30
|
@extra_inputs = extra_inputs
|
@@ -62,8 +62,13 @@ module DIY #:nodoc:#
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
unless obj
|
65
|
-
|
66
|
-
|
65
|
+
case @defs[key]
|
66
|
+
when MethodDef
|
67
|
+
@cache[key] = construct_method(key)
|
68
|
+
else
|
69
|
+
obj = construct_object(key)
|
70
|
+
@cache[key] = obj if @defs[key].singleton?
|
71
|
+
end
|
67
72
|
end
|
68
73
|
obj
|
69
74
|
end
|
@@ -130,7 +135,11 @@ module DIY #:nodoc:#
|
|
130
135
|
# namespace: use a module(s) prefix for the classname of contained object defs
|
131
136
|
# NOTE: namespacing is NOT scope... it's just a convenient way to setup class names for a group of objects.
|
132
137
|
get_defs_from info, parse_namespace(name)
|
133
|
-
|
138
|
+
when /^method/
|
139
|
+
key_name = name.gsub(/^method\s/, "")
|
140
|
+
@defs[key_name] = MethodDef.new(:name => key_name,
|
141
|
+
:object => info['object'],
|
142
|
+
:method => info['method'])
|
134
143
|
else
|
135
144
|
# Normal object def
|
136
145
|
info ||= {}
|
@@ -154,14 +163,21 @@ module DIY #:nodoc:#
|
|
154
163
|
end
|
155
164
|
end
|
156
165
|
|
157
|
-
|
166
|
+
|
167
|
+
def construct_method(key)
|
168
|
+
method_definition = @defs[key]
|
169
|
+
object = get_object(method_definition.object)
|
170
|
+
return object.method(method_definition.method)
|
171
|
+
rescue Exception => oops
|
172
|
+
build_and_raise_construction_error(key, oops)
|
173
|
+
end
|
174
|
+
|
158
175
|
def construct_object(key)
|
159
176
|
# Find the object definition
|
160
177
|
obj_def = @defs[key]
|
161
178
|
raise "No object definition for '#{key}'" unless obj_def
|
162
|
-
|
163
179
|
# If object def mentions a library, load it
|
164
|
-
require obj_def.library
|
180
|
+
require obj_def.library if obj_def.library
|
165
181
|
|
166
182
|
# Resolve all components for the object
|
167
183
|
arg_hash = {}
|
@@ -186,11 +202,15 @@ module DIY #:nodoc:#
|
|
186
202
|
return big_c.new
|
187
203
|
end
|
188
204
|
rescue Exception => oops
|
189
|
-
|
205
|
+
build_and_raise_construction_error(key, oops)
|
206
|
+
end
|
207
|
+
|
208
|
+
def build_and_raise_construction_error(key, oops)
|
209
|
+
cerr = ConstructionError.new(key,oops)
|
190
210
|
cerr.set_backtrace(oops.backtrace)
|
191
211
|
raise cerr
|
192
212
|
end
|
193
|
-
|
213
|
+
|
194
214
|
def get_class_for_name_with_module_delimeters(class_name)
|
195
215
|
class_name.split(/::/).inject(Object) do |mod,const_name| mod.const_get(const_name) end
|
196
216
|
end
|
@@ -206,7 +226,7 @@ module DIY #:nodoc:#
|
|
206
226
|
Namespace.new(str)
|
207
227
|
end
|
208
228
|
end
|
209
|
-
|
229
|
+
|
210
230
|
class Namespace #:nodoc:#
|
211
231
|
def initialize(str)
|
212
232
|
# 'using_namespace Animal Reptile'
|
@@ -234,7 +254,15 @@ module DIY #:nodoc:#
|
|
234
254
|
@name = obj_name
|
235
255
|
end
|
236
256
|
end
|
237
|
-
|
257
|
+
|
258
|
+
class MethodDef
|
259
|
+
attr_accessor :name, :object, :method
|
260
|
+
|
261
|
+
def initialize(opts)
|
262
|
+
@name, @object, @method = opts[:name], opts[:object], opts[:method]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
238
266
|
class ObjectDef #:nodoc:
|
239
267
|
attr_accessor :name, :class_name, :library, :components
|
240
268
|
def initialize(opts)
|
data/sample_code/car.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "diy"
|
3
|
+
|
4
|
+
class Car
|
5
|
+
attr_reader :engine, :chassis
|
6
|
+
def initialize(arg_hash)
|
7
|
+
@engine = arg_hash[:engine]
|
8
|
+
@chassis = arg_hash[:chassis]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Chassis
|
13
|
+
def to_s
|
14
|
+
"Chassis"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Engine
|
19
|
+
def to_s
|
20
|
+
"Engine"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context = DIY::Context.from_file("objects.yml")
|
25
|
+
car = context['car']
|
26
|
+
puts "Car is made of: #{car.engine} and #{car.chassis}"
|
data/test/constructor.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
CONSTRUCTOR_VERSION = '1.0.2' #:nodoc:#
|
2
|
+
|
3
|
+
class Class #:nodoc:#
|
4
|
+
def constructor(*attrs, &block)
|
5
|
+
call_block = ''
|
6
|
+
if block_given?
|
7
|
+
@constructor_block = block
|
8
|
+
call_block = 'self.instance_eval(&self.class.constructor_block)'
|
9
|
+
end
|
10
|
+
# Look for embedded options in the listing:
|
11
|
+
opts = attrs.find { |a| a.kind_of?(Hash) and attrs.delete(a) }
|
12
|
+
do_acc = opts.nil? ? false : opts[:accessors] == true
|
13
|
+
require_args = opts.nil? ? true : opts[:strict] != false
|
14
|
+
super_args = opts.nil? ? nil : opts[:super]
|
15
|
+
|
16
|
+
# Incorporate superclass's constructor keys, if our superclass
|
17
|
+
if superclass.constructor_keys
|
18
|
+
similar_keys = superclass.constructor_keys & attrs
|
19
|
+
raise "Base class already has keys #{similar_keys.inspect}" unless similar_keys.empty?
|
20
|
+
attrs = [attrs,superclass.constructor_keys].flatten
|
21
|
+
end
|
22
|
+
# Generate ivar assigner code lines
|
23
|
+
assigns = ''
|
24
|
+
attrs.each do |k|
|
25
|
+
assigns += "@#{k.to_s} = args[:#{k.to_s}]\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
# If accessors option is on, declare accessors for the attributes:
|
29
|
+
if do_acc
|
30
|
+
self.class_eval "attr_accessor " + attrs.map {|x| ":#{x.to_s}"}.join(',')
|
31
|
+
end
|
32
|
+
|
33
|
+
# If user supplied super-constructor hints:
|
34
|
+
super_call = ''
|
35
|
+
if super_args
|
36
|
+
list = super_args.map do |a|
|
37
|
+
case a
|
38
|
+
when String
|
39
|
+
%|"#{a}"|
|
40
|
+
when Symbol
|
41
|
+
%|:#{a}|
|
42
|
+
end
|
43
|
+
end
|
44
|
+
super_call = %|super(#{list.join(',')})|
|
45
|
+
end
|
46
|
+
|
47
|
+
# If strict is on, define the constructor argument validator method,
|
48
|
+
# and setup the initializer to invoke the validator method.
|
49
|
+
# Otherwise, insert lax code into the initializer.
|
50
|
+
validation_code = "return if args.nil?"
|
51
|
+
if require_args
|
52
|
+
self.class_eval do
|
53
|
+
def _validate_constructor_args(args)
|
54
|
+
# First, make sure we've got args of some kind
|
55
|
+
unless args and args.keys and args.keys.size > 0
|
56
|
+
raise ConstructorArgumentError.new(self.class.constructor_keys)
|
57
|
+
end
|
58
|
+
# Scan for missing keys in the argument hash
|
59
|
+
a_keys = args.keys
|
60
|
+
missing = []
|
61
|
+
self.class.constructor_keys.each do |ck|
|
62
|
+
unless a_keys.member?(ck)
|
63
|
+
missing << ck
|
64
|
+
end
|
65
|
+
a_keys.delete(ck) # Delete inbound keys as we address them
|
66
|
+
end
|
67
|
+
if missing.size > 0 || a_keys.size > 0
|
68
|
+
raise ConstructorArgumentError.new(missing,a_keys)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# Setup the code to insert into the initializer:
|
73
|
+
validation_code = "_validate_constructor_args args "
|
74
|
+
end
|
75
|
+
|
76
|
+
# Generate the initializer code
|
77
|
+
self.class_eval %{
|
78
|
+
def initialize(args=nil)
|
79
|
+
#{super_call}
|
80
|
+
#{validation_code}
|
81
|
+
#{assigns}
|
82
|
+
setup if respond_to?(:setup)
|
83
|
+
#{call_block}
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
# Remember our constructor keys
|
88
|
+
@_ctor_keys = attrs
|
89
|
+
end
|
90
|
+
|
91
|
+
# Access the constructor keys for this class
|
92
|
+
def constructor_keys; @_ctor_keys ||=[]; end
|
93
|
+
|
94
|
+
def constructor_block #:nodoc:#
|
95
|
+
@constructor_block
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# Fancy validation exception, based on missing and extraneous keys.
|
101
|
+
class ConstructorArgumentError < RuntimeError #:nodoc:#
|
102
|
+
def initialize(missing,rejected=[])
|
103
|
+
err_msg = ''
|
104
|
+
if missing.size > 0
|
105
|
+
err_msg = "Missing constructor args [#{missing.join(',')}]"
|
106
|
+
end
|
107
|
+
if rejected.size > 0
|
108
|
+
# Some inbound keys were not addressed earlier; this means they're unwanted
|
109
|
+
if err_msg
|
110
|
+
err_msg << "; " # Appending to earlier message about missing items
|
111
|
+
else
|
112
|
+
err_msg = ''
|
113
|
+
end
|
114
|
+
# Enumerate the rejected key names
|
115
|
+
err_msg << "Rejected constructor args [#{rejected.join(',')}]"
|
116
|
+
end
|
117
|
+
super err_msg
|
118
|
+
end
|
119
|
+
end
|
data/test/diy_test.rb
CHANGED
@@ -7,7 +7,7 @@ class DIYTest < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
def setup
|
9
9
|
# Add load paths:
|
10
|
-
%w|gnu dog cat yak donkey goat horse fud non_singleton namespace|.each do |p|
|
10
|
+
%w|gnu dog cat yak donkey goat horse fud non_singleton namespace functions|.each do |p|
|
11
11
|
libdir = path_to_test_file(p)
|
12
12
|
$: << libdir unless $:.member?(libdir)
|
13
13
|
end
|
@@ -74,7 +74,7 @@ class DIYTest < Test::Unit::TestCase
|
|
74
74
|
@diy.build_everything
|
75
75
|
assert_not_nil @diy['foo/bar/qux'], "Should have got my qux (which is hiding in a couple modules)"
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
def test_keys
|
79
79
|
load_context "dog/simple.yml"
|
80
80
|
assert_equal %w|dog_model dog_presenter dog_view file_resolver other_thing|, @diy.keys.sort
|
@@ -492,7 +492,7 @@ class DIYTest < Test::Unit::TestCase
|
|
492
492
|
assert_same sky, bird.sky, "Bird has wrong Sky"
|
493
493
|
assert_same bird, lizard.bird, "Lizard has wrong Bird"
|
494
494
|
end
|
495
|
-
|
495
|
+
|
496
496
|
def test_should_combine_a_given_class_name_with_the_namespace
|
497
497
|
load_context "namespace/class_name_combine.yml"
|
498
498
|
assert_not_nil @diy['garfield'], "No garfield"
|
@@ -533,6 +533,44 @@ class DIYTest < Test::Unit::TestCase
|
|
533
533
|
assert_match(/no such file to load -- fuzzy_creature\/bird/, ex.message)
|
534
534
|
end
|
535
535
|
|
536
|
+
def test_should_be_able_define_and_access_bounded_methods
|
537
|
+
load_context "functions/objects.yml"
|
538
|
+
@diy.build_everything
|
539
|
+
build_thing = @diy['build_thing']
|
540
|
+
|
541
|
+
assert_not_nil build_thing, "should not be nil"
|
542
|
+
assert_kind_of(Method, build_thing)
|
543
|
+
assert_same(build_thing, @diy['build_thing'])
|
544
|
+
end
|
545
|
+
|
546
|
+
def test_bounded_method_can_be_used
|
547
|
+
load_context "functions/objects.yml"
|
548
|
+
@diy.build_everything
|
549
|
+
build_thing = @diy['build_thing']
|
550
|
+
|
551
|
+
thing = build_thing["the name", "flying"]
|
552
|
+
|
553
|
+
assert_equal("the name", thing.name)
|
554
|
+
assert_equal("flying", thing.ability)
|
555
|
+
end
|
556
|
+
|
557
|
+
def test_building_bounded_method_uses_object_in_diy_context_correctly
|
558
|
+
load_context "functions/objects.yml"
|
559
|
+
@diy.build_everything
|
560
|
+
assert_equal(@diy['build_thing'], @diy['thing_builder'].method(:build))
|
561
|
+
|
562
|
+
load_context "functions/nonsingleton_objects.yml"
|
563
|
+
@diy.build_everything
|
564
|
+
assert_not_equal(@diy['build_thing'], @diy['thing_builder'].method(:build))
|
565
|
+
end
|
566
|
+
|
567
|
+
def test_raises_construction_error_if_invalid_method_specified
|
568
|
+
load_context "functions/invalid_method.yml"
|
569
|
+
assert_raises DIY::ConstructionError do
|
570
|
+
@diy.build_everything
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
536
574
|
#
|
537
575
|
# HELPERS
|
538
576
|
#
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'thing'
|
2
|
+
|
3
|
+
class ThingBuilder
|
4
|
+
@@builder_count = 0
|
5
|
+
|
6
|
+
def self.reset_builder_count
|
7
|
+
@@builder_count = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.builder_count
|
11
|
+
@@builder_count
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@@builder_count += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def build(name, ability)
|
19
|
+
Thing.new(:name => name, :ability => ability)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
this is the info
|
@@ -0,0 +1,22 @@
|
|
1
|
+
road:
|
2
|
+
|
3
|
+
sky:
|
4
|
+
|
5
|
+
using_namespace Animal:
|
6
|
+
|
7
|
+
cat:
|
8
|
+
compose: road
|
9
|
+
|
10
|
+
|
11
|
+
+aviary:
|
12
|
+
using_namespace Animal:
|
13
|
+
bird:
|
14
|
+
compose: sky
|
15
|
+
|
16
|
+
using_namespace Animal Reptile:
|
17
|
+
lizard:
|
18
|
+
compose: bird
|
19
|
+
|
20
|
+
using_namespace Animal::Reptile::Hardshell:
|
21
|
+
turtle:
|
22
|
+
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: diy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
platform:
|
4
|
+
version: "1.1"
|
5
|
+
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Atomic Object
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2008-05-20 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version: 1.
|
31
|
+
version: 1.5.1
|
32
32
|
version:
|
33
33
|
description: "== DESCRIPTION: DIY (Dependency Injection in YAML) is a simple dependency injection library which focuses on declarative composition of objects through constructor injection. == INSTALL: * gem install diy"
|
34
34
|
email: dev@atomicobject.com
|
@@ -40,12 +40,31 @@ extra_rdoc_files:
|
|
40
40
|
- History.txt
|
41
41
|
- Manifest.txt
|
42
42
|
- README.txt
|
43
|
+
- TODO.txt
|
44
|
+
- homepage/Notes.txt
|
45
|
+
- test/files/namespace/hello.txt
|
43
46
|
files:
|
44
47
|
- History.txt
|
45
48
|
- Manifest.txt
|
46
49
|
- README.txt
|
47
50
|
- Rakefile
|
51
|
+
- TODO.txt
|
52
|
+
- homepage/Notes.txt
|
53
|
+
- homepage/Rakefile
|
54
|
+
- homepage/diy_example.png
|
55
|
+
- homepage/index.erb
|
56
|
+
- homepage/index.html
|
57
|
+
- homepage/objects_yml.png
|
58
|
+
- homepage/page_header.graffle
|
59
|
+
- homepage/page_header.html
|
60
|
+
- homepage/page_header.png
|
48
61
|
- lib/diy.rb
|
62
|
+
- sample_code/car.rb
|
63
|
+
- sample_code/chassis.rb
|
64
|
+
- sample_code/diy_example.rb
|
65
|
+
- sample_code/engine.rb
|
66
|
+
- sample_code/objects.yml
|
67
|
+
- test/constructor.rb
|
49
68
|
- test/diy_test.rb
|
50
69
|
- test/files/broken_construction.yml
|
51
70
|
- test/files/cat/cat.rb
|
@@ -63,6 +82,11 @@ files:
|
|
63
82
|
- test/files/donkey/foo/bar/qux.rb
|
64
83
|
- test/files/fud/objects.yml
|
65
84
|
- test/files/fud/toy.rb
|
85
|
+
- test/files/functions/invalid_method.yml
|
86
|
+
- test/files/functions/nonsingleton_objects.yml
|
87
|
+
- test/files/functions/objects.yml
|
88
|
+
- test/files/functions/thing.rb
|
89
|
+
- test/files/functions/thing_builder.rb
|
66
90
|
- test/files/gnu/objects.yml
|
67
91
|
- test/files/gnu/thinger.rb
|
68
92
|
- test/files/goat/base.rb
|
@@ -75,6 +99,18 @@ files:
|
|
75
99
|
- test/files/goat/wings.rb
|
76
100
|
- test/files/horse/holder_thing.rb
|
77
101
|
- test/files/horse/objects.yml
|
102
|
+
- test/files/namespace/animal/bird.rb
|
103
|
+
- test/files/namespace/animal/cat.rb
|
104
|
+
- test/files/namespace/animal/reptile/hardshell/turtle.rb
|
105
|
+
- test/files/namespace/animal/reptile/lizard.rb
|
106
|
+
- test/files/namespace/bad_module_specified.yml
|
107
|
+
- test/files/namespace/class_name_combine.yml
|
108
|
+
- test/files/namespace/hello.txt
|
109
|
+
- test/files/namespace/no_module_specified.yml
|
110
|
+
- test/files/namespace/objects.yml
|
111
|
+
- test/files/namespace/road.rb
|
112
|
+
- test/files/namespace/sky.rb
|
113
|
+
- test/files/namespace/subcontext.yml
|
78
114
|
- test/files/non_singleton/air.rb
|
79
115
|
- test/files/non_singleton/fat_cat.rb
|
80
116
|
- test/files/non_singleton/objects.yml
|
@@ -117,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
153
|
requirements: []
|
118
154
|
|
119
155
|
rubyforge_project: atomicobjectrb
|
120
|
-
rubygems_version:
|
156
|
+
rubygems_version: 1.1.1
|
121
157
|
signing_key:
|
122
158
|
specification_version: 2
|
123
159
|
summary: Constructor-based dependency injection container using YAML input.
|