whirled_peas 0.1.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +32 -0
  4. data/Gemfile +1 -0
  5. data/README.md +240 -79
  6. data/Rakefile +37 -3
  7. data/bin/debug +35 -0
  8. data/exe/whirled_peas +7 -0
  9. data/lib/whirled_peas.rb +17 -37
  10. data/lib/whirled_peas/command_line.rb +263 -0
  11. data/lib/whirled_peas/config.rb +21 -0
  12. data/lib/whirled_peas/debugger.rb +80 -0
  13. data/lib/whirled_peas/errors.rb +7 -0
  14. data/lib/whirled_peas/frame.rb +0 -8
  15. data/lib/whirled_peas/frame/consumer.rb +14 -51
  16. data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
  17. data/lib/whirled_peas/frame/event_loop.rb +68 -38
  18. data/lib/whirled_peas/frame/producer.rb +37 -34
  19. data/lib/whirled_peas/graphics.rb +5 -0
  20. data/lib/whirled_peas/graphics/box_painter.rb +100 -0
  21. data/lib/whirled_peas/graphics/canvas.rb +107 -0
  22. data/lib/whirled_peas/graphics/container_coords.rb +61 -0
  23. data/lib/whirled_peas/graphics/container_dimensions.rb +65 -0
  24. data/lib/whirled_peas/graphics/container_painter.rb +116 -0
  25. data/lib/whirled_peas/graphics/debugger.rb +43 -0
  26. data/lib/whirled_peas/graphics/grid_painter.rb +56 -0
  27. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  28. data/lib/whirled_peas/graphics/painter.rb +24 -0
  29. data/lib/whirled_peas/graphics/renderer.rb +49 -0
  30. data/lib/whirled_peas/graphics/screen.rb +65 -0
  31. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  32. data/lib/whirled_peas/graphics/text_painter.rb +38 -0
  33. data/lib/whirled_peas/settings.rb +5 -0
  34. data/lib/whirled_peas/settings/bg_color.rb +22 -0
  35. data/lib/whirled_peas/settings/border.rb +101 -0
  36. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  37. data/lib/whirled_peas/settings/color.rb +69 -0
  38. data/lib/whirled_peas/settings/container_settings.rb +128 -0
  39. data/lib/whirled_peas/settings/debugger.rb +87 -0
  40. data/lib/whirled_peas/settings/display_flow.rb +25 -0
  41. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  42. data/lib/whirled_peas/settings/grid_settings.rb +11 -0
  43. data/lib/whirled_peas/settings/margin.rb +8 -0
  44. data/lib/whirled_peas/settings/padding.rb +8 -0
  45. data/lib/whirled_peas/settings/position.rb +15 -0
  46. data/lib/whirled_peas/settings/spacing.rb +24 -0
  47. data/lib/whirled_peas/settings/text_align.rb +19 -0
  48. data/lib/whirled_peas/settings/text_color.rb +19 -0
  49. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  50. data/lib/whirled_peas/template.rb +5 -0
  51. data/lib/whirled_peas/template/box_element.rb +8 -0
  52. data/lib/whirled_peas/template/composer.rb +68 -0
  53. data/lib/whirled_peas/template/container.rb +28 -0
  54. data/lib/whirled_peas/template/debugger.rb +34 -0
  55. data/lib/whirled_peas/template/element.rb +13 -0
  56. data/lib/whirled_peas/template/grid_element.rb +8 -0
  57. data/lib/whirled_peas/template/text_element.rb +24 -0
  58. data/lib/whirled_peas/utils.rb +5 -0
  59. data/lib/whirled_peas/utils/ansi.rb +53 -0
  60. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  61. data/lib/whirled_peas/utils/title_font.rb +75 -0
  62. data/lib/whirled_peas/version.rb +1 -1
  63. data/screen_test/rendered/elements/box.frame +1 -0
  64. data/screen_test/rendered/elements/box.rb +20 -0
  65. data/screen_test/rendered/elements/grid.frame +1 -0
  66. data/screen_test/rendered/elements/grid.rb +13 -0
  67. data/screen_test/rendered/elements/screen_overflow.rb +9 -0
  68. data/screen_test/rendered/elements/text.frame +1 -0
  69. data/screen_test/rendered/elements/text.rb +9 -0
  70. data/screen_test/rendered/elements/text_multiline.frame +1 -0
  71. data/screen_test/rendered/elements/text_multiline.rb +9 -0
  72. data/screen_test/rendered/settings/align/box.frame +1 -0
  73. data/screen_test/rendered/settings/align/box.rb +20 -0
  74. data/screen_test/rendered/settings/align/children_center.frame +1 -0
  75. data/screen_test/rendered/settings/align/children_center.rb +13 -0
  76. data/screen_test/rendered/settings/align/children_left.frame +1 -0
  77. data/screen_test/rendered/settings/align/children_left.rb +13 -0
  78. data/screen_test/rendered/settings/align/children_right.frame +1 -0
  79. data/screen_test/rendered/settings/align/children_right.rb +13 -0
  80. data/screen_test/rendered/settings/align/grid.frame +1 -0
  81. data/screen_test/rendered/settings/align/grid.rb +20 -0
  82. data/screen_test/rendered/settings/ansi/bold.frame +1 -0
  83. data/screen_test/rendered/settings/ansi/bold.rb +15 -0
  84. data/screen_test/rendered/settings/ansi/color.frame +1 -0
  85. data/screen_test/rendered/settings/ansi/color.rb +37 -0
  86. data/screen_test/rendered/settings/ansi/underline.frame +1 -0
  87. data/screen_test/rendered/settings/ansi/underline.rb +15 -0
  88. data/screen_test/rendered/settings/border.frame +1 -0
  89. data/screen_test/rendered/settings/border.rb +13 -0
  90. data/screen_test/rendered/settings/flow/l2r.frame +1 -0
  91. data/screen_test/rendered/settings/flow/l2r.rb +24 -0
  92. data/screen_test/rendered/settings/flow/t2b.frame +1 -0
  93. data/screen_test/rendered/settings/flow/t2b.rb +24 -0
  94. data/screen_test/rendered/settings/height/box.frame +1 -0
  95. data/screen_test/rendered/settings/height/box.rb +13 -0
  96. data/screen_test/rendered/settings/height/grid.frame +1 -0
  97. data/screen_test/rendered/settings/height/grid.rb +14 -0
  98. data/screen_test/rendered/settings/height/overflow_box.frame +1 -0
  99. data/screen_test/rendered/settings/height/overflow_box.rb +13 -0
  100. data/screen_test/rendered/settings/height/overflow_box_l2r.frame +1 -0
  101. data/screen_test/rendered/settings/height/overflow_box_l2r.rb +15 -0
  102. data/screen_test/rendered/settings/height/overflow_box_t2b.frame +1 -0
  103. data/screen_test/rendered/settings/height/overflow_box_t2b.rb +14 -0
  104. data/screen_test/rendered/settings/height/overflow_grid.frame +1 -0
  105. data/screen_test/rendered/settings/height/overflow_grid.rb +16 -0
  106. data/screen_test/rendered/settings/margin.frame +1 -0
  107. data/screen_test/rendered/settings/margin.rb +14 -0
  108. data/screen_test/rendered/settings/padding.frame +1 -0
  109. data/screen_test/rendered/settings/padding.rb +11 -0
  110. data/screen_test/rendered/settings/position/box_left.frame +1 -0
  111. data/screen_test/rendered/settings/position/box_left.rb +17 -0
  112. data/screen_test/rendered/settings/position/box_left_negative.frame +1 -0
  113. data/screen_test/rendered/settings/position/box_left_negative.rb +17 -0
  114. data/screen_test/rendered/settings/position/box_top.frame +1 -0
  115. data/screen_test/rendered/settings/position/box_top.rb +17 -0
  116. data/screen_test/rendered/settings/position/box_top_negative.frame +1 -0
  117. data/screen_test/rendered/settings/position/box_top_negative.rb +17 -0
  118. data/screen_test/rendered/settings/position/grid_left.frame +1 -0
  119. data/screen_test/rendered/settings/position/grid_left.rb +18 -0
  120. data/screen_test/rendered/settings/position/grid_left_negative.frame +1 -0
  121. data/screen_test/rendered/settings/position/grid_left_negative.rb +18 -0
  122. data/screen_test/rendered/settings/position/grid_top.frame +1 -0
  123. data/screen_test/rendered/settings/position/grid_top.rb +18 -0
  124. data/screen_test/rendered/settings/position/grid_top_negative.frame +1 -0
  125. data/screen_test/rendered/settings/position/grid_top_negative.rb +18 -0
  126. data/screen_test/rendered/settings/title_font.frame +1 -0
  127. data/screen_test/rendered/settings/title_font.rb +12 -0
  128. data/screen_test/rendered/settings/width/box.frame +1 -0
  129. data/screen_test/rendered/settings/width/box.rb +13 -0
  130. data/screen_test/rendered/settings/width/grid.frame +1 -0
  131. data/screen_test/rendered/settings/width/grid.rb +14 -0
  132. data/screen_test/rendered/settings/width/overflow_box.frame +1 -0
  133. data/screen_test/rendered/settings/width/overflow_box.rb +11 -0
  134. data/screen_test/rendered/settings/width/overflow_box_l2r.frame +1 -0
  135. data/screen_test/rendered/settings/width/overflow_box_l2r.rb +14 -0
  136. data/screen_test/rendered/settings/width/overflow_box_t2b.frame +1 -0
  137. data/screen_test/rendered/settings/width/overflow_box_t2b.rb +15 -0
  138. data/screen_test/rendered/settings/width/overflow_grid.frame +1 -0
  139. data/screen_test/rendered/settings/width/overflow_grid.rb +14 -0
  140. data/screen_test/screen_tester.rb +191 -0
  141. data/whirled_peas.gemspec +4 -2
  142. metadata +136 -20
  143. data/lib/whirled_peas/ui.rb +0 -7
  144. data/lib/whirled_peas/ui/ansi.rb +0 -154
  145. data/lib/whirled_peas/ui/canvas.rb +0 -35
  146. data/lib/whirled_peas/ui/element.rb +0 -199
  147. data/lib/whirled_peas/ui/painter.rb +0 -283
  148. data/lib/whirled_peas/ui/screen.rb +0 -62
  149. data/lib/whirled_peas/ui/settings.rb +0 -512
  150. data/lib/whirled_peas/ui/stroke.rb +0 -29
  151. data/sandbox/auto.rb +0 -13
  152. data/sandbox/box.rb +0 -19
  153. data/sandbox/grid.rb +0 -13
  154. data/sandbox/sandbox.rb +0 -17
  155. data/sandbox/text.rb +0 -33
