whirled_peas 0.4.0 → 0.7.1

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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +38 -0
  4. data/README.md +450 -103
  5. data/Rakefile +28 -3
  6. data/examples/intro.rb +52 -0
  7. data/examples/scrolling.rb +53 -0
  8. data/lib/whirled_peas.rb +4 -8
  9. data/lib/whirled_peas/command_line.rb +44 -55
  10. data/lib/whirled_peas/errors.rb +2 -0
  11. data/lib/whirled_peas/frame.rb +0 -1
  12. data/lib/whirled_peas/frame/consumer.rb +30 -0
  13. data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
  14. data/lib/whirled_peas/frame/event_loop.rb +28 -29
  15. data/lib/whirled_peas/frame/producer.rb +11 -5
  16. data/lib/whirled_peas/graphics.rb +19 -0
  17. data/lib/whirled_peas/graphics/box_painter.rb +101 -0
  18. data/lib/whirled_peas/graphics/canvas.rb +118 -0
  19. data/lib/whirled_peas/graphics/composer.rb +80 -0
  20. data/lib/whirled_peas/graphics/container_coords.rb +72 -0
  21. data/lib/whirled_peas/graphics/container_dimensions.rb +93 -0
  22. data/lib/whirled_peas/graphics/container_painter.rb +272 -0
  23. data/lib/whirled_peas/graphics/debugger.rb +52 -0
  24. data/lib/whirled_peas/graphics/grid_painter.rb +69 -0
  25. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  26. data/lib/whirled_peas/graphics/painter.rb +23 -0
  27. data/lib/whirled_peas/graphics/renderer.rb +26 -0
  28. data/lib/whirled_peas/graphics/screen.rb +70 -0
  29. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  30. data/lib/whirled_peas/graphics/text_painter.rb +40 -0
  31. data/lib/whirled_peas/settings.rb +5 -0
  32. data/lib/whirled_peas/settings/alignment.rb +24 -0
  33. data/lib/whirled_peas/settings/bg_color.rb +24 -0
  34. data/lib/whirled_peas/settings/border.rb +101 -0
  35. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  36. data/lib/whirled_peas/settings/color.rb +68 -0
  37. data/lib/whirled_peas/settings/container_settings.rb +223 -0
  38. data/lib/whirled_peas/settings/debugger.rb +96 -0
  39. data/lib/whirled_peas/settings/display_flow.rb +27 -0
  40. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  41. data/lib/whirled_peas/settings/grid_settings.rb +19 -0
  42. data/lib/whirled_peas/settings/margin.rb +8 -0
  43. data/lib/whirled_peas/settings/padding.rb +8 -0
  44. data/lib/whirled_peas/settings/position.rb +15 -0
  45. data/lib/whirled_peas/settings/scrollbar.rb +15 -0
  46. data/lib/whirled_peas/settings/sizing.rb +19 -0
  47. data/lib/whirled_peas/settings/spacing.rb +58 -0
  48. data/lib/whirled_peas/settings/text_color.rb +21 -0
  49. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  50. data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
  51. data/lib/whirled_peas/utils/ansi.rb +6 -56
  52. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  53. data/lib/whirled_peas/utils/title_font.rb +1 -1
  54. data/lib/whirled_peas/version.rb +1 -1
  55. data/screen_test/elements/box.frame +1 -0
  56. data/screen_test/elements/box.rb +20 -0
  57. data/screen_test/elements/grid.frame +1 -0
  58. data/screen_test/elements/grid.rb +13 -0
  59. data/screen_test/elements/screen_overflow_x.frame +1 -0
  60. data/screen_test/elements/screen_overflow_x.rb +9 -0
  61. data/screen_test/elements/screen_overflow_y.frame +1 -0
  62. data/screen_test/elements/screen_overflow_y.rb +9 -0
  63. data/screen_test/elements/text.frame +1 -0
  64. data/screen_test/elements/text.rb +9 -0
  65. data/screen_test/elements/text_multiline.frame +1 -0
  66. data/screen_test/elements/text_multiline.rb +9 -0
  67. data/screen_test/settings/align/box_around.frame +1 -0
  68. data/screen_test/settings/align/box_around.rb +16 -0
  69. data/screen_test/settings/align/box_between.frame +1 -0
  70. data/screen_test/settings/align/box_between.rb +16 -0
  71. data/screen_test/settings/align/box_center.frame +1 -0
  72. data/screen_test/settings/align/box_center.rb +21 -0
  73. data/screen_test/settings/align/box_default.frame +1 -0
  74. data/screen_test/settings/align/box_default.rb +20 -0
  75. data/screen_test/settings/align/box_evenly.frame +1 -0
  76. data/screen_test/settings/align/box_evenly.rb +16 -0
  77. data/screen_test/settings/align/box_left.frame +1 -0
  78. data/screen_test/settings/align/box_left.rb +21 -0
  79. data/screen_test/settings/align/box_right.frame +1 -0
  80. data/screen_test/settings/align/box_right.rb +21 -0
  81. data/screen_test/settings/align/children_center.frame +1 -0
  82. data/screen_test/settings/align/children_center.rb +15 -0
  83. data/screen_test/settings/align/children_left.frame +1 -0
  84. data/screen_test/settings/align/children_left.rb +15 -0
  85. data/screen_test/settings/align/children_right.frame +1 -0
  86. data/screen_test/settings/align/children_right.rb +15 -0
  87. data/screen_test/settings/align/grid_center.frame +1 -0
  88. data/screen_test/settings/align/grid_center.rb +18 -0
  89. data/screen_test/settings/align/grid_default.frame +1 -0
  90. data/screen_test/settings/align/grid_default.rb +17 -0
  91. data/screen_test/settings/align/grid_left.frame +1 -0
  92. data/screen_test/settings/align/grid_left.rb +18 -0
  93. data/screen_test/settings/align/grid_right.frame +1 -0
  94. data/screen_test/settings/align/grid_right.rb +18 -0
  95. data/screen_test/settings/ansi/bold.frame +1 -0
  96. data/screen_test/settings/ansi/bold.rb +14 -0
  97. data/screen_test/settings/ansi/color.frame +1 -0
  98. data/screen_test/settings/ansi/color.rb +37 -0
  99. data/screen_test/settings/ansi/underline.frame +1 -0
  100. data/screen_test/settings/ansi/underline.rb +14 -0
  101. data/screen_test/settings/border.frame +1 -0
  102. data/screen_test/settings/border.rb +13 -0
  103. data/screen_test/settings/flow/box_b2t.frame +1 -0
  104. data/screen_test/settings/flow/box_b2t.rb +26 -0
  105. data/screen_test/settings/flow/box_l2r.frame +1 -0
  106. data/screen_test/settings/flow/box_l2r.rb +26 -0
  107. data/screen_test/settings/flow/box_r2l.frame +1 -0
  108. data/screen_test/settings/flow/box_r2l.rb +26 -0
  109. data/screen_test/settings/flow/box_t2b.frame +1 -0
  110. data/screen_test/settings/flow/box_t2b.rb +26 -0
  111. data/screen_test/settings/flow/grid_b2t.frame +1 -0
  112. data/screen_test/settings/flow/grid_b2t.rb +14 -0
  113. data/screen_test/settings/flow/grid_l2r.frame +1 -0
  114. data/screen_test/settings/flow/grid_l2r.rb +14 -0
  115. data/screen_test/settings/flow/grid_r2l.frame +1 -0
  116. data/screen_test/settings/flow/grid_r2l.rb +14 -0
  117. data/screen_test/settings/flow/grid_t2b.frame +1 -0
  118. data/screen_test/settings/flow/grid_t2b.rb +14 -0
  119. data/screen_test/settings/height/box.frame +1 -0
  120. data/screen_test/settings/height/box.rb +13 -0
  121. data/screen_test/settings/height/box_border_sizing.frame +1 -0
  122. data/screen_test/settings/height/box_border_sizing.rb +15 -0
  123. data/screen_test/settings/height/grid.frame +1 -0
  124. data/screen_test/settings/height/grid.rb +14 -0
  125. data/screen_test/settings/height/overflow_box.frame +1 -0
  126. data/screen_test/settings/height/overflow_box.rb +13 -0
  127. data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
  128. data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
  129. data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
  130. data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
  131. data/screen_test/settings/height/overflow_grid.frame +1 -0
  132. data/screen_test/settings/height/overflow_grid.rb +16 -0
  133. data/screen_test/settings/margin.frame +1 -0
  134. data/screen_test/settings/margin.rb +16 -0
  135. data/screen_test/settings/padding.frame +1 -0
  136. data/screen_test/settings/padding.rb +13 -0
  137. data/screen_test/settings/position/box_left.frame +1 -0
  138. data/screen_test/settings/position/box_left.rb +17 -0
  139. data/screen_test/settings/position/box_left_negative.frame +1 -0
  140. data/screen_test/settings/position/box_left_negative.rb +17 -0
  141. data/screen_test/settings/position/box_top.frame +1 -0
  142. data/screen_test/settings/position/box_top.rb +17 -0
  143. data/screen_test/settings/position/box_top_negative.frame +1 -0
  144. data/screen_test/settings/position/box_top_negative.rb +17 -0
  145. data/screen_test/settings/position/grid_left.frame +1 -0
  146. data/screen_test/settings/position/grid_left.rb +18 -0
  147. data/screen_test/settings/position/grid_left_negative.frame +1 -0
  148. data/screen_test/settings/position/grid_left_negative.rb +18 -0
  149. data/screen_test/settings/position/grid_top.frame +1 -0
  150. data/screen_test/settings/position/grid_top.rb +18 -0
  151. data/screen_test/settings/position/grid_top_negative.frame +1 -0
  152. data/screen_test/settings/position/grid_top_negative.rb +18 -0
  153. data/screen_test/settings/scroll/horiz_box.frame +1 -0
  154. data/screen_test/settings/scroll/horiz_box.rb +17 -0
  155. data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
  156. data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
  157. data/screen_test/settings/scroll/vert_box.frame +1 -0
  158. data/screen_test/settings/scroll/vert_box.rb +20 -0
  159. data/screen_test/settings/title_font.frame +1 -0
  160. data/screen_test/settings/title_font.rb +12 -0
  161. data/screen_test/settings/valign/box_around.frame +1 -0
  162. data/screen_test/settings/valign/box_around.rb +17 -0
  163. data/screen_test/settings/valign/box_between.frame +1 -0
  164. data/screen_test/settings/valign/box_between.rb +17 -0
  165. data/screen_test/settings/valign/box_bottom.frame +1 -0
  166. data/screen_test/settings/valign/box_bottom.rb +17 -0
  167. data/screen_test/settings/valign/box_default.frame +1 -0
  168. data/screen_test/settings/valign/box_default.rb +16 -0
  169. data/screen_test/settings/valign/box_evenly.frame +1 -0
  170. data/screen_test/settings/valign/box_evenly.rb +17 -0
  171. data/screen_test/settings/valign/box_middle.frame +1 -0
  172. data/screen_test/settings/valign/box_middle.rb +17 -0
  173. data/screen_test/settings/valign/box_top.frame +1 -0
  174. data/screen_test/settings/valign/box_top.rb +17 -0
  175. data/screen_test/settings/valign/grid_bottom.frame +1 -0
  176. data/screen_test/settings/valign/grid_bottom.rb +15 -0
  177. data/screen_test/settings/valign/grid_default.frame +1 -0
  178. data/screen_test/settings/valign/grid_default.rb +14 -0
  179. data/screen_test/settings/valign/grid_middle.frame +1 -0
  180. data/screen_test/settings/valign/grid_middle.rb +15 -0
  181. data/screen_test/settings/valign/grid_top.frame +1 -0
  182. data/screen_test/settings/valign/grid_top.rb +15 -0
  183. data/screen_test/settings/width/box_border_sizing.frame +1 -0
  184. data/screen_test/settings/width/box_border_sizing.rb +15 -0
  185. data/screen_test/settings/width/box_content.frame +1 -0
  186. data/screen_test/settings/width/box_content.rb +15 -0
  187. data/screen_test/settings/width/box_default.frame +1 -0
  188. data/screen_test/settings/width/box_default.rb +14 -0
  189. data/screen_test/settings/width/grid.frame +1 -0
  190. data/screen_test/settings/width/grid.rb +14 -0
  191. data/screen_test/settings/width/overflow_align_center.frame +1 -0
  192. data/screen_test/settings/width/overflow_align_center.rb +14 -0
  193. data/screen_test/settings/width/overflow_align_right.frame +1 -0
  194. data/screen_test/settings/width/overflow_align_right.rb +14 -0
  195. data/screen_test/settings/width/overflow_box.frame +1 -0
  196. data/screen_test/settings/width/overflow_box.rb +13 -0
  197. data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
  198. data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
  199. data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
  200. data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
  201. data/screen_test/settings/width/overflow_grid.frame +1 -0
  202. data/screen_test/settings/width/overflow_grid.rb +14 -0
  203. data/tools/whirled_peas/tools/screen_tester.rb +233 -0
  204. metadata +191 -12
  205. data/bin/title_fonts +0 -6
  206. data/lib/whirled_peas/frame/print_consumer.rb +0 -33
  207. data/lib/whirled_peas/template.rb +0 -5
  208. data/lib/whirled_peas/template/element.rb +0 -230
  209. data/lib/whirled_peas/template/settings.rb +0 -530
  210. data/lib/whirled_peas/ui.rb +0 -5
  211. data/lib/whirled_peas/ui/canvas.rb +0 -68
  212. data/lib/whirled_peas/ui/painter.rb +0 -287
  213. data/lib/whirled_peas/ui/screen.rb +0 -63
  214. data/lib/whirled_peas/utils/color.rb +0 -101
