whirled_peas 0.2.0 → 0.6.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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +38 -0
  4. data/Gemfile +1 -0
  5. data/README.md +275 -81
  6. data/Rakefile +38 -3
  7. data/examples/intro.rb +52 -0
  8. data/examples/scrolling.rb +53 -0
  9. data/exe/whirled_peas +7 -0
  10. data/lib/whirled_peas.rb +12 -42
  11. data/lib/whirled_peas/command_line.rb +255 -0
  12. data/lib/whirled_peas/config.rb +21 -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 -50
  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 +36 -32
  19. data/lib/whirled_peas/graphics.rb +5 -0
  20. data/lib/whirled_peas/graphics/box_painter.rb +108 -0
  21. data/lib/whirled_peas/graphics/canvas.rb +107 -0
  22. data/lib/whirled_peas/graphics/composer.rb +80 -0
  23. data/lib/whirled_peas/graphics/container_coords.rb +71 -0
  24. data/lib/whirled_peas/graphics/container_dimensions.rb +75 -0
  25. data/lib/whirled_peas/graphics/container_painter.rb +234 -0
  26. data/lib/whirled_peas/graphics/debugger.rb +52 -0
  27. data/lib/whirled_peas/graphics/grid_painter.rb +68 -0
  28. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  29. data/lib/whirled_peas/graphics/painter.rb +19 -0
  30. data/lib/whirled_peas/graphics/renderer.rb +21 -0
  31. data/lib/whirled_peas/graphics/screen.rb +70 -0
  32. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  33. data/lib/whirled_peas/graphics/text_painter.rb +40 -0
  34. data/lib/whirled_peas/settings.rb +5 -0
  35. data/lib/whirled_peas/settings/bg_color.rb +22 -0
  36. data/lib/whirled_peas/settings/border.rb +101 -0
  37. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  38. data/lib/whirled_peas/settings/color.rb +69 -0
  39. data/lib/whirled_peas/settings/container_settings.rb +139 -0
  40. data/lib/whirled_peas/settings/debugger.rb +96 -0
  41. data/lib/whirled_peas/settings/display_flow.rb +25 -0
  42. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  43. data/lib/whirled_peas/settings/grid_settings.rb +15 -0
  44. data/lib/whirled_peas/settings/margin.rb +8 -0
  45. data/lib/whirled_peas/settings/padding.rb +8 -0
  46. data/lib/whirled_peas/settings/position.rb +15 -0
  47. data/lib/whirled_peas/settings/scrollbar.rb +15 -0
  48. data/lib/whirled_peas/settings/spacing.rb +24 -0
  49. data/lib/whirled_peas/settings/text_align.rb +19 -0
  50. data/lib/whirled_peas/settings/text_color.rb +19 -0
  51. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  52. data/lib/whirled_peas/utils.rb +5 -0
  53. data/lib/whirled_peas/utils/ansi.rb +53 -0
  54. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  55. data/lib/whirled_peas/utils/title_font.rb +75 -0
  56. data/lib/whirled_peas/version.rb +1 -1
  57. data/screen_test/rendered/elements/box.frame +1 -0
  58. data/screen_test/rendered/elements/box.rb +20 -0
  59. data/screen_test/rendered/elements/grid.frame +1 -0
  60. data/screen_test/rendered/elements/grid.rb +13 -0
  61. data/screen_test/rendered/elements/screen_overflow.frame +1 -0
  62. data/screen_test/rendered/elements/screen_overflow.rb +9 -0
  63. data/screen_test/rendered/elements/text.frame +1 -0
  64. data/screen_test/rendered/elements/text.rb +9 -0
  65. data/screen_test/rendered/elements/text_multiline.frame +1 -0
  66. data/screen_test/rendered/elements/text_multiline.rb +9 -0
  67. data/screen_test/rendered/settings/align/box.frame +1 -0
  68. data/screen_test/rendered/settings/align/box.rb +24 -0
  69. data/screen_test/rendered/settings/align/children_center.frame +1 -0
  70. data/screen_test/rendered/settings/align/children_center.rb +13 -0
  71. data/screen_test/rendered/settings/align/children_left.frame +1 -0
  72. data/screen_test/rendered/settings/align/children_left.rb +13 -0
  73. data/screen_test/rendered/settings/align/children_right.frame +1 -0
  74. data/screen_test/rendered/settings/align/children_right.rb +13 -0
  75. data/screen_test/rendered/settings/align/grid.frame +1 -0
  76. data/screen_test/rendered/settings/align/grid.rb +20 -0
  77. data/screen_test/rendered/settings/ansi/bold.frame +1 -0
  78. data/screen_test/rendered/settings/ansi/bold.rb +15 -0
  79. data/screen_test/rendered/settings/ansi/color.frame +1 -0
  80. data/screen_test/rendered/settings/ansi/color.rb +37 -0
  81. data/screen_test/rendered/settings/ansi/underline.frame +1 -0
  82. data/screen_test/rendered/settings/ansi/underline.rb +15 -0
  83. data/screen_test/rendered/settings/border.frame +1 -0
  84. data/screen_test/rendered/settings/border.rb +13 -0
  85. data/screen_test/rendered/settings/flow/box_b2t.frame +1 -0
  86. data/screen_test/rendered/settings/flow/box_b2t.rb +24 -0
  87. data/screen_test/rendered/settings/flow/box_l2r.frame +1 -0
  88. data/screen_test/rendered/settings/flow/box_l2r.rb +24 -0
  89. data/screen_test/rendered/settings/flow/box_r2l.frame +1 -0
  90. data/screen_test/rendered/settings/flow/box_r2l.rb +24 -0
  91. data/screen_test/rendered/settings/flow/box_t2b.frame +1 -0
  92. data/screen_test/rendered/settings/flow/box_t2b.rb +24 -0
  93. data/screen_test/rendered/settings/flow/grid_b2t.frame +1 -0
  94. data/screen_test/rendered/settings/flow/grid_b2t.rb +14 -0
  95. data/screen_test/rendered/settings/flow/grid_l2r.frame +1 -0
  96. data/screen_test/rendered/settings/flow/grid_l2r.rb +14 -0
  97. data/screen_test/rendered/settings/flow/grid_r2l.frame +1 -0
  98. data/screen_test/rendered/settings/flow/grid_r2l.rb +14 -0
  99. data/screen_test/rendered/settings/flow/grid_t2b.frame +1 -0
  100. data/screen_test/rendered/settings/flow/grid_t2b.rb +14 -0
  101. data/screen_test/rendered/settings/height/box.frame +1 -0
  102. data/screen_test/rendered/settings/height/box.rb +13 -0
  103. data/screen_test/rendered/settings/height/grid.frame +1 -0
  104. data/screen_test/rendered/settings/height/grid.rb +14 -0
  105. data/screen_test/rendered/settings/height/overflow_box.frame +1 -0
  106. data/screen_test/rendered/settings/height/overflow_box.rb +13 -0
  107. data/screen_test/rendered/settings/height/overflow_box_l2r.frame +1 -0
  108. data/screen_test/rendered/settings/height/overflow_box_l2r.rb +15 -0
  109. data/screen_test/rendered/settings/height/overflow_box_t2b.frame +1 -0
  110. data/screen_test/rendered/settings/height/overflow_box_t2b.rb +14 -0
  111. data/screen_test/rendered/settings/height/overflow_grid.frame +1 -0
  112. data/screen_test/rendered/settings/height/overflow_grid.rb +16 -0
  113. data/screen_test/rendered/settings/margin.frame +1 -0
  114. data/screen_test/rendered/settings/margin.rb +14 -0
  115. data/screen_test/rendered/settings/padding.frame +1 -0
  116. data/screen_test/rendered/settings/padding.rb +11 -0
  117. data/screen_test/rendered/settings/position/box_left.frame +1 -0
  118. data/screen_test/rendered/settings/position/box_left.rb +17 -0
  119. data/screen_test/rendered/settings/position/box_left_negative.frame +1 -0
  120. data/screen_test/rendered/settings/position/box_left_negative.rb +17 -0
  121. data/screen_test/rendered/settings/position/box_top.frame +1 -0
  122. data/screen_test/rendered/settings/position/box_top.rb +17 -0
  123. data/screen_test/rendered/settings/position/box_top_negative.frame +1 -0
  124. data/screen_test/rendered/settings/position/box_top_negative.rb +17 -0
  125. data/screen_test/rendered/settings/position/grid_left.frame +1 -0
  126. data/screen_test/rendered/settings/position/grid_left.rb +18 -0
  127. data/screen_test/rendered/settings/position/grid_left_negative.frame +1 -0
  128. data/screen_test/rendered/settings/position/grid_left_negative.rb +18 -0
  129. data/screen_test/rendered/settings/position/grid_top.frame +1 -0
  130. data/screen_test/rendered/settings/position/grid_top.rb +18 -0
  131. data/screen_test/rendered/settings/position/grid_top_negative.frame +1 -0
  132. data/screen_test/rendered/settings/position/grid_top_negative.rb +18 -0
  133. data/screen_test/rendered/settings/scroll/horiz_box.frame +1 -0
  134. data/screen_test/rendered/settings/scroll/horiz_box.rb +15 -0
  135. data/screen_test/rendered/settings/scroll/vert_box.frame +1 -0
  136. data/screen_test/rendered/settings/scroll/vert_box.rb +18 -0
  137. data/screen_test/rendered/settings/title_font.frame +1 -0
  138. data/screen_test/rendered/settings/title_font.rb +12 -0
  139. data/screen_test/rendered/settings/width/box.frame +1 -0
  140. data/screen_test/rendered/settings/width/box.rb +13 -0
  141. data/screen_test/rendered/settings/width/grid.frame +1 -0
  142. data/screen_test/rendered/settings/width/grid.rb +14 -0
  143. data/screen_test/rendered/settings/width/overflow_box.frame +1 -0
  144. data/screen_test/rendered/settings/width/overflow_box.rb +11 -0
  145. data/screen_test/rendered/settings/width/overflow_box_l2r.frame +1 -0
  146. data/screen_test/rendered/settings/width/overflow_box_l2r.rb +14 -0
  147. data/screen_test/rendered/settings/width/overflow_box_t2b.frame +1 -0
  148. data/screen_test/rendered/settings/width/overflow_box_t2b.rb +15 -0
  149. data/screen_test/rendered/settings/width/overflow_grid.frame +1 -0
  150. data/screen_test/rendered/settings/width/overflow_grid.rb +14 -0
  151. data/screen_test/screen_tester.rb +201 -0
  152. data/whirled_peas.gemspec +4 -2
  153. metadata +147 -20
  154. data/lib/whirled_peas/ui.rb +0 -7
  155. data/lib/whirled_peas/ui/ansi.rb +0 -154
  156. data/lib/whirled_peas/ui/canvas.rb +0 -35
  157. data/lib/whirled_peas/ui/element.rb +0 -225
  158. data/lib/whirled_peas/ui/painter.rb +0 -283
  159. data/lib/whirled_peas/ui/screen.rb +0 -62
  160. data/lib/whirled_peas/ui/settings.rb +0 -521
  161. data/lib/whirled_peas/ui/stroke.rb +0 -29
  162. data/sandbox/auto.rb +0 -13
  163. data/sandbox/box.rb +0 -19
  164. data/sandbox/grid.rb +0 -13
  165. data/sandbox/sandbox.rb +0 -17
  166. data/sandbox/text.rb +0 -33
