whirled_peas 0.7.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +25 -0
  4. data/README.md +467 -120
  5. data/Rakefile +1 -20
  6. data/bin/easing +33 -0
  7. data/bin/reset_cursor +11 -0
  8. data/bin/screen_test +68 -0
  9. data/examples/graph.rb +54 -0
  10. data/examples/intro.rb +3 -3
  11. data/examples/scrolling.rb +5 -4
  12. data/lib/data/themes.yaml +13 -0
  13. data/lib/whirled_peas.rb +12 -6
  14. data/lib/whirled_peas/animator.rb +5 -0
  15. data/lib/whirled_peas/animator/debug_consumer.rb +17 -0
  16. data/lib/whirled_peas/animator/easing.rb +72 -0
  17. data/lib/whirled_peas/animator/frame.rb +5 -0
  18. data/lib/whirled_peas/animator/frameset.rb +33 -0
  19. data/lib/whirled_peas/animator/producer.rb +35 -0
  20. data/lib/whirled_peas/animator/renderer_consumer.rb +31 -0
  21. data/lib/whirled_peas/command.rb +5 -0
  22. data/lib/whirled_peas/command/base.rb +86 -0
  23. data/lib/whirled_peas/command/config_command.rb +43 -0
  24. data/lib/whirled_peas/command/debug.rb +21 -0
  25. data/lib/whirled_peas/command/fonts.rb +22 -0
  26. data/lib/whirled_peas/command/frame_command.rb +34 -0
  27. data/lib/whirled_peas/command/frames.rb +24 -0
  28. data/lib/whirled_peas/command/help.rb +38 -0
  29. data/lib/whirled_peas/command/play.rb +111 -0
  30. data/lib/whirled_peas/command/record.rb +57 -0
  31. data/lib/whirled_peas/command/still.rb +29 -0
  32. data/lib/whirled_peas/command/themes.rb +76 -0
  33. data/lib/whirled_peas/command_line.rb +24 -212
  34. data/lib/whirled_peas/config.rb +56 -6
  35. data/lib/whirled_peas/device.rb +5 -0
  36. data/lib/whirled_peas/device/null_device.rb +8 -0
  37. data/lib/whirled_peas/device/output_file.rb +19 -0
  38. data/lib/whirled_peas/device/screen.rb +26 -0
  39. data/lib/whirled_peas/graphics/composer.rb +23 -2
  40. data/lib/whirled_peas/graphics/container_painter.rb +91 -0
  41. data/lib/whirled_peas/graphics/content_dimensions.rb +19 -0
  42. data/lib/whirled_peas/graphics/content_painter.rb +20 -0
  43. data/lib/whirled_peas/graphics/graph_dimensions.rb +12 -0
  44. data/lib/whirled_peas/graphics/graph_painter.rb +97 -0
  45. data/lib/whirled_peas/graphics/grid_painter.rb +1 -4
  46. data/lib/whirled_peas/graphics/painter.rb +10 -0
  47. data/lib/whirled_peas/graphics/renderer.rb +8 -2
  48. data/lib/whirled_peas/graphics/text_painter.rb +7 -11
  49. data/lib/whirled_peas/settings/border.rb +25 -4
  50. data/lib/whirled_peas/settings/container_settings.rb +2 -4
  51. data/lib/whirled_peas/settings/element_settings.rb +12 -3
  52. data/lib/whirled_peas/settings/graph_settings.rb +21 -0
  53. data/lib/whirled_peas/settings/grid_settings.rb +7 -0
  54. data/lib/whirled_peas/settings/text_settings.rb +1 -0
  55. data/lib/whirled_peas/settings/theme.rb +40 -0
  56. data/lib/whirled_peas/settings/theme_library.rb +63 -0
  57. data/lib/whirled_peas/utils/ansi.rb +13 -0
  58. data/lib/whirled_peas/utils/file_handler.rb +57 -0
  59. data/lib/whirled_peas/version.rb +1 -1
  60. data/screen_test/elements/box.frame +1 -1
  61. data/screen_test/elements/box.rb +1 -1
  62. data/screen_test/elements/graph.frame +1 -0
  63. data/screen_test/elements/graph.rb +12 -0
  64. data/screen_test/elements/grid.frame +1 -1
  65. data/screen_test/elements/grid.rb +1 -1
  66. data/screen_test/elements/screen_overflow_x.frame +1 -1
  67. data/screen_test/elements/screen_overflow_x.rb +1 -1
  68. data/screen_test/elements/screen_overflow_y.frame +1 -1
  69. data/screen_test/elements/screen_overflow_y.rb +1 -1
  70. data/screen_test/elements/text.frame +1 -1
  71. data/screen_test/elements/text.rb +1 -1
  72. data/screen_test/elements/text_multiline.frame +1 -1
  73. data/screen_test/elements/text_multiline.rb +1 -1
  74. data/screen_test/elements/theme.frame +1 -0
  75. data/screen_test/elements/theme.rb +26 -0
  76. data/screen_test/settings/align/box_around.frame +1 -1
  77. data/screen_test/settings/align/box_around.rb +1 -1
  78. data/screen_test/settings/align/box_between.frame +1 -1
  79. data/screen_test/settings/align/box_between.rb +1 -1
  80. data/screen_test/settings/align/box_center.frame +1 -1
  81. data/screen_test/settings/align/box_center.rb +1 -1
  82. data/screen_test/settings/align/box_default.frame +1 -1
  83. data/screen_test/settings/align/box_default.rb +1 -1
  84. data/screen_test/settings/align/box_evenly.frame +1 -1
  85. data/screen_test/settings/align/box_evenly.rb +1 -1
  86. data/screen_test/settings/align/box_left.frame +1 -1
  87. data/screen_test/settings/align/box_left.rb +1 -1
  88. data/screen_test/settings/align/box_right.frame +1 -1
  89. data/screen_test/settings/align/box_right.rb +1 -1
  90. data/screen_test/settings/align/children_center.frame +1 -1
  91. data/screen_test/settings/align/children_center.rb +1 -1
  92. data/screen_test/settings/align/children_left.frame +1 -1
  93. data/screen_test/settings/align/children_left.rb +1 -1
  94. data/screen_test/settings/align/children_right.frame +1 -1
  95. data/screen_test/settings/align/children_right.rb +1 -1
  96. data/screen_test/settings/align/grid_center.frame +1 -1
  97. data/screen_test/settings/align/grid_center.rb +1 -1
  98. data/screen_test/settings/align/grid_default.frame +1 -1
  99. data/screen_test/settings/align/grid_default.rb +1 -1
  100. data/screen_test/settings/align/grid_left.frame +1 -1
  101. data/screen_test/settings/align/grid_left.rb +1 -1
  102. data/screen_test/settings/align/grid_right.frame +1 -1
  103. data/screen_test/settings/align/grid_right.rb +1 -1
  104. data/screen_test/settings/ansi/bold.frame +1 -1
  105. data/screen_test/settings/ansi/bold.rb +1 -1
  106. data/screen_test/settings/ansi/color.frame +1 -1
  107. data/screen_test/settings/ansi/color.rb +1 -1
  108. data/screen_test/settings/ansi/underline.frame +1 -1
  109. data/screen_test/settings/ansi/underline.rb +1 -1
  110. data/screen_test/settings/border.frame +1 -1
  111. data/screen_test/settings/border.rb +1 -1
  112. data/screen_test/settings/flow/box_b2t.frame +1 -1
  113. data/screen_test/settings/flow/box_b2t.rb +1 -1
  114. data/screen_test/settings/flow/box_l2r.frame +1 -1
  115. data/screen_test/settings/flow/box_l2r.rb +1 -1
  116. data/screen_test/settings/flow/box_r2l.frame +1 -1
  117. data/screen_test/settings/flow/box_r2l.rb +1 -1
  118. data/screen_test/settings/flow/box_t2b.frame +1 -1
  119. data/screen_test/settings/flow/box_t2b.rb +1 -1
  120. data/screen_test/settings/flow/grid_b2t.frame +1 -1
  121. data/screen_test/settings/flow/grid_b2t.rb +2 -2
  122. data/screen_test/settings/flow/grid_l2r.frame +1 -1
  123. data/screen_test/settings/flow/grid_l2r.rb +2 -2
  124. data/screen_test/settings/flow/grid_r2l.frame +1 -1
  125. data/screen_test/settings/flow/grid_r2l.rb +2 -2
  126. data/screen_test/settings/flow/grid_t2b.frame +1 -1
  127. data/screen_test/settings/flow/grid_t2b.rb +2 -2
  128. data/screen_test/settings/height/box.frame +1 -1
  129. data/screen_test/settings/height/box.rb +1 -1
  130. data/screen_test/settings/height/box_border_sizing.frame +1 -1
  131. data/screen_test/settings/height/box_border_sizing.rb +1 -1
  132. data/screen_test/settings/height/grid.frame +1 -1
  133. data/screen_test/settings/height/grid.rb +1 -1
  134. data/screen_test/settings/height/overflow_box.frame +1 -1
  135. data/screen_test/settings/height/overflow_box.rb +1 -1
  136. data/screen_test/settings/height/overflow_box_l2r.frame +1 -1
  137. data/screen_test/settings/height/overflow_box_l2r.rb +1 -1
  138. data/screen_test/settings/height/overflow_box_t2b.frame +1 -1
  139. data/screen_test/settings/height/overflow_box_t2b.rb +1 -1
  140. data/screen_test/settings/height/overflow_grid.frame +1 -1
  141. data/screen_test/settings/height/overflow_grid.rb +1 -1
  142. data/screen_test/settings/margin.frame +1 -1
  143. data/screen_test/settings/margin.rb +1 -1
  144. data/screen_test/settings/padding.frame +1 -1
  145. data/screen_test/settings/padding.rb +1 -1
  146. data/screen_test/settings/position/box_left.frame +1 -1
  147. data/screen_test/settings/position/box_left.rb +1 -1
  148. data/screen_test/settings/position/box_left_negative.frame +1 -1
  149. data/screen_test/settings/position/box_left_negative.rb +1 -1
  150. data/screen_test/settings/position/box_top.frame +1 -1
  151. data/screen_test/settings/position/box_top.rb +1 -1
  152. data/screen_test/settings/position/box_top_negative.frame +1 -1
  153. data/screen_test/settings/position/box_top_negative.rb +1 -1
  154. data/screen_test/settings/position/grid_left.frame +1 -1
  155. data/screen_test/settings/position/grid_left.rb +1 -1
  156. data/screen_test/settings/position/grid_left_negative.frame +1 -1
  157. data/screen_test/settings/position/grid_left_negative.rb +1 -1
  158. data/screen_test/settings/position/grid_top.frame +1 -1
  159. data/screen_test/settings/position/grid_top.rb +1 -1
  160. data/screen_test/settings/position/grid_top_negative.frame +1 -1
  161. data/screen_test/settings/position/grid_top_negative.rb +1 -1
  162. data/screen_test/settings/scroll/horiz_box.frame +1 -1
  163. data/screen_test/settings/scroll/horiz_box.rb +1 -1
  164. data/screen_test/settings/scroll/horiz_box_align_center.rb +1 -1
  165. data/screen_test/settings/scroll/horiz_box_align_right.rb +1 -1
  166. data/screen_test/settings/scroll/vert_box.frame +1 -1
  167. data/screen_test/settings/scroll/vert_box.rb +1 -1
  168. data/screen_test/settings/title_font.frame +1 -1
  169. data/screen_test/settings/title_font.rb +1 -1
  170. data/screen_test/settings/valign/box_around.frame +1 -1
  171. data/screen_test/settings/valign/box_around.rb +1 -1
  172. data/screen_test/settings/valign/box_between.frame +1 -1
  173. data/screen_test/settings/valign/box_between.rb +1 -1
  174. data/screen_test/settings/valign/box_bottom.frame +1 -1
  175. data/screen_test/settings/valign/box_bottom.rb +1 -1
  176. data/screen_test/settings/valign/box_default.frame +1 -1
  177. data/screen_test/settings/valign/box_default.rb +1 -1
  178. data/screen_test/settings/valign/box_evenly.frame +1 -1
  179. data/screen_test/settings/valign/box_evenly.rb +1 -1
  180. data/screen_test/settings/valign/box_middle.frame +1 -1
  181. data/screen_test/settings/valign/box_middle.rb +1 -1
  182. data/screen_test/settings/valign/box_top.frame +1 -1
  183. data/screen_test/settings/valign/box_top.rb +1 -1
  184. data/screen_test/settings/valign/grid_bottom.frame +1 -1
  185. data/screen_test/settings/valign/grid_bottom.rb +1 -1
  186. data/screen_test/settings/valign/grid_default.frame +1 -1
  187. data/screen_test/settings/valign/grid_default.rb +1 -1
  188. data/screen_test/settings/valign/grid_middle.frame +1 -1
  189. data/screen_test/settings/valign/grid_middle.rb +1 -1
  190. data/screen_test/settings/valign/grid_top.frame +1 -1
  191. data/screen_test/settings/valign/grid_top.rb +1 -1
  192. data/screen_test/settings/width/box_border_sizing.frame +1 -1
  193. data/screen_test/settings/width/box_border_sizing.rb +1 -1
  194. data/screen_test/settings/width/box_content.frame +1 -1
  195. data/screen_test/settings/width/box_content.rb +1 -1
  196. data/screen_test/settings/width/box_default.frame +1 -1
  197. data/screen_test/settings/width/box_default.rb +1 -1
  198. data/screen_test/settings/width/grid.frame +1 -1
  199. data/screen_test/settings/width/grid.rb +1 -1
  200. data/screen_test/settings/width/overflow_align_center.frame +1 -1
  201. data/screen_test/settings/width/overflow_align_center.rb +1 -1
  202. data/screen_test/settings/width/overflow_align_right.frame +1 -1
  203. data/screen_test/settings/width/overflow_align_right.rb +1 -1
  204. data/screen_test/settings/width/overflow_box.frame +1 -1
  205. data/screen_test/settings/width/overflow_box.rb +1 -1
  206. data/screen_test/settings/width/overflow_box_l2r.frame +1 -1
  207. data/screen_test/settings/width/overflow_box_l2r.rb +1 -1
  208. data/screen_test/settings/width/overflow_box_t2b.frame +1 -1
  209. data/screen_test/settings/width/overflow_box_t2b.rb +1 -1
  210. data/screen_test/settings/width/overflow_grid.frame +1 -1
  211. data/screen_test/settings/width/overflow_grid.rb +1 -1
  212. data/tools/whirled_peas/tools/screen_tester.rb +131 -65
  213. metadata +42 -9
  214. data/lib/whirled_peas/frame.rb +0 -6
  215. data/lib/whirled_peas/frame/consumer.rb +0 -30
  216. data/lib/whirled_peas/frame/debug_consumer.rb +0 -30
  217. data/lib/whirled_peas/frame/event_loop.rb +0 -90
  218. data/lib/whirled_peas/frame/producer.rb +0 -67
  219. data/lib/whirled_peas/graphics/screen.rb +0 -70
  220. data/lib/whirled_peas/graphics/text_dimensions.rb +0 -15
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |composer, settings|
7
7
  settings.flow = :t2b
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━┓┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┗━┛ABC[?25h
1
+ [?25l                        ┏━┓┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┗━┛ABC[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |composer, settings|
7
7
  settings.flow = :t2b
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
1
+ [?25l                        ┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_grid('Alignment') do |composer, settings|
7
7
  settings.num_cols = 1
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
1
+ [?25l                        ┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_grid('Alignment') do |composer, settings|
7
7
  settings.num_cols = 1
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
1
+ [?25l                        ┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_grid('Alignment') do |composer, settings|
7
7
  settings.num_cols = 1
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
1
+ [?25l                        ┏━┓┃ ┃┃ ┃┃ ┃┗━┛A[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_grid('Alignment') do |composer, settings|
7
7
  settings.num_cols = 1
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━┛15/bor[?25h
1
+ [?25l                        ┏━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━┛15/bor[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box('Wide') do |_, settings|
7
7
  settings.full_border
8
8
  settings.set_padding(left: 3, right: 4)
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━┛15/content[?25h
1
+ [?25l                        ┏━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━┛15/content[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box('Wide') do |_, settings|
7
7
  settings.full_border
8
8
  settings.set_padding(left: 3, right: 4)
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━┛15/default[?25h
1
+ [?25l                        ┏━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━┛15/default[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box('Wide') do |_, settings|
7
7
  settings.full_border
8
8
  settings.set_padding(left: 3, right: 4)
@@ -1 +1 @@
1
- [?25l┏━━━━━━┳━━━━━━┓┃ ┃ ┃┣━━━━━━╋━━━━━━┫┃ ┃ ┃┣━━━━━━╋━━━━━━┫┃ ┃ ┃┗━━━━━━┻━━━━━━┛666666[?25h
1
+ [?25l                        ┏━━━━━━┳━━━━━━┓┃ ┃ ┃┣━━━━━━╋━━━━━━┫┃ ┃ ┃┣━━━━━━╋━━━━━━┫┃ ┃ ┃┗━━━━━━┻━━━━━━┛666666[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_grid('Wide') do |_, settings|
7
7
  settings.full_border
8
8
  settings.width = 6
@@ -1 +1 @@
1
- [?25l┏━━━┓┃ ┃┗━━━┛345[?25h
1
+ [?25l                        ┏━━━┓┃ ┃┗━━━┛345[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box('Container') do |composer, settings|
7
7
  settings.width = 3
8
8
  settings.align = :center
@@ -1 +1 @@
1
- [?25l┏━━━┓┃ ┃┗━━━┛456[?25h
1
+ [?25l                        ┏━━━┓┃ ┃┗━━━┛456[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |composer, settings|
7
7
  settings.width = 3
8
8
  settings.align = :right
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛ABCDEFGHIJ[?25h
1
+ [?25l                        ┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛ABCDEFGHIJ[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |_, settings|
7
7
  settings.width = 10
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛0|0|1|0|1|[?25h
1
+ [?25l                        ┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛0|0|1|0|1|[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |composer, settings|
7
7
  settings.width = 10
8
8
  settings.full_border
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━┓┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┗━━━━━━━━━━┛XOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXO[?25h
1
+ [?25l                        ┏━━━━━━━━━━┓┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┗━━━━━━━━━━┛XOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXO[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer|
5
+ WhirledPeas.template(:test) do |composer|
6
6
  composer.add_box do |composer, settings|
7
7
  settings.width = 10
8
8
  settings.flow = :t2b
@@ -1 +1 @@
1
- [?25l┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛ABCDEFGHIJ[?25h
1
+ [?25l                        ┏━━━━━━━━━━┓┃ ┃┗━━━━━━━━━━┛ABCDEFGHIJ[?25h
@@ -2,7 +2,7 @@ require 'whirled_peas'
2
2
 
3
3
  class TemplateFactory
4
4
  def build(*)
5
- WhirledPeas.template do |composer, settings|
5
+ WhirledPeas.template(:test) do |composer, settings|
6
6
  composer.add_grid('grid') do |_, settings|
7
7
  settings.width = 10
8
8
  settings.full_border
@@ -1,34 +1,66 @@
1
1
  require 'bundler/setup'
2
2
  require 'whirled_peas'
3
- require 'whirled_peas/frame/event_loop'
4
- require 'whirled_peas/frame/producer'
3
+ require 'whirled_peas/animator/producer'
4
+ require 'whirled_peas/animator/renderer_consumer'
5
+ require 'whirled_peas/device/screen'
5
6
  require 'whirled_peas/graphics/debugger'
6
7
  require 'whirled_peas/graphics/renderer'
7
- require 'whirled_peas/graphics/screen'
8
8
  require 'whirled_peas/settings/text_color'
9
+ require 'whirled_peas/settings/theme'
10
+ require 'whirled_peas/settings/theme_library'
11
+ require 'whirled_peas/utils/ansi'
9
12
  require 'whirled_peas/utils/formatted_string'
10
13
 
11
14
  module WhirledPeas
15
+ # Useful code for managing the repository that should not be distributed with the gem
12
16
  module Tools
13
- # levels_up = 0 returns the directory of the current file. If the current file is a
14
- # directory, then it will return a parent directory
17
+ # Return the parent directory N-levels up from the current file. If levels_up = 0 return
18
+ # the directory of the current file. E.g.
19
+ #
20
+ # parent_directory("/path/to/file.rb")
21
+ # # => "/path/to"
22
+ #
23
+ # parent_directory("really/long/path/to/another/file.rb", 3)
24
+ # # => "really/long"
25
+ #
15
26
  def self.parent_directory(file, levels_up=0)
16
27
  return File.dirname(file) if levels_up == 0
17
28
  parent_directory(File.dirname(file), levels_up - 1)
18
29
  end
19
30
 
20
31
  class ScreenTester
32
+ # The output of a rendered frame is depenend upon the width and height of the screen.
33
+ # Thus for the sake of reproduceability, the same width and height should be used for
34
+ # all runs of the test. The values should be relatively small to discourage testing
35
+ # complicated templates.
21
36
  SCREEN_WIDTH = 32
22
37
  SCREEN_HEIGHT = 24
23
38
 
39
+ # Path to screen tests relative to the base of this repository
40
+ SCREEN_TEST_DIR = 'screen_test'
41
+
42
+ # Return the base directory of this repository
24
43
  def self.base_dir
25
44
  Tools.parent_directory(__FILE__, 3)
26
45
  end
27
46
 
47
+ # Return all screen test files
28
48
  def self.test_files
29
- Dir.glob(File.join(base_dir, 'screen_test', '**', '*.rb'))
49
+ Dir.glob(File.join(base_dir, SCREEN_TEST_DIR, '**', '*.rb'))
50
+ end
51
+
52
+ def self.define_test_theme
53
+ return if @defined_theme_library
54
+ theme = Settings::Theme.new
55
+ theme.color = :bright_white
56
+ theme.bg_color = :black
57
+ theme.border_color = :bright_white
58
+ theme.axis_color = :bright_white
59
+ Settings::ThemeLibrary.add(:test, theme)
60
+ @defined_theme_library = true
30
61
  end
31
62
 
63
+ # Run all screen tests that exist in the screen test directory
32
64
  def self.run_all
33
65
  failures = {}
34
66
  pendings = Set.new
@@ -50,71 +82,135 @@ module WhirledPeas
50
82
  puts
51
83
  puts if pendings.count > 0
52
84
  pendings.each do |file|
53
- puts Utils::FormattedString.new("PENDING: #{file}", Settings::TextColor::YELLOW)
85
+ puts Utils::FormattedString.new(
86
+ "PENDING: #{file}",
87
+ Settings::TextColor::YELLOW
88
+ )
54
89
  end
55
90
  puts if failures.count > 0
56
91
  failures.each do |file, error|
57
- puts Utils::FormattedString.new("Failed: #{file}:\n\n #{error}\n", Settings::TextColor::RED)
92
+ puts Utils::FormattedString.new(
93
+ "Failed: #{file}:\n\n #{error}\n",
94
+ Settings::TextColor::RED
95
+ )
58
96
  end
59
97
 
60
98
  if failures.count == 0
61
99
  puts
62
- puts Utils::FormattedString.new('No failures', Settings::TextColor::GREEN)
100
+ puts Utils::FormattedString.new(
101
+ 'No failures',
102
+ Settings::TextColor::GREEN
103
+ )
104
+ exit(0)
63
105
  else
64
106
  exit(1)
65
107
  end
66
108
  end
67
109
 
68
- def self.update_all
110
+ # View rendered output for each pending test, giving the user the option to save the output
111
+ # as the expected output
112
+ def self.view_pending
69
113
  num_attempted = 0
70
114
  test_files.map do |file|
71
- num_attempted += 1 if new(file).update(false)
115
+ tester = new(file)
116
+ if tester.pending?
117
+ puts "File: #{tester.test_file}"
118
+ puts Utils::FormattedString.new(
119
+ 'Frame file does not exist', Settings::TextColor::YELLOW
120
+ )
121
+ print 'View rendered frame? [Y/n/q] '
122
+ STDOUT.flush
123
+ response = STDIN.gets.strip.downcase
124
+ case response
125
+ when 'q'
126
+ exit
127
+ when 'n'
128
+ next
129
+ end
130
+ tester.ask_pending
131
+ num_attempted += 1
132
+ end
133
+ end
134
+ if num_attempted == 0
135
+ puts 'No pending tests.'
136
+ end
137
+ end
138
+
139
+ # View expected and rendered output for each failed test, giving the user the option
140
+ # to overwrite the expected output with the rendered output
141
+ def self.view_failed
142
+ num_attempted = 0
143
+ test_files.map do |file|
144
+ tester = new(file)
145
+ if tester.failed?
146
+ puts "File: #{tester.test_file}"
147
+ puts Utils::FormattedString.new(
148
+ 'Output from test does not match saved output', Settings::TextColor::RED
149
+ )
150
+ print 'View expected output? [Y/q] '
151
+ STDOUT.flush
152
+ exit if 'q' == STDIN.gets.strip.downcase
153
+ tester.ask_failed
154
+ num_attempted += 1
155
+ end
72
156
  end
73
157
  if num_attempted == 0
74
158
  puts 'All rendered output matched expected.'
75
159
  end
76
160
  end
77
161
 
78
- attr_reader :error
162
+ attr_reader :error, :test_file
79
163
 
80
164
  def initialize(test_file)
165
+ # Convert the input file path to an absolute path (if necessary)
81
166
  @full_test_file = test_file[0] == '/' ? test_file : File.join(Dir.pwd, test_file)
82
167
  raise ArgumentError, "File not found: #{test_file}" unless File.exist?(@full_test_file)
168
+
169
+ # Remove the base directory from the full file path for a more readable file name
83
170
  @test_file = @full_test_file.sub(self.class.base_dir, '').sub(/^\//, '')
171
+
172
+ # The output file has the same base name as the test file, but ends in `.frame`
84
173
  @full_output_file = @full_test_file.sub(/\.rb$/, '.frame')
174
+
175
+ # Remove the base directory from the full file path for a more readable file name
85
176
  @output_file = @full_output_file.sub(self.class.base_dir, '').sub(/^\//, '')
86
177
  end
87
178
 
88
- def update(report_passing=true)
179
+ # Display the rendered output of the test and
180
+ #
181
+ # * If the expected ouptput matches the rendered output, simply display that output
182
+ # * If the expected ouptput does not match the rendered output, show the expect, then
183
+ # show the actual and give the user the option to overwrite expected with actual
184
+ # * If no expected output is saved for the test, give the user the option to save the
185
+ # rendered output as the expected output
186
+ def view
89
187
  if pending?
90
188
  ask_pending
91
- return true
92
189
  elsif failed?
93
190
  ask_failed
94
- return true
95
- elsif report_passing
96
- puts "Actual rendered output for #{test_file} matches expected."
191
+ else
192
+ puts rendered
193
+ puts "Rendered output for #{test_file} matches expected."
97
194
  end
98
- false
99
195
  end
100
196
 
197
+ # Return true if no output file exists for the test
101
198
  def pending?
102
199
  !File.exist?(full_output_file)
103
200
  end
104
201
 
202
+ # Return true if the rendered output does not match the expected outptu
105
203
  def failed?
204
+ return false if pending?
106
205
  if rendered != File.read(full_output_file)
107
- @error = 'Rendered output does not match saved output'
206
+ @error = 'Rendered output does not match expected.'
108
207
  end
109
208
  !@error.nil?
110
209
  end
111
210
 
112
- def view
113
- with_template_factory do |template_factory|
114
- render_screen(template_factory, STDOUT)
115
- end
116
- end
117
-
211
+ # Enable the Graphics debugger to print out debug information. Also render the template,
212
+ # but do not display it as rendering will clear the screen of debug output before the user
213
+ # can read it.
118
214
  def debug
119
215
  with_template_factory do |template_factory|
120
216
  orig_debug = Graphics.debug
@@ -124,6 +220,7 @@ module WhirledPeas
124
220
  end
125
221
  end
126
222
 
223
+ # Print out the template tree
127
224
  def template
128
225
  with_template_factory do |template_factory|
129
226
  template = template_factory.build('Test', {})
@@ -131,44 +228,13 @@ module WhirledPeas
131
228
  end
132
229
  end
133
230
 
134
- def save
135
- if File.exist?(full_output_file)
136
- puts "Existing output file found: #{full_output_file}"
137
- puts "overwriting..."
138
- else
139
- puts "Writing output to file: #{full_output_file}"
140
- end
141
-
142
- with_template_factory do |template_factory|
143
- File.open(full_output_file, 'w') do |file|
144
- render_screen(template_factory, file)
145
- end
146
- end
147
- end
148
-
149
231
  def ask_pending
150
- puts "File: #{test_file}"
151
- puts Utils::FormattedString.new('Frame file does not exist', Settings::TextColor::YELLOW)
152
- print 'View rendered frame? [Y/n/q] '
153
- STDOUT.flush
154
- response = STDIN.gets.strip.downcase
155
- case response
156
- when 'q'
157
- exit
158
- when 'n'
159
- return
160
- end
161
232
  puts rendered
162
233
  STDOUT.flush
163
234
  ask_to_save
164
235
  end
165
236
 
166
237
  def ask_failed
167
- puts "File: #{test_file}"
168
- puts Utils::FormattedString.new('Output from test does not match saved output', Settings::TextColor::RED)
169
- print 'View expected output? [Y/q] '
170
- STDOUT.flush
171
- exit if 'q' == STDIN.gets.strip.downcase
172
238
  puts File.read(full_output_file)
173
239
  puts "File: #{test_file}"
174
240
  print 'View actual output? [Y/q] '
@@ -181,15 +247,13 @@ module WhirledPeas
181
247
 
182
248
  private
183
249
 
184
- attr_reader :full_test_file, :test_file, :full_output_file, :output_file
250
+ attr_reader :full_test_file, :full_output_file, :output_file
185
251
 
186
252
  def ask_to_save
187
253
  puts "File: #{test_file}"
188
254
  print 'Save actual as the expected test output? [y/N/q] '
189
255
  STDOUT.flush
190
256
  response = STDIN.gets.strip.downcase
191
- print Utils::Ansi.cursor_pos(left: 0, top: 0)
192
- print Utils::Ansi.clear_down
193
257
  if response == 'y'
194
258
  File.open(full_output_file, 'w') { |file| file.print(rendered) }
195
259
  puts "Saved to #{output_file}"
@@ -212,6 +276,7 @@ module WhirledPeas
212
276
  end
213
277
 
214
278
  def with_template_factory(&block)
279
+ self.class.define_test_theme
215
280
  require full_test_file
216
281
  raise 'TemplateFactory must be defined' unless defined?(TemplateFactory)
217
282
  yield TemplateFactory.new
@@ -220,12 +285,13 @@ module WhirledPeas
220
285
  end
221
286
 
222
287
  def render_screen(template_factory, output)
223
- screen = Graphics::Screen.new(output: output, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
224
- consumer = Frame::EventLoop.new(
225
- template_factory, screen: screen, refresh_rate: 100000
226
- )
227
- Frame::Producer.produce(consumer) do |producer|
228
- producer.send_frame('test', args: {})
288
+ Utils::Ansi.with_screen(output, width: SCREEN_WIDTH, height: SCREEN_HEIGHT) do
289
+ rendered = Graphics::Renderer.new(
290
+ template_factory.build('test', {}),
291
+ SCREEN_WIDTH,
292
+ SCREEN_HEIGHT
293
+ ).paint
294
+ Device::Screen.new(10000, output: output).handle_renders([rendered])
229
295
  end
230
296
  end
231
297
  end