metro 0.3.3 → 0.3.4
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/changelog.md +8 -1
- data/lib/core_ext/class.rb +14 -0
- data/lib/metro.rb +1 -0
- data/lib/metro/events/event_data.rb +3 -4
- data/lib/metro/events/event_state_manager.rb +63 -0
- data/lib/metro/events/events.rb +3 -0
- data/lib/metro/events/hit_list.rb +4 -5
- data/lib/metro/events/unknown_sender.rb +1 -1
- data/lib/metro/models/model.rb +14 -25
- data/lib/metro/models/model_factory.rb +1 -1
- data/lib/metro/models/models.rb +62 -0
- data/lib/metro/models/properties/position_property.rb +1 -1
- data/lib/metro/models/ui/animated_sprite.rb +85 -0
- data/lib/metro/models/ui/border.rb +44 -18
- data/lib/metro/models/ui/fps.rb +1 -1
- data/lib/metro/models/ui/generic.rb +24 -3
- data/lib/metro/models/ui/model_label.rb +1 -1
- data/lib/metro/models/ui/model_labeler.rb +2 -2
- data/lib/metro/models/ui/rectangle.rb +1 -1
- data/lib/metro/models/ui/sprite.rb +79 -0
- data/lib/metro/models/ui/ui.rb +12 -0
- data/lib/metro/scene.rb +13 -61
- data/lib/metro/scenes.rb +11 -13
- data/lib/metro/transitions/edit_transition_scene.rb +2 -2
- data/lib/metro/units/calculation_validations.rb +74 -0
- data/lib/metro/units/dimensions.rb +11 -19
- data/lib/metro/units/point.rb +6 -22
- data/lib/metro/units/rectangle_bounds.rb +10 -6
- data/lib/metro/units/scale.rb +7 -0
- data/lib/metro/units/units.rb +1 -0
- data/lib/metro/version.rb +1 -1
- data/lib/metro/window.rb +7 -3
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +6 -6
- data/lib/templates/game/models/hero.rb +35 -6
- data/lib/templates/model.rb.tt +1 -1
- data/spec/core_ext/string_spec.rb +0 -20
- data/spec/metro/units/point_spec.rb +132 -0
- data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
- data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
- metadata +21 -9
    
        data/lib/metro/models/ui/fps.rb
    CHANGED
    
    
| @@ -35,9 +35,30 @@ module Metro | |
| 35 35 | 
             
                  private
         | 
| 36 36 |  | 
| 37 37 | 
             
                  def cannot_draw_message
         | 
| 38 | 
            -
                     | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 38 | 
            +
                    %{Unable to draw #{name} in #{scene}
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              The actor named '#{name}' does not specify a suitable model so it could not be drawn in the scene.
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              #{properties}
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              Did you mean to use one of the following models:
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              Models defined in #{Game.name}:
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              #{user_defined_models.join(', ')}
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              Models defined in Metro:
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              #{metro_models.join(', ')}
         | 
| 53 | 
            +
            }
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def metro_models
         | 
| 57 | 
            +
                    Models.list.find_all {|m| m =~ /metro(::|\/).+(::|\/).+/i }
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def user_defined_models
         | 
| 61 | 
            +
                    Models.list - metro_models
         | 
| 41 62 | 
             
                  end
         | 
| 42 63 |  | 
| 43 64 | 
             
                end
         | 
| @@ -9,7 +9,7 @@ module Metro | |
| 9 9 | 
             
                # the bounding boxes and labeles around all the actors within the scene
         | 
| 10 10 | 
             
                # being edited.
         | 
| 11 11 | 
             
                #
         | 
| 12 | 
            -
                class ModelLabeler <  | 
| 12 | 
            +
                class ModelLabeler < Model
         | 
| 13 13 |  | 
| 14 14 | 
             
                  # @attribute
         | 
| 15 15 | 
             
                  # The color use for the border surrounding each actor and the background
         | 
| @@ -58,7 +58,7 @@ module Metro | |
| 58 58 | 
             
                      label = labels[drawer.name]
         | 
| 59 59 |  | 
| 60 60 | 
             
                      unless label
         | 
| 61 | 
            -
                        label = create "metro::ui:: | 
| 61 | 
            +
                        label = create "metro::ui::model_label", target: drawer
         | 
