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