tyrano_dsl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +290 -0
  8. data/Rakefile +10 -0
  9. data/bin/setup +8 -0
  10. data/bin/tyrano_dsl.rb +21 -0
  11. data/lib/tyrano_dsl/elements/background.rb +31 -0
  12. data/lib/tyrano_dsl/elements/character.rb +49 -0
  13. data/lib/tyrano_dsl/elements/elements_module.rb +7 -0
  14. data/lib/tyrano_dsl/elements/jump_target.rb +18 -0
  15. data/lib/tyrano_dsl/elements/label.rb +19 -0
  16. data/lib/tyrano_dsl/elements/scene.rb +21 -0
  17. data/lib/tyrano_dsl/elements/stance.rb +26 -0
  18. data/lib/tyrano_dsl/elements/title_screen.rb +16 -0
  19. data/lib/tyrano_dsl/elements/variable.rb +22 -0
  20. data/lib/tyrano_dsl/elements/world.rb +62 -0
  21. data/lib/tyrano_dsl/elements_writers/background_writer.rb +30 -0
  22. data/lib/tyrano_dsl/elements_writers/character_writer.rb +32 -0
  23. data/lib/tyrano_dsl/elements_writers/characters_writer.rb +43 -0
  24. data/lib/tyrano_dsl/elements_writers/elements_writers_module.rb +27 -0
  25. data/lib/tyrano_dsl/elements_writers/scene_writer.rb +30 -0
  26. data/lib/tyrano_dsl/elements_writers/title_screen_writer.rb +87 -0
  27. data/lib/tyrano_dsl/elements_writers/variables_writer.rb +30 -0
  28. data/lib/tyrano_dsl/file_actions/clear_directory.rb +34 -0
  29. data/lib/tyrano_dsl/file_actions/create_file.rb +33 -0
  30. data/lib/tyrano_dsl/file_actions/file_copy.rb +36 -0
  31. data/lib/tyrano_dsl/file_actions/files_actions_module.rb +28 -0
  32. data/lib/tyrano_dsl/file_actions/json_patch.rb +47 -0
  33. data/lib/tyrano_dsl/main.rb +18 -0
  34. data/lib/tyrano_dsl/parsed_word.rb +22 -0
  35. data/lib/tyrano_dsl/parser.rb +58 -0
  36. data/lib/tyrano_dsl/parsing_context.rb +18 -0
  37. data/lib/tyrano_dsl/parsing_words/ask_question.rb +32 -0
  38. data/lib/tyrano_dsl/parsing_words/conditional_jump.rb +42 -0
  39. data/lib/tyrano_dsl/parsing_words/declare_background.rb +32 -0
  40. data/lib/tyrano_dsl/parsing_words/declare_character.rb +38 -0
  41. data/lib/tyrano_dsl/parsing_words/declare_label.rb +20 -0
  42. data/lib/tyrano_dsl/parsing_words/declare_variable.rb +30 -0
  43. data/lib/tyrano_dsl/parsing_words/display_text.rb +22 -0
  44. data/lib/tyrano_dsl/parsing_words/hide_character.rb +20 -0
  45. data/lib/tyrano_dsl/parsing_words/hide_message_window.rb +16 -0
  46. data/lib/tyrano_dsl/parsing_words/include_file.rb +26 -0
  47. data/lib/tyrano_dsl/parsing_words/jump.rb +22 -0
  48. data/lib/tyrano_dsl/parsing_words/parsing_words_module.rb +72 -0
  49. data/lib/tyrano_dsl/parsing_words/set_background.rb +21 -0
  50. data/lib/tyrano_dsl/parsing_words/set_character_stance.rb +23 -0
  51. data/lib/tyrano_dsl/parsing_words/set_title_screen_background.rb +25 -0
  52. data/lib/tyrano_dsl/parsing_words/show_character.rb +26 -0
  53. data/lib/tyrano_dsl/parsing_words/show_message_window.rb +16 -0
  54. data/lib/tyrano_dsl/parsing_words/start_scene.rb +30 -0
  55. data/lib/tyrano_dsl/parsing_words/update_variable.rb +37 -0
  56. data/lib/tyrano_dsl/tyrano_dsl.rb +3 -0
  57. data/lib/tyrano_dsl/tyrano_exception.rb +6 -0
  58. data/lib/tyrano_dsl/vocabulary.rb +84 -0
  59. data/lib/tyrano_dsl/writer.rb +114 -0
  60. data/lib/tyrano_dsl/writing_context.rb +123 -0
  61. data/lib/tyrano_dsl/writing_words/ask_question.rb +28 -0
  62. data/lib/tyrano_dsl/writing_words/conditional_jump.rb +37 -0
  63. data/lib/tyrano_dsl/writing_words/declare_background.rb +5 -0
  64. data/lib/tyrano_dsl/writing_words/declare_character.rb +5 -0
  65. data/lib/tyrano_dsl/writing_words/declare_label.rb +18 -0
  66. data/lib/tyrano_dsl/writing_words/declare_variable.rb +5 -0
  67. data/lib/tyrano_dsl/writing_words/display_text.rb +16 -0
  68. data/lib/tyrano_dsl/writing_words/hide_character.rb +13 -0
  69. data/lib/tyrano_dsl/writing_words/hide_message_window.rb +12 -0
  70. data/lib/tyrano_dsl/writing_words/include_file.rb +5 -0
  71. data/lib/tyrano_dsl/writing_words/jump.rb +18 -0
  72. data/lib/tyrano_dsl/writing_words/nop.rb +8 -0
  73. data/lib/tyrano_dsl/writing_words/set_background.rb +18 -0
  74. data/lib/tyrano_dsl/writing_words/set_character_stance.rb +20 -0
  75. data/lib/tyrano_dsl/writing_words/set_title_screen_background.rb +4 -0
  76. data/lib/tyrano_dsl/writing_words/show_character.rb +31 -0
  77. data/lib/tyrano_dsl/writing_words/show_message_window.rb +12 -0
  78. data/lib/tyrano_dsl/writing_words/start_scene.rb +9 -0
  79. data/lib/tyrano_dsl/writing_words/update_variable.rb +28 -0
  80. data/lib/tyrano_dsl/writing_words/writing_words_module.rb +43 -0
  81. data/tyrano_dsl.gemspec +37 -0
  82. metadata +210 -0