data/Rakefile CHANGED
@@ -1,6 +1,31 @@
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
+ require_relative 'tools/whirled_peas/tools/screen_tester'
9
+ WhirledPeas::Tools::ScreenTester.new(file).send(method)
10
+ end
11
+
12
+ namespace :screen_test do
13
+ %i[template view run save update debug].each do |t|
14
+ task t, [:file] do |_, args|
15
+ screen_test(args[:file], t)
16
+ end
17
+ end
18
+
19
+ task :update_all do
20
+ require_relative 'tools/whirled_peas/tools/screen_tester'
21
+ WhirledPeas::Tools::ScreenTester.update_all
22
+ end
23
+ end
24
+
25
+ task :screen_test do
26
+ require_relative 'tools/whirled_peas/tools/screen_tester'
27
+ WhirledPeas::Tools::ScreenTester.run_all
28
+ end
29
+
30
+ task default: :ci
31
+ task ci: %i[spec screen_test]
@@ -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
@@ -1,11 +1,10 @@
1
1
  require 'logger'
2
2
 
3
3
  require 'whirled_peas/errors'
4
-
5
4
  require 'whirled_peas/config'
6
5
  require 'whirled_peas/frame'
7
- require 'whirled_peas/template'
8
- require 'whirled_peas/ui'
6
+ require 'whirled_peas/graphics'
7
+ require 'whirled_peas/settings'
9
8
  require 'whirled_peas/utils'
