whirled_peas 0.3.0 → 0.7.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +38 -0
  4. data/README.md +549 -85
  5. data/Rakefile +28 -3
  6. data/examples/intro.rb +52 -0
  7. data/examples/scrolling.rb +53 -0
  8. data/exe/whirled_peas +7 -0
  9. data/lib/whirled_peas.rb +12 -36
  10. data/lib/whirled_peas/command_line.rb +255 -0
  11. data/lib/whirled_peas/config.rb +21 -0
  12. data/lib/whirled_peas/errors.rb +7 -0
  13. data/lib/whirled_peas/frame.rb +0 -5
  14. data/lib/whirled_peas/frame/consumer.rb +30 -0
  15. data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
  16. data/lib/whirled_peas/frame/event_loop.rb +69 -38
  17. data/lib/whirled_peas/frame/producer.rb +36 -19
  18. data/lib/whirled_peas/graphics.rb +19 -0
  19. data/lib/whirled_peas/graphics/box_painter.rb +101 -0
  20. data/lib/whirled_peas/graphics/canvas.rb +118 -0
  21. data/lib/whirled_peas/graphics/composer.rb +80 -0
  22. data/lib/whirled_peas/graphics/container_coords.rb +72 -0
  23. data/lib/whirled_peas/graphics/container_dimensions.rb +93 -0
  24. data/lib/whirled_peas/graphics/container_painter.rb +272 -0
  25. data/lib/whirled_peas/graphics/debugger.rb +52 -0
  26. data/lib/whirled_peas/graphics/grid_painter.rb +69 -0
  27. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  28. data/lib/whirled_peas/graphics/painter.rb +23 -0
  29. data/lib/whirled_peas/graphics/renderer.rb +26 -0
  30. data/lib/whirled_peas/graphics/screen.rb +70 -0
  31. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  32. data/lib/whirled_peas/graphics/text_painter.rb +40 -0
  33. data/lib/whirled_peas/settings.rb +5 -0
  34. data/lib/whirled_peas/settings/alignment.rb +24 -0
  35. data/lib/whirled_peas/settings/bg_color.rb +24 -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 +68 -0
  39. data/lib/whirled_peas/settings/container_settings.rb +223 -0
  40. data/lib/whirled_peas/settings/debugger.rb +96 -0
  41. data/lib/whirled_peas/settings/display_flow.rb +27 -0
  42. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  43. data/lib/whirled_peas/settings/grid_settings.rb +19 -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/sizing.rb +19 -0
  49. data/lib/whirled_peas/settings/spacing.rb +58 -0
  50. data/lib/whirled_peas/settings/text_color.rb +21 -0
  51. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  52. data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
  53. data/lib/whirled_peas/utils.rb +5 -0
  54. data/lib/whirled_peas/utils/ansi.rb +53 -0
  55. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  56. data/lib/whirled_peas/utils/title_font.rb +75 -0
  57. data/lib/whirled_peas/version.rb +1 -1
  58. data/screen_test/elements/box.frame +1 -0
  59. data/screen_test/elements/box.rb +20 -0
  60. data/screen_test/elements/grid.frame +1 -0
  61. data/screen_test/elements/grid.rb +13 -0
  62. data/screen_test/elements/screen_overflow_x.frame +1 -0
  63. data/screen_test/elements/screen_overflow_x.rb +9 -0
  64. data/screen_test/elements/screen_overflow_y.frame +1 -0
  65. data/screen_test/elements/screen_overflow_y.rb +9 -0
  66. data/screen_test/elements/text.frame +1 -0
  67. data/screen_test/elements/text.rb +9 -0
  68. data/screen_test/elements/text_multiline.frame +1 -0
  69. data/screen_test/elements/text_multiline.rb +9 -0
  70. data/screen_test/settings/align/box_around.frame +1 -0
  71. data/screen_test/settings/align/box_around.rb +16 -0
  72. data/screen_test/settings/align/box_between.frame +1 -0
  73. data/screen_test/settings/align/box_between.rb +16 -0
  74. data/screen_test/settings/align/box_center.frame +1 -0
  75. data/screen_test/settings/align/box_center.rb +21 -0
  76. data/screen_test/settings/align/box_default.frame +1 -0
  77. data/screen_test/settings/align/box_default.rb +20 -0
  78. data/screen_test/settings/align/box_evenly.frame +1 -0
  79. data/screen_test/settings/align/box_evenly.rb +16 -0
  80. data/screen_test/settings/align/box_left.frame +1 -0
  81. data/screen_test/settings/align/box_left.rb +21 -0
  82. data/screen_test/settings/align/box_right.frame +1 -0
  83. data/screen_test/settings/align/box_right.rb +21 -0
  84. data/screen_test/settings/align/children_center.frame +1 -0
  85. data/screen_test/settings/align/children_center.rb +15 -0
  86. data/screen_test/settings/align/children_left.frame +1 -0
  87. data/screen_test/settings/align/children_left.rb +15 -0
  88. data/screen_test/settings/align/children_right.frame +1 -0
  89. data/screen_test/settings/align/children_right.rb +15 -0
  90. data/screen_test/settings/align/grid_center.frame +1 -0
  91. data/screen_test/settings/align/grid_center.rb +18 -0
  92. data/screen_test/settings/align/grid_default.frame +1 -0
  93. data/screen_test/settings/align/grid_default.rb +17 -0
  94. data/screen_test/settings/align/grid_left.frame +1 -0
  95. data/screen_test/settings/align/grid_left.rb +18 -0
  96. data/screen_test/settings/align/grid_right.frame +1 -0
  97. data/screen_test/settings/align/grid_right.rb +18 -0
  98. data/screen_test/settings/ansi/bold.frame +1 -0
  99. data/screen_test/settings/ansi/bold.rb +14 -0
  100. data/screen_test/settings/ansi/color.frame +1 -0
  101. data/screen_test/settings/ansi/color.rb +37 -0
  102. data/screen_test/settings/ansi/underline.frame +1 -0
  103. data/screen_test/settings/ansi/underline.rb +14 -0
  104. data/screen_test/settings/border.frame +1 -0
  105. data/screen_test/settings/border.rb +13 -0
  106. data/screen_test/settings/flow/box_b2t.frame +1 -0
  107. data/screen_test/settings/flow/box_b2t.rb +26 -0
  108. data/screen_test/settings/flow/box_l2r.frame +1 -0
  109. data/screen_test/settings/flow/box_l2r.rb +26 -0
  110. data/screen_test/settings/flow/box_r2l.frame +1 -0
  111. data/screen_test/settings/flow/box_r2l.rb +26 -0
  112. data/screen_test/settings/flow/box_t2b.frame +1 -0
  113. data/screen_test/settings/flow/box_t2b.rb +26 -0
  114. data/screen_test/settings/flow/grid_b2t.frame +1 -0
  115. data/screen_test/settings/flow/grid_b2t.rb +14 -0
  116. data/screen_test/settings/flow/grid_l2r.frame +1 -0
  117. data/screen_test/settings/flow/grid_l2r.rb +14 -0
  118. data/screen_test/settings/flow/grid_r2l.frame +1 -0
  119. data/screen_test/settings/flow/grid_r2l.rb +14 -0
  120. data/screen_test/settings/flow/grid_t2b.frame +1 -0
  121. data/screen_test/settings/flow/grid_t2b.rb +14 -0
  122. data/screen_test/settings/height/box.frame +1 -0
  123. data/screen_test/settings/height/box.rb +13 -0
  124. data/screen_test/settings/height/box_border_sizing.frame +1 -0
  125. data/screen_test/settings/height/box_border_sizing.rb +15 -0
  126. data/screen_test/settings/height/grid.frame +1 -0
  127. data/screen_test/settings/height/grid.rb +14 -0
  128. data/screen_test/settings/height/overflow_box.frame +1 -0
  129. data/screen_test/settings/height/overflow_box.rb +13 -0
  130. data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
  131. data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
  132. data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
  133. data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
  134. data/screen_test/settings/height/overflow_grid.frame +1 -0
  135. data/screen_test/settings/height/overflow_grid.rb +16 -0
  136. data/screen_test/settings/margin.frame +1 -0
  137. data/screen_test/settings/margin.rb +16 -0
  138. data/screen_test/settings/padding.frame +1 -0
  139. data/screen_test/settings/padding.rb +13 -0
  140. data/screen_test/settings/position/box_left.frame +1 -0
  141. data/screen_test/settings/position/box_left.rb +17 -0
  142. data/screen_test/settings/position/box_left_negative.frame +1 -0
  143. data/screen_test/settings/position/box_left_negative.rb +17 -0
  144. data/screen_test/settings/position/box_top.frame +1 -0
  145. data/screen_test/settings/position/box_top.rb +17 -0
  146. data/screen_test/settings/position/box_top_negative.frame +1 -0
  147. data/screen_test/settings/position/box_top_negative.rb +17 -0
  148. data/screen_test/settings/position/grid_left.frame +1 -0
  149. data/screen_test/settings/position/grid_left.rb +18 -0
  150. data/screen_test/settings/position/grid_left_negative.frame +1 -0
  151. data/screen_test/settings/position/grid_left_negative.rb +18 -0
  152. data/screen_test/settings/position/grid_top.frame +1 -0
  153. data/screen_test/settings/position/grid_top.rb +18 -0
  154. data/screen_test/settings/position/grid_top_negative.frame +1 -0
  155. data/screen_test/settings/position/grid_top_negative.rb +18 -0
  156. data/screen_test/settings/scroll/horiz_box.frame +1 -0
  157. data/screen_test/settings/scroll/horiz_box.rb +17 -0
  158. data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
  159. data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
  160. data/screen_test/settings/scroll/vert_box.frame +1 -0
  161. data/screen_test/settings/scroll/vert_box.rb +20 -0
  162. data/screen_test/settings/title_font.frame +1 -0
  163. data/screen_test/settings/title_font.rb +12 -0
  164. data/screen_test/settings/valign/box_around.frame +1 -0
  165. data/screen_test/settings/valign/box_around.rb +17 -0
  166. data/screen_test/settings/valign/box_between.frame +1 -0
  167. data/screen_test/settings/valign/box_between.rb +17 -0
  168. data/screen_test/settings/valign/box_bottom.frame +1 -0
  169. data/screen_test/settings/valign/box_bottom.rb +17 -0
  170. data/screen_test/settings/valign/box_default.frame +1 -0
  171. data/screen_test/settings/valign/box_default.rb +16 -0
  172. data/screen_test/settings/valign/box_evenly.frame +1 -0
  173. data/screen_test/settings/valign/box_evenly.rb +17 -0
  174. data/screen_test/settings/valign/box_middle.frame +1 -0
  175. data/screen_test/settings/valign/box_middle.rb +17 -0
  176. data/screen_test/settings/valign/box_top.frame +1 -0
  177. data/screen_test/settings/valign/box_top.rb +17 -0
  178. data/screen_test/settings/valign/grid_bottom.frame +1 -0
  179. data/screen_test/settings/valign/grid_bottom.rb +15 -0
  180. data/screen_test/settings/valign/grid_default.frame +1 -0
  181. data/screen_test/settings/valign/grid_default.rb +14 -0
  182. data/screen_test/settings/valign/grid_middle.frame +1 -0
  183. data/screen_test/settings/valign/grid_middle.rb +15 -0
  184. data/screen_test/settings/valign/grid_top.frame +1 -0
  185. data/screen_test/settings/valign/grid_top.rb +15 -0
  186. data/screen_test/settings/width/box_border_sizing.frame +1 -0
  187. data/screen_test/settings/width/box_border_sizing.rb +15 -0
  188. data/screen_test/settings/width/box_content.frame +1 -0
  189. data/screen_test/settings/width/box_content.rb +15 -0
  190. data/screen_test/settings/width/box_default.frame +1 -0
  191. data/screen_test/settings/width/box_default.rb +14 -0
  192. data/screen_test/settings/width/grid.frame +1 -0
  193. data/screen_test/settings/width/grid.rb +14 -0
  194. data/screen_test/settings/width/overflow_align_center.frame +1 -0
  195. data/screen_test/settings/width/overflow_align_center.rb +14 -0
  196. data/screen_test/settings/width/overflow_align_right.frame +1 -0
  197. data/screen_test/settings/width/overflow_align_right.rb +14 -0
  198. data/screen_test/settings/width/overflow_box.frame +1 -0
  199. data/screen_test/settings/width/overflow_box.rb +13 -0
  200. data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
  201. data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
  202. data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
  203. data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
  204. data/screen_test/settings/width/overflow_grid.frame +1 -0
  205. data/screen_test/settings/width/overflow_grid.rb +14 -0
  206. data/tools/whirled_peas/tools/screen_tester.rb +233 -0
  207. data/whirled_peas.gemspec +4 -1
  208. metadata +215 -17
  209. data/lib/whirled_peas/ui.rb +0 -7
  210. data/lib/whirled_peas/ui/ansi.rb +0 -103
  211. data/lib/whirled_peas/ui/canvas.rb +0 -68
  212. data/lib/whirled_peas/ui/color.rb +0 -101
  213. data/lib/whirled_peas/ui/element.rb +0 -224
  214. data/lib/whirled_peas/ui/painter.rb +0 -283
  215. data/lib/whirled_peas/ui/screen.rb +0 -60
  216. data/lib/whirled_peas/ui/settings.rb +0 -523
  217. data/sandbox/auto.rb +0 -13
  218. data/sandbox/box.rb +0 -19
  219. data/sandbox/grid.rb +0 -13
  220. data/sandbox/sandbox.rb +0 -17
  221. data/sandbox/text.rb +0 -33
