whirled_peas 0.7.0 → 0.10.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 (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