10
9
  require 'whirled_peas/version'
11
10
 
@@ -19,10 +18,7 @@ module WhirledPeas
19
18
  end
20
19
 
21
20
  def self.template(&block)
22
- require 'whirled_peas/template/element'
23
-
24
- template = UI::Template.new
25
- yield template, template.settings
26
- template
21
+ require 'whirled_peas/graphics/composer'
22
+ Graphics::Composer.build(&block)
27
23
  end
28
24
  end
@@ -1,7 +1,14 @@
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
+
1
10
  module WhirledPeas
2
11
  class Command
3
- DEFAULT_REFRESH_RATE = 30
4
-
5
12
  DEFAULT_LOG_LEVEL = Logger::INFO
6
13
  DEFAULT_FORMATTER = proc do |severity, datetime, progname, msg|
7
14
  if msg.is_a?(Exception)
@@ -66,11 +73,13 @@ module WhirledPeas
66
73
 
67
74
  class ConfigCommand < Command
68
75
  def start
69
- require args[0]
76
+ require config
70
77
  end
71
78
 
72
79
  private
73
80
 
81
+ attr_reader :config
82
+
74
83
  def validate!
75
84
  if args.length == 0
76
85
  @error_text = "#{self.class.command_name} requires a config file"
@@ -78,6 +87,8 @@ module WhirledPeas
78
87
  @error_text = "File not found: #{args[0]}"
