metro 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -0
- data/changelog.md +10 -0
- data/lib/assets/missing.mp3 +0 -0
- data/lib/assets/missing.wav +0 -0
- data/lib/gosu_ext/image.rb +4 -0
- data/lib/gosu_ext/sample.rb +18 -0
- data/lib/gosu_ext/song.rb +18 -0
- data/lib/metro.rb +2 -0
- data/lib/metro/animation/easing/ease_in.rb +15 -0
- data/lib/metro/animation/easing/easing.rb +51 -0
- data/lib/metro/animation/easing/linear.rb +15 -0
- data/lib/metro/animation/has_animations.rb +17 -0
- data/lib/metro/animation/implicit_animation.rb +5 -24
- data/lib/metro/models/draws.rb +10 -1
- data/lib/metro/models/model.rb +117 -89
- data/lib/metro/models/models/image.rb +8 -9
- data/lib/metro/models/models/label.rb +4 -8
- data/lib/metro/models/models/menu.rb +7 -9
- data/lib/metro/models/models/rectangle.rb +7 -12
- data/lib/metro/models/models/song.rb +33 -0
- data/lib/metro/models/properties/dimensions_property.rb +18 -1
- data/lib/metro/models/properties/image_property.rb +2 -2
- data/lib/metro/models/properties/position_property.rb +6 -0
- data/lib/metro/models/properties/property.rb +129 -23
- data/lib/metro/models/properties/sample_property.rb +97 -0
- data/lib/metro/models/properties/song_property.rb +113 -0
- data/lib/metro/scene.rb +2 -11
- data/lib/metro/scenes.rb +14 -7
- data/lib/metro/transitions/fade_transition_scene.rb +8 -1
- data/lib/metro/units/bounds.rb +8 -0
- data/lib/metro/units/dimensions.rb +23 -5
- data/lib/metro/units/point.rb +26 -1
- data/lib/metro/units/rectangle_bounds.rb +52 -0
- data/lib/metro/units/scale.rb +16 -0
- data/lib/metro/units/units.rb +3 -1
- data/lib/metro/version.rb +1 -1
- data/lib/metro/window.rb +7 -0
- data/lib/templates/game/README.md.tt +20 -1
- data/spec/metro/models/models/label_spec.rb +4 -4
- data/spec/metro/models/properties/dimensions_spec.rb +29 -0
- data/spec/metro/models/properties/position_property_spec.rb +5 -5
- data/spec/spec_helper.rb +3 -1
- metadata +22 -9
- data/lib/metro/animation/easing.rb +0 -31
- data/lib/metro/models/rectangle_bounds.rb +0 -28
data/README.md
CHANGED
@@ -12,6 +12,8 @@ Metro is a framework built around [gosu](https://github.com/jlnr/gosu) (the 2D g
|
|
12
12
|
|
13
13
|
> NOTE: This project is very early in development and at this point mostly a prototype to explore more of theses concepts to gain an understanding of core tools necessary to make games.
|
14
14
|
|
15
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/burtlo/metro)
|
16
|
+
|
15
17
|
## Installation
|
16
18
|
|
17
19
|
$ gem install metro
|
data/changelog.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Metro
|
2
2
|
|
3
|
+
## 0.2.2 / 2012-11-10
|
4
|
+
|
5
|
+
* Song support added (scene methods and model properties)
|
6
|
+
* Sample support added (model properties)
|
7
|
+
* Added a missing sample/song
|
8
|
+
* Implicit Animation easings can now be more easily created and registered.
|
9
|
+
* Properties can now be defined with a block
|
10
|
+
* FIX Dimensions parse creation called wrong method
|
11
|
+
* Removed support for specifying a color in animation
|
12
|
+
|
3
13
|
## 0.2.1 / 2012-11-08
|
4
14
|
|
5
15
|
* FIX Scene fade transition color changing and implicit animations
|
Binary file
|
Binary file
|
data/lib/gosu_ext/image.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# Sample is a wrapper class for a Gosu Sample. This allows for additional data to be stored
|
5
|
+
# without relying on monkey-patching on functionality.
|
6
|
+
#
|
7
|
+
class Sample < SimpleDelegator
|
8
|
+
|
9
|
+
attr_accessor :sample, :path
|
10
|
+
|
11
|
+
def initialize(sample,path)
|
12
|
+
super(sample)
|
13
|
+
@sample = sample
|
14
|
+
@path = path
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# Song is a wrapper class for a Gosu Song. This allows for additional data to be stored
|
5
|
+
# without relying on monkey-patching on functionality.
|
6
|
+
#
|
7
|
+
class Song < SimpleDelegator
|
8
|
+
|
9
|
+
attr_accessor :song, :path
|
10
|
+
|
11
|
+
def initialize(song,path)
|
12
|
+
super(song)
|
13
|
+
@song = song
|
14
|
+
@path = path
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/metro.rb
CHANGED
@@ -13,6 +13,8 @@ require 'active_support/hash_with_indifferent_access'
|
|
13
13
|
require 'gosu_ext/color'
|
14
14
|
require 'gosu_ext/image'
|
15
15
|
require 'gosu_ext/animation'
|
16
|
+
require 'gosu_ext/song'
|
17
|
+
require 'gosu_ext/sample'
|
16
18
|
require 'gosu_ext/gosu_constants'
|
17
19
|
require 'core_ext/numeric'
|
18
20
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Metro
|
2
|
+
class Easing
|
3
|
+
|
4
|
+
#
|
5
|
+
# Perform a ease-in motion between the start position and the final position.
|
6
|
+
#
|
7
|
+
class EaseIn < Easing
|
8
|
+
def self.calculation(moment,start,change,interval)
|
9
|
+
change * (moment = moment / interval) * moment + start
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
register :ease_in, EaseIn
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# An easing is a means to calculate the steps between the start and the final
|
5
|
+
# over an interval.
|
6
|
+
#
|
7
|
+
class Easing
|
8
|
+
|
9
|
+
#
|
10
|
+
# The calculate method is called within the ImplicitAnimation and will create
|
11
|
+
# an array of all the states between the start and the final value.
|
12
|
+
#
|
13
|
+
def self.calculate(start,final,interval)
|
14
|
+
change = final - start
|
15
|
+
(1..interval).map { |time| calculation(time.to_f,start,change,interval) }
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# The calculation method is to be overriden in the Easing subclasses.
|
20
|
+
# This calculation figures out the value at the current moemnt.
|
21
|
+
#
|
22
|
+
def self.calculation(moment,start,change,interval) ; 0 ; end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Register an easing within the game system.
|
26
|
+
#
|
27
|
+
def self.register(name,easing_class)
|
28
|
+
easings[name] = easing_class.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# @return the easing class based on the specified easing name.
|
33
|
+
#
|
34
|
+
def self.easing_for(easing)
|
35
|
+
easing_classname = easings[easing]
|
36
|
+
easing_classname.constantize
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# A hash of all the supported easings within metro or game.
|
41
|
+
#
|
42
|
+
def self.easings
|
43
|
+
@easings_hash ||= HashWithIndifferentAccess.new("Metro::Easing::Linear")
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
require_relative 'linear'
|
51
|
+
require_relative 'ease_in'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Metro
|
2
|
+
class Easing
|
3
|
+
|
4
|
+
#
|
5
|
+
# Perform a linear motion between the start position and the final position.
|
6
|
+
#
|
7
|
+
class Linear < Easing
|
8
|
+
def self.calculation(moment,start,change,interval)
|
9
|
+
change * moment / interval + start
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
register :linear, Linear
|
14
|
+
end
|
15
|
+
end
|
@@ -7,6 +7,20 @@ module Metro
|
|
7
7
|
base.extend ClassMethods
|
8
8
|
end
|
9
9
|
|
10
|
+
#
|
11
|
+
# A simplier syntax to enqueue an animation. At the moment this animation is going
|
12
|
+
# to be an implicit animation.
|
13
|
+
#
|
14
|
+
def animate(actor_or_actor_name,options,&block)
|
15
|
+
options[:actor] = actor(actor_or_actor_name)
|
16
|
+
options[:context] = self
|
17
|
+
animation_group = SceneAnimation.build options, &block
|
18
|
+
enqueue animation_group
|
19
|
+
end
|
20
|
+
|
21
|
+
# An alternative to stating `animate` syntax.
|
22
|
+
alias_method :change, :animate
|
23
|
+
|
10
24
|
module ClassMethods
|
11
25
|
|
12
26
|
#
|
@@ -24,6 +38,9 @@ module Metro
|
|
24
38
|
animations.push scene_animation
|
25
39
|
end
|
26
40
|
|
41
|
+
# Provide an alternative to the `animate` syntax.
|
42
|
+
alias_method :change, :animate
|
43
|
+
|
27
44
|
#
|
28
45
|
# All the animations that are defined for the scene to be run the scene starts.
|
29
46
|
#
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative 'easing'
|
1
|
+
require_relative 'easing/easing'
|
2
2
|
|
3
3
|
module Metro
|
4
4
|
|
@@ -52,21 +52,7 @@ module Metro
|
|
52
52
|
def after_initialize
|
53
53
|
to.each do |attribute,final|
|
54
54
|
start = actor.send(attribute)
|
55
|
-
|
56
|
-
if attribute == :color
|
57
|
-
final = Gosu::Color.new final
|
58
|
-
|
59
|
-
# @TODO: This is not going to work when the color uses a non-standard
|
60
|
-
# name for the color property.
|
61
|
-
|
62
|
-
animations.push build_animation_step(:red,start.red,final.red)
|
63
|
-
animations.push build_animation_step(:green,start.green,final.green)
|
64
|
-
animations.push build_animation_step(:blue,start.blue,final.blue)
|
65
|
-
animations.push build_animation_step(:alpha,start.alpha,final.alpha)
|
66
|
-
else
|
67
|
-
animations.push build_animation_step(attribute,start,final)
|
68
|
-
end
|
69
|
-
|
55
|
+
animations.push build_animation_step(attribute,start,final)
|
70
56
|
end
|
71
57
|
end
|
72
58
|
|
@@ -74,7 +60,7 @@ module Metro
|
|
74
60
|
step = AnimationStep.new
|
75
61
|
step.actor = actor
|
76
62
|
step.attribute = attribute
|
77
|
-
step.deltas =
|
63
|
+
step.deltas = easing_for(easing).calculate(start.to_f,final.to_f,interval.to_f)
|
78
64
|
step
|
79
65
|
end
|
80
66
|
|
@@ -90,13 +76,8 @@ module Metro
|
|
90
76
|
# @return the correct easing based on the specified name. When the name
|
91
77
|
# provided does not match anything then default to linear easing.
|
92
78
|
#
|
93
|
-
def
|
94
|
-
|
95
|
-
hash = HashWithIndifferentAccess.new("Metro::Easing::Linear")
|
96
|
-
hash.merge! linear: "Metro::Easing::Linear",
|
97
|
-
ease_in: "Metro::Easing::EaseIn"
|
98
|
-
end
|
99
|
-
@steppings[stepping].constantize
|
79
|
+
def easing_for(name)
|
80
|
+
Metro::Easing.easing_for(name)
|
100
81
|
end
|
101
82
|
|
102
83
|
#
|
data/lib/metro/models/draws.rb
CHANGED
@@ -12,7 +12,7 @@ module Metro
|
|
12
12
|
#
|
13
13
|
# Define an actor with the given name and options.
|
14
14
|
#
|
15
|
-
# As a
|
15
|
+
# As a convenience the draw method will define `getter` and `setter`
|
16
16
|
# methods for the specified actor.
|
17
17
|
#
|
18
18
|
# @example Defining a title label within a scene
|
@@ -48,6 +48,15 @@ module Metro
|
|
48
48
|
drawings.push scene_actor
|
49
49
|
end
|
50
50
|
|
51
|
+
#
|
52
|
+
# Define a sound actor with the given anem and options.
|
53
|
+
#
|
54
|
+
# @see #draw
|
55
|
+
#
|
56
|
+
def play(song_name,options={})
|
57
|
+
draw song_name, options.merge(model: "metro::models::song")
|
58
|
+
end
|
59
|
+
|
51
60
|
#
|
52
61
|
# Define several actors to be drawn.
|
53
62
|
#
|
data/lib/metro/models/model.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative 'key_value_coding'
|
2
|
-
require_relative 'rectangle_bounds'
|
3
2
|
require_relative 'properties/property'
|
4
3
|
|
5
4
|
module Metro
|
@@ -16,6 +15,31 @@ module Metro
|
|
16
15
|
class Model
|
17
16
|
include Units
|
18
17
|
|
18
|
+
#
|
19
|
+
# This is an entry point for customization. As the model's {#initialize}
|
20
|
+
# method performs may perform some initialization that may be necessary.
|
21
|
+
#
|
22
|
+
# At this point the model has been created. However, the window and scene
|
23
|
+
# of the model will not have been defined and defined properties rely on
|
24
|
+
# the window or scene will return nil values. Other properties also will
|
25
|
+
# likely not be set.
|
26
|
+
#
|
27
|
+
# @note This method should be implemented in the Model subclass.
|
28
|
+
#
|
29
|
+
def after_initialize ; end
|
30
|
+
|
31
|
+
|
32
|
+
#
|
33
|
+
# This is an entry point for customization. After the model's properties
|
34
|
+
# have been set and the model has been assigned to the window and scene
|
35
|
+
# this method is called. Here is where customization of properties or
|
36
|
+
# final positioning can be performed.
|
37
|
+
#
|
38
|
+
# @note This method may be implemented in the Model subclass.
|
39
|
+
#
|
40
|
+
def show ; end
|
41
|
+
|
42
|
+
|
19
43
|
#
|
20
44
|
# This is called every update interval while the actor is in the scene
|
21
45
|
#
|
@@ -23,6 +47,7 @@ module Metro
|
|
23
47
|
#
|
24
48
|
def update ; end
|
25
49
|
|
50
|
+
|
26
51
|
#
|
27
52
|
# This is called after an update. A model normally is not removed after
|
28
53
|
# an update, however if the model responds true to #completed? then it
|
@@ -34,7 +59,41 @@ module Metro
|
|
34
59
|
def completed? ; false ; end
|
35
60
|
|
36
61
|
|
37
|
-
|
62
|
+
#
|
63
|
+
# This is called after every {#update} and when the OS wants the window to
|
64
|
+
# repaint itself.
|
65
|
+
#
|
66
|
+
# @note This method should be implemented in the Model subclass.
|
67
|
+
#
|
68
|
+
def draw ; end
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
#
|
73
|
+
# Define a property for the model. A property has a name and then can optionally specify
|
74
|
+
# a property type which will receive additional options.
|
75
|
+
#
|
76
|
+
# @example Defining various propertys for a model
|
77
|
+
#
|
78
|
+
# class Player
|
79
|
+
# property :position
|
80
|
+
# property :angle, default: 0.0
|
81
|
+
# property :turn_amount, default: 4.5
|
82
|
+
# property :image, path: "player.png"
|
83
|
+
# property :motto, type: :text, default: 'Hometown Heroes!'
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# When the property name matches a property definition with that name they will be used. This is what
|
87
|
+
# happens for the 'position' and 'image' properties defined above. Both of those map to respective
|
88
|
+
# properties with matching names.
|
89
|
+
#
|
90
|
+
# Properties by default are assumed to be numeric properties so the types does not have to be stated.
|
91
|
+
# This is the case for 'angle' and 'turn_amount' properties.
|
92
|
+
#
|
93
|
+
# You may use any particular name for your properties as long as you specify the type. This is the case
|
94
|
+
# for the 'motto' property.
|
95
|
+
#
|
96
|
+
def self.property(name,options={},&block)
|
38
97
|
|
39
98
|
# Use the name as the property type if one has not been provided.
|
40
99
|
|
@@ -42,6 +101,18 @@ module Metro
|
|
42
101
|
|
43
102
|
property_class = Property.property(property_type)
|
44
103
|
|
104
|
+
define_method name do
|
105
|
+
raw_value = properties[name]
|
106
|
+
property_class.new(self,options,&block).get raw_value
|
107
|
+
end
|
108
|
+
|
109
|
+
define_method "#{name}=" do |value|
|
110
|
+
prepared_value = property_class.new(self,options).set(value)
|
111
|
+
properties[name] = prepared_value
|
112
|
+
end
|
113
|
+
|
114
|
+
# Define any sub-properties defined on this property
|
115
|
+
|
45
116
|
# When the name does not match the property type then we want to force
|
46
117
|
# the prefixing to be on for our sub-properties. This is to make sure
|
47
118
|
# that when people define multiple fonts and colors that they do not
|
@@ -49,72 +120,60 @@ module Metro
|
|
49
120
|
|
50
121
|
override_prefix = !(name == property_type)
|
51
122
|
|
52
|
-
# Define any properties defined on this property
|
53
|
-
|
54
123
|
property_class.defined_properties.each do |subproperty|
|
55
124
|
sub_options = { prefix: override_prefix }.merge(subproperty.options)
|
56
125
|
sub_options = sub_options.merge(parents: (Array(sub_options[:parents]) + [name]))
|
57
|
-
|
58
|
-
property subproperty.name, sub_options
|
126
|
+
_sub_property subproperty.name, sub_options
|
59
127
|
end
|
60
128
|
|
61
|
-
|
62
|
-
# parent property for which they are dependent on we will need
|
63
|
-
# to know this information because we need to behave appropriately
|
64
|
-
# within the getter and setter blocks below.
|
65
|
-
|
66
|
-
is_a_dependency = true if options[:parents]
|
67
|
-
|
68
|
-
if is_a_dependency
|
129
|
+
end
|
69
130
|
|
70
|
-
|
131
|
+
#
|
132
|
+
# Defines the sub-properties defined within the property. This is to be used internally
|
133
|
+
# by the #property method.
|
134
|
+
#
|
135
|
+
def self._sub_property(name,options={},&block)
|
71
136
|
|
72
|
-
|
137
|
+
# Use the name as the property type if one has not been provided.
|
73
138
|
|
74
|
-
|
75
|
-
method_name = (parents + [name]).join("_")
|
76
|
-
end
|
139
|
+
property_type = options[:type] || name
|
77
140
|
|
78
|
-
|
79
|
-
# parent properties, finally returning the filtered value
|
141
|
+
property_class = Property.property(property_type)
|
80
142
|
|
81
|
-
|
82
|
-
raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) }
|
83
|
-
property_class.new(self,options).get raw_value
|
84
|
-
end
|
143
|
+
parents = Array(options[:parents])
|
85
144
|
|
86
|
-
|
87
|
-
# value and set itself on that with the filtered value. The parent
|
88
|
-
# is then set.
|
89
|
-
#
|
90
|
-
# @TODO: If getters return dups and not instances of the original object then a very
|
91
|
-
# deep setter will not be valid.
|
92
|
-
#
|
93
|
-
define_method "#{method_name}=" do |value|
|
94
|
-
parent_value = parents.inject(self) {|current,method| current.send(method) }
|
145
|
+
method_name = name
|
95
146
|
|
96
|
-
|
97
|
-
|
147
|
+
if options[:prefix]
|
148
|
+
method_name = (parents + [name]).join("_")
|
149
|
+
end
|
98
150
|
|
99
|
-
|
100
|
-
|
151
|
+
# Define a getter for the sub-property that will traverse the
|
152
|
+
# parent properties, finally returning the filtered value
|
101
153
|
|
102
|
-
|
154
|
+
define_method method_name do
|
155
|
+
raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) }
|
156
|
+
property_class.new(self,options).get raw_value
|
157
|
+
end
|
103
158
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
159
|
+
# Define a setter for the sub-property that will find the parent
|
160
|
+
# value and set itself on that with the filtered value. The parent
|
161
|
+
# is then set.
|
162
|
+
#
|
163
|
+
# @TODO: If getters return dups and not instances of the original object then a very
|
164
|
+
# deep setter will not be valid.
|
165
|
+
#
|
166
|
+
define_method "#{method_name}=" do |value|
|
167
|
+
parent_value = parents.inject(self) {|current,method| current.send(method) }
|
108
168
|
|
109
|
-
|
110
|
-
|
111
|
-
properties[name] = prepared_value
|
112
|
-
end
|
169
|
+
prepared_value = property_class.new(self,options,&block).set(value)
|
170
|
+
parent_value.send("#{name}=",prepared_value)
|
113
171
|
|
172
|
+
send("#{parents.last}=",parent_value)
|
114
173
|
end
|
115
|
-
|
116
174
|
end
|
117
175
|
|
176
|
+
|
118
177
|
def properties
|
119
178
|
@properties ||= {}
|
120
179
|
end
|
@@ -122,14 +181,6 @@ module Metro
|
|
122
181
|
property :model, type: :text
|
123
182
|
property :name, type: :text
|
124
183
|
|
125
|
-
#
|
126
|
-
# This is called after every {#update} and when the OS wants the window to
|
127
|
-
# repaint itself.
|
128
|
-
#
|
129
|
-
# @note This method should be implemented in the Model subclass.
|
130
|
-
#
|
131
|
-
def draw ; end
|
132
|
-
|
133
184
|
#
|
134
185
|
# The window that this model that this window is currently being
|
135
186
|
# displayed.
|
@@ -153,14 +204,6 @@ module Metro
|
|
153
204
|
|
154
205
|
include KeyValueCoding
|
155
206
|
|
156
|
-
#
|
157
|
-
# This is an entry point for customization. As the model's {#initialize}
|
158
|
-
# method performs may perform some initialization that may be necessary.
|
159
|
-
#
|
160
|
-
# @note This method should be implemented in the Model subclass.
|
161
|
-
#
|
162
|
-
def after_initialize ; end
|
163
|
-
|
164
207
|
#
|
165
208
|
# Generate a custom notification event with the given name.
|
166
209
|
#
|
@@ -253,19 +296,12 @@ module Metro
|
|
253
296
|
#
|
254
297
|
# Captures all classes that subclass Model.
|
255
298
|
#
|
256
|
-
# @see #self.
|
299
|
+
# @see #self.models_hash
|
257
300
|
#
|
258
|
-
def self.inherited(
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
#
|
263
|
-
# All subclasses of Model, this should be all the defined model within the game.
|
264
|
-
#
|
265
|
-
# @return an Array of Scene subclasses
|
266
|
-
#
|
267
|
-
def self.models
|
268
|
-
@models ||= []
|
301
|
+
def self.inherited(model)
|
302
|
+
models_hash[model.to_s] = model.to_s
|
303
|
+
models_hash[model.to_s.downcase] = model.to_s
|
304
|
+
models_hash[model.to_s.underscore] = model.to_s
|
269
305
|
end
|
270
306
|
|
271
307
|
#
|
@@ -273,20 +309,11 @@ module Metro
|
|
273
309
|
#
|
274
310
|
# @return the Model class given the specified model name.
|
275
311
|
def self.model(name)
|
276
|
-
|
277
|
-
|
278
|
-
hash = HashWithIndifferentAccess.new("Metro::Models::Generic")
|
279
|
-
|
280
|
-
models.each do |model|
|
281
|
-
hash[model.to_s] = model
|
282
|
-
hash[model.downcase] = model
|
283
|
-
hash[model.to_s.underscore] = model
|
284
|
-
end
|
285
|
-
|
286
|
-
hash
|
287
|
-
end
|
312
|
+
models_hash[name]
|
313
|
+
end
|
288
314
|
|
289
|
-
|
315
|
+
def self.models_hash
|
316
|
+
@models_hash ||= HashWithIndifferentAccess.new("Metro::Models::Generic")
|
290
317
|
end
|
291
318
|
|
292
319
|
end
|
@@ -298,3 +325,4 @@ require_relative 'models/menu'
|
|
298
325
|
require_relative 'models/image'
|
299
326
|
require_relative 'models/rectangle'
|
300
327
|
require_relative 'models/grid_drawer'
|
328
|
+
require_relative 'models/song'
|