@@ -0,0 +1,19 @@
1
+ require 'whirled_peas/utils/title_font'
2
+
3
+ require_relative 'container_settings'
4
+
5
+ module WhirledPeas
6
+ module Settings
7
+ class GridSettings < ContainerSettings
8
+ attr_accessor :num_cols
9
+
10
+ def set_scrollbar(*)
11
+ raise NotImplementedError, 'Grids do not support scrollbars'
12
+ end
13
+
14
+ def sizing=(*)
15
+ raise NotImplementedError, 'Grids only support the default sizing model'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'spacing'
2
+
3
+ module WhirledPeas
4
+ module Settings
5
+ class Margin < Spacing
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'spacing'
2
+
3
+ module WhirledPeas
4
+ module Settings
5
+ class Padding < Spacing
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module WhirledPeas
2
+ module Settings
3
+ class Position
4
+ attr_writer :left, :top
5
+
6
+ def left
7
+ @left || 0
8
+ end
9
+
10
+ def top
11
+ @top || 0
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module WhirledPeas
2
+ module Settings
3
+ class Scrollbar
4
+ attr_writer :horiz, :vert
5
+
6
+ def horiz?
7
+ @horiz == true
8
+ end
9
+
10
+ def vert?
11
+ @vert == true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module WhirledPeas
2
+ module Settings
3
+ class Sizing
4
+ CONTENT = :content
5
+ BORDER = :border
6
+
7
+ DEFAULT = CONTENT
8
+
9
+ VALID = [CONTENT, BORDER]
10
+ private_constant :VALID
11
+
12
+ def self.validate!(sizing)
13
+ return if sizing.nil?
14
+ return sizing if VALID.include?(sizing)
15
+ raise ArgumentError, "Unsupported sizing model: #{sizing.inspect}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,58 @@
1
+ module WhirledPeas
2
+ module Settings
3
+ class Spacing
4
+ attr_writer :left, :top, :right, :bottom
5
+
6
+ def left=(value)
7
+ @left = validate!(value)
8
+ end
9
+
10
+ def left
11
+ @left || 0
12
+ end
13
+
14
+ def top=(value)
15
+ @top = validate!(value)
16
+ end
17
+
18
+ def top
19
+ @top || 0
20
+ end
21
+
22
+ def right=(value)
23
+ @right = validate!(value)
24
+ end
25
+
26
+ def right
27
+ @right || 0
28
+ end
29
+
30
+ def bottom=(value)
31
+ @bottom = validate!(value)
32
+ end
33
+
34
+ def bottom
35
+ @bottom || 0
36
+ end
37
+
38
+ def horiz=(value)
39
+ self.left = self.right = value
40
+ end
41
+
42
+ def vert=(value)
43
+ self.top = self.bottom = value
44
+ end
45
+
46
+ private
47
+
48
+ def validate!(value)
49
+ if value && value < 0
50
+ raise ArgumentError, "Negative values for #{self.class.name.split('::').last.downcase} are not allowed"
51
+ else
52
+ value
53
+ end
54
+ end
55
+ end
56
+ private_constant :Spacing
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ require 'whirled_peas/utils/ansi'
2
+
3
+ require_relative 'color'
4
+
5
+ module WhirledPeas
6
+ module Settings
7
+ class TextColor < Color
8
+ BLACK = new(Utils::Ansi::BLACK)
9
+ RED = new(Utils::Ansi::RED)
10
+ GREEN = new(Utils::Ansi::GREEN)
11
+ YELLOW = new(Utils::Ansi::YELLOW)
12
+ BLUE = new(Utils::Ansi::BLUE)
13
+ MAGENTA = new(Utils::Ansi::MAGENTA)
14
+ CYAN = new(Utils::Ansi::CYAN)
15
+ WHITE = new(Utils::Ansi::WHITE)
16
+ GRAY = BLACK.bright
17
+
18
+ DEFAULT = nil # Use system defined default
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'whirled_peas/utils/title_font'
2
+
3
+ require_relative 'element_settings'
4
+
5
+ module WhirledPeas
6
+ module Settings
7
+ class TextSettings < ElementSettings
8
+ attr_reader :title_font
9
+
10
+ def title_font=(font)
11
+ @title_font = Utils::TitleFont.validate!(font)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module WhirledPeas
2
+ module Settings
3
+ module VertAlignment
4
+ TOP = :top
5
+ MIDDLE = :middle
6
+ BOTTOM = :bottom
7
+ BETWEEN = :between
8
+ AROUND = :around
9
+ EVENLY = :evenly
10
+
11
+ DEFAULT = TOP
12
+
13
+ VALID = [TOP, MIDDLE, BOTTOM, BETWEEN, AROUND, EVENLY]
14
+ private_constant :VALID
15
+
16
+ def self.validate!(valign)
17
+ return if valign.nil?
18
+ return valign if VALID.include?(valign)
19
+ raise ArgumentError, "Unsupported vertical alignment: #{valign.inspect}"
20
+ end
21
+ end
22
+ private_constant :VertAlignment
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module WhirledPeas
2
+ module Utils
3
+ end
4
+ private_constant :Utils
5
+ end
@@ -0,0 +1,53 @@
1
+ module WhirledPeas
2
+ module Utils
3
+ # Helper module for working with ANSI escape codes. The most useful ANSI escape codes
4
+ # relate to text formatting.
5
+ #
6
+ # @see https://en.wikipedia.org/wiki/ANSI_escape_code
7
+ module Ansi
8
+ ESC = "\033"
9
+
10
+ END_FORMATTING = 0
11
+ private_constant :END_FORMATTING
12
+
13
+ # Text formatting constants
14
+ BOLD = 1
15
+ UNDERLINE = 4
16
+
17
+ # Text and background color constants
18
+ BLACK = 30
19
+ RED = 31
20
+ GREEN = 32
21
+ YELLOW = 33
22
+ BLUE = 34
23
+ MAGENTA = 35
24
+ CYAN = 36
25
+ WHITE = 37
26
+
27
+ # Bright colors are offset by this much from their standard versions
28
+ BRIGHT_OFFSET = 60
29
+
30
+ class << self
31
+ def cursor_pos(top: 0, left: 0)
32
+ "#{ESC}[#{top + 1};#{left + 1}H"
33
+ end
34
+
35
+ def cursor_visible(visible)
36
+ visible ? "#{ESC}[?25h" : "#{ESC}[?25l"
37
+ end
38
+
39
+ def clear_down
40
+ "#{ESC}[J"
41
+ end
42
+
43
+ def clear
44
+ esc_seq(END_FORMATTING)
45
+ end
46
+
47
+ def esc_seq(code)
48
+ "#{ESC}[#{code}m"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,64 @@
1
+ require_relative 'ansi'
2
+
3
+ module WhirledPeas
4
+ module Utils
5
+ class FormattedString
6
+ def self.blank
7
+ new('')
8
+ end
9
+
10
+ def initialize(raw, formatting=nil)
11
+ @raw = raw
12
+ @formatting = [*formatting]
13
+ end
14
+
15
+ def length
16
+ raw.length
17
+ end
18
+
19
+ def [](index_or_range)
20
+ self.class.new(raw[index_or_range], foramtting)
21
+ end
22
+
23
+ def blank?
24
+ raw.empty?
25
+ end
26
+
27
+ def hash
28
+ [raw, formatting].hash
29
+ end
30
+
31
+ def ==(other)
32
+ case other
33
+ when self.class
34
+ hash == other.hash
35
+ when String
36
+ formatting.empty? && raw == other
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ def to_s
43
+ if raw.empty? || formatting.length == 0
44
+ raw
45
+ else
46
+ start_formatting = formatting.map { |code| Ansi.esc_seq(code) }.join
47
+ "#{start_formatting}#{raw}#{Ansi.clear}"
48
+ end
49
+ end
50
+
51
+ def inspect
52
+ if raw.empty? || formatting.length == 0
53
+ raw.inspect
54
+ else
55
+ "<#{formatting.join(', ')}>#{raw}<0>".inspect
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ attr_reader :raw, :formatting
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,75 @@
1
+ module WhirledPeas
2
+ module Utils
3
+ module TitleFont
4
+ PREFERRED_DEFAULT_FONT = :ansishadow
5
+ FONT_CACHE = File.join(ENV['HOME'] || '.', '.whirled_peas.fonts')
6
+
7
+ class << self
8
+ def validate!(font_key)
9
+ return if font_key.nil?
10
+ return font_key if fonts.key?(font_key)
11
+ allowed = fonts.keys.map(&:inspect).sort
12
+ message = "Unrecognized font: '#{font_key.inspect}', expecting one of #{allowed.join(', ')}"
13
+ raise ArgumentError, message
14
+ end
15
+
16
+ def to_s(string, font_key)
17
+ require 'ruby_figlet'
18
+ RubyFiglet::Figlet.new(string, fonts[font_key]).to_s
19
+ end
20
+
21
+ def fonts
22
+ return @fonts if @fonts
23
+ File.exist?(FONT_CACHE) ? load_fonts_from_cache : load_fonts_from_figlet
24
+ @fonts
25
+ end
26
+
27
+ def load_fonts_from_cache
28
+ require 'json'
29
+ @fonts = {}
30
+ File.open(FONT_CACHE, 'r') do |fp|
31
+ JSON.parse(fp.read).each do |key, value|
32
+ @fonts[key.to_sym] = value
33
+ end
34
+ end
35
+ @fonts
36
+ end
37
+
38
+ def load_fonts_from_figlet
39
+ require 'ruby_figlet'
40
+ require 'json'
41
+ @fonts = {}
42
+ RubyFiglet::Figlet.available.strip.split("\n").each do |font|
43
+ # Load the font to be sure it exists on the system
44
+ next unless available?(font)
45
+ string_key = font.downcase.gsub(/\W/, '')
46
+ string_key = "_#{string_key}" if string_key[0] !~ /[a-z]/
47
+ string_key.gsub!(/\d+$/, '')
48
+ next if @fonts.key?(string_key)
49
+ @fonts[string_key.to_sym] = font
50
+ end
51
+ @fonts[:default] ||= @fonts[PREFERRED_DEFAULT_FONT] || @fonts.values.first
52
+ File.open(FONT_CACHE, 'w') { |fp| fp.write(JSON.generate(@fonts)) }
53
+ @fonts
54
+ end
55
+
56
+ private
57
+
58
+ def available?(font)
59
+ # Figlet's font loader prints to STDOUT if the font file is not found.
60
+ # Temporarily redirect STDOUT to /dev/null while the font file is loaded
61
+ # then remove the redirect in an ensure block. Also, if a font file is
62
+ # not available, a SystemExit is raise :/
63
+ original_stdout = $stdout.clone
64
+ $stdout.reopen(File.new('/dev/null', 'w'))
65
+ RubyFiglet::Figlet.new('Text', font)
66
+ true
67
+ rescue SystemExit, NoMethodError
68
+ false
69
+ ensure
70
+ $stdout.reopen(original_stdout)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,3 +1,3 @@
1
1
  module WhirledPeas
2
- VERSION = '0.3.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -0,0 +1 @@
1
+ [?25lTOP LEFTBOTTOM LEFT TOP RIGHT  BOTTOM RIGHT[?25h
@@ -0,0 +1,20 @@
1
+ require 'whirled_peas'
2
+
3
+ class TemplateFactory
4
+ def build(*)
5
+ WhirledPeas.template do |composer|
6
+ composer.add_box('Container') do |composer, settings|
7
+ composer.add_box do |composer, settings|
8
+ settings.flow = :t2b
9
+ composer.add_box('TopLeft') { "TOP LEFT" }
10
+ composer.add_box('BottomLeft') { "BOTTOM LEFT" }
11
+ end
12
+ composer.add_box do |composer, settings|
13
+ settings.flow = :t2b
14
+ composer.add_box('TopRight') { " TOP RIGHT " }
15
+ composer.add_box('BottomRight') { " BOTTOM RIGHT" }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end