| 62 62 | 
             
                        labels[drawer.name] = label
         | 
| 63 63 | 
             
                      end
         | 
| 64 64 |  | 
| @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            module Metro
         | 
| 2 | 
            +
              module UI
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                #
         | 
| 5 | 
            +
                # A sprite is a Metro model that is specially designed to draw and manage
         | 
| 6 | 
            +
                # an image. A sprite maintains an image, location information, and rotation.
         | 
| 7 | 
            +
                #
         | 
| 8 | 
            +
                class Sprite < Model
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # @attribute
         | 
| 11 | 
            +
                  # The image that will be drawn for the sprite
         | 
| 12 | 
            +
                  property :image
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  # @attribute
         | 
| 15 | 
            +
                  # The point at which the sprite should be drawn
         | 
| 16 | 
            +
                  property :position
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # @attribute
         | 
| 19 | 
            +
                  # This is the color of the spirte. The color usually remains white, and
         | 
| 20 | 
            +
                  # the color property is implemented by the `alpha` value is the one thing
         | 
| 21 | 
            +
                  # that is altered to fade in and fade out the sprite.
         | 
| 22 | 
            +
                  property :color
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # @attribute
         | 
| 25 | 
            +
                  # The scale at which to draw the sprite. This is default scale of 1.
         | 
| 26 | 
            +
                  property :scale
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # @attribute
         | 
| 29 | 
            +
                  # The center, horizontal position, as expressed in a ratio, of the image.
         | 
| 30 | 
            +
                  property :center_x, type: :numeric, default: 0.5
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  # @attribute
         | 
| 33 | 
            +
                  # The center, vertical position, as expressed in a ratio, of the image.
         | 
| 34 | 
            +
                  property :center_y, type: :numeric, default: 0.5
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  # @attribute
         | 
| 37 | 
            +
                  # The angle at which the sprite should be drawn. This is by default 0.
         | 
| 38 | 
            +
                  property :angle
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  # @attribute
         | 
| 41 | 
            +
                  # The height and width of the sprite is based on the image of the sprite.
         | 
| 42 | 
            +
                  property :dimensions do
         | 
| 43 | 
            +
                    image.dimensions
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # @return [RectangleBounds] the bounds of the sprite.
         | 
| 47 | 
            +
                  def bounds
         | 
| 48 | 
            +
                    Bounds.new left: left, right: right, top: top, bottom: bottom
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  # @return [Float] the left-most x position of the sprite
         | 
| 52 | 
            +
                  def left
         | 
| 53 | 
            +
                    x - width * center_x
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  # @return [Float] the right-most x position of the sprite
         | 
| 57 | 
            +
                  def right
         | 
| 58 | 
            +
                    left + width * x_factor
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  # @return [Float] the top-most y position of the sprite
         | 
| 62 | 
            +
                  def top
         | 
| 63 | 
            +
                    y - height * center_y
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  # @return [Float] the bottom-most y position of the sprite
         | 
| 67 | 
            +
                  def bottom
         | 
| 68 | 
            +
                    top + height * y_factor
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  #
         | 
| 72 | 
            +
                  # By default the sprite will draw the image defined for it.
         | 
| 73 | 
            +
                  #
         | 
| 74 | 
            +
                  def draw
         | 
| 75 | 
            +
                    image.draw_rot x, y, z_order, angle, center_x, center_y, x_factor, y_factor, color
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require_relative 'generic'
         | 
| 2 | 
            +
            require_relative 'label'
         | 
| 3 | 
            +
            require_relative 'menu'
         | 
| 4 | 
            +
            require_relative 'image'
         | 
| 5 | 
            +
            require_relative 'rectangle'
         | 
| 6 | 
            +
            require_relative 'grid_drawer'
         | 
| 7 | 
            +
            require_relative 'border'
         | 
| 8 | 
            +
            require_relative 'model_label'
         | 
| 9 | 
            +
            require_relative 'model_labeler'
         | 
| 10 | 
            +
            require_relative 'fps'
         | 
| 11 | 
            +
            require_relative 'sprite'
         | 
| 12 | 
            +
            require_relative 'animated_sprite'
         | 
    
        data/lib/metro/scene.rb
    CHANGED
    
    | @@ -1,9 +1,5 @@ | |
| 1 1 | 
             
            require_relative 'views/scene_view'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require_relative 'events/has_events'
         | 
