gamebox 0.2.1 → 0.3.2

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.
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
-