gamebox 0.2.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/Gemfile +1 -8
  2. data/Rakefile +13 -37
  3. data/TODO.txt +27 -27
  4. data/docs/getting_started.rdoc +2 -2
  5. data/gamebox.gemspec +33 -191
  6. data/lib/gamebox.rb +18 -14
  7. data/lib/gamebox/actor.rb +37 -27
  8. data/lib/gamebox/actor_factory.rb +4 -5
  9. data/lib/gamebox/actor_view.rb +8 -0
  10. data/lib/gamebox/actors/collidable_debugger.rb +2 -2
  11. data/lib/gamebox/actors/curtain.rb +3 -3
  12. data/lib/gamebox/actors/emitter.rb +51 -0
  13. data/lib/gamebox/actors/label.rb +27 -7
  14. data/lib/gamebox/actors/logo.rb +1 -1
  15. data/lib/gamebox/actors/spatial_debugger.rb +25 -10
  16. data/lib/gamebox/arbiter.rb +61 -34
  17. data/lib/gamebox/behavior.rb +3 -3
  18. data/lib/gamebox/behaviors/animated.rb +1 -1
  19. data/lib/gamebox/behaviors/audible.rb +1 -1
  20. data/lib/gamebox/behaviors/collidable.rb +9 -4
  21. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +26 -1
  22. data/lib/gamebox/behaviors/collidable/circle_collidable.rb +3 -3
  23. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
  24. data/lib/gamebox/behaviors/graphical.rb +30 -4
  25. data/lib/gamebox/behaviors/layered.rb +1 -1
  26. data/lib/gamebox/behaviors/physical.rb +113 -30
  27. data/lib/gamebox/behaviors/timed.rb +33 -0
  28. data/lib/gamebox/behaviors/updatable.rb +1 -1
  29. data/lib/gamebox/class_finder.rb +1 -21
  30. data/lib/gamebox/console_app.rb +33 -31
  31. data/lib/gamebox/constants.rb +481 -0
  32. data/lib/gamebox/data/config/objects.yml +7 -0
  33. data/lib/gamebox/gamebox_application.rb +10 -33
  34. data/lib/gamebox/gamebox_generator.rb +32 -32
  35. data/lib/gamebox/input_manager.rb +73 -32
  36. data/lib/gamebox/lib/inflector.rb +1 -1
  37. data/lib/gamebox/lib/range_ext.rb +5 -0
  38. data/lib/gamebox/lib/rect.rb +548 -548
  39. data/lib/gamebox/lib/sorted_list.rb +1 -1
  40. data/lib/gamebox/lib/symbol_ext.rb +8 -0
  41. data/lib/gamebox/physical_director.rb +1 -1
  42. data/lib/gamebox/physical_stage.rb +3 -3
  43. data/lib/gamebox/physics.rb +0 -3
  44. data/lib/gamebox/resource_manager.rb +22 -17
  45. data/lib/gamebox/sound_manager.rb +3 -2
  46. data/lib/gamebox/spatial_hash.rb +60 -31
  47. data/lib/gamebox/spatial_stagehand.rb +30 -6
  48. data/lib/gamebox/spec/helper.rb +7 -7
  49. data/lib/gamebox/stage.rb +18 -19
  50. data/lib/gamebox/stage_manager.rb +33 -23
  51. data/lib/gamebox/stagehand.rb +3 -0
  52. data/lib/gamebox/svg_document.rb +1 -1
  53. data/lib/gamebox/tasks/gamebox_tasks.rake +133 -0
  54. data/lib/gamebox/templates/actor.erb +0 -2
  55. data/lib/gamebox/templates/actor_view.erb +1 -3
  56. data/lib/gamebox/templates/template_app/Gemfile +3 -2
  57. data/lib/gamebox/templates/template_app/Rakefile +3 -8
  58. data/lib/gamebox/templates/template_app/config/environment.rb +7 -39
  59. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -2
  60. data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -3
  61. data/lib/gamebox/version.rb +2 -2
  62. data/lib/gamebox/viewport.rb +44 -8
  63. data/lib/gamebox/views/graphical_actor_view.rb +22 -16
  64. data/lib/gamebox/wrapped_screen.rb +9 -1
  65. data/script/perf_spatial_hash.rb +49 -58
  66. data/script/perf_struct_vs_array.rb +32 -0
  67. data/spec/actor_factory_spec.rb +61 -0
  68. data/spec/actor_spec.rb +24 -18
  69. data/spec/actor_view_spec.rb +51 -6
  70. data/spec/animated_spec.rb +27 -6
  71. data/spec/arbiter_spec.rb +12 -24
  72. data/spec/backstage_spec.rb +1 -1
  73. data/spec/behavior_spec.rb +3 -3
  74. data/spec/class_finder_spec.rb +13 -0
  75. data/spec/collidable_spec.rb +30 -10
  76. data/spec/emitter_spec.rb +20 -0
  77. data/spec/helper.rb +5 -21
  78. data/spec/input_manager_spec.rb +134 -0
  79. data/spec/label_spec.rb +0 -1
  80. data/spec/physical_spec.rb +114 -5
  81. data/spec/resource_manager_spec.rb +1 -2
  82. data/spec/spatial_hash_spec.rb +23 -7
  83. data/spec/spatial_stagehand_spec.rb +97 -0
  84. data/spec/stage_manager_spec.rb +0 -1
  85. data/spec/stage_spec.rb +2 -2
  86. data/spec/viewport_spec.rb +92 -48
  87. metadata +223 -119
  88. data/.gitignore +0 -11
  89. data/History.txt +0 -80
  90. data/VERSION +0 -1
  91. data/lib/gamebox/event_compat.rb +0 -285
  92. data/lib/gamebox/lib/diy.rb +0 -371
  93. data/lib/gamebox/lib/numbers_ext.rb +0 -3
  94. data/lib/gamebox/tasks/gamebox_tasks.rb +0 -61
  95. data/load_paths.rb +0 -20
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- pkg
2
- *.swp
3
- *.log
4
- doc
5
- coverage
6
- .DS_Store
7
- .yardoc
8
- tmp
9
- tags
10
- .bundle
11
- *.lock
data/History.txt DELETED
@@ -1,80 +0,0 @@
1
- === 0.0.1 / 2009-06-19
2
-
3
- * Gamebox lives!
4
- * got game generation working in ruby 1.8
5
- * initial objects built
6
- * Actor/ActorViews (game objects)
7
- * Director manages actors
8
- * Level manages directors, backgrounds, level goals
9
- * Mode manages level loading and order
10
- * Behavior system for adding behaviors to actors (ie physical to put an actor into a physical space)
11
- * Loading of Levels from an SVG file
12
- * Polaris A* path finder
13
- * Lots more to come!
14
- * examples to show how to use it
15
- * netris
16
- * roids
17
- * rague
18
- * nario
19
-
20
- === 0.0.2 / 2009-06-26
21
-
22
- * Bug fix release for RubyWeekend #3
23
- * input_manager had problems with mouse events
24
-
25
- === 0.0.3 / 2009-06-26
26
-
27
- * Bug fix release for RubyWeekend #3
28
- * updatable behavior was not in the manifest
29
-
30
- === 0.0.4 / 2009-06-27
31
-
32
- * Bug fix release for RubyWeekend #3
33
- * added registering for events with input_manager that have no ids (ie i.reg KeyDownEvent do |e| ... will get all keys pressed)
34
-
35
- === 0.0.5 / 2009-06-28
36
-
37
- * Bug fix release for RubyWeekend #3
38
- * sound manager now ignores txt files
39
-
40
- === 0.0.6 / 2009-06-30
41
-
42
- * Multiple fixes and features
43
- * added rake run to all gamebox games
44
- * added rake debug to all gamebox games
45
- * added input_manager to levels
46
- * added usage -help to gamebox
47
- * added ./script/generate to generate actors (ie ./script/generate actor Foo)
48
- * migrated all test to use rspec
49
- * changed clear_hooks to take a listener instance
50
-
51
- === 0.0.7 / 2009-07-04
52
-
53
- * New Particle System code in roids
54
- * Changed license to MIT
55
- * Bug fixes
56
- * added OpenGL option for screen (per jacius request)
57
- * reorganized code
58
- * changed :parts to :shapes in the physical behavior
59
- * merged in jacius' new event system
60
- * new physics playground example
61
- * new major ruby platformer example
62
- * merged Mode/Level into Stage
63
- * added curtain transitions
64
-
65
- === 0.0.8 / 2010-02-05
66
-
67
- * Cleaning up APIs
68
- * Adding basic collision detection system
69
- * added timers to stage for calling blocks on an interval
70
-
71
- === 0.0.9 / 2010-02-18
72
-
73
- * bug fixes for rspec requires
74
- * cleaning up docs
75
- * added support for stagehands
76
-
77
- === 0.1.2 / 2010-04-28
78
-
79
- * added dist tasks to package up windows executables
80
- * added spatial hash and updated collision detection
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.2.1
@@ -1,285 +0,0 @@
1
-
2
- # Basic event compatibility layer. Should allow most Gamebox games
3
- # that use old-style Rubygame events to run using new-style events
4
- # under the hood without even knowing it.
5
-
6
-
7
- ExposeEvent = Rubygame::Events::WindowExposed
8
- KeyDownEvent = Rubygame::Events::KeyPressed
9
- KeyUpEvent = Rubygame::Events::KeyReleased
10
- MouseDownEvent = Rubygame::Events::MousePressed
11
- MouseUpEvent = Rubygame::Events::MouseReleased
12
- MouseMotionEvent = Rubygame::Events::MouseMoved
13
- QuitEvent = Rubygame::Events::QuitRequested
14
- ResizeEvent = Rubygame::Events::WindowResized
15
-
16
-
17
-
18
-
19
- K_BACKSPACE = :backspace
20
- K_TAB = :tab
21
- K_CLEAR = :clear
22
- K_RETURN = :return
23
- K_PAUSE = :pause
24
- K_ESCAPE = :escape
25
- K_SPACE = :space
26
- K_EXCLAIM = :exclamation_mark
27
- K_QUOTEDBL = :double_quote
28
- K_HASH = :hash
29
- K_DOLLAR = :dollar
30
- K_AMPERSAND = :ampersand
31
- K_QUOTE = :quote
32
- K_LEFTPAREN = :left_parenthesis
33
- K_RIGHTPAREN = :right_parenthesis
34
- K_ASTERISK = :asterisk
35
- K_PLUS = :plus
36
- K_COMMA = :comma
37
- K_MINUS = :minus
38
- K_PERIOD = :period
39
- K_SLASH = :slash
40
- K_0 = :number_0
41
- K_1 = :number_1
42
- K_2 = :number_2
43
- K_3 = :number_3
44
- K_4 = :number_4
45
- K_5 = :number_5
46
- K_6 = :number_6
47
- K_7 = :number_7
48
- K_8 = :number_8
49
- K_9 = :number_9
50
- K_COLON = :colon
51
- K_SEMICOLON = :semicolon
52
- K_LESS = :less_than
53
- K_EQUALS = :equals
54
- K_GREATER = :greater_than
55
- K_QUESTION = :question_mark
56
- K_AT = :at
57
- K_LEFTBRACKET = :left_bracket
58
- K_BACKSLASH = :backslash
59
- K_RIGHTBRACKET = :right_bracket
60
- K_CARET = :caret
61
- K_UNDERSCORE = :underscore
62
- K_BACKQUOTE = :backquote
63
- K_A = :a
64
- K_B = :b
65
- K_C = :c
66
- K_D = :d
67
- K_E = :e
68
- K_F = :f
69
- K_G = :g
70
- K_H = :h
71
- K_I = :i
72
- K_J = :j
73
- K_K = :k
74
- K_L = :l
75
- K_M = :m
76
- K_N = :n
77
- K_O = :o
78
- K_P = :p
79
- K_Q = :q
80
- K_R = :r
81
- K_S = :s
82
- K_T = :t
83
- K_U = :u
84
- K_V = :v
85
- K_W = :w
86
- K_X = :x
87
- K_Y = :y
88
- K_Z = :z
89
- K_DELETE = :delete
90
-
91
-
92
- # International keyboard symbols
93
- K_WORLD_0 = :world_0
94
- K_WORLD_1 = :world_1
95
- K_WORLD_2 = :world_2
96
- K_WORLD_3 = :world_3
97
- K_WORLD_4 = :world_4
98
- K_WORLD_5 = :world_5
99
- K_WORLD_6 = :world_6
100
- K_WORLD_7 = :world_7
101
- K_WORLD_8 = :world_8
102
- K_WORLD_9 = :world_9
103
- K_WORLD_10 = :world_10
104
- K_WORLD_11 = :world_11
105
- K_WORLD_12 = :world_12
106
- K_WORLD_13 = :world_13
107
- K_WORLD_14 = :world_14
108
- K_WORLD_15 = :world_15
109
- K_WORLD_16 = :world_16
110
- K_WORLD_17 = :world_17
111
- K_WORLD_18 = :world_18
112
- K_WORLD_19 = :world_19
113
- K_WORLD_20 = :world_20
114
- K_WORLD_21 = :world_21
115
- K_WORLD_22 = :world_22
116
- K_WORLD_23 = :world_23
117
- K_WORLD_24 = :world_24
118
- K_WORLD_25 = :world_25
119
- K_WORLD_26 = :world_26
120
- K_WORLD_27 = :world_27
121
- K_WORLD_28 = :world_28
122
- K_WORLD_29 = :world_29
123
- K_WORLD_30 = :world_30
124
- K_WORLD_31 = :world_31
125
- K_WORLD_32 = :world_32
126
- K_WORLD_33 = :world_33
127
- K_WORLD_34 = :world_34
128
- K_WORLD_35 = :world_35
129
- K_WORLD_36 = :world_36
130
- K_WORLD_37 = :world_37
131
- K_WORLD_38 = :world_38
132
- K_WORLD_39 = :world_39
133
- K_WORLD_40 = :world_40
134
- K_WORLD_41 = :world_41
135
- K_WORLD_42 = :world_42
136
- K_WORLD_43 = :world_43
137
- K_WORLD_44 = :world_44
138
- K_WORLD_45 = :world_45
139
- K_WORLD_46 = :world_46
140
- K_WORLD_47 = :world_47
141
- K_WORLD_48 = :world_48
142
- K_WORLD_49 = :world_49
143
- K_WORLD_50 = :world_50
144
- K_WORLD_51 = :world_51
145
- K_WORLD_52 = :world_52
146
- K_WORLD_53 = :world_53
147
- K_WORLD_54 = :world_54
148
- K_WORLD_55 = :world_55
149
- K_WORLD_56 = :world_56
150
- K_WORLD_57 = :world_57
151
- K_WORLD_58 = :world_58
152
- K_WORLD_59 = :world_59
153
- K_WORLD_60 = :world_60
154
- K_WORLD_61 = :world_61
155
- K_WORLD_62 = :world_62
156
- K_WORLD_63 = :world_63
157
- K_WORLD_64 = :world_64
158
- K_WORLD_65 = :world_65
159
- K_WORLD_66 = :world_66
160
- K_WORLD_67 = :world_67
161
- K_WORLD_68 = :world_68
162
- K_WORLD_69 = :world_69
163
- K_WORLD_70 = :world_70
164
- K_WORLD_71 = :world_71
165
- K_WORLD_72 = :world_72
166
- K_WORLD_73 = :world_73
167
- K_WORLD_74 = :world_74
168
- K_WORLD_75 = :world_75
169
- K_WORLD_76 = :world_76
170
- K_WORLD_77 = :world_77
171
- K_WORLD_78 = :world_78
172
- K_WORLD_79 = :world_79
173
- K_WORLD_80 = :world_80
174
- K_WORLD_81 = :world_81
175
- K_WORLD_82 = :world_82
176
- K_WORLD_83 = :world_83
177
- K_WORLD_84 = :world_84
178
- K_WORLD_85 = :world_85
179
- K_WORLD_86 = :world_86
180
- K_WORLD_87 = :world_87
181
- K_WORLD_88 = :world_88
182
- K_WORLD_89 = :world_89
183
- K_WORLD_90 = :world_90
184
- K_WORLD_91 = :world_91
185
- K_WORLD_92 = :world_92
186
- K_WORLD_93 = :world_93
187
- K_WORLD_94 = :world_94
188
- K_WORLD_95 = :world_95
189
-
190
-
191
- # Numeric keypad symbols
192
- K_KP0 = :keypad_0
193
- K_KP1 = :keypad_1
194
- K_KP2 = :keypad_2
195
- K_KP3 = :keypad_3
196
- K_KP4 = :keypad_4
197
- K_KP5 = :keypad_5
198
- K_KP6 = :keypad_6
199
- K_KP7 = :keypad_7
200
- K_KP8 = :keypad_8
201
- K_KP9 = :keypad_9
202
- K_KP_PERIOD = :keypad_period
203
- K_KP_DIVIDE = :keypad_divide
204
- K_KP_MULTIPLY = :keypad_multiply
205
- K_KP_MINUS = :keypad_minus
206
- K_KP_PLUS = :keypad_plus
207
- K_KP_ENTER = :keypad_enter
208
- K_KP_EQUALS = :keypad_equals
209
-
210
-
211
- # Arrows + Home/End pad
212
- K_UP = :up
213
- K_DOWN = :down
214
- K_RIGHT = :right
215
- K_LEFT = :left
216
- K_INSERT = :insert
217
- K_HOME = :home
218
- K_END = :end
219
- K_PAGEUP = :pageup
220
- K_PAGEDOWN = :pagedown
221
-
222
-
223
- # Function keys
224
- K_F1 = :f1
225
- K_F2 = :f2
226
- K_F3 = :f3
227
- K_F4 = :f4
228
- K_F5 = :f5
229
- K_F6 = :f6
230
- K_F7 = :f7
231
- K_F8 = :f8
232
- K_F9 = :f9
233
- K_F10 = :f10
234
- K_F11 = :f11
235
- K_F12 = :f12
236
- K_F13 = :f13
237
- K_F14 = :f14
238
- K_F15 = :f15
239
-
240
-
241
- # Key state modifier keys
242
- K_NUMLOCK = :numlock
243
- K_CAPSLOCK = :capslock
244
- K_SCROLLOCK = :scrollock
245
- K_RSHIFT = :right_shift
246
- K_LSHIFT = :left_shift
247
- K_RCTRL = :right_ctrl
248
- K_LCTRL = :left_ctrl
249
- K_RALT = :right_alt
250
- K_LALT = :left_alt
251
- K_RMETA = :right_meta
252
- K_LMETA = :left_meta
253
- K_LSUPER = :left_super
254
- K_RSUPER = :right_super
255
- K_MODE = :mode
256
-
257
-
258
- # Miscellaneous keys
259
- K_HELP = :help
260
- K_PRINT = :print
261
- K_SYSREQ = :sysreq
262
- K_BREAK = :break
263
- K_MENU = :menu
264
- K_POWER = :power
265
- K_EURO = :euro
266
-
267
-
268
-
269
- # Mouse constants
270
- MOUSE_LEFT = :mouse_left
271
- MOUSE_MIDDLE = :mouse_middle
272
- MOUSE_RIGHT = :mouse_right
273
-
274
-
275
-
276
- # Joystick constants
277
- HAT_CENTERED = nil
278
- HAT_UP = :up
279
- HAT_RIGHT = :right
280
- HAT_DOWN = :down
281
- HAT_LEFT = :left
282
- HAT_RIGHTUP = :up_right
283
- HAT_RIGHTDOWN = :down_right
284
- HAT_LEFTUP = :up_left
285
- HAT_LEFTDOWN = :down_left
@@ -1,371 +0,0 @@
1
- require 'yaml'
2
- require 'set'
3
-
4
- #
5
- # DIY (Dependency Injection in Yaml) is a simple dependency injection library
6
- # which focuses on declarative composition of objects through setter injection.
7
- #
8
- # == Examples
9
- #
10
- # === A Simple Context
11
- #
12
- # The context is a hash specified in in a yaml file. Each top-level key identifies
13
- # an object. When the context is created and queried for an object, by default,
14
- # the context will require a file with the same name:
15
- # require 'foo'
16
- # next, by default, it will call new on a class from the camel-cased name of the key:
17
- # Foo.new
18
- #
19
- # foo.rb:
20
- # class Foo; end
21
- #
22
- # context.yml:
23
- # ---
24
- # foo:
25
- # bar:
26
- #
27
- # c = DIY::Context.from_file('context.yml')
28
- # c[:foo] #=> #<Foo:0x81eb0>
29
- #
30
- # === Specifying Class Name
31
- #
32
- # If the class name isn't the camel-cased key:
33
- #
34
- # foo.rb:
35
- # class MyFoo; end
36
- #
37
- # context.yml:
38
- # ---
39
- # foo:
40
- # class: MyFoo
41
- # bar:
42
- #
43
- # === Specifying Ruby File to Require
44
- #
45
- # If the file the class resides in isn't named after they key:
46
- #
47
- # fun_stuff.rb:
48
- # class Foo; end
49
- #
50
- # context.yml:
51
- # ---
52
- # foo:
53
- # lib: fun_stuff
54
- # bar:
55
- #
56
- # === Constructor Arguments
57
- #
58
- # DIY allows specification of constructor arguments as hash key-value pairs
59
- # using the <tt>compose</tt> directive.
60
- #
61
- # foo.rb:
62
- # class Foo
63
- # def initialize(args)
64
- # @bar = args[:bar]
65
- # @other = args[:other]
66
- # end
67
- # end
68
- #
69
- # context.yml:
70
- # ---
71
- # foo:
72
- # compose: bar, other
73
- # bar:
74
- # other:
75
- #
76
- # To make constructor definition easier use constructor:
77
- #
78
- # foo.rb:
79
- # class Foo
80
- # constructor :bar, :other
81
- # end
82
- #
83
- # If the constructor argument names don't match up with the object keys
84
- # in the context, they can be mapped explicitly.
85
- #
86
- # foo.rb:
87
- # class Foo
88
- # constructor :bar, :other
89
- # end
90
- #
91
- # context.yml:
92
- # ---
93
- # foo:
94
- # bar: my_bar
95
- # other: the_other_one
96
- # my_bar:
97
- # the_other_one:
98
- #
99
- # === Non-singleton objects
100
- #
101
- # Non-singletons will be re-instantiated each time they are needed.
102
- #
103
- # context.yml:
104
- # ---
105
- # foo:
106
- # singleton: false
107
- #
108
- # bar:
109
- #
110
- # engine:
111
- # compose: foo, bar
112
- #
113
- module DIY
114
- class Context
115
- def initialize(context_hash, extra_inputs={})
116
- raise "Nil context hash" unless context_hash
117
- raise "Need a hash" unless context_hash.kind_of?(Hash)
118
- [ "[]", "keys" ].each do |mname|
119
- unless extra_inputs.respond_to?(mname)
120
- raise "Extra inputs must respond to hash-like [] operator and methods #keys and #each"
121
- end
122
- end
123
-
124
- # store extra inputs
125
- if extra_inputs.kind_of?(Hash)
126
- @extra_inputs = {}
127
- extra_inputs.each { |k,v| @extra_inputs[k.to_s] = v } # smooth out the names
128
- else
129
- @extra_inputs = extra_inputs
130
- end
131
-
132
- # Collect object and subcontext definitions
133
- @defs = {}
134
- @sub_context_defs = {}
135
- context_hash.each do |name,info|
136
- name = name.to_s
137
- case name
138
- when /^\+/
139
- # subcontext
140
- @sub_context_defs[name.gsub(/^\+/,'')] = info
141
-
142
- else
143
- # Normal singleton object def
144
- if extra_inputs_has(name)
145
- raise ConstructionError.new(name, "Object definition conflicts with parent context")
146
- end
147
- @defs[name] = ObjectDef.new(:name => name, :info => info)
148
- end
149
- end
150
-
151
-
152
- # init the cache
153
- @cache = {}
154
- @cache['this_context'] = self
155
- end
156
-
157
-
158
- def self.from_yaml(io_or_string, extra_inputs={})
159
- raise "nil input to YAML" unless io_or_string
160
- Context.new(YAML.load(io_or_string), extra_inputs)
161
- end
162
-
163
- def self.from_file(fname, extra_inputs={})
164
- raise "nil file name" unless fname
165
- self.from_yaml(File.read(fname), extra_inputs)
166
- end
167
-
168
- def get_object(obj_name)
169
- key = obj_name.to_s
170
- obj = @cache[key]
171
- unless obj
172
- if extra_inputs_has(key)
173
- obj = @extra_inputs[key]
174
- end
175
- end
176
- unless obj
177
- obj = construct_object(key)
178
- @cache[key] = obj if @defs[key].singleton?
179
- end
180
- obj
181
- end
182
- alias :[] :get_object
183
-
184
- def set_object(obj_name,obj)
185
- key = obj_name.to_s
186
- raise "object '#{key}' already exists in context" if @cache.keys.include?(key)
187
- @cache[key] = obj
188
- end
189
- alias :[]= :set_object
190
-
191
- def keys
192
- (@defs.keys.to_set + @extra_inputs.keys.to_set).to_a
193
- end
194
-
195
- # Instantiate and yield the named subcontext
196
- def within(sub_context_name)
197
- # Find the subcontext definitaion:
198
- context_def = @sub_context_defs[sub_context_name.to_s]
199
- raise "No sub-context named #{sub_context_name}" unless context_def
200
- # Instantiate a new context using self as parent:
201
- context = Context.new( context_def, self )
202
-
203
- yield context
204
- end
205
-
206
- def contains_object(obj_name)
207
- key = obj_name.to_s
208
- @defs.keys.member?(key) or extra_inputs_has(key)
209
- end
210
-
211
- def build_everything
212
- @defs.keys.each { |k| self[k] }
213
- end
214
- alias :build_all :build_everything
215
- alias :preinstantiate_singletons :build_everything
216
-
217
- private
218
-
219
- def construct_object(key)
220
- # Find the object definition
221
- obj_def = @defs[key]
222
- raise "No object definition for '#{key}'" unless obj_def
223
-
224
- # If object def mentions a library, load it
225
- require obj_def.library if obj_def.library
226
-
227
- # Resolve all components for the object
228
- arg_hash = {}
229
- obj_def.components.each do |name,value|
230
- case value
231
- when Lookup
232
- arg_hash[name.to_sym] = get_object(value.name)
233
- when StringValue
234
- arg_hash[name.to_sym] = value.literal_value
235
- else
236
- raise "Cannot cope with component definition '#{value.inspect}'"
237
- end
238
- end
239
-
240
- if obj_def.code.nil?
241
- # Get a reference to the class for the object
242
- big_c = get_class_for_name_with_module_delimeters(obj_def.class_name)
243
- # Make and return the instance
244
- if arg_hash.keys.size > 0
245
- return big_c.new(arg_hash)
246
- else
247
- return big_c.new
248
- end
249
- else
250
- eval_ret = eval(obj_def.code)
251
- return eval_ret
252
- end
253
- rescue Exception => oops
254
- cerr = ConstructionError.new(key,oops)
255
- cerr.set_backtrace(oops.backtrace)
256
- raise cerr
257
- end
258
-
259
- def get_class_for_name_with_module_delimeters(class_name)
260
- class_name.split(/::/).inject(Object) do |mod,const_name| mod.const_get(const_name) end
261
- end
262
-
263
- def extra_inputs_has(key)
264
- if key.nil? or key.strip == ''
265
- raise ArgumentError.new("Cannot lookup objects with nil keys")
266
- end
267
- @extra_inputs.keys.member?(key) or @extra_inputs.keys.member?(key.to_sym)
268
- end
269
- end
270
-
271
- class Lookup #:nodoc:
272
- attr_reader :name
273
- def initialize(obj_name)
274
- @name = obj_name
275
- end
276
- end
277
-
278
- class ObjectDef #:nodoc:
279
- attr_accessor :name, :class_name, :library, :components, :code
280
- def initialize(opts)
281
- name = opts[:name]
282
- raise "Can't make an ObjectDef without a name" if name.nil?
283
-
284
- info = opts[:info] || {}
285
- info = info.clone
286
-
287
- @components = {}
288
-
289
- # Object name
290
- @name = name
291
-
292
- # Class name
293
- @class_name = info.delete 'class'
294
- @class_name ||= info.delete 'type'
295
- @class_name ||= camelize(@name)
296
-
297
- # Library
298
- @library = info.delete 'library'
299
- @library ||= info.delete 'lib'
300
- @library ||= underscore(@class_name)
301
-
302
- @library = nil if @library == "nil"
303
-
304
- # Code
305
- @code = info.delete 'code'
306
-
307
- # Auto-compose
308
- compose = info.delete 'compose'
309
- if compose
310
- case compose
311
- when Array
312
- auto_names = compose.map { |x| x.to_s }
313
- when String
314
- auto_names = compose.split(',').map { |x| x.to_s.strip }
315
- when Symbol
316
- auto_names = [ compose.to_s ]
317
- else
318
- raise "Cannot auto compose object #{@name}, bad 'compose' format: #{compose.inspect}"
319
- end
320
- end
321
- auto_names ||= []
322
- auto_names.each do |cname|
323
- @components[cname] = Lookup.new(cname)
324
- end
325
-
326
- # Singleton status
327
- if info['singleton'].nil?
328
- @singleton = true
329
- else
330
- @singleton = info['singleton']
331
- end
332
- info.delete 'singleton'
333
-
334
- # Remaining keys
335
- info.each do |key,val|
336
- @components[key.to_s] = Lookup.new(val.to_s)
337
- end
338
-
339
- end
340
-
341
- def singleton?
342
- @singleton
343
- end
344
-
345
- private
346
- # Ganked this from Inflector:
347
- def camelize(lower_case_and_underscored_word)
348
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
349
- end
350
- # Ganked this from Inflector:
351
- def underscore(camel_cased_word)
352
- camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
353
- end
354
- end
355
-
356
- # Exception raised when an object can't be created which is defined in the context.
357
- class ConstructionError < RuntimeError
358
- def initialize(object_name, cause=nil) #:nodoc:
359
- object_name = object_name
360
- cause = cause
361
- m = "Failed to construct '#{object_name}'"
362
- if cause
363
- m << "\n ...caused by:\n >>> #{cause}"
364
- end
365
- super m
366
- end
367
- end
368
- end
369
-
370
-
371
-