| 4 | 
            -
            require_relative 'events/event_relay'
         | 
| 5 | 
            -
            require_relative 'events/unknown_sender'
         | 
| 6 | 
            -
             | 
| 2 | 
            +
            require_relative 'events/events'
         | 
| 7 3 | 
             
            require_relative 'models/draws'
         | 
| 8 4 |  | 
| 9 5 | 
             
            require_relative 'animation/has_animations'
         | 
| @@ -19,7 +15,6 @@ module Metro | |
| 19 15 | 
             
              # @see #show
         | 
| 20 16 | 
             
              # @see #update
         | 
| 21 17 | 
             
              # @see #draw
         | 
| 22 | 
            -
              # @see #events
         | 
| 23 18 | 
             
              #
         | 
| 24 19 | 
             
              # A fair number of private methods within Scene are prefaced with an underscore.
         | 
| 25 20 | 
             
              # These methods often call non-underscored methods within those methods. This allows
         | 
| @@ -102,16 +97,12 @@ module Metro | |
| 102 97 | 
             
                end
         | 
| 103 98 |  | 
| 104 99 | 
             
                #
         | 
| 105 | 
            -
                # Post a custom notification event. This will trigger  | 
| 106 | 
            -
                # for  | 
| 100 | 
            +
                # Post a custom notification event. This will trigger an event for all the
         | 
| 101 | 
            +
                # objects that are registered for notification with the current state.
         | 
| 107 102 | 
             
                #
         | 
| 108 103 | 
             
                def notification(event,sender=nil)
         | 
| 109 | 
            -
             | 
| 110 104 | 
             
                  sender = sender || UnknownSender
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                  event_relays.each do |relay|
         | 
| 113 | 
            -
                    relay.fire_events_for_notification(event,sender)
         | 
| 114 | 
            -
                  end
         | 
| 105 | 
            +
                  state.fire_events_for_notification(event,sender)
         | 
| 115 106 | 
             
                end
         | 
| 116 107 |  | 
| 117 108 | 
             
                #
         | 
| @@ -203,7 +194,8 @@ module Metro | |
| 203 194 | 
             
                def window=(window)
         | 
| 204 195 | 
             
                  @window = window
         | 
| 205 196 |  | 
| 206 | 
            -
                   | 
| 197 | 
            +
                  state.window = window
         | 
| 198 | 
            +
                  state.clear
         | 
| 207 199 |  | 
| 208 200 | 
             
                  register_events!
         | 
| 209 201 | 
             
                  register_actors!
         | 
| @@ -335,11 +327,9 @@ module Metro | |
| 335 327 | 
             
                #
         | 
| 336 328 | 
             
                # Captures all classes that subclass Scene.
         | 
| 337 329 | 
             
                #
         | 
| 338 | 
            -
                # @see #self.scenes
         | 
| 339 | 
            -
                #
         | 
| 340 330 | 
             
                def self.inherited(base)
         | 
| 341 331 | 
             
                  scenes << base.to_s
         | 
| 342 | 
            -
                  Scenes. | 
| 332 | 
            +
                  Scenes.add(base)
         | 
| 343 333 | 
             
                end
         | 
| 344 334 |  | 
| 345 335 | 
             
                #
         | 
| @@ -455,58 +445,20 @@ module Metro | |
| 455 445 | 
             
                #   be mapped to the specified target.
         | 
| 456 446 | 
             
                #
         | 
| 457 447 | 
             
                def register_events_for_target(target,events)
         | 
| 458 | 
            -
                   | 
| 459 | 
            -
             | 
| 460 | 
            -
                  events.each do |target_event|
         | 
| 461 | 
            -
                    target_relay.send target_event.event, *target_event.buttons, &target_event.block
         | 
| 462 | 
            -
                  end
         | 
| 463 | 
            -
             | 
| 464 | 
            -
                  event_relays.push(target_relay)
         | 
| 448 | 
            +
                  state.add_events_for_target(target,events)
         | 
| 465 449 | 
             
                end
         | 
| 466 450 |  | 
| 467 451 | 
             
                #
         | 
| 468 | 
            -
                # The  | 
| 469 | 
            -
                # all the gamepad and keyboard events defined. By default a scene  | 
| 470 | 
            -
                #  | 
