gamebox 0.2.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -8
- data/Rakefile +13 -37
- data/TODO.txt +27 -27
- data/docs/getting_started.rdoc +2 -2
- data/gamebox.gemspec +33 -191
- data/lib/gamebox.rb +18 -14
- data/lib/gamebox/actor.rb +37 -27
- data/lib/gamebox/actor_factory.rb +4 -5
- data/lib/gamebox/actor_view.rb +8 -0
- data/lib/gamebox/actors/collidable_debugger.rb +2 -2
- data/lib/gamebox/actors/curtain.rb +3 -3
- data/lib/gamebox/actors/emitter.rb +51 -0
- data/lib/gamebox/actors/label.rb +27 -7
- data/lib/gamebox/actors/logo.rb +1 -1
- data/lib/gamebox/actors/spatial_debugger.rb +25 -10
- data/lib/gamebox/arbiter.rb +61 -34
- data/lib/gamebox/behavior.rb +3 -3
- data/lib/gamebox/behaviors/animated.rb +1 -1
- data/lib/gamebox/behaviors/audible.rb +1 -1
- data/lib/gamebox/behaviors/collidable.rb +9 -4
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +26 -1
- data/lib/gamebox/behaviors/collidable/circle_collidable.rb +3 -3
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
- data/lib/gamebox/behaviors/graphical.rb +30 -4
- data/lib/gamebox/behaviors/layered.rb +1 -1
- data/lib/gamebox/behaviors/physical.rb +113 -30
- data/lib/gamebox/behaviors/timed.rb +33 -0
- data/lib/gamebox/behaviors/updatable.rb +1 -1
- data/lib/gamebox/class_finder.rb +1 -21
- data/lib/gamebox/console_app.rb +33 -31
- data/lib/gamebox/constants.rb +481 -0
- data/lib/gamebox/data/config/objects.yml +7 -0
- data/lib/gamebox/gamebox_application.rb +10 -33
- data/lib/gamebox/gamebox_generator.rb +32 -32
- data/lib/gamebox/input_manager.rb +73 -32
- data/lib/gamebox/lib/inflector.rb +1 -1
- data/lib/gamebox/lib/range_ext.rb +5 -0
- data/lib/gamebox/lib/rect.rb +548 -548
- data/lib/gamebox/lib/sorted_list.rb +1 -1
- data/lib/gamebox/lib/symbol_ext.rb +8 -0
- data/lib/gamebox/physical_director.rb +1 -1
- data/lib/gamebox/physical_stage.rb +3 -3
- data/lib/gamebox/physics.rb +0 -3
- data/lib/gamebox/resource_manager.rb +22 -17
- data/lib/gamebox/sound_manager.rb +3 -2
- data/lib/gamebox/spatial_hash.rb +60 -31
- data/lib/gamebox/spatial_stagehand.rb +30 -6
- data/lib/gamebox/spec/helper.rb +7 -7
- data/lib/gamebox/stage.rb +18 -19
- data/lib/gamebox/stage_manager.rb +33 -23
- data/lib/gamebox/stagehand.rb +3 -0
- data/lib/gamebox/svg_document.rb +1 -1
- data/lib/gamebox/tasks/gamebox_tasks.rake +133 -0
- data/lib/gamebox/templates/actor.erb +0 -2
- data/lib/gamebox/templates/actor_view.erb +1 -3
- data/lib/gamebox/templates/template_app/Gemfile +3 -2
- data/lib/gamebox/templates/template_app/Rakefile +3 -8
- data/lib/gamebox/templates/template_app/config/environment.rb +7 -39
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -2
- data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -3
- data/lib/gamebox/version.rb +2 -2
- data/lib/gamebox/viewport.rb +44 -8
- data/lib/gamebox/views/graphical_actor_view.rb +22 -16
- data/lib/gamebox/wrapped_screen.rb +9 -1
- data/script/perf_spatial_hash.rb +49 -58
- data/script/perf_struct_vs_array.rb +32 -0
- data/spec/actor_factory_spec.rb +61 -0
- data/spec/actor_spec.rb +24 -18
- data/spec/actor_view_spec.rb +51 -6
- data/spec/animated_spec.rb +27 -6
- data/spec/arbiter_spec.rb +12 -24
- data/spec/backstage_spec.rb +1 -1
- data/spec/behavior_spec.rb +3 -3
- data/spec/class_finder_spec.rb +13 -0
- data/spec/collidable_spec.rb +30 -10
- data/spec/emitter_spec.rb +20 -0
- data/spec/helper.rb +5 -21
- data/spec/input_manager_spec.rb +134 -0
- data/spec/label_spec.rb +0 -1
- data/spec/physical_spec.rb +114 -5
- data/spec/resource_manager_spec.rb +1 -2
- data/spec/spatial_hash_spec.rb +23 -7
- data/spec/spatial_stagehand_spec.rb +97 -0
- data/spec/stage_manager_spec.rb +0 -1
- data/spec/stage_spec.rb +2 -2
- data/spec/viewport_spec.rb +92 -48
- metadata +223 -119
- data/.gitignore +0 -11
- data/History.txt +0 -80
- data/VERSION +0 -1
- data/lib/gamebox/event_compat.rb +0 -285
- data/lib/gamebox/lib/diy.rb +0 -371
- data/lib/gamebox/lib/numbers_ext.rb +0 -3
- data/lib/gamebox/tasks/gamebox_tasks.rb +0 -61
- data/load_paths.rb +0 -20
data/.gitignore
DELETED
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
|
data/lib/gamebox/event_compat.rb
DELETED
@@ -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
|
data/lib/gamebox/lib/diy.rb
DELETED
@@ -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
|
-
|