data/Rakefile CHANGED
@@ -1,6 +1,41 @@
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[template view run save debug].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: :ci
41
+ task ci: [:screen_test, :spec]
@@ -0,0 +1,52 @@
1
+ require 'bundler/setup'
2
+ require 'whirled_peas'
3
+
4
+ class TemplateFactory
5
+ TITLE_FONT = :default #roman
6
+ PRIMARY_COLOR = :bright_blue
7
+ SECONDARY_COLOR = :blue
8
+ BG_COLOR = :bright_white
9
+
10
+ def build(name, args)
11
+ WhirledPeas.template do |composer, settings|
12
+ settings.set_padding(left: 10, top: 6, right: 10, bottom: 6)
13
+ settings.align = :center
14
+ settings.width = 120
15
+ settings.flow = :t2b
16
+ settings.bold = true
17
+ settings.bg_color = BG_COLOR
18
+
19
+ composer.add_box do |composer, settings|
20
+ composer.add_text do |_, settings|
21
+ settings.title_font = TITLE_FONT
22
+ settings.color = PRIMARY_COLOR
23
+ 'Visualize'
24
+ end
25
+ end
26
+ composer.add_box do |_, settings|
27
+ settings.set_margin(top: 1)
28
+ settings.color = SECONDARY_COLOR
29
+ "your code's execution with"
30
+ end
31
+ composer.add_box do |composer, settings|
32
+ settings.set_margin(top: 1)
33
+ composer.add_text do |_, settings|
34
+ settings.title_font = TITLE_FONT
35
+ settings.color = PRIMARY_COLOR
36
+ 'Whirled Peas'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ class Driver
44
+ def start(producer)
45
+ producer.send_frame('intro', duration: 5)
46
+ end
47
+ end
48
+
49
+ WhirledPeas.configure do |config|
50
+ config.template_factory = TemplateFactory.new
51
+ config.driver = Driver.new
52
+ end
@@ -0,0 +1,53 @@
1
+ require 'bundler/setup'
2
+ require 'whirled_peas'
3
+
4
+ class TemplateFactory
5
+ HPADDING = 0
6
+ VPADDING = 0
7
+ ITEM_COUNT = 64
8
+
9
+ def build(name, args)
10
+ top = args[:top]
11
+ WhirledPeas.template do |composer, settings|
12
+ settings.color = :green
13
+ composer.add_box('Vert') do |composer, settings|
14
+ settings.bg_color = :bright_red
15
+ settings.full_border(color: :blue)
16
+ settings.set_scrollbar(vert: true)
17
+ settings.height = 12
18
+ composer.add_box('Inner') do |composer, settings|
19
+ settings.flow = :t2b
20
+ settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
21
+ settings.set_position(top: top)
22
+ ITEM_COUNT.times do |i|
23
+ composer.add_text { "%2d" % i }
24
+ end
25
+ end
26
+ end
27
+ composer.add_box('Horiz') do |composer, settings|
28
+ settings.bg_color = :bright_red
29
+ settings.full_border(color: :blue)
30
+ settings.set_padding(left: HPADDING, right: HPADDING, top: VPADDING, bottom: VPADDING)
31
+ settings.set_scrollbar(horiz: true)
32
+ settings.width = 12
33
+ composer.add_box('Inner') do |composer, settings|
34
+ settings.set_position(left: top)
35
+ ITEM_COUNT.times.map { |i| (i % 10).to_s }.join
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ class Driver
43
+ def start(producer)
44
+ 53.times do |i|
45
+ producer.send_frame('intro', duration: 0.3, args: { top: -i })
46
+ end
47
+ end
48
+ end
49
+
50
+ WhirledPeas.configure do |config|
51
+ config.template_factory = TemplateFactory.new
52
+ config.driver = Driver.new
53
+ end
@@ -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,54 +1,24 @@
1
1
  require 'logger'