data/Rakefile CHANGED
@@ -1,6 +1,40 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ def screen_test(file, method)
7
+ raise ArgumentError, 'Missing argument: file' unless file
8
+
9
+ require 'bundler/setup'
10
+ require 'whirled_peas'
11
+ require_relative 'screen_test/screen_tester'
12
+
13
+ WhirledPeas::ScreenTester.new(file).send(method)
14
+ end
15
+
16
+ namespace :screen_test do
17
+ %i[debug run save view].each do |t|
18
+ task t, [:file] do |_, args|
19
+ screen_test(args[:file], t)
20
+ end
21
+ end
22
+
23
+ task :update_all do
24
+ require 'bundler/setup'
25
+ require 'whirled_peas'
26
+ require_relative 'screen_test/screen_tester'
27
+
28
+ WhirledPeas::ScreenTester.update_all
29
+ end
30
+ end
31
+
32
+ task :screen_test do
33
+ require 'bundler/setup'
34
+ require 'whirled_peas'
35
+ require_relative 'screen_test/screen_tester'
36
+
37
+ WhirledPeas::ScreenTester.run_all
38
+ end
39
+
40
+ task default: [:screen_test, :spec]
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def print_usage
4
+ puts "Usage: #{$0} <config file> [options]"
5
+ puts
6
+ puts 'options include'
7
+ puts ' --disable-screen Disable the screen (useful when printing debug statements)'
8
+ puts ' --painter Print the painter debug tree and exit'
9
+ puts ' --template Print the template debug tree and exit'
10
+ end
11
+
12
+ if !(1..2).include?(ARGV.length)
13
+ print_usage
14
+ exit(1)
15
+ elsif !File.exist?(ARGV.first)
16
+ puts "File not found: #{ARGV.first}"
17
+ print_usage
18
+ exit(1)
19
+ elsif ARGV.length == 2 && !%w[--disable-screen --template --painter].include?(ARGV[1])
20
+ puts "Unrecognized option: #{ARGV[1]}"
21
+ print_usage
22
+ exit(1)
23
+ end
24
+
25
+ require 'bundler/setup'
26
+ require 'whirled_peas'
27
+
28
+ if ARGV.length == 1
29
+ option = nil
30
+ else
31
+ option = ARGV[1].sub(/^--/, '').gsub(/-/, '_').to_sym
32
+ end
33
+
34
+ template_file = ARGV.first[0] == '/' ? ARGV.first : File.join(Dir.pwd, ARGV.first)
35
+ WhirledPeas.debug(template_file, option)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'whirled_peas'
5
+ require 'whirled_peas/command_line'
6
+
7
+ WhirledPeas::CommandLine.new(ARGV).start
@@ -1,50 +1,30 @@
1
1
  require 'logger'