@@ -0,0 +1,87 @@
1
+ require_relative '../file_actions/create_file'
2
+ require_relative 'elements_writers_module'
3
+
4
+ # Write the title screen
5
+ class TyranoDsl::ElementsWriters::TitleScreenWriter
6
+
7
+ include TyranoDsl::ElementsWriters::ElementsWritersModule
8
+
9
+ # @param [TyranoDsl::Elements::World] world
10
+ # @return [Array]
11
+ def write(world)
12
+ log {'Writing title screen'}
13
+ background = get_background(world)
14
+ first_scene = get_first_scene(world)
15
+
16
+ content_text_content = title_screen_content(background, first_scene)
17
+ preload_text_content = preload_text([background.target_long_file_name])
18
+ [
19
+ TyranoDsl::FileActions::CreateFile.new(
20
+ File.join('data', 'scenario', "title_screen.ks"),
21
+ content_text_content
22
+ ),
23
+ TyranoDsl::FileActions::CreateFile.new(
24
+ File.join('data', 'scenario', 'system', "_title_screen.ks"),
25
+ preload_text_content
26
+ )
27
+
28
+ ]
29
+ end
30
+
31
+ private
32
+
33
+ # @param [TyranoDsl::Elements::Background] background
34
+ # @param [TyranoDsl::Elements::Scene] first_scene
35
+ def title_screen_content(background, first_scene)
36
+ <<HEREDOC
37
+ [_tb_system_call storage=system/_title_screen.ks]
38
+
39
+ [hidemenubutton]
40
+
41
+ [tb_keyconfig flag="0" ]
42
+ [tb_hide_message_window ]
43
+ [bg storage="#{background.target_short_file_name}" ]
44
+ *title
45
+
46
+ [glink text="New&nbsp;Game" x="600" y="370" target="*start" ]
47
+ [glink text="Load&nbsp;Game" x="600" y="470" target="*load" ]
48
+ [s ]
49
+ *start
50
+
51
+ [showmenubutton]
52
+
53
+ [cm ]
54
+ [tb_keyconfig flag="1" ]
55
+ [jump storage="#{first_scene.target_name}.ks" target="" ]
56
+ [s ]
57
+ *load
58
+
59
+ [cm ]
60
+ [showload]
61
+
62
+ [jump target="*title" storage="" ]
63
+ [s ]
64
+ HEREDOC
65
+ end
66
+
67
+ # @param [TyranoDsl::Elements::World] world
68
+ # @return [TyranoDsl::Elements::Scene]
69
+ def get_first_scene(world)
70
+ first_scene_name = world.title_screen.first_scene_name
71
+ unless first_scene_name
72
+ raise TyranoDsl::TyranoException, 'No scene defined'
73
+ end
74
+ world.scenes[first_scene_name]
75
+ end
76
+
77
+ # @param [TyranoDsl::Elements::World] world
78
+ # @return [TyranoDsl::Elements::Background]
79
+ def get_background(world)
80
+ background_name = world.title_screen.background
81
+ unless background_name
82
+ raise TyranoDsl::TyranoException, 'No background defined for the title screen'
83
+ end
84
+ world.backgrounds[background_name]
85
+ end
86
+
87
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../elements/variable'
2
+ require_relative '../file_actions/json_patch'
3
+ require_relative 'elements_writers_module'
4
+
5
+ # Write a variable
6
+ class TyranoDsl::ElementsWriters::VariablesWriter
7
+
8
+ include TyranoDsl::ElementsWriters::ElementsWritersModule
9
+
10
+ # @param [TyranoDsl::Elements::World] world
11
+ # @return [Array]
12
+ def write(world)
13
+ log {'Writing variables'}
14
+ variable_content = {}
15
+ world.variables.values.each do |variable|
16
+ variable_content[variable.target_name] = {
17
+ :val => variable.initial_value,
18
+ :kind => 'f'
19
+ }
20
+ end
21
+ [
22
+ TyranoDsl::FileActions::JsonPatch.new(
23
+ 'builder_config.json',
24
+ ['map_var'],
25
+ variable_content
26
+ )
27
+ ]
28
+ end
29
+
30
+ end
@@ -0,0 +1,34 @@
1
+ require 'fileutils'
2
+
3
+ require_relative 'files_actions_module'
4
+
5
+ # Remove all files from a directory
6
+
7
+ class TyranoDsl::FileActions::ClearDirectory
8
+
9
+ include TyranoDsl::FileActions::FileActionsModule
10
+
11
+ # @return [String]
12
+ attr_reader :path
13
+
14
+ # @param [String] path
15
+ def initialize(path)
16
+ @path = path
17
+ log {to_s}
18
+ end
19
+
20
+ # @param [String] tyrano_project_path
21
+ def run(tyrano_project_path)
22
+ full_path = File.join(tyrano_project_path, path)
23
+ log {"Cleaning [#{full_path}]"}
24
+ if File.exists? full_path
25
+ FileUtils.remove_entry full_path
26
+ end
27
+ FileUtils.mkdir_p full_path
28
+ end
29
+
30
+ def to_s
31
+ "Clear directory [#{path}]"
32
+ end
33
+
34
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'files_actions_module'
2
+
3
+ # Create a file with a custom content
4
+ class TyranoDsl::FileActions::CreateFile
5
+
6
+ include TyranoDsl::FileActions::FileActionsModule
7
+
8
+ # @return [String]
9
+ attr_reader :content
10
+ # @return [String]
11
+ attr_reader :path
12
+
13
+ # @param [String] path
14
+ # @param [String] content
15
+ def initialize(path, content)
16
+ @path = path
17
+ @content = content
18
+ log {self.to_s}
19
+ end
20
+
21
+ # @param [String] tyrano_project_path
22
+ def run(tyrano_project_path)
23
+ full_path = File.join(tyrano_project_path, path)
24
+ log {"Creating file [#{full_path}]"}
25
+ create_parent_dir_if_not_exist(full_path)
26
+ File.write(full_path, content)
27
+ end
28
+
29
+ def to_s
30
+ "Create file [#{path}]"
31
+ end
32
+
33
+ end
@@ -0,0 +1,36 @@
1
+ require 'fileutils'
2
+
3
+ require_relative 'files_actions_module'
4
+
5
+
6
+ # Direct copy of a file from a source to a destination
7
+ class TyranoDsl::FileActions::FileCopy
8
+
9
+ # @return [String]
10
+ attr_reader :from_path
11
+ # @return [String]
12
+ attr_reader :to_path
13
+
14
+ include TyranoDsl::FileActions::FileActionsModule
15
+
16
+ # @param [String] from_path
17
+ # @param [String] to_path
18
+ def initialize(from_path, to_path)
19
+ @from_path = from_path
20
+ @to_path = to_path
21
+ log {self.to_s}
22
+ end
23
+
24
+ # @param [String] tyrano_project_path
25
+ def run(tyrano_project_path)
26
+ full_path = File.join(tyrano_project_path, to_path)
27
+ log {"Copy file [#{from_path}] to [#{full_path}]"}
28
+ create_parent_dir_if_not_exist(full_path)
29
+ FileUtils.copy_file from_path, full_path
30
+ end
31
+
32
+ def to_s
33
+ "Copy file [#{from_path}] to [#{to_path}]"
34
+ end
35
+
36
+ end
@@ -0,0 +1,28 @@
1
+ require 'logger'
2
+
3
+ module TyranoDsl
4
+ module FileActions
5
+
6
+ # Helpers to write file actions
7
+ module FileActionsModule
8
+
9
+ protected
10
+
11
+ def create_parent_dir_if_not_exist(file_path)
12
+ parent_dir = File.dirname(file_path)
13
+ unless File.exists? parent_dir
14
+ FileUtils.mkdir_p parent_dir
15
+ end
16
+ end
17
+
18
+ def logger
19
+ @logger ||= Logger.new(STDOUT)
20
+ end
21
+
22
+ def log
23
+ logger.info(self.class) {yield}
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+
3
+ require_relative 'files_actions_module'
4
+
5
+ # Path a JSON file
6
+ class TyranoDsl::FileActions::JsonPatch
7
+
8
+ include TyranoDsl::FileActions::FileActionsModule
9
+
10
+ # @return [String]
11
+ attr_reader :file_path
12
+ # @return [Object]
13
+ attr_reader :patched_content
14
+ # @return [Array<String>]
15
+ attr_reader :patching_path
16
+
17
+ # @param [String] file_path
18
+ # @param [Array<String>] patching_path
19
+ # @param [Object] patched_content
20
+ def initialize(file_path, patching_path, patched_content)
21
+ @file_path = file_path
22
+ @patching_path = patching_path
23
+ @patched_content = patched_content
24
+ log {self.to_s}
25
+ end
26
+
27
+ # @param [String] tyrano_project_path
28
+ def run(tyrano_project_path)
29
+ full_path = File.join(tyrano_project_path, file_path)
30
+ log {"Patching file [#{full_path}] at #{patching_path}"}
31
+ unless File.exist? full_path
32
+ raise TyranoDsl::TyranoException, "Missing file [#{full_path}]"
33
+ end
34
+ content = JSON.parse(IO.read(full_path))
35
+ current_subtree = content
36
+ 0.upto(patching_path.length - 2) do |path_segment_index|
37
+ current_subtree = current_subtree[patching_path[path_segment_index]]
38
+ end
39
+ current_subtree[patching_path.last] = patched_content
40
+ File.write(full_path, JSON.pretty_generate(content))
41
+ end
42
+
43
+ def to_s
44
+ "Patch JSON [#{file_path}] at #{patching_path}"
45
+ end
46
+
47
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'parser'
2
+ require_relative 'parsing_context'
3
+ require_relative 'tyrano_exception'
4
+ require_relative 'tyrano_dsl'
5
+ require_relative 'writer'
6
+
7
+ class TyranoDsl::Main
8
+
9
+ # @param [String] file_path path to the DSL file
10
+ # @return [TyranoDsl::WritingContext]
11
+ def run(file_path)
12
+ parsing_context = TyranoDsl::ParsingContext.new
13
+ parser = TyranoDsl::Parser.new(parsing_context, file_path)
14
+ parser.include_file(file_path)
15
+ TyranoDsl::Writer.new.write(parsing_context.world, parsing_context.words)
16
+ end
17
+
18
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'tyrano_dsl'
2
+
3
+ # A parsed word
4
+ class TyranoDsl::ParsedWord
5
+
6
+ # @return [Hash]
7
+ attr_reader :parameters
8
+ # @return [String]
9
+ attr_reader :word
10
+ # @return [Array<String>]
11
+ attr_reader :word_location
12
+
13
+ # @param [String] word
14
+ # @param [Array<String>] word_location
15
+ # @param [Hash] parameters
16
+ def initialize(word, word_location, parameters)
17
+ @word = word
18
+ @word_location = word_location
19
+ @parameters = parameters
20
+ end
21
+
22
+ end
@@ -0,0 +1,58 @@
1
+ require 'logger'
2
+
3
+ require_relative 'parsed_word'
4
+ require_relative 'tyrano_exception'
5
+ require_relative 'tyrano_dsl'
6
+ require_relative 'vocabulary'
7
+
8
+ # Parse the DSL
9
+ class TyranoDsl::Parser
10
+
11
+ # @return [TyranoDsl::ParsingContext]
12
+ attr_reader :context
13
+ # @return [Array<String>]
14
+ attr_accessor :word_location
15
+ # @return [Array<String>]
16
+ attr_reader :included_files_hierarchy
17
+
18
+ TyranoDsl::Vocabulary.get_words_class('parsing_words') do |word, word_module|
19
+ include word_module
20
+
21
+ # Patch the method to store the location when a word is called
22
+ symbol_word = word.to_sym
23
+ old_method = instance_method(symbol_word)
24
+ define_method(symbol_word) do |*args|
25
+ self.word_location = caller
26
+ old_method.bind(self).call(*args)
27
+ end
28
+ end
29
+
30
+ # @param [TyranoDsl::ParsingContext] parsing_context
31
+ # @param [String] initial_file_path
32
+ def initialize(parsing_context, initial_file_path)
33
+ @context = parsing_context
34
+ @logger = Logger.new(STDOUT)
35
+ @included_files_hierarchy = [initial_file_path]
36
+ end
37
+
38
+ protected
39
+
40
+ # Add a parsed word
41
+ # @param [String] word
42
+ # @param [Hash{String => Object}] parameters
43
+ # @return [void]
44
+ def add_parsed_word(word, parameters = {})
45
+ context.words << TyranoDsl::ParsedWord.new(
46
+ word,
47
+ word_location,
48
+ parameters
49
+ )
50
+ end
51
+
52
+ private
53
+
54
+ def log
55
+ @logger.info(self.class) {yield}
56
+ end
57
+
58
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'elements/world'
2
+ require_relative 'parsed_word'
3
+ require_relative 'tyrano_dsl'
4
+
5
+ # Context for parsing, used by words to store content
6
+ class TyranoDsl::ParsingContext
7
+
8
+ # @return [Array<TyranoDsl::ParsedWord>]
9
+ attr_reader :words
10
+ # @return [TyranoDsl::Elements::World]
11
+ attr_reader :world
12
+
13
+ def initialize
14
+ @words = []
15
+ @world = TyranoDsl::Elements::World.new
16
+ end
17
+
18
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../vocabulary'
2
+ require_relative 'parsing_words_module'
3
+ module TyranoDsl::ParsingWords::AskQuestion
4
+
5
+ include TyranoDsl::ParsingWords::ParsingWordsModule
6
+
7
+ # @return [void]
8
+ # @raise [TyranoDsl::TyranoException]
9
+ # @param [Hash{String=>Hash\nil}] possible_answers
10
+ def ask_question(possible_answers)
11
+ symbolized_possible_answers = possible_answers.collect do |possible_answer|
12
+ unless possible_answer.is_a? Hash
13
+ raise TyranoDsl::TyranoException, 'Parameter is not a Hash'
14
+ end
15
+ symbolized_possible_answer = symbolize_keys(possible_answer)
16
+ [:text, :left, :top, :scene].each do |param_name|
17
+ unless symbolized_possible_answer.key? param_name
18
+ raise TyranoDsl::TyranoException, "Missing value for #{param_name}"
19
+ end
20
+ end
21
+ scene = symbolized_possible_answer[:scene]
22
+ label = symbolized_possible_answer[:label]
23
+ context.world.jump_targets << TyranoDsl::Elements::JumpTarget.new(scene, label ? context.world.label_value(label) : nil)
24
+ symbolized_possible_answer
25
+ end
26
+ add_parsed_word(
27
+ TyranoDsl::Vocabulary::ASK_QUESTION,
28
+ possible_answers: symbolized_possible_answers
29
+ )
30
+ end
31
+
32
+ end