| 452 | 
            +
                # The event state manager is configured through the {#events} method, which
         | 
| 453 | 
            +
                # stores all the gamepad and keyboard events defined. By default a scene is
         | 
| 454 | 
            +
                # placed in the default state and events that are added to this basic state.
         | 
| 471 455 | 
             
                #
         | 
| 472 456 | 
             
                # @see Events
         | 
| 473 | 
            -
                # @see #add_event_relay
         | 
| 474 457 | 
             
                #
         | 
| 475 | 
            -
                def  | 
| 476 | 
            -
                  @ | 
| 458 | 
            +
                def state
         | 
| 459 | 
            +
                  @event_state_manager ||= EventStateManager.new
         | 
| 477 460 | 
             
                end
         | 
| 478 461 |  | 
| 479 | 
            -
                #
         | 
| 480 | 
            -
                # This method is called during a scene update and will fire all the events
         | 
| 481 | 
            -
                # that have been defined for all held buttons for all defined event relays.
         | 
| 482 | 
            -
                #
         | 
| 483 | 
            -
                def fire_events_for_held_buttons
         | 
| 484 | 
            -
                  event_relays.each do |relay|
         | 
| 485 | 
            -
                    relay.fire_events_for_held_buttons
         | 
| 486 | 
            -
                  end
         | 
| 487 | 
            -
                end
         | 
| 488 | 
            -
             | 
| 489 | 
            -
                #
         | 
| 490 | 
            -
                # This method is called before a scene update and passes the button up events
         | 
| 491 | 
            -
                # to each of the defined event relays.
         | 
| 492 | 
            -
                #
         | 
| 493 | 
            -
                def button_up(id)
         | 
| 494 | 
            -
                  event_relays.each do |relay|
         | 
| 495 | 
            -
                    relay.fire_button_up(id)
         | 
| 496 | 
            -
                  end
         | 
| 497 | 
            -
                end
         | 
| 498 | 
            -
             | 
| 499 | 
            -
                #
         | 
| 500 | 
            -
                # This method is called before a scene update and passes the button down events
         | 
| 501 | 
            -
                # to each of the defined event relays.
         | 
| 502 | 
            -
                #
         | 
| 503 | 
            -
                def button_down(id)
         | 
| 504 | 
            -
                  event_relays.each do |relay|
         | 
| 505 | 
            -
                    relay.fire_button_down(id)
         | 
| 506 | 
            -
                  end
         | 
| 507 | 
            -
                end
         | 
| 508 | 
            -
             | 
| 509 | 
            -
             | 
| 510 462 | 
             
                #
         | 
| 511 463 | 
             
                # A Scene represented as a hash currently only contains the drawers
         | 
| 512 464 | 
             
                #
         | 
    
        data/lib/metro/scenes.rb
    CHANGED
    
    | @@ -33,7 +33,7 @@ module Metro | |
| 33 33 | 
             
                #
         | 
| 34 34 | 
             
                # @param [Scene] scene the scene to be added to the hash of Scenes.
         | 
| 35 35 | 
             
                #
         | 
| 36 | 
            -
                def  | 
| 36 | 
            +
                def add(scene)
         | 
| 37 37 | 
             
                  all_scenes_for(scene).each { |scene| scenes_hash[scene.scene_name] = scene.to_s }
         | 
| 38 38 | 
             
                end
         | 
| 39 39 |  | 
| @@ -44,7 +44,14 @@ module Metro | |
| 44 44 | 
             
                # @return the Scene class that is found matching the specified scene name.
         | 
| 45 45 | 
             
                #
         | 
| 46 46 | 
             
                def find(scene_name)
         | 
| 47 | 
            -
                   | 
| 47 | 
            +
                  scenes_hash[scene_name].constantize
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                #
         | 
| 51 | 
            +
                # @return [Array<String>] all the names supported by the scenes hash.
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
                def list
         | 
| 54 | 
            +
                  scenes_hash.keys
         | 
| 48 55 | 
             
                end
         | 
| 49 56 |  | 
| 50 57 | 
             
                #
         | 
| @@ -119,7 +126,7 @@ module Metro | |
| 119 126 | 
             
                #
         | 
| 120 127 | 
             
                def hash_with_missing_scene_default
         | 
| 121 128 | 
             
                  hash = HashWithIndifferentAccess.new do |hash,key|
         | 