2
2
 
3
+ require 'whirled_peas/errors'
4
+ require 'whirled_peas/config'
5
+ require 'whirled_peas/debugger'
3
6
  require 'whirled_peas/frame'
4
- require 'whirled_peas/ui'
7
+ require 'whirled_peas/graphics'
8
+ require 'whirled_peas/settings'
9
+ require 'whirled_peas/template'
10
+ require 'whirled_peas/utils'
5
11
  require 'whirled_peas/version'
6
12
 
7
13
  module WhirledPeas
8
- class Error < StandardError; end
9
-
10
- DEFAULT_HOST = 'localhost'
11
- DEFAULT_PORT = 8765
12
- DEFAULT_REFRESH_RATE = 30
13
-
14
- LOGGER_ID = 'MAIN'
15
-
16
- def self.start(driver, template_factory, log_level: Logger::INFO, refresh_rate: DEFAULT_REFRESH_RATE, host: DEFAULT_HOST, port: DEFAULT_PORT)
17
- logger = Logger.new(File.open('whirled_peas.log', 'a'))
18
- logger.level = log_level
19
- logger.formatter = proc do |severity, datetime, progname, msg|
20
- "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
21
- end
22
-
23
- consumer = Frame::Consumer.new(template_factory, refresh_rate, logger)
24
- consumer_thread = Thread.new do
25
- Thread.current.report_on_exception = false
26
- consumer.start(host: host, port: port)
27
- end
14
+ def self.config
15
+ @config ||= Config.new
16
+ end
28
17
 