2
2
 
3
+ require 'whirled_peas/errors'
4
+ require 'whirled_peas/config'
3
5
  require 'whirled_peas/frame'
4
- require 'whirled_peas/ui'
6
+ require 'whirled_peas/graphics'
7
+ require 'whirled_peas/settings'
8
+ require 'whirled_peas/utils'
5
9
  require 'whirled_peas/version'
6
10
 
7
11
  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
- if msg.is_a?(Exception)
21
- msg = %Q(#{msg.class}: #{msg.to_s}\n #{msg.backtrace.join("\n ")})
22
- end
23
- "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
24
- end
25
-
26
- consumer = Frame::Consumer.new(template_factory, refresh_rate, logger)
27
- consumer_thread = Thread.new do
28
- Thread.current.report_on_exception = false
29
- consumer.start(host: host, port: port)
30
- end
31
-
32
- Frame::Producer.start(logger: logger, host: host, port: port) do |producer|
33
- begin
34
- driver.start(producer)
35
- producer.stop
36
- rescue Errno::EPIPE
37
- logger.error(LOGGER_ID) { 'Producer cannot connect to consumer, exiting...' }
38
- rescue => e
39
- logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
40
- logger.error(LOGGER_ID) { e }
41
- producer.terminate
42
- raise
43
- end
44
- end
12
+ def self.config
13
+ @config ||= Config.new
14
+ end
45
15
 
46
- consumer_thread.join
16
+ def self.configure(&block)
17
+ yield config
47
18
  end
48
19
 
49
20
  def self.template(&block)
50
- template = UI::Template.new
51
- yield template, template.settings
52
- template
21
+ require 'whirled_peas/graphics/composer'
22
+ Graphics::Composer.build(&block)
53
23
  end
54
24
  end
@@ -0,0 +1,255 @@
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
+
10
+ module WhirledPeas
11
+ class Command
12
+ DEFAULT_LOG_LEVEL = Logger::INFO
13
+ DEFAULT_FORMATTER = proc do |severity, datetime, progname, msg|
14
+ if msg.is_a?(Exception)
15
+ msg = %Q(#{msg.class}: #{msg.to_s}\n #{msg.backtrace.join("\n ")})
16
+ end
17
+ "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
18
+ end
19
+
20
+ def self.command_name
21
+ self.name.split('::').last.sub(/Command$/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
22
+ end
23
+
24
+ def self.build_logger(output, level=DEFAULT_LOG_LEVEL, formatter=DEFAULT_FORMATTER)
25
+ logger = Logger.new(output)
26
+ logger.level = level
27
+ logger.formatter = formatter
28
+ logger
29
+ end
30
+
31
+ attr_reader :args
32
+
33
+ def initialize(args)
34
+ @args = args
35
+ end
36
+
37
+ def valid?
38
+ @error_text = nil
39
+ validate!
40
+ @error_text.nil?
41
+ end
42
+
43
+ def print_error
44
+ puts @error_text if @error_text
45
+ print_usage
46
+ end
47
+
48
+ def start
49
+ end
50
+
51
+ private
52
+
53
+ def print_usage
54
+ puts "Usage: #{$0} #{self.class.command_name}"
55
+ end
56
+
57
+ def validate!
58
+ # Set @error_text if the options are not valid
59
+ end
60
+ end
61
+
62
+ class TitleFontsCommand < Command
63
+ def start
64
+ require 'whirled_peas/utils/title_font'
65
+
66
+ Utils::TitleFont.fonts.keys.each do |key|
67
+ puts Utils::TitleFont.to_s(key.to_s, key)
68
+ puts key.inspect
69
+ puts
70
+ end
71
+ end
72
+ end
73
+
74
+ class ConfigCommand < Command
75
+ def start
76
+ require config
77
+ end
78
+
79
+ private
80
+
81
+ attr_reader :config
82
+
83
+ def validate!
84
+ if args.length == 0
85
+ @error_text = "#{self.class.command_name} requires a config file"
86
+ elsif !File.exist?(args[0])
87
+ @error_text = "File not found: #{args[0]}"
88
+ elsif args[0][-3..-1] != '.rb'
89
+ @error_text = 'Config file should be a .rb file'
90
+ else
91
+ @config = args[0][0] == '/' ? args[0] : File.join(Dir.pwd, args[0])
92
+ end
93
+ end
94
+
95
+ def print_usage
96
+ puts "Usage: #{$0} #{self.class.command_name} <config file>"
97
+ end
98
+ end
99
+
100
+ class StartCommand < ConfigCommand
101
+ LOGGER_ID = 'MAIN'
102
+
103
+ def start
104
+ super
105
+
106
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
107
+
108
+ consumer = Frame::EventLoop.new(
109
+ WhirledPeas.config.template_factory,
110
+ WhirledPeas.config.loading_template_factory,
111
+ logger: logger
112
+ )
113
+ Frame::Producer.produce(consumer, logger) do |producer|
114
+ begin
115
+ WhirledPeas.config.driver.start(producer)
116
+ rescue => e
117
+ logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
118
+ logger.error(LOGGER_ID) { e }
119
+ raise
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ class ListFramesCommand < ConfigCommand
126
+ def start
127
+ super
128
+
129
+ Frame::Producer.produce(Frame::DebugConsumer.new) do |producer|
130
+ WhirledPeas.config.driver.start(producer)
131
+ end
132
+ end
133
+ end
134
+
135
+ class PlayFrameCommand < ConfigCommand
136
+ def start
137
+ super
138
+
139
+ if args.last == '--template'
140
+ template = WhirledPeas.config.template_factory.build(frame, frame_args)
141
+ puts Graphics::Debugger.new(template).debug
142
+ else
143
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
144
+ consumer = Frame::EventLoop.new(
145
+ WhirledPeas.config.template_factory,
146
+ logger: logger
147
+ )
148
+ Frame::Producer.produce(consumer, logger) do |producer|
149
+ producer.send_frame(frame, args: frame_args)
150
+ end
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ attr_reader :frame, :frame_args
157
+
158
+ def validate!
159
+ super
160
+ if !@error_text.nil?
161
+ return
162
+ elsif args.length < 2
163
+ @error_text = "#{self.class.command_name} requires a frame name"
164
+ else
165
+ @frame = args[1]
166
+ @frame_args = {}
167
+ return if args.length < 3 || args[2][0..1] == '--'
168
+ JSON.parse(args[2] || '{}').each do |key, value|
169
+ @frame_args[key.to_sym] = value
170
+ end
171
+ end
172
+ end
173
+
174
+ def print_usage
175
+ puts "Usage: #{$0} #{self.class.command_name} <config file> <frame> [args as a JSON string] [--template]"
176
+ end
177
+ end
178
+
179
+ class LoadingCommand < ConfigCommand
180
+ def start
181
+ super
182
+ unless WhirledPeas.config.loading_template_factory
183
+ puts 'No loading screen configured'
184
+ exit(1)
185
+ end
186
+
187
+ if args.last == '--template'
188
+ template = WhirledPeas.config.loading_template_factory.build
189
+ puts Graphics::Debugger.new(template).debug
190
+ else
191
+ logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
192
+ consumer = Frame::EventLoop.new(
193
+ WhirledPeas.config.template_factory,
194
+ WhirledPeas.config.loading_template_factory,
195
+ logger: logger
196
+ )
197
+ Frame::Producer.produce(consumer, logger) { sleep(5) }
198
+ end
199
+ end
200
+
201
+ private
202
+
203
+ def print_usage
204
+ puts "Usage: #{$0} #{self.class.command_name} [--template]"
205
+ end
206
+ end
207
+
208
+ class CommandLine
209
+ COMMANDS = [
210
+ StartCommand,
211
+ ListFramesCommand,
212
+ PlayFrameCommand,
213
+ LoadingCommand,
214
+ TitleFontsCommand
215
+ ].map.with_object({}) { |c, h| h[c.command_name] = c }
216
+
217
+ def initialize(args)
218
+ @args = args
219
+ end
220
+
221
+ def start
222
+ if args.length < 1
223
+ print_usage
224
+ exit(1)
225
+ end
226
+
227
+ command = args.shift
228
+
229
+ unless COMMANDS.key?(command)
230
+ puts "Unrecognized command: #{command}"
231
+ print_usage
232
+ exit(1)
233
+ end
234
+
235
+ cmd = COMMANDS[command].new(args)
236
+
237
+ unless cmd.valid?
238
+ cmd.print_error
239
+ exit(1)
240
+ end
241
+
242
+ cmd.start
243
+ end
244
+
245
+ private
246
+
247
+ attr_reader :args
248
+
249
+ def print_usage
250
+ puts "Usage: #{$0} <command> [command options]"
251
+ puts
252
+ puts "Available commands: #{COMMANDS.keys.join(', ')}"
253
+ end
254
+ end
255
+ end