metro-ld26 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +14 -0
- data/Guardfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +177 -0
- data/Rakefile +18 -0
- data/bin/metro +16 -0
- data/changelog.md +153 -0
- data/lib/assets/menu-movement.wav +0 -0
- data/lib/assets/menu-selection.wav +0 -0
- data/lib/assets/missing.ogg +0 -0
- data/lib/assets/missing.png +0 -0
- data/lib/assets/missing.wav +0 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_game.rb +13 -0
- data/lib/commands/generate_model.rb +25 -0
- data/lib/commands/generate_scene.rb +36 -0
- data/lib/commands/generate_view.rb +21 -0
- data/lib/commands/thor.rb +83 -0
- data/lib/core_ext/class.rb +14 -0
- data/lib/core_ext/numeric.rb +59 -0
- data/lib/gosu_ext/color.rb +62 -0
- data/lib/gosu_ext/gosu_constants.rb +53 -0
- data/lib/locale/en.yml +35 -0
- data/lib/locale/locale.rb +1 -0
- data/lib/metro.rb +144 -0
- data/lib/metro/animation.rb +135 -0
- data/lib/metro/animation/after_interval_factory.rb +12 -0
- data/lib/metro/animation/animation_factory.rb +15 -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 +70 -0
- data/lib/metro/animation/implicit_animation.rb +100 -0
- data/lib/metro/animation/on_update_operation.rb +96 -0
- data/lib/metro/animation/scene_animation.rb +16 -0
- data/lib/metro/asset_path.rb +97 -0
- data/lib/metro/events/control_definition.rb +11 -0
- data/lib/metro/events/controls.rb +42 -0
- data/lib/metro/events/event_data.rb +60 -0
- data/lib/metro/events/event_dictionary.rb +52 -0
- data/lib/metro/events/event_factory.rb +17 -0
- data/lib/metro/events/event_relay.rb +342 -0
- data/lib/metro/events/event_state_manager.rb +70 -0
- data/lib/metro/events/events.rb +3 -0
- data/lib/metro/events/has_events.rb +108 -0
- data/lib/metro/events/hit_list.rb +75 -0
- data/lib/metro/events/unknown_sender.rb +5 -0
- data/lib/metro/font.rb +69 -0
- data/lib/metro/game.rb +102 -0
- data/lib/metro/game/dsl.rb +68 -0
- data/lib/metro/image.rb +75 -0
- data/lib/metro/logging.rb +33 -0
- data/lib/metro/missing_scene.rb +21 -0
- data/lib/metro/models/audio/song.rb +33 -0
- data/lib/metro/models/draws.rb +86 -0
- data/lib/metro/models/key_value_coding.rb +38 -0
- data/lib/metro/models/model.rb +246 -0
- data/lib/metro/models/model_factory.rb +32 -0
- data/lib/metro/models/models.rb +62 -0
- data/lib/metro/models/properties/animation_property.rb +115 -0
- data/lib/metro/models/properties/array_property.rb +24 -0
- data/lib/metro/models/properties/boolean_property.rb +27 -0
- data/lib/metro/models/properties/color_property.rb +116 -0
- data/lib/metro/models/properties/dimensions_property.rb +84 -0
- data/lib/metro/models/properties/font_property.rb +130 -0
- data/lib/metro/models/properties/image_property.rb +96 -0
- data/lib/metro/models/properties/model_property.rb +84 -0
- data/lib/metro/models/properties/numeric_property.rb +29 -0
- data/lib/metro/models/properties/options_property/no_option.rb +29 -0
- data/lib/metro/models/properties/options_property/options.rb +98 -0
- data/lib/metro/models/properties/options_property/options_property.rb +125 -0
- data/lib/metro/models/properties/position_property.rb +90 -0
- data/lib/metro/models/properties/property.rb +221 -0
- data/lib/metro/models/properties/property_owner.rb +137 -0
- data/lib/metro/models/properties/sample_property.rb +84 -0
- data/lib/metro/models/properties/scale_property.rb +80 -0
- data/lib/metro/models/properties/song_property.rb +89 -0
- data/lib/metro/models/properties/text_property.rb +75 -0
- data/lib/metro/models/ui/animated_sprite.rb +85 -0
- data/lib/metro/models/ui/border.rb +95 -0
- data/lib/metro/models/ui/fps.rb +54 -0
- data/lib/metro/models/ui/generic.rb +66 -0
- data/lib/metro/models/ui/grid_drawer.rb +74 -0
- data/lib/metro/models/ui/image.rb +87 -0
- data/lib/metro/models/ui/label.rb +175 -0
- data/lib/metro/models/ui/menu.rb +214 -0
- data/lib/metro/models/ui/model_label.rb +65 -0
- data/lib/metro/models/ui/model_labeler.rb +79 -0
- data/lib/metro/models/ui/rectangle.rb +59 -0
- data/lib/metro/models/ui/sprite.rb +79 -0
- data/lib/metro/models/ui/tile_map.rb +132 -0
- data/lib/metro/models/ui/tmx/isometric_position.rb +43 -0
- data/lib/metro/models/ui/tmx/orthogonal_position.rb +15 -0
- data/lib/metro/models/ui/tmx/tile_layer.rb +78 -0
- data/lib/metro/models/ui/ui.rb +13 -0
- data/lib/metro/parameters/command_line_args_parser.rb +68 -0
- data/lib/metro/parameters/options.rb +25 -0
- data/lib/metro/parameters/parameters.rb +2 -0
- data/lib/metro/sample.rb +40 -0
- data/lib/metro/scene.rb +478 -0
- data/lib/metro/scenes.rb +154 -0
- data/lib/metro/song.rb +56 -0
- data/lib/metro/template_message.rb +60 -0
- data/lib/metro/transitions/edit_transition_scene.rb +100 -0
- data/lib/metro/transitions/fade_transition_scene.rb +66 -0
- data/lib/metro/transitions/scene_transitions.rb +44 -0
- data/lib/metro/transitions/transition_scene.rb +19 -0
- data/lib/metro/units/bounds.rb +8 -0
- data/lib/metro/units/calculation_validations.rb +74 -0
- data/lib/metro/units/dimensions.rb +60 -0
- data/lib/metro/units/point.rb +51 -0
- data/lib/metro/units/rectangle_bounds.rb +148 -0
- data/lib/metro/units/scale.rb +46 -0
- data/lib/metro/units/units.rb +6 -0
- data/lib/metro/version.rb +32 -0
- data/lib/metro/views/json_view.rb +60 -0
- data/lib/metro/views/no_view.rb +34 -0
- data/lib/metro/views/parsers.rb +42 -0
- data/lib/metro/views/scene_view.rb +107 -0
- data/lib/metro/views/view.rb +133 -0
- data/lib/metro/views/writers.rb +43 -0
- data/lib/metro/views/yaml_view.rb +94 -0
- data/lib/metro/window.rb +95 -0
- data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
- data/lib/setup_handlers/game_execution.rb +65 -0
- data/lib/setup_handlers/load_game_configuration.rb +65 -0
- data/lib/setup_handlers/load_game_files.rb +101 -0
- data/lib/setup_handlers/move_to_game_directory.rb +25 -0
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
- data/lib/templates/game/README.md.tt +43 -0
- data/lib/templates/game/assets/brand.jpg +0 -0
- data/lib/templates/game/assets/hero.png +0 -0
- data/lib/templates/game/lib/custom_easing.rb +32 -0
- data/lib/templates/game/metro.tt +63 -0
- data/lib/templates/game/models/hero.rb +62 -0
- data/lib/templates/game/scenes/brand_scene.rb +19 -0
- data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
- data/lib/templates/game/scenes/first_scene.rb +28 -0
- data/lib/templates/game/scenes/game_scene.rb +43 -0
- data/lib/templates/game/scenes/title_scene.rb +15 -0
- data/lib/templates/game/views/brand.yaml +4 -0
- data/lib/templates/game/views/brand_to_title.yaml +8 -0
- data/lib/templates/game/views/first.yaml +26 -0
- data/lib/templates/game/views/title.yaml +11 -0
- data/lib/templates/message.erb +23 -0
- data/lib/templates/model.rb.tt +111 -0
- data/lib/templates/scene.rb.tt +140 -0
- data/lib/templates/view.yaml.tt +11 -0
- data/lib/tmx_ext/object.rb +26 -0
- data/lib/tmx_ext/tile_set.rb +41 -0
- data/metro.gemspec +57 -0
- data/metro.png +0 -0
- data/spec/core_ext/numeric_spec.rb +78 -0
- data/spec/core_ext/string_spec.rb +33 -0
- data/spec/gosu_ext/color_spec.rb +80 -0
- data/spec/metro/image_spec.rb +33 -0
- data/spec/metro/models/key_value_coding_spec.rb +61 -0
- data/spec/metro/models/properties/array_property_spec.rb +60 -0
- data/spec/metro/models/properties/color_property_spec.rb +85 -0
- data/spec/metro/models/properties/dimensions_spec.rb +29 -0
- data/spec/metro/models/properties/font_property_spec.rb +127 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
- data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
- data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/models/ui/label_spec.rb +259 -0
- data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
- data/spec/metro/scene_spec.rb +15 -0
- data/spec/metro/scene_views/json_view_spec.rb +27 -0
- data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
- data/spec/metro/scenes_spec.rb +77 -0
- data/spec/metro/units/point_spec.rb +132 -0
- data/spec/metro/units/rectangle_bounds_spec.rb +56 -0
- data/spec/metro/views/view_spec.rb +53 -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
- data/spec/spec_helper.rb +20 -0
- data/spec/tmx_ext/object_spec.rb +96 -0
- data/spec/tmx_ext/tile_set_spec.rb +24 -0
- metadata +379 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module Views
|
5
|
+
|
6
|
+
#
|
7
|
+
# Provides support for a JSON Representation of a view.
|
8
|
+
#
|
9
|
+
class JSONView
|
10
|
+
|
11
|
+
#
|
12
|
+
# Determine if a view exists for this specified format
|
13
|
+
#
|
14
|
+
# @param [String] view_path the name of the view to find
|
15
|
+
# @return a true if the json view exists and false if it does not exist.
|
16
|
+
#
|
17
|
+
def self.exists?(view_path)
|
18
|
+
File.exists? json_view_path(view_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Parse the contents of the view given the name.
|
23
|
+
#
|
24
|
+
# @param [String] view_path the name of the view to read
|
25
|
+
# @return a Hash that contains the contents of the view.
|
26
|
+
#
|
27
|
+
def self.parse(view_path)
|
28
|
+
JSON.parse File.read json_view_path(view_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# @return the file type format of this view.
|
33
|
+
#
|
34
|
+
def self.format
|
35
|
+
:json
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Writes the content out to the spcified view path
|
40
|
+
#
|
41
|
+
def self.write(view_path,content)
|
42
|
+
filename = json_view_path(view_path)
|
43
|
+
json_content = JSON.pretty_generate(content)
|
44
|
+
File.write(filename,json_content)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
#
|
50
|
+
# A helper method to generate the name of the json view file. In this case
|
51
|
+
# it is the view name with the suffix .json.
|
52
|
+
#
|
53
|
+
def self.json_view_path(view_path)
|
54
|
+
File.extname(view_path) == "" ? "#{view_path}.json" : view_path
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Metro
|
2
|
+
module Views
|
3
|
+
|
4
|
+
class NoView
|
5
|
+
|
6
|
+
#
|
7
|
+
# A NoView is a last resort view which means this is will always will exist.
|
8
|
+
#
|
9
|
+
# @param [String] view_path the name of the view to find
|
10
|
+
# @return a true all the time as this is the last resort format.
|
11
|
+
#
|
12
|
+
def self.exists?(view_path)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# A NoView will return an empty Hash to provide compatibility with other view
|
18
|
+
# types.
|
19
|
+
#
|
20
|
+
def self.parse(view_path)
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# @return the file type format of this view.
|
26
|
+
#
|
27
|
+
def self.format
|
28
|
+
:none
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'yaml_view'
|
2
|
+
require_relative 'json_view'
|
3
|
+
require_relative 'no_view'
|
4
|
+
|
5
|
+
module Metro
|
6
|
+
module Views
|
7
|
+
|
8
|
+
module Parsers
|
9
|
+
extend self
|
10
|
+
|
11
|
+
#
|
12
|
+
# Register a view parser.
|
13
|
+
#
|
14
|
+
# A parser is any class or instance that responds to #exists?(view_path),
|
15
|
+
# #parse(view_path) and #format.
|
16
|
+
#
|
17
|
+
# @param [Parser] parser the parser to add to the list of available parsers.
|
18
|
+
#
|
19
|
+
def register(parser)
|
20
|
+
parsers.push parser
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# @return [Array<Parsers>] an array of all the registered view parsers. The
|
25
|
+
# last parser is the NoView parser.
|
26
|
+
#
|
27
|
+
def parsers
|
28
|
+
@parsers ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def parsers_with_no_view_fallback
|
32
|
+
parsers + [ NoView ]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
Parsers.register YAMLView
|
38
|
+
Parsers.register JSONView
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative 'view'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
|
5
|
+
#
|
6
|
+
# SceneView provides support for a Scene to have a view as well as giving
|
7
|
+
# additional tools to also help draw that view.
|
8
|
+
#
|
9
|
+
module SceneView
|
10
|
+
|
11
|
+
#
|
12
|
+
# A Scene by default uses the name of the Scene to find it's associated
|
13
|
+
# view.
|
14
|
+
#
|
15
|
+
# @example Standard View Name
|
16
|
+
#
|
17
|
+
# class OpeningScene < Metro::Scene
|
18
|
+
#
|
19
|
+
# def show
|
20
|
+
# puts "View Brought To You By: #{view_name} # => View Brought To You By opening
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# @example Custom View Name
|
25
|
+
#
|
26
|
+
# class ClosingScene < Metro::Scene
|
27
|
+
# view_name 'alternative'
|
28
|
+
#
|
29
|
+
# def show
|
30
|
+
# puts "View Brought To You By: #{view_name} # => View Brought To You By alternative
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
def view_name
|
35
|
+
self.class.view_name
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# @return the view for this scene.
|
40
|
+
#
|
41
|
+
def view
|
42
|
+
self.class.view
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Loads and caches the view content based on the avilable view parsers and
|
47
|
+
# the view files defined.
|
48
|
+
#
|
49
|
+
# @return the content contained within the view
|
50
|
+
#
|
51
|
+
def view_content
|
52
|
+
view.content
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Saves the current content of the view back through the view's writer
|
57
|
+
#
|
58
|
+
def save_view
|
59
|
+
view.content = self.to_hash
|
60
|
+
view.save
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# When the module is included insure that all the class helper methods are added
|
65
|
+
# at the same time.
|
66
|
+
#
|
67
|
+
def self.included(base)
|
68
|
+
base.extend ClassMethods
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
|
73
|
+
#
|
74
|
+
# A Scene by default uses the name of the Scene to find it's associated
|
75
|
+
# view.
|
76
|
+
#
|
77
|
+
# @example Custom View Name
|
78
|
+
#
|
79
|
+
# class ClosingScene < Metro::Scene
|
80
|
+
# view_name 'alternative'
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# ClosingScene.view_name # => views/alternative
|
84
|
+
#
|
85
|
+
def view_name(name = nil)
|
86
|
+
name ? view.name = name : view.name
|
87
|
+
view.name
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Loads and caches the view content based on the avilable view parsers and
|
92
|
+
# the view files defined.
|
93
|
+
#
|
94
|
+
# @return a view object
|
95
|
+
#
|
96
|
+
def view
|
97
|
+
@view ||=begin
|
98
|
+
view = View.new
|
99
|
+
view.name = scene_name
|
100
|
+
view
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require_relative 'parsers'
|
2
|
+
require_relative 'writers'
|
3
|
+
|
4
|
+
module Metro
|
5
|
+
|
6
|
+
#
|
7
|
+
# A view represents the representation of the content found within
|
8
|
+
# the view file. A view has the ability to save/load the content
|
9
|
+
# as well.
|
10
|
+
#
|
11
|
+
class View
|
12
|
+
|
13
|
+
#
|
14
|
+
# The name of the view, which is used to influence the file path.
|
15
|
+
#
|
16
|
+
attr_accessor :name
|
17
|
+
|
18
|
+
#
|
19
|
+
# The content contained within the view.
|
20
|
+
#
|
21
|
+
def content
|
22
|
+
@content ||= begin
|
23
|
+
parsed_content = parse
|
24
|
+
parsed_content.default = {}
|
25
|
+
parsed_content
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Set the content of the view.
|
31
|
+
#
|
32
|
+
# @param [Hash] value the hash content that will represent this view
|
33
|
+
#
|
34
|
+
def content=(value)
|
35
|
+
value.default = {}
|
36
|
+
@content = value
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# A Scene view path is based on the view name.
|
41
|
+
#
|
42
|
+
# @example Standard View Path
|
43
|
+
#
|
44
|
+
# class OpeningScene < Metro::Scene
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# OpeniningScene.view_path # => views/opening
|
48
|
+
#
|
49
|
+
# @example Custom View Path
|
50
|
+
#
|
51
|
+
# class ClosingScene < Metro::Scene
|
52
|
+
# view_name 'alternative'
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# ClosingScene.view_path # => views/alternative
|
56
|
+
#
|
57
|
+
def view_path
|
58
|
+
File.join "views", name
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Parse the content found at the view path for the view.
|
63
|
+
#
|
64
|
+
# @return the hash of content stored within the view file.
|
65
|
+
#
|
66
|
+
def parse
|
67
|
+
parser.parse(view_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# The parser for this view is one of the supported parsers. A parser
|
72
|
+
# is selected if the parser is capable of finding the content to
|
73
|
+
# load.
|
74
|
+
#
|
75
|
+
def parser
|
76
|
+
@parser ||= supported_parsers.find { |parser| parser.exists? view_path }
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Supported view formats
|
81
|
+
#
|
82
|
+
def supported_parsers
|
83
|
+
Views::Parsers.parsers_with_no_view_fallback
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Ask the parser to save the current content of the view at the view path
|
88
|
+
#
|
89
|
+
def save
|
90
|
+
writer.write(view_path,content)
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Return the format of the view. By default the format of the view is dictated
|
95
|
+
# by the format of the content that is parsed.
|
96
|
+
#
|
97
|
+
def format
|
98
|
+
@format || parser.format
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Setting the format allows the view to be changed from the current format as
|
103
|
+
# dictated what is parsed by the parser.
|
104
|
+
#
|
105
|
+
# This is mostly to benefit the edit transition scene which inherits all the view
|
106
|
+
# related data from the scene that is being edited but does not inherit the
|
107
|
+
# the view (which would have the parser).
|
108
|
+
#
|
109
|
+
# @see EditTransitionScene
|
110
|
+
#
|
111
|
+
attr_writer :format
|
112
|
+
|
113
|
+
#
|
114
|
+
# The writer for this view. If the view has already been parsed then use
|
115
|
+
#
|
116
|
+
def writer
|
117
|
+
@writer ||= begin
|
118
|
+
writer_matching_existing_parser = supported_writers.find { |writer| writer.format == format }
|
119
|
+
writer_matching_existing_parser || default_writer
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def supported_writers
|
124
|
+
Views::Writers.writers
|
125
|
+
end
|
126
|
+
|
127
|
+
def default_writer
|
128
|
+
Views::Writers.default_writer
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'yaml_view'
|
2
|
+
require_relative 'json_view'
|
3
|
+
|
4
|
+
module Metro
|
5
|
+
module Views
|
6
|
+
|
7
|
+
module Writers
|
8
|
+
extend self
|
9
|
+
|
10
|
+
#
|
11
|
+
# Register a view writer
|
12
|
+
#
|
13
|
+
# A writer is any class or instance that responds to #write(view_path,content),
|
14
|
+
# and #format.
|
15
|
+
#
|
16
|
+
# @param [Writer] writer the writer to add to the list of available writers..
|
17
|
+
#
|
18
|
+
def register(writer)
|
19
|
+
writers.push writer
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# @return [Array<Writers>] an array of all the registered view writers.
|
24
|
+
#
|
25
|
+
def writers
|
26
|
+
@writers ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# The default view writer, this is the one that will be used if no view
|
31
|
+
# can be found by the writers.
|
32
|
+
#
|
33
|
+
attr_accessor :default_writer
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
Writers.register YAMLView
|
38
|
+
Writers.register JSONView
|
39
|
+
Writers.default_writer = YAMLView
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module Views
|
5
|
+
|
6
|
+
class YAMLView
|
7
|
+
|
8
|
+
#
|
9
|
+
# Determine if a view exists for this specified format
|
10
|
+
#
|
11
|
+
# @param [String] view_path the name of the view to find
|
12
|
+
# @return a true if the yaml view exists and false if it does not exist.
|
13
|
+
#
|
14
|
+
def self.exists?(view_path)
|
15
|
+
yaml_view_paths(view_path).find { |view_path| File.exists? view_path }
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Parse the contents of the view given the name.
|
20
|
+
#
|
21
|
+
# @param [String] view_path the name of the view to read
|
22
|
+
# @return a Hash that contains the contents of the view.
|
23
|
+
#
|
24
|
+
def self.parse(view_path)
|
25
|
+
YAML.load(File.read(yaml_view_path(view_path))) or { }
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# @return the file type format of this view.
|
30
|
+
#
|
31
|
+
def self.format
|
32
|
+
:yaml
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# @param [String] view_path the file path to the view which to save the content
|
37
|
+
# @param [Hash] content the content to save within the view
|
38
|
+
#
|
39
|
+
def self.write(view_path,content)
|
40
|
+
filename = write_filepath(view_path)
|
41
|
+
yaml_content = content.to_yaml
|
42
|
+
File.write(filename,yaml_content)
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# @return the default extension to use when saving yaml files.
|
47
|
+
#
|
48
|
+
def self.default_extname
|
49
|
+
@default_extname || ".yaml"
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Set the default extname
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
#
|
57
|
+
# Metro::Views::YAMLView.default_extname = ".yml"
|
58
|
+
#
|
59
|
+
def self.default_extname=(value)
|
60
|
+
@default_extname = value
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
#
|
66
|
+
# If a file already exists with .yaml or .yml use that extension. Otherwise, we
|
67
|
+
# will fall back to the default extension name.
|
68
|
+
#
|
69
|
+
def self.write_filepath(view_path)
|
70
|
+
if existing_file = exists?(view_path)
|
71
|
+
existing_file
|
72
|
+
else
|
73
|
+
"#{view_path}#{default_extname}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# A helper method to get the view file.
|
79
|
+
#
|
80
|
+
def self.yaml_view_path(view_path)
|
81
|
+
yaml_view_paths(view_path).find { |view_path| File.exists? view_path }
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# A helper method to generate the name of the yaml view file. In this case
|
86
|
+
# it is the view name with the suffix `.yaml` or `.yml`.
|
87
|
+
#
|
88
|
+
def self.yaml_view_paths(view_path)
|
89
|
+
File.extname(view_path) == "" ? [ "#{view_path}.yaml", "#{view_path}.yml" ] : [ view_path ]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|