| 122 | 
            -
                    missing_scene =  | 
| 129 | 
            +
                    missing_scene = hash[:missing_scene].constantize
         | 
| 123 130 | 
             
                    missing_scene.missing_scene = key.to_sym
         | 
| 124 131 | 
             
                    missing_scene
         | 
| 125 132 | 
             
                  end
         | 
| @@ -136,20 +143,11 @@ module Metro | |
| 136 143 | 
             
                #
         | 
| 137 144 | 
             
                def all_scenes_for(scenes)
         | 
| 138 145 | 
             
                  Array(scenes).map do |scene_class_name|
         | 
| 139 | 
            -
                    scene =  | 
| 146 | 
            +
                    scene = scene_class_name.constantize
         | 
| 140 147 | 
             
                    [ scene ] + all_scenes_for(scene.scenes)
         | 
| 141 148 | 
             
                  end.flatten.compact
         | 
| 142 149 | 
             
                end
         | 
| 143 150 |  | 
| 144 | 
            -
                #
         | 
| 145 | 
            -
                # @param [String,Symbol] class_name the name of the class that you want the class
         | 
| 146 | 
            -
                #
         | 
| 147 | 
            -
                # @return the class with the given class name
         | 
| 148 | 
            -
                #
         | 
| 149 | 
            -
                def scene_class(class_or_class_name)
         | 
| 150 | 
            -
                  class_or_class_name.class == Class ? class_or_class_name : class_or_class_name.constantize
         | 
| 151 | 
            -
                end
         | 
| 152 | 
            -
             | 
| 153 151 | 
             
              end
         | 
| 154 152 | 
             
            end
         | 
| 155 153 |  | 
| @@ -28,8 +28,8 @@ module Metro | |
| 28 28 | 
             
                  # easier to dup scenes.
         | 
| 29 29 | 
             
                  #
         | 
| 30 30 | 
             
                  self.class.drawings.clear
         | 
| 31 | 
            -
                  self.class.draw :overlay, model: "metro::ui:: | 
| 32 | 
            -
                  self.class.draw :labeler, model: "metro::ui:: | 
| 31 | 
            +
                  self.class.draw :overlay, model: "metro::ui::grid_drawer"
         | 
| 32 | 
            +
                  self.class.draw :labeler, model: "metro::ui::model_labeler"
         | 
| 33 33 | 
             
                  add_actors_to_scene
         | 
| 34 34 | 
             
                  after_initialize
         | 
| 35 35 | 
             
                end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            module Metro
         | 
| 2 | 
            +
              module Units
         | 
| 3 | 
            +
                module CalculationValidations
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  #
         | 
| 6 | 
            +
                  # @param [Object] value the other object that needs to be validated.
         | 
| 7 | 
            +
                  #
         | 
| 8 | 
            +
                  def check_calculation_requirements(value)
         | 
| 9 | 
            +
                    if calculation_requirements.find { |method| ! value.respond_to?(method) }
         | 
| 10 | 
            +
                      raise "Unable to perform operation with #{value} #{value.class} It is missing a property #{calculation_requirements.join(",")}"
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  # @return [Array] an array of methods that are required to be on the
         | 
| 16 | 
            +
                  #   object for it to be correctly calculated.
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  # @note this method is intended to be defined in the including class. This
         | 
| 19 | 
            +
                  #   method is included here when one has not been provided.
         | 
| 20 | 
            +
                  def calculation_requirements
         | 
| 21 | 
            +
                    []
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # Add this object to another object.
         | 
| 26 | 
            +
                  #
         | 
| 27 | 
            +
                  # @return a new object that is the sum of the two objects
         | 
| 28 | 
            +
                  #
         | 
| 29 | 
            +
                  def +(value)
         | 
| 30 | 
            +
                    self.class.new *calculate(value,:+)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  #
         | 
| 34 | 
            +
                  # Subtract the other object from this object.
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  # @return a new object that is the difference of the original object
         | 
| 37 | 
            +
                  #   and the value specified.
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  def -(value)
         | 
| 40 | 
            +
                    self.class.new *calculate(value,:-)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  # Multiply this object and another object.
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  # @return a new object that is the product of the two objects.
         | 
| 47 | 
            +
                  #
         | 