29
- Frame::Producer.start(logger: logger, host: host, port: port) do |producer|
30
- begin
31
- driver.start(producer)
32
- producer.stop
33
- rescue => e
34
- logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
35
- logger.error(LOGGER_ID) { e }
36
- logger.error(LOGGER_ID) { e.backtrace.join("\n") }
37
- producer.terminate
38
- raise
39
- end
40
- end
18
+ def self.configure(&block)
19
+ yield config
20
+ end
41
21
 
42
- consumer_thread.join
22
+ def self.debug(config_file, option=nil)
23
+ Debugger.new(config_file, option).debug
43
24
  end
44
25
 
45
26
  def self.template(&block)
46
- template = UI::Template.new
47
- yield template, template.settings
48
- template
27
+ require 'whirled_peas/template/composer'
28
+ Template::Composer.build(&block)
49
29
  end
50
30
  end
@@ -0,0 +1,263 @@
1
+ require 'json'
2
+
3
+ require 'whirled_peas/graphics/debugger'
4
+ require 'whirled_peas/graphics/renderer'
5
+ require 'whirled_peas/graphics/screen'
6
+ require 'whirled_peas/frame/debug_consumer'
7
+ require 'whirled_peas/frame/event_loop'
8
+ require 'whirled_peas/frame/producer'
9
+ require 'whirled_peas/template/debugger'
10
+
11
+ module WhirledPeas
12
+ class Command
13
+ DEFAULT_LOG_LEVEL = Logger::INFO
14
+ DEFAULT_FORMATTER = proc do |severity, datetime, progname, msg|
15
+ if msg.is_a?(Exception)
16
+ msg = %Q(#{msg.class}: #{msg.to_s}\n #{msg.backtrace.join("\n ")})
17
+ end
18
+ "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
19
+ end
20
+
21
+ def self.command_name
22
+ self.name.split('::').last.sub(/Command$/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
23
+ end
24
+
25
+ def self.build_logger(output, level=DEFAULT_LOG_LEVEL, formatter=DEFAULT_FORMATTER)
26
+ logger = Logger.new(output)
27
+ logger.level = level
28
+ logger.formatter = formatter
29
+ logger
30
+ end
31
+
32
+ attr_reader :args
33
+
34
+ def initialize(args)
35
+ @args = args
36
+ end
37
+
38
+ def valid?
39
+ @error_text = nil
40
+ validate!
41
+ @error_text.nil?
42
+ end
43
+
44
+ def print_error
45
+ puts @error_text if @error_text
46
+ print_usage
47
+ end
48
+
49
+ def start
50
+ end
51
+
52
+ private
53
+
54
+ def print_usage
55
+ puts "Usage: #{$0} #{self.class.command_name}"
56
+ end
57
+
58
+ def validate!
59
+ # Set @error_text if the options are not valid
60
+ end
61
+ end
62
+
63
+ class TitleFontsCommand < Command
64
+ def start
65
+ require 'whirled_peas/utils/title_font'
66
+
67
+ Utils::TitleFont.fonts.keys.each do |key|
68
+ puts Utils::TitleFont.to_s(key.to_s, key)
69
+ puts key.inspect
70
+ puts
71
+ end
72
+ end
73
+ end
74
+
75
+ class ConfigCommand < Command
76
+ def start
77
+ require config
78
+ end
79
+
80
+ private
81
+
82
+ attr_reader :config
83
+
84
+ def validate!
85
+ if args.length == 0
86
+ @error_text = "#{self.class.command_name} requires a config file"
87
+ elsif !File.exist?(args[0])
88
+ @error_text = "File not found: #{args[0]}"
89
+ elsif args[0][-3..-1] != '.rb'
90
+ @error_text = 'Config file should be a .rb file'
91
+ else
92
+ @config = args[0][0] == '/' ? args[0] : File.join(Dir.pwd, args[0])
93
+ end
94
+ end
95
+
96
+ def print_usage
97
+ puts "Usage: #{$0} #{self.class.command_name} <config file>"
98
+ end
99
+ end
100
+
101
+ class StartCommand < ConfigCommand
102
+ LOGGER_ID = 'MAIN'
103
+
104
+ def start
105
+ super
106
+
107
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
108
+
109
+ consumer = Frame::EventLoop.new(
110
+ WhirledPeas.config.template_factory,
111
+ WhirledPeas.config.loading_template_factory,
112
+ logger: logger
113
+ )
114
+ Frame::Producer.produce(consumer, logger) do |producer|
115
+ begin
116
+ WhirledPeas.config.driver.start(producer)
117
+ rescue => e
118
+ logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
119
+ logger.error(LOGGER_ID) { e }
120
+ raise
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ class ListFramesCommand < ConfigCommand
127
+ def start
128
+ super
129
+
130
+ Frame::Producer.produce(Frame::DebugConsumer.new) do |producer|
131
+ WhirledPeas.config.driver.start(producer)
132
+ end
133
+ end
134
+ end
135
+
136
+ class PlayFrameCommand < ConfigCommand
137
+ def start
138
+ super
139
+
140
+ if args.last == '--template'
141
+ element = WhirledPeas.config.template_factory.build(frame, frame_args)
142
+ puts Template::Debugger.new(element).debug
143
+ exit
144
+ elsif args.last == '--painter'
145
+ element = WhirledPeas.config.template_factory.build(frame, frame_args)
146
+ painter = Graphics::Renderer.new(element, *Graphics::Screen.current_dimensions).painter
147
+ puts Graphics::Debugger.new(painter).debug
148
+ exit
149
+ end
150
+
151
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
152
+
153
+ consumer = Frame::EventLoop.new(
154
+ WhirledPeas.config.template_factory,
155
+ logger: logger
156
+ )
157
+ Frame::Producer.produce(consumer, logger) do |producer|
158
+ producer.send_frame(frame, args: frame_args)
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ attr_reader :frame, :frame_args
165
+
166
+ def validate!
167
+ super
168
+ if !@error_text.nil?
169
+ return
170
+ elsif args.length < 2
171
+ @error_text = "#{self.class.command_name} requires a frame name"
172
+ else
173
+ @frame = args[1]
174
+ @frame_args = {}
175
+ return if args.length < 3 || args[2][0..1] == '--'
176
+ JSON.parse(args[2] || '{}').each do |key, value|
177
+ @frame_args[key.to_sym] = value
178
+ end
179
+ end
180
+ end
181
+
182
+ def print_usage
183
+ puts "Usage: #{$0} #{self.class.command_name} <config file> <frame> [args as a JSON string] [--debug]"
184
+ end
185
+ end
186
+
187
+ class LoadingCommand < ConfigCommand
188
+ def start
189
+ super
190
+ unless WhirledPeas.config.loading_template_factory
191
+ puts 'No loading screen configured'
192
+ exit
193
+ end
194
+
195
+ if args.last == '--debug'
196
+ puts WhirledPeas.config.loading_template_factory.build.inspect
197
+ exit
198
+ end
199
+
200
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
201
+ consumer = Frame::EventLoop.new(
202
+ WhirledPeas.config.template_factory,
203
+ WhirledPeas.config.loading_template_factory,
204
+ logger: logger
205
+ )
206
+ Frame::Producer.produce(consumer, logger) { sleep(5) }
207
+ end
208
+
209
+ private
210
+
211
+ def print_usage
212
+ puts "Usage: #{$0} #{self.class.command_name} [--debug]"
213
+ end
214
+ end
215
+
216
+ class CommandLine
217
+ COMMANDS = [
218
+ StartCommand,
219
+ ListFramesCommand,
220
+ PlayFrameCommand,
221
+ LoadingCommand,
222
+ TitleFontsCommand
223
+ ].map.with_object({}) { |c, h| h[c.command_name] = c }
224
+
225
+ def initialize(args)
226
+ @args = args
227
+ end
228
+
229
+ def start
230
+ if args.length < 1
231
+ print_usage
232
+ exit(1)
233
+ end
234
+
235
+ command = args.shift
236
+
237
+ unless COMMANDS.key?(command)
238
+ puts "Unrecognized command: #{command}"
239
+ print_usage
240
+ exit(1)
241
+ end
242
+
243
+ cmd = COMMANDS[command].new(args)
244
+
245
+ unless cmd.valid?
246
+ cmd.print_error
247
+ exit(1)
248
+ end
249
+
250
+ cmd.start
251
+ end
252
+
253
+ private
254
+
255
+ attr_reader :args
256
+
257
+ def print_usage
258
+ puts "Usage: #{$0} <command> [command options]"
259
+ puts
260
+ puts "Available commands: #{COMMANDS.keys.join(', ')}"
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,21 @@
1
+ module WhirledPeas
2
+ class Config
3
+ attr_writer :driver, :template_factory
4
+ attr_accessor :loading_template_factory
5
+
6
+ def driver
7
+ unless @driver
8
+ raise ConfigurationError, 'driver must be configured'
9
+ end
10
+ @driver
11
+ end
12
+
13
+ def template_factory
14
+ unless @template_factory
15
+ raise ConfigurationError, 'template_factory must be configured'
16
+ end
17
+ @template_factory
18
+ end
19
+ end
20
+ private_constant :Config
21
+ end
@@ -0,0 +1,80 @@
1
+ require 'whirled_peas/frame/event_loop'
2
+ require 'whirled_peas/frame/producer'
3
+ require 'whirled_peas/graphics/debugger'
4
+ require 'whirled_peas/graphics/mock_screen'
5
+ require 'whirled_peas/graphics/renderer'
6
+ require 'whirled_peas/graphics/screen'
7
+ require 'whirled_peas/template/debugger'
8
+
9
+ module WhirledPeas
10
+ class Debugger
11
+ module Option
12
+ DISABLE_SCREEN = :disable_screen
13
+ PAINTER = :painter
14
+ TEMPLATE = :template
15
+
16
+ VALID = [DISABLE_SCREEN, PAINTER, TEMPLATE]
17
+ end
18
+ private_constant :Option
19
+
20
+ FRAME = 'debug'
21
+ private_constant :FRAME
22
+
23
+ def initialize(template_file, option=nil)
24
+ unless option.nil? || Option::VALID.include?(option)
25
+ message =
26
+ "Invalid option: #{option}, expecting one of #{Option::VALID.join(', ')}"
27
+ raise ArgumentError, message
28
+ end
29
+ @template_file = template_file
30
+ @option = option
31
+ end
32
+
33
+ def debug
34
+ require template_file
35
+ template_factory = TemplateFactory.new
36
+ if play_frame?
37
+ screen = if disable_screen?
38
+ Graphics::MockScreen.new(80, 40)
39
+ else
40
+ Graphics::Screen.new
41
+ end
42
+ consumer = Frame::EventLoop.new(template_factory, screen: screen)
43
+ Frame::Producer.produce(consumer) do |producer|
44
+ producer.send_frame(FRAME, args: {})
45
+ end
46
+ return
47
+ end
48
+
49
+ template = template_factory.build(FRAME, {})
50
+ if print_painter?
51
+ painter = Graphics::Renderer.new(template, *Graphics::Screen.current_dimensions).painter
52
+ puts Graphics::Debugger.new(painter).debug
53
+ elsif print_template?
54
+ puts Template::Debugger.new(template).debug
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ attr_reader :template_file, :option
61
+
62
+ def play_frame?
63
+ option.nil? || option == Option::DISABLE_SCREEN
64
+ end
65
+
66
+ def disable_screen?
67
+ !option.nil? && option == Option::DISABLE_SCREEN
68
+ end
69
+
70
+ def print_painter?
71
+ !option.nil? && option == Option::PAINTER
72
+ end
73
+
74
+ def print_template?
75
+ !option.nil? && option == Option::TEMPLATE
76
+ end
77
+ end
78
+
79
+ private_constant :Debugger
80
+ end