gemini 1.0.0
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/bin/gemini +18 -0
- data/build_configuration.rb +24 -0
- data/lib/ibxm.jar +0 -0
- data/lib/jinput.jar +0 -0
- data/lib/jogg-0.0.7.jar +0 -0
- data/lib/jorbis-0.0.15.jar +0 -0
- data/lib/jruby-complete.jar +0 -0
- data/lib/lwjgl.jar +0 -0
- data/lib/lwjgl_util_applet.jar +0 -0
- data/lib/native_files/OpenAL32.dll +0 -0
- data/lib/native_files/jinput-dx8.dll +0 -0
- data/lib/native_files/jinput-raw.dll +0 -0
- data/lib/native_files/libjinput-linux.so +0 -0
- data/lib/native_files/libjinput-linux64.so +0 -0
- data/lib/native_files/libjinput-osx.jnilib +0 -0
- data/lib/native_files/liblwjgl.jnilib +0 -0
- data/lib/native_files/liblwjgl.so +0 -0
- data/lib/native_files/liblwjgl64.so +0 -0
- data/lib/native_files/libopenal.so +0 -0
- data/lib/native_files/lwjgl.dll +0 -0
- data/lib/native_files/openal.dylib +0 -0
- data/lib/natives-linux.jar +0 -0
- data/lib/natives-mac.jar +0 -0
- data/lib/natives-win32.jar +0 -0
- data/lib/phys2d.jar +0 -0
- data/lib/slick.jar +0 -0
- data/package/jar/gemini.jar +0 -0
- data/src/base_state.rb +112 -0
- data/src/behavior.rb +230 -0
- data/src/behavior_event.rb +23 -0
- data/src/behaviors.txt +5 -0
- data/src/behaviors/animated_sprite.rb +51 -0
- data/src/behaviors/audible.rb +11 -0
- data/src/behaviors/axis_stateful.rb +33 -0
- data/src/behaviors/big_sprite.rb +56 -0
- data/src/behaviors/bounding_box_collidable.rb +25 -0
- data/src/behaviors/camera_anchored_drawable.rb +20 -0
- data/src/behaviors/cardinal_movable.rb +114 -0
- data/src/behaviors/clickable.rb +18 -0
- data/src/behaviors/countable.rb +31 -0
- data/src/behaviors/debug_physical.rb +31 -0
- data/src/behaviors/debug_tangible.rb +30 -0
- data/src/behaviors/drawable.rb +6 -0
- data/src/behaviors/drawable_shape.rb +43 -0
- data/src/behaviors/fading_image_trail_emittable.rb +28 -0
- data/src/behaviors/game_object_emittable.rb +12 -0
- data/src/behaviors/gravity_source.rb +21 -0
- data/src/behaviors/inertial.rb +11 -0
- data/src/behaviors/movable2d.rb +9 -0
- data/src/behaviors/multi_animated_sprite.rb +22 -0
- data/src/behaviors/physical.rb +348 -0
- data/src/behaviors/physical_cardinal_movable.rb +110 -0
- data/src/behaviors/physical_sprite.rb +29 -0
- data/src/behaviors/platformer_controllable.rb +144 -0
- data/src/behaviors/pointer.rb +28 -0
- data/src/behaviors/pressable.rb +13 -0
- data/src/behaviors/receives_events.rb +21 -0
- data/src/behaviors/regional.rb +71 -0
- data/src/behaviors/rotates_to_point.rb +18 -0
- data/src/behaviors/spatial.rb +41 -0
- data/src/behaviors/spline_stretchable_sprite.rb +45 -0
- data/src/behaviors/sprite.rb +99 -0
- data/src/behaviors/stateful.rb +31 -0
- data/src/behaviors/taggable.rb +27 -0
- data/src/behaviors/tangible.rb +51 -0
- data/src/behaviors/timeable.rb +79 -0
- data/src/behaviors/top_down_vehicle.rb +41 -0
- data/src/behaviors/triangle_trail_emittable.rb +41 -0
- data/src/behaviors/updates.rb +10 -0
- data/src/behaviors/updates_at_consistant_rate.rb +27 -0
- data/src/behaviors/vectored_movement.rb +47 -0
- data/src/behaviors/world_collidable.rb +8 -0
- data/src/color.rb +70 -0
- data/src/game_object.rb +174 -0
- data/src/game_objects/background.rb +9 -0
- data/src/game_objects/fading_image.rb +23 -0
- data/src/game_objects/icon_strip_counter_display.rb +58 -0
- data/src/game_objects/static_sprite.rb +18 -0
- data/src/game_objects/tangible_object.rb +4 -0
- data/src/game_objects/text.rb +59 -0
- data/src/game_objects/triangle_trail.rb +85 -0
- data/src/gemini.rb +110 -0
- data/src/gemini_version.rb +3 -0
- data/src/inflector.rb +68 -0
- data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
- data/src/listenable_mixin.rb +15 -0
- data/src/managers/basic_game_object_manager.rb +81 -0
- data/src/managers/basic_physics_manager.rb +97 -0
- data/src/managers/basic_render_manager.rb +48 -0
- data/src/managers/basic_tangible_manager.rb +33 -0
- data/src/managers/basic_update_manager.rb +27 -0
- data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
- data/src/managers/input_manager.rb +229 -0
- data/src/managers/input_support/input_mapping.rb +126 -0
- data/src/managers/input_support/input_message.rb +5 -0
- data/src/managers/input_support/slick_input_listener.rb +19 -0
- data/src/managers/input_support/slick_input_message.rb +11 -0
- data/src/managers/input_support/slick_input_translator.rb +15 -0
- data/src/managers/message_queue.rb +54 -0
- data/src/managers/scrolling_render_manager.rb +44 -0
- data/src/managers/sound_manager.rb +60 -0
- data/src/managers/tag_manager.rb +43 -0
- data/src/math.rb +13 -0
- data/src/music.rb +14 -0
- data/src/org/rubyforge/rawr/Main.java +67 -0
- data/src/platform.rb +28 -0
- data/src/proc_enhancement.rb +5 -0
- data/src/project_generator.rb +122 -0
- data/src/skeleton.txt +10 -0
- data/src/spline.rb +13 -0
- data/src/states/input_diagnostic_state.rb +53 -0
- data/src/vector.rb +99 -0
- data/test/test_state.rb +3 -0
- metadata +181 -0
data/bin/gemini
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'src'))
|
3
|
+
require 'project_generator'
|
4
|
+
|
5
|
+
rawr_install_args = ''
|
6
|
+
project_dir = nil
|
7
|
+
until ARGV.empty?
|
8
|
+
arg = ARGV.shift
|
9
|
+
case arg
|
10
|
+
when /-RI(.+)/
|
11
|
+
rawr_install_args << $1 + ' '
|
12
|
+
else
|
13
|
+
project_dir = arg
|
14
|
+
end
|
15
|
+
end
|
16
|
+
raise "No project dir provided" if project_dir.nil?
|
17
|
+
generator = Gemini::ProjectGenerator.new(:project_dir => project_dir, :rawr_install => rawr_install_args)
|
18
|
+
generator.generate_project
|
@@ -0,0 +1,24 @@
|
|
1
|
+
configuration do |c|
|
2
|
+
c.project_name = 'gemini'
|
3
|
+
c.output_dir = 'package'
|
4
|
+
# c.main_ruby_file = 'main'
|
5
|
+
# c.main_java_file = 'org.rubyforge.rawr.Main'
|
6
|
+
|
7
|
+
# Compile all Ruby and Java files recursively
|
8
|
+
# Copy all other files taking into account exclusion filter
|
9
|
+
c.source_dirs = ['src']
|
10
|
+
c.source_exclude_filter = []
|
11
|
+
|
12
|
+
c.jruby_jar = 'lib/jruby-complete.jar'
|
13
|
+
c.compile_ruby_files = false
|
14
|
+
#c.java_lib_files = []
|
15
|
+
c.java_lib_dirs = ['lib']
|
16
|
+
#c.files_to_copy = Dir.glob('lib/native_files/*')
|
17
|
+
|
18
|
+
c.target_jvm_version = 1.5
|
19
|
+
#c.jars[:data] = { :directory => 'data/images', :location_in_jar => 'images', :exclude => /bak/}
|
20
|
+
#c.jvm_arguments = ""
|
21
|
+
|
22
|
+
# Bundler options
|
23
|
+
# c.do_not_generate_plist = false
|
24
|
+
end
|
data/lib/ibxm.jar
ADDED
Binary file
|
data/lib/jinput.jar
ADDED
Binary file
|
data/lib/jogg-0.0.7.jar
ADDED
Binary file
|
Binary file
|
Binary file
|
data/lib/lwjgl.jar
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/natives-mac.jar
ADDED
Binary file
|
Binary file
|
data/lib/phys2d.jar
ADDED
Binary file
|
data/lib/slick.jar
ADDED
Binary file
|
Binary file
|
data/src/base_state.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
module Gemini
|
2
|
+
class BaseState
|
3
|
+
@@active_state = nil
|
4
|
+
def self.active_state
|
5
|
+
@@active_state
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.active_state=(state)
|
9
|
+
@@active_state = state
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(container, game)
|
13
|
+
@container = container
|
14
|
+
@game = game
|
15
|
+
|
16
|
+
game_object_manager = BasicGameObjectManager.new(self)
|
17
|
+
update_manager = BasicUpdateManager.new(self)
|
18
|
+
render_manager = BasicRenderManager.new(self)
|
19
|
+
input_manager = InputManager.new(self, container)
|
20
|
+
message_manager = MessageQueue.new(self)
|
21
|
+
|
22
|
+
@managers = {:game_object => game_object_manager,
|
23
|
+
:update => update_manager,
|
24
|
+
:render => render_manager,
|
25
|
+
:input => input_manager,
|
26
|
+
:message_queue => message_manager
|
27
|
+
}
|
28
|
+
|
29
|
+
@paused = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def screen_width
|
33
|
+
@game.screen_width
|
34
|
+
end
|
35
|
+
|
36
|
+
def screen_height
|
37
|
+
@game.screen_height
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_on_layer(type, layer_name, *params)
|
41
|
+
game_object_type = begin
|
42
|
+
type.constantize
|
43
|
+
rescue NameError
|
44
|
+
begin
|
45
|
+
require type.underscore
|
46
|
+
begin
|
47
|
+
type.constantize
|
48
|
+
rescue NameError
|
49
|
+
"Gemini::#{type}".constantize
|
50
|
+
end
|
51
|
+
rescue LoadError
|
52
|
+
"Gemini::#{type}".constantize
|
53
|
+
end
|
54
|
+
end
|
55
|
+
game_object = game_object_type.new(self, *params)
|
56
|
+
add_game_object_to_layer game_object, layer_name
|
57
|
+
game_object
|
58
|
+
end
|
59
|
+
|
60
|
+
def create(type, *params)
|
61
|
+
create_on_layer(type, :default, *params)
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_game_object(type, *params)
|
65
|
+
warn "create_game_object is deprecated, use create instead"
|
66
|
+
create(type, *params)
|
67
|
+
end
|
68
|
+
|
69
|
+
def manager(type)
|
70
|
+
@managers[type]
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_game_object(game_object)
|
74
|
+
@managers[:game_object].add_game_object game_object
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_game_object_to_layer(game_object, layer_name)
|
78
|
+
@managers[:game_object].add_game_object_to_layer game_object, layer_name
|
79
|
+
end
|
80
|
+
|
81
|
+
def remove(game_object)
|
82
|
+
@managers[:game_object].remove_game_object(game_object)
|
83
|
+
end
|
84
|
+
|
85
|
+
def remove_game_object(game_object)
|
86
|
+
warn "remove_game_object is deprecated, use remove instead"
|
87
|
+
remove(game_object)
|
88
|
+
end
|
89
|
+
|
90
|
+
def switch_state(state_name, *args)
|
91
|
+
state = @game.load_state state_name, args
|
92
|
+
@game.queue_state state
|
93
|
+
#self.class.active_state = state
|
94
|
+
#state.load
|
95
|
+
state
|
96
|
+
end
|
97
|
+
|
98
|
+
def load_keymap(keymap)
|
99
|
+
@managers[:input].load_keymap keymap
|
100
|
+
end
|
101
|
+
|
102
|
+
def load(*args); end
|
103
|
+
|
104
|
+
def quit_game
|
105
|
+
java.lang.System.exit 0
|
106
|
+
end
|
107
|
+
private
|
108
|
+
def set_manager(type, manager)
|
109
|
+
@managers[type] = manager
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/src/behavior.rb
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'listenable_mixin'
|
2
|
+
|
3
|
+
module Gemini
|
4
|
+
class MethodExistsError < Exception; end
|
5
|
+
class InvalidWrapWithCallbacksError < Exception; end
|
6
|
+
|
7
|
+
class ValueChangedEvent
|
8
|
+
attr_accessor :previous_value, :desired_value
|
9
|
+
|
10
|
+
def initialize(previous_value, desired_value)
|
11
|
+
@previous_value, @desired_value = previous_value, desired_value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Behavior
|
16
|
+
include ListenableMixin
|
17
|
+
attr_reader :reference_count, :target
|
18
|
+
|
19
|
+
def self.method_added(method)
|
20
|
+
if callback_methods_to_wrap.member? method
|
21
|
+
begin
|
22
|
+
return if callback_methods_wrapped.member? method #instance_method(:"wrapped_#{method}") #&& wrapped_methods.member?(method)
|
23
|
+
rescue NameError; end #Intentionally swallow, this section is to prevent infinite recursion
|
24
|
+
callback_methods_wrapped << method
|
25
|
+
alias_method :"wrapped_#{method}", method
|
26
|
+
arity = instance_method(:"wrapped_#{method}").arity
|
27
|
+
if arity.abs > 0
|
28
|
+
args = (1..arity.abs).inject([]){|args, i| args << "arg#{i}" }
|
29
|
+
args[-1].insert(0,"*") if arity < 0
|
30
|
+
end
|
31
|
+
if match = /^(.*)=$/.match(method.to_s)
|
32
|
+
method_name = match[1]
|
33
|
+
code = <<-ENDL
|
34
|
+
def #{method}(#{args})
|
35
|
+
raise Gemini::InvalidWrapWithCallbacksError.new("Cannot wrap #{method} with callbacks without \\"#{method_name}\\"") unless respond_to?(:#{method_name})
|
36
|
+
event = ValueChangedEvent.new(@target.#{method_name}, #{args})
|
37
|
+
callback_abort = CallbackStatus.new
|
38
|
+
@target.notify :before_#{method_name}_changes, event
|
39
|
+
if callback_abort.continue?
|
40
|
+
self.wrapped_#{method}(#{args})
|
41
|
+
@target.notify :after_#{method_name}_changes, event
|
42
|
+
end
|
43
|
+
end
|
44
|
+
ENDL
|
45
|
+
wrapped_methods << "before_#{method_name}_changes"
|
46
|
+
wrapped_methods << "after_#{method_name}_changes"
|
47
|
+
else
|
48
|
+
code = <<-ENDL
|
49
|
+
def #{method}(#{(args.join(",") + ",") if args} &block)
|
50
|
+
callback_abort = CallbackStatus.new
|
51
|
+
@target.notify :before_#{method}, callback_abort
|
52
|
+
if callback_abort.continue?
|
53
|
+
self.wrapped_#{method}(#{(args.join(",") + ",") if args} &block)
|
54
|
+
@target.notify :after_#{method}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
ENDL
|
58
|
+
wrapped_methods << "before_#{method}"
|
59
|
+
wrapped_methods << "after_#{method}"
|
60
|
+
end
|
61
|
+
self.class_eval(code, __FILE__, __LINE__)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def self.depends_on(behavior)
|
70
|
+
require "behaviors/#{behavior.underscore}"
|
71
|
+
add_dependency(behavior)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.depends_on_kind_of(behavior)
|
75
|
+
add_kind_of_dependency(behavior)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.wrap_with_callbacks(*args)
|
79
|
+
@@callback_methods_to_wrap[self].concat args
|
80
|
+
end
|
81
|
+
|
82
|
+
@@callback_methods_to_wrap = Hash.new {|h,k| h[k] = []}
|
83
|
+
def self.callback_methods_to_wrap
|
84
|
+
@@callback_methods_to_wrap[self]
|
85
|
+
end
|
86
|
+
|
87
|
+
@@callback_methods_wrapped = Hash.new {|h,k| h[k] = []}
|
88
|
+
def self.callback_methods_wrapped
|
89
|
+
@@callback_methods_wrapped[self]
|
90
|
+
end
|
91
|
+
|
92
|
+
@@wrapped_methods = Hash.new {|h,k| h[k] = []}
|
93
|
+
def self.wrapped_methods
|
94
|
+
@@wrapped_methods[self]
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def self.new(*args)
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.declared_method_list
|
104
|
+
public_instance_methods - Behavior.public_instance_methods
|
105
|
+
end
|
106
|
+
|
107
|
+
@@behavior_dependencies = Hash.new{|h,k| h[k] = []}
|
108
|
+
def self.dependencies
|
109
|
+
@@behavior_dependencies[self]
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.add_dependency(behavior)
|
113
|
+
@@behavior_dependencies[self] << behavior
|
114
|
+
end
|
115
|
+
|
116
|
+
@@kind_of_behavior_dependencies = Hash.new{|h,k| h[k] = []}
|
117
|
+
def self.kind_of_dependencies
|
118
|
+
@@kind_of_behavior_dependencies[self]
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.add_kind_of_dependency(behavior)
|
122
|
+
@@kind_of_behavior_dependencies[self] << behavior
|
123
|
+
end
|
124
|
+
|
125
|
+
def initialize(target)
|
126
|
+
@target = target
|
127
|
+
@dependant_behaviors = []
|
128
|
+
@reference_count = 0
|
129
|
+
|
130
|
+
self.class.dependencies.each do |dependant_behavior|
|
131
|
+
begin
|
132
|
+
dependant_behavior_class = Object.const_get(dependant_behavior)
|
133
|
+
rescue NameError
|
134
|
+
raise "Cannot load dependant behavior '#{dependant_behavior}' in behavior '#{self.class}'"
|
135
|
+
end
|
136
|
+
unless @target.kind_of? dependant_behavior_class
|
137
|
+
@target.add_behavior dependant_behavior_class.to_s
|
138
|
+
@dependant_behaviors << dependant_behavior
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#TODO: Move this to GameObject
|
143
|
+
behavior_list = @target.send(:instance_variable_get, :@__behaviors)
|
144
|
+
return unless behavior_list[self.class.name.to_sym].nil?
|
145
|
+
behavior_list[self.class.name.to_sym] = self
|
146
|
+
|
147
|
+
# self.class.kind_of_dependencies.each do |dependant_behavior|
|
148
|
+
# dependency = dependant_behavior.constantize
|
149
|
+
# next if behavior_list.find {|behavior| behavior.last.kind_of?(dependency)}
|
150
|
+
#
|
151
|
+
# raise "Dependant behavior '#{dependant_behavior}' was not found on class #{self.class}"
|
152
|
+
# end
|
153
|
+
|
154
|
+
self.class.declared_method_list.each do |method|
|
155
|
+
#TODO: Tell us which behavior is being overridden
|
156
|
+
#TODO: Allow for overriding
|
157
|
+
raise MethodExistsError.new("Error while adding the behavior #{self.class}. The method #{method} already exists on game object #{@target}.") if @target.respond_to? method
|
158
|
+
if method.to_s =~ /=/
|
159
|
+
code = <<-ENDL
|
160
|
+
def #{method}(arg)
|
161
|
+
@__behaviors[:#{self.class}].#{method}(arg)
|
162
|
+
end
|
163
|
+
ENDL
|
164
|
+
else
|
165
|
+
code = <<-ENDL
|
166
|
+
def #{method}(*args, &blk)
|
167
|
+
@__behaviors[:#{self.class}].#{method}(*args, &blk)
|
168
|
+
end
|
169
|
+
ENDL
|
170
|
+
end
|
171
|
+
@target.send(:instance_eval, code, __FILE__, __LINE__)
|
172
|
+
end
|
173
|
+
|
174
|
+
self.class.wrapped_methods.each do |method|
|
175
|
+
@target.enable_listeners_for method
|
176
|
+
end
|
177
|
+
|
178
|
+
load
|
179
|
+
end
|
180
|
+
|
181
|
+
def delete
|
182
|
+
return if @deleted
|
183
|
+
unload
|
184
|
+
__remove_listeners
|
185
|
+
self.class.declared_method_list.each do |method_name|
|
186
|
+
target_class = class <<@target; self; end
|
187
|
+
target_class.send(:remove_method, method_name)
|
188
|
+
end
|
189
|
+
#TODO: Make sure we don't delete dependent behaviors that still have depending behaviors
|
190
|
+
@dependant_behaviors.each do |dependant|
|
191
|
+
@target.remove_behavior dependant
|
192
|
+
end
|
193
|
+
@deleted = true
|
194
|
+
end
|
195
|
+
|
196
|
+
public
|
197
|
+
|
198
|
+
def set_event_aliases(mappings, block)
|
199
|
+
if mappings.kind_of? Hash
|
200
|
+
mappings.each do |event, event_alias|
|
201
|
+
@target.handle_event(event_alias) do |message|
|
202
|
+
send(event, message)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else mappings.kind_of? Symbol
|
206
|
+
@target.handle_event(mappings) do |message|
|
207
|
+
message = message.dup
|
208
|
+
send(block.call(message), message)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def add_reference_count
|
214
|
+
@reference_count += 1
|
215
|
+
end
|
216
|
+
|
217
|
+
def remove_reference_count
|
218
|
+
@reference_count -= 1
|
219
|
+
end
|
220
|
+
|
221
|
+
def load; end
|
222
|
+
def unload; end
|
223
|
+
end
|
224
|
+
|
225
|
+
class CallbackStatus
|
226
|
+
def continue?
|
227
|
+
true
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#TODO: This appears to be un-used. Use it or drop it.
|
2
|
+
|
3
|
+
module Gemini
|
4
|
+
class BehaviorEvent
|
5
|
+
def initialize(*args)
|
6
|
+
@memoizations = Hash.new { |h,k| h[k] = {} }
|
7
|
+
load(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def load(*args); end
|
11
|
+
|
12
|
+
def self.method_added(name)
|
13
|
+
match = /^memoize_(.+)$/.match name.to_s
|
14
|
+
return unless match
|
15
|
+
public_name = match[1]
|
16
|
+
eval <<-ENDL
|
17
|
+
def #{public_name}(*args)
|
18
|
+
@memoizations[:#{public_name}][args] ||= #{name}
|
19
|
+
end
|
20
|
+
ENDL
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|