| 48 | 
            +
                  def *(value)
         | 
| 49 | 
            +
                    self.class.new *calculate(value,:*)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  # This generic method will perform the calculation defined by the
         | 
| 54 | 
            +
                  # operation for all the calculation requirements defined.
         | 
| 55 | 
            +
                  #
         | 
| 56 | 
            +
                  # @param [value] value this is the other value that is being added,
         | 
| 57 | 
            +
                  #   subtracted, etc. to the current object.
         | 
| 58 | 
            +
                  # @param [Symbol] operation this is the mathematical operation that
         | 
| 59 | 
            +
                  #   is being performed between all the calc requirements of the current
         | 
| 60 | 
            +
                  #   object and other value.
         | 
| 61 | 
            +
                  #
         | 
| 62 | 
            +
                  # @return [Array] an array of reults from the calculations of all the
         | 
| 63 | 
            +
                  #   requirements.
         | 
| 64 | 
            +
                  #
         | 
| 65 | 
            +
                  def calculate(value,operation)
         | 
| 66 | 
            +
                    check_calculation_requirements(value)
         | 
| 67 | 
            +
                    calculation_requirements.map do |requirement|
         | 
| 68 | 
            +
                      send(requirement).send(operation,value.send(requirement))
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -5,6 +5,7 @@ module Metro | |
| 5 5 | 
             
                # Represents an object that contains both the width and height.
         | 
| 6 6 | 
             
                #
         | 
| 7 7 | 
             
                class Dimensions < Struct.new(:width,:height)
         | 
| 8 | 
            +
                  include CalculationValidations
         | 
| 8 9 |  | 
| 9 10 | 
             
                  #
         | 
| 10 11 | 
             
                  # Create a dimensions objects with zero width and zero height.
         | 
| @@ -37,30 +38,21 @@ module Metro | |
| 37 38 | 
             
                  end
         | 
| 38 39 |  | 
| 39 40 | 
             
                  #
         | 
| 40 | 
            -
                  #  | 
| 41 | 
            -
                  # dimensions like structure is anything that responds to width and height.
         | 
| 41 | 
            +
                  # Compare the dimension to another dimensions-like structure.
         | 
| 42 42 | 
             
                  #
         | 
| 43 | 
            -
                  # @return  | 
| 43 | 
            +
                  # @return [Fixnum] -1 if the dimensions is smaller than the other dimension,
         | 
| 44 | 
            +
                  #   0 if the dimensions are exactly the same, 1 if the dimensions are bigger
         | 
| 45 | 
            +
                  #   then the other dimensions.
         | 
| 44 46 | 
             
                  #
         | 
| 45 | 
            -
                  def  | 
| 46 | 
            -
                     | 
| 47 | 
            -
                     | 
| 47 | 
            +
                  def <=>(value)
         | 
| 48 | 
            +
                    check_calculation_requirements(value)
         | 
| 49 | 
            +
                    (width * height) <=> (value.width * value.height)
         | 
| 48 50 | 
             
                  end
         | 
| 49 51 |  | 
| 50 | 
            -
                   | 
| 51 | 
            -
                  # Subtract the dimensions-like structure from this dimension. A
         | 
| 52 | 
            -
                  # dimensions like structure is anything that responds to width and height.
         | 
| 53 | 
            -
                  #
         | 
| 54 | 
            -
                  # @return a new dimensions which is the different of the two dimensions
         | 
| 55 | 
            -
                  #
         | 
| 56 | 
            -
                  def -(value)
         | 
| 57 | 
            -
                    raise "Unable to subtract from these dimensions with #{value} #{value.class}" if [ :width, :height ].find { |method| ! value.respond_to?(method) }
         | 
| 58 | 
            -
                    self.class.of (width - value.width.to_f), (height - value.height.to_f)
         | 
| 59 | 
            -
                  end
         | 
| 52 | 
            +
                  private
         | 
| 60 53 |  | 
| 61 | 
            -
                  def  | 
| 62 | 
            -
                     | 
| 63 | 
            -
                    (width * height) <=> (value.width * value.height)
         | 
| 54 | 
            +
                  def calculation_requirements
         | 
| 55 | 
            +
                    [ :width, :height ]
         | 
| 64 56 | 
             
                  end
         | 
| 65 57 |  | 
| 66 58 | 
             
                end
         |