79
88
  elsif args[0][-3..-1] != '.rb'
80
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])
81
92
  end
82
93
  end
83
94
 
@@ -91,16 +102,13 @@ module WhirledPeas
91
102
 
92
103
  def start
93
104
  super
94
- require 'whirled_peas/frame/event_loop'
95
- require 'whirled_peas/frame/producer'
96
105
 
97
106
  logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
98
107
 
99
108
  consumer = Frame::EventLoop.new(
100
109
  WhirledPeas.config.template_factory,
101
110
  WhirledPeas.config.loading_template_factory,
102
- DEFAULT_REFRESH_RATE,
103
- logger
111
+ logger: logger
104
112
  )
105
113
  Frame::Producer.produce(consumer, logger) do |producer|
106
114
  begin
@@ -117,18 +125,9 @@ module WhirledPeas
117
125
  class ListFramesCommand < ConfigCommand
118
126
  def start
119
127
  super
120
- require 'whirled_peas/frame/print_consumer'
121
- require 'whirled_peas/frame/producer'
122
128
 
123
- logger = self.class.build_logger(STDOUT)
124
- Frame::Producer.produce(Frame::PrintConsumer.new, logger) do |producer|
125
- begin
126
- WhirledPeas.config.driver.start(producer)
127
- rescue => e
128
- logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
129
- logger.error(LOGGER_ID) { e }
130
- raise
131
- end
129
+ Frame::Producer.produce(Frame::DebugConsumer.new) do |producer|
130
+ WhirledPeas.config.driver.start(producer)
132
131
  end
133
132
  end
134
133
  end
@@ -137,24 +136,18 @@ module WhirledPeas
137
136
  def start
138
137
  super
139
138
 
140
- if args.last == '--debug'
141
- puts WhirledPeas.config.template_factory.build(frame, frame_args).inspect
142
- exit
143
- end
144
-
145
- require 'whirled_peas/frame/event_loop'
146
- require 'whirled_peas/frame/producer'
147
-
148
- logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
149
-
150
- consumer = Frame::EventLoop.new(
151
- WhirledPeas.config.template_factory,
152
- WhirledPeas.config.loading_template_factory,
153
- DEFAULT_REFRESH_RATE,
154
- logger
155
- )
156
- Frame::Producer.produce(consumer, logger) do |producer|
157
- producer.send_frame(args[1], duration: 5, args: frame_args)
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
158
151
  end
159
152
  end
160
153
 
@@ -169,9 +162,9 @@ module WhirledPeas
169
162
  elsif args.length < 2
170
163
  @error_text = "#{self.class.command_name} requires a frame name"
171
164
  else
172
- require 'json'
173
165
  @frame = args[1]
174
166
  @frame_args = {}
167
+ return if args.length < 3 || args[2][0..1] == '--'
175
168
  JSON.parse(args[2] || '{}').each do |key, value|
176
169
  @frame_args[key.to_sym] = value
177
170
  end
@@ -179,7 +172,7 @@ module WhirledPeas
179
172
  end
180
173
 
181
174
  def print_usage
182
- puts "Usage: #{$0} #{self.class.command_name} <config file> <frame> [args as a JSON string] [--debug]"
175
+ puts "Usage: #{$0} #{self.class.command_name} <config file> <frame> [args as a JSON string] [--template]"
183
176
  end
184
177
  end
185
178
 
@@ -188,31 +181,27 @@ module WhirledPeas
188
181
  super
189
182
  unless WhirledPeas.config.loading_template_factory
190
183
  puts 'No loading screen configured'
191
- exit
184
+ exit(1)
192
185
  end
193
186
 
194
- if args.last == '--debug'
195
- puts WhirledPeas.config.loading_template_factory.build.inspect
196
- exit
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) }
197
198
  end
198
-
199
- require 'whirled_peas/frame/event_loop'
200
- require 'whirled_peas/frame/producer'
201
-
202
- logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
203
- consumer = Frame::EventLoop.new(
204
- WhirledPeas.config.template_factory,
205
- WhirledPeas.config.loading_template_factory,
206
- DEFAULT_REFRESH_RATE,
207
- logger
208
- )
209
- Frame::Producer.produce(consumer, logger) { sleep(5) }
210
199
  end
211
200
 
212
201
  private
213
202
 
214
203
  def print_usage
215
- puts "Usage: #{$0} #{self.class.command_name} [--debug]"
204
+ puts "Usage: #{$0} #{self.class.command_name} [--template]"
216
205
  end
217
206
  end
218
207
 
@@ -2,4 +2,6 @@ module WhirledPeas
2
2
  class Error < StandardError; end
3
3
 
4
4
  class ConfigurationError < Error; end
5
+
6
+ class SettingsError < Error; end
5
7
  end
@@ -1,6 +1,5 @@
1
1
  module WhirledPeas
2
2
  module Frame
3
- EOF = '__EOF__'
4
3
  end
5
4
 
6
5
  private_constant :Frame
@@ -0,0 +1,30 @@
1
+ module WhirledPeas
2
+ module Frame
3
+ # Abstract class for consuming frame events.
4
+ class Consumer
5
+ EOF = '__EOF__'
6
+
7
+ def enqueue(name, duration, args)
8
+ raise NotImplemented, "#{self.class} must implement #enqueue"
9
+ end
10
+
11
+ def running?
12
+ @running == true
13
+ end
14
+
15
+ def start
16
+ self.running = true
17
+ end
18
+
19
+ def stop
20
+ enqueue(EOF, nil, {})
21
+ end
22
+
23
+ private
24
+
25
+ attr_writer :running
26
+ end
27
+
28
+ private_constant :Consumer
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'whirled_peas/null_logger'
2
+
3
+ require_relative 'consumer'
4
+
5
+ module WhirledPeas
6
+ module Frame
7
+ class DebugConsumer < Consumer
8
+ LOGGER_ID = 'PRINTER'
9
+
10
+ def initialize(output=STDOUT, logger=NullLogger.new)
11
+ @output = output
12
+ @logger = logger
13
+ end
14
+
15
+ def enqueue(name, duration, args)
16
+ if name == EOF
17
+ output.puts "EOF frame detected"
18
+ else
19
+ displayed_for = duration ? "#{duration} second(s)" : '1 frame'
20
+ args_str = args.empty? ? '' : " '#{JSON.generate(args)}'"
21
+ output.puts "Frame '#{name}' displayed for #{displayed_for}#{args_str}"
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :output, :logger
28
+ end
29
+ end
30
+ end
@@ -1,17 +1,28 @@
1
- require_relative '../null_logger'
2
- require_relative '../ui/screen'
1
+ require 'whirled_peas/null_logger'
2
+ require 'whirled_peas/graphics/screen'
3
+
4
+ require_relative 'consumer'
3
5
 
4
6
  module WhirledPeas
5
7
  module Frame
6
- class EventLoop
8
+ class EventLoop < Consumer
9
+ DEFAULT_REFRESH_RATE = 30
10
+
7
11
  LOGGER_ID = 'EVENT LOOP'
8
12
 
9
- def initialize(template_factory, loading_template_factory, refresh_rate, logger=NullLogger.new)
13
+ def initialize(
14
+ template_factory,
15
+ loading_template_factory=nil,
16
+ refresh_rate: DEFAULT_REFRESH_RATE,
17
+ logger: NullLogger.new,
18
+ screen: Graphics::Screen.new
19
+ )
10
20
  @template_factory = template_factory
11
21
  @loading_template_factory = loading_template_factory
12
22
  @queue = Queue.new
13
23
  @frame_duration = 1.0 / refresh_rate
14
24
  @logger = logger
25
+ @screen = screen
15
26
  end
16
27
 
17
28
  def enqueue(name, duration, args)
@@ -19,50 +30,38 @@ module WhirledPeas
19
30
  queue.push([name, duration || frame_duration, args])
20
31
  end
21
32
 
22
- def running?
23
- @running
24
- end
25
-
26
33
  def start
27
- screen = UI::Screen.new
28
- wait_for_content(screen)
29
- play_content(screen)
34
+ super
35
+ wait_for_content
36
+ play_content
30
37
  rescue
38
+ self.running = false
31
39
  logger.warn(LOGGER_ID) { 'Exiting with error' }
32
40
  raise
33
41
  ensure
34
- # We may have exited due to an EOF or a raised exception, set state so that
35
- # instance reflects actual state.
36
- @running = false
37
- screen.finalize if screen
38
- end
39
-
40
- def stop
41
- logger.info(LOGGER_ID) { 'Stopping...' }
42
- @running = false
42
+ screen.finalize
43
43
  end
44
44
 
45
45
  private
46
46
 
47
- attr_reader :template_factory, :loading_template_factory, :queue, :frame_duration, :logger
47
+ attr_reader :template_factory, :loading_template_factory, :queue, :frame_duration, :logger, :screen
48
48
 
49
- def wait_for_content(screen)
49
+ def wait_for_content
50
50
  if loading_template_factory
51
- play_loading_screen(screen)
51
+ play_loading_screen
52
52
  else
53
53
  sleep(frame_duration) while queue.empty?
54
54
  end
55
55
  end
56
56
 
57
- def play_loading_screen(screen)
57
+ def play_loading_screen
58
58
  while queue.empty?
59
59
  screen.paint(loading_template_factory.build)
60
60
  sleep(frame_duration)
61
61
  end
62
62
  end
63
63
 
64
- def play_content(screen)
65
- @running = true
64
+ def play_content
66
65
  template = nil
67
66
  frame_until = Time.new(0) # Tell the loop to immediately pick up a new frame
68
67
  while running?
@@ -73,15 +72,15 @@ module WhirledPeas
73
72
  screen.refresh
74
73
  elsif !queue.empty?
75
74
  name, duration, args = queue.pop
76
- if name == Frame::EOF
77
- @running = false
75
+ if name == EOF
76
+ self.running = false
78
77
  else
79
78
  frame_until = frame_start + duration
80
79
  template = template_factory.build(name, args)
81
80
  screen.paint(template)
82
81
  end
83
82
  else
84
- wait_for_content(screen)
83
+ wait_for_content
85
84
  end
86
85
  sleep([0, next_frame_at - Time.now].max)
87
86
  end