whirled_peas 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +111 -73
  4. data/Rakefile +37 -3
  5. data/bin/debug +35 -0
  6. data/lib/whirled_peas.rb +9 -7
  7. data/lib/whirled_peas/command_line.rb +25 -32
  8. data/lib/whirled_peas/debugger.rb +80 -0
  9. data/lib/whirled_peas/errors.rb +2 -0
  10. data/lib/whirled_peas/frame.rb +0 -1
  11. data/lib/whirled_peas/frame/consumer.rb +30 -0
  12. data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
  13. data/lib/whirled_peas/frame/event_loop.rb +29 -30
  14. data/lib/whirled_peas/frame/producer.rb +11 -5
  15. data/lib/whirled_peas/graphics.rb +5 -0
  16. data/lib/whirled_peas/graphics/box_painter.rb +100 -0
  17. data/lib/whirled_peas/graphics/canvas.rb +107 -0
  18. data/lib/whirled_peas/graphics/container_coords.rb +61 -0
  19. data/lib/whirled_peas/graphics/container_dimensions.rb +65 -0
  20. data/lib/whirled_peas/graphics/container_painter.rb +116 -0
  21. data/lib/whirled_peas/graphics/debugger.rb +43 -0
  22. data/lib/whirled_peas/graphics/grid_painter.rb +56 -0
  23. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  24. data/lib/whirled_peas/graphics/painter.rb +24 -0
  25. data/lib/whirled_peas/graphics/renderer.rb +49 -0
  26. data/lib/whirled_peas/graphics/screen.rb +65 -0
  27. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  28. data/lib/whirled_peas/graphics/text_painter.rb +38 -0
  29. data/lib/whirled_peas/settings.rb +5 -0
  30. data/lib/whirled_peas/settings/bg_color.rb +22 -0
  31. data/lib/whirled_peas/settings/border.rb +101 -0
  32. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  33. data/lib/whirled_peas/{utils → settings}/color.rb +3 -35
  34. data/lib/whirled_peas/settings/container_settings.rb +128 -0
  35. data/lib/whirled_peas/settings/debugger.rb +87 -0
  36. data/lib/whirled_peas/settings/display_flow.rb +25 -0
  37. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  38. data/lib/whirled_peas/settings/grid_settings.rb +11 -0
  39. data/lib/whirled_peas/settings/margin.rb +8 -0
  40. data/lib/whirled_peas/settings/padding.rb +8 -0
  41. data/lib/whirled_peas/settings/position.rb +15 -0
  42. data/lib/whirled_peas/settings/spacing.rb +24 -0
  43. data/lib/whirled_peas/settings/text_align.rb +19 -0
  44. data/lib/whirled_peas/settings/text_color.rb +19 -0
  45. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  46. data/lib/whirled_peas/template/box_element.rb +8 -0
  47. data/lib/whirled_peas/template/composer.rb +68 -0
  48. data/lib/whirled_peas/template/container.rb +28 -0
  49. data/lib/whirled_peas/template/debugger.rb +34 -0
  50. data/lib/whirled_peas/template/element.rb +1 -218
  51. data/lib/whirled_peas/template/grid_element.rb +8 -0
  52. data/lib/whirled_peas/template/text_element.rb +24 -0
  53. data/lib/whirled_peas/utils/ansi.rb +6 -56
  54. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  55. data/lib/whirled_peas/version.rb +1 -1
  56. data/screen_test/rendered/elements/box.frame +1 -0
  57. data/screen_test/rendered/elements/box.rb +20 -0
  58. data/screen_test/rendered/elements/grid.frame +1 -0
  59. data/screen_test/rendered/elements/grid.rb +13 -0
  60. data/screen_test/rendered/elements/screen_overflow.rb +9 -0
  61. data/screen_test/rendered/elements/text.frame +1 -0
  62. data/screen_test/rendered/elements/text.rb +9 -0
  63. data/screen_test/rendered/elements/text_multiline.frame +1 -0
  64. data/screen_test/rendered/elements/text_multiline.rb +9 -0
  65. data/screen_test/rendered/settings/align/box.frame +1 -0
  66. data/screen_test/rendered/settings/align/box.rb +20 -0
  67. data/screen_test/rendered/settings/align/children_center.frame +1 -0
  68. data/screen_test/rendered/settings/align/children_center.rb +13 -0
  69. data/screen_test/rendered/settings/align/children_left.frame +1 -0
  70. data/screen_test/rendered/settings/align/children_left.rb +13 -0
  71. data/screen_test/rendered/settings/align/children_right.frame +1 -0
  72. data/screen_test/rendered/settings/align/children_right.rb +13 -0
  73. data/screen_test/rendered/settings/align/grid.frame +1 -0
  74. data/screen_test/rendered/settings/align/grid.rb +20 -0
  75. data/screen_test/rendered/settings/ansi/bold.frame +1 -0
  76. data/screen_test/rendered/settings/ansi/bold.rb +15 -0
  77. data/screen_test/rendered/settings/ansi/color.frame +1 -0
  78. data/screen_test/rendered/settings/ansi/color.rb +37 -0
  79. data/screen_test/rendered/settings/ansi/underline.frame +1 -0
  80. data/screen_test/rendered/settings/ansi/underline.rb +15 -0
  81. data/screen_test/rendered/settings/border.frame +1 -0
  82. data/screen_test/rendered/settings/border.rb +13 -0
  83. data/screen_test/rendered/settings/flow/l2r.frame +1 -0
  84. data/screen_test/rendered/settings/flow/l2r.rb +24 -0
  85. data/screen_test/rendered/settings/flow/t2b.frame +1 -0
  86. data/screen_test/rendered/settings/flow/t2b.rb +24 -0
  87. data/screen_test/rendered/settings/height/box.frame +1 -0
  88. data/screen_test/rendered/settings/height/box.rb +13 -0
  89. data/screen_test/rendered/settings/height/grid.frame +1 -0
  90. data/screen_test/rendered/settings/height/grid.rb +14 -0
  91. data/screen_test/rendered/settings/height/overflow_box.frame +1 -0
  92. data/screen_test/rendered/settings/height/overflow_box.rb +13 -0
  93. data/screen_test/rendered/settings/height/overflow_box_l2r.frame +1 -0
  94. data/screen_test/rendered/settings/height/overflow_box_l2r.rb +15 -0
  95. data/screen_test/rendered/settings/height/overflow_box_t2b.frame +1 -0
  96. data/screen_test/rendered/settings/height/overflow_box_t2b.rb +14 -0
  97. data/screen_test/rendered/settings/height/overflow_grid.frame +1 -0
  98. data/screen_test/rendered/settings/height/overflow_grid.rb +16 -0
  99. data/screen_test/rendered/settings/margin.frame +1 -0
  100. data/screen_test/rendered/settings/margin.rb +14 -0
  101. data/screen_test/rendered/settings/padding.frame +1 -0
  102. data/screen_test/rendered/settings/padding.rb +11 -0
  103. data/screen_test/rendered/settings/position/box_left.frame +1 -0
  104. data/screen_test/rendered/settings/position/box_left.rb +17 -0
  105. data/screen_test/rendered/settings/position/box_left_negative.frame +1 -0
  106. data/screen_test/rendered/settings/position/box_left_negative.rb +17 -0
  107. data/screen_test/rendered/settings/position/box_top.frame +1 -0
  108. data/screen_test/rendered/settings/position/box_top.rb +17 -0
  109. data/screen_test/rendered/settings/position/box_top_negative.frame +1 -0
  110. data/screen_test/rendered/settings/position/box_top_negative.rb +17 -0
  111. data/screen_test/rendered/settings/position/grid_left.frame +1 -0
  112. data/screen_test/rendered/settings/position/grid_left.rb +18 -0
  113. data/screen_test/rendered/settings/position/grid_left_negative.frame +1 -0
  114. data/screen_test/rendered/settings/position/grid_left_negative.rb +18 -0
  115. data/screen_test/rendered/settings/position/grid_top.frame +1 -0
  116. data/screen_test/rendered/settings/position/grid_top.rb +18 -0
  117. data/screen_test/rendered/settings/position/grid_top_negative.frame +1 -0
  118. data/screen_test/rendered/settings/position/grid_top_negative.rb +18 -0
  119. data/screen_test/rendered/settings/title_font.frame +1 -0
  120. data/screen_test/rendered/settings/title_font.rb +12 -0
  121. data/screen_test/rendered/settings/width/box.frame +1 -0
  122. data/screen_test/rendered/settings/width/box.rb +13 -0
  123. data/screen_test/rendered/settings/width/grid.frame +1 -0
  124. data/screen_test/rendered/settings/width/grid.rb +14 -0
  125. data/screen_test/rendered/settings/width/overflow_box.frame +1 -0
  126. data/screen_test/rendered/settings/width/overflow_box.rb +11 -0
  127. data/screen_test/rendered/settings/width/overflow_box_l2r.frame +1 -0
  128. data/screen_test/rendered/settings/width/overflow_box_l2r.rb +14 -0
  129. data/screen_test/rendered/settings/width/overflow_box_t2b.frame +1 -0
  130. data/screen_test/rendered/settings/width/overflow_box_t2b.rb +15 -0
  131. data/screen_test/rendered/settings/width/overflow_grid.frame +1 -0
  132. data/screen_test/rendered/settings/width/overflow_grid.rb +14 -0
  133. data/screen_test/screen_tester.rb +191 -0
  134. metadata +122 -10
  135. data/bin/title_fonts +0 -6
  136. data/lib/whirled_peas/frame/print_consumer.rb +0 -33
  137. data/lib/whirled_peas/template/settings.rb +0 -530
  138. data/lib/whirled_peas/ui.rb +0 -5
  139. data/lib/whirled_peas/ui/canvas.rb +0 -68
  140. data/lib/whirled_peas/ui/painter.rb +0 -287
  141. data/lib/whirled_peas/ui/screen.rb +0 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 563cc06007d90aa0599b61c5366a5d9b2c5224ec2973367b6c358cad95ddaedc
4
- data.tar.gz: fa798abdfb8a8e4fd229f08b964c8ee4f4d480939ece9ddaeb5731c171985504
3
+ metadata.gz: 1b374c9d4250b281d3f87284f446e82c01ece7ff2fe196687be50502b2e42960
4
+ data.tar.gz: 0ebd7b96a154277121767eb8c33d63b831db37770ff0172b76f28fcf89c5dec9
5
5
  SHA512:
6
- metadata.gz: 1be24e74d75f87a001b26f216e320d4a4680c48513e48c42047d2c2168a9404471704731df97ced5954facdc4ca7316580f6078db5670e45067c7e8ed3ee4cd3
7
- data.tar.gz: 86f3b995575fc7ff8b6bb83adf368182a684faece1584cffb7b1150bd47ce082adaba5b0d4ce0b83d19d2ec2d795bd31db19d35c990e6d0065698c050161bcd0
6
+ metadata.gz: f6dcc7dc00852a343f55056646db886903bc5735a21bd9af71a885e28ff70aa85bb3f26ff4f97c23dc4292fa401c1c624284c347b17fb957fb8e0069301b7ef9
7
+ data.tar.gz: 1f0ae0e07baf45703dff90396be7b6c705f17f8c9cb4fcd4e0b4b433513efc94dd8c3a056f50f1d3f47f7e3179c308d36264ef4e4be0c179815e650a6136a11a
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.5.0 - 2021-01-25
4
+
5
+ BREAKING: there was a significant amount of structural refactoring in this release. While that aspect did not add or remove any features, it fixed several layout bugs (some known and some unknown), so most template with moderate complexity will now be laid out slightly differently.
6
+
7
+ - [3ddfede](https://github.com/tcollier/whirled_peas/tree/3ddfedee4ab2fadeecbe82c7c9caf25c2988f095): Allow relative positioning of containers
8
+ - [507e77c](https://github.com/tcollier/whirled_peas/tree/507e77c551bcb9cc832d5c24e2f24eb1afe4eddc): Add height attribute for container settings
9
+ - [af8ef19](https://github.com/tcollier/whirled_peas/tree/af8ef1950edebcd23a57a04982b22a56296ee09b): Add automated screen testing
10
+
11
+ ## v0.4.1 - 2021-01-22
12
+
13
+ - [0f7aa6c](https://github.com/tcollier/whirled_peas/tree/0f7aa6ccc07323230dd602cb43e0341de5a69ad8): Allow relative path for config files
14
+
3
15
  ## v0.4.0 - 2021-01-22
4
16
 
5
17
  - [7fd6712](https://github.com/tcollier/whirled_peas/tree/7fd6712818c94cdbfd81828277ca67c705e01793): BREAKING: replace `WhirledPeas.start` with command line executable
data/README.md CHANGED
@@ -36,8 +36,8 @@ require 'whirled_peas'
36
36
 
37
37
  class TemplateFactory
38
38
  def build(frame, args)
39
- WhirledPeas.template do |body|
40
- body.add_box('Title') do |_, settings|
39
+ WhirledPeas.template do |composer|
40
+ composer.add_box('Title') do |_, settings|
41
41
  settings.underline = true
42
42
  "Hello #{args[:name]}"
43
43
  end
@@ -70,10 +70,10 @@ The optional loading screen can be configured like
70
70
  ```ruby
71
71
  class LoadingTemplateFactory
72
72
  def build
73
- WhirledPeas.template do |t|
74
- t.add_box('Loading') do |box, settings|
73
+ WhirledPeas.template do |composer|
74
+ composer.add_box('Loading') do |_, settings|
75
75
  settings.set_margin(top: 15)
76
- settings.auto_margin = true
76
+ settings.align = :center
77
77
  settings.full_border(color: :blue, style: :double)
78
78
  "Loading..."
79
79
  end
@@ -113,7 +113,7 @@ def send_frame(name, duration:, args:)
113
113
  end
114
114
  ```
115
115
 
116
- **IMPORTANT**: the keys for arguments must be symbols.
116
+ **IMPORTANT**: the keys in the `args` hash must be symbols!
117
117
 
118
118
  #### Example
119
119
 
@@ -148,31 +148,31 @@ end
148
148
 
149
149
  ### Template Factory
150
150
 
151
- To render the frame events sent by the driver, the application requires a template factory. This factory will be called for each frame event, with the frame name and the arguments supplied by the driver. A template factory can be a simple ruby class and thus can maintain state. Whirled Peas provides a few basic building blocks to make simple, yet elegant terminal-based UIs.
151
+ To render the frame events sent by the driver, the application requires a template factory. This factory will be called for each frame event, with the frame name and the arguments supplied by the driver. A template factory can be an instance of ruby class and thus can maintain state. Whirled Peas provides a few basic building blocks to make simple, yet elegant terminal-based UIs.
152
152
 
153
153
  #### Loading Template Factory
154
154
 
155
- `WhirledPeas.start` takes an optional template facotry to build a loading screen. This instance must implement `#build` (taking no arguments). The template returned by that method will be painted while the event loop is waiting for frames. The factory method will be called once per refresh cycle, so it's possible to implement animation.
155
+ `WhirledPeas.configure` takes an optional template factory to build a loading screen. This instance must implement `#build` (taking no arguments). The template returned by that method will be painted while the event loop is waiting for frames. The factory method will be called once per refresh cycle, so it's possible to implement animation.
156
156
 
157
157
  #### Building Blocks
158
158
 
159
- A template is created with `WhirledPeas.template`, which yields a `Template` object and `TemplateSettings`. This template object is a `ComposableElement`, which allows for attaching child elements and setting layout options. `GridElement` and `BoxElement` are two other composable elements and `TextElement` is a simple element that can hold a text/number value and has layout options, but cannot have any child elements.
159
+ A template is created with `WhirledPeas.template`, which yields a `Composer` object for a `BoxElement` and `BoxSettings`. The composer allows for attaching child elements and the settings for setting layout options.
160
160
 
161
- A `ComposableElement` provides the following methods to add child elements, each of these takes an optional string argument that is set as the name of the element (which can be useful when debugging).
161
+ A `Composer` provides the following methods to add child elements, each of these takes an optional string argument that is set as the name of the element (which can be useful when debugging).
162
162
 
163
- - `add_box` - yields a `ComposableElement` and a `BoxSettings`, which will be added to the parent's children
164
- - `add_grid` - yields a `ComposableElement` and a `GridSettings`, which will be added to the parent's children
163
+ - `add_box` - yields a `Composer` and a `BoxSettings`, which will be added to the parent's children
164
+ - `add_grid` - yields a `Composer` and a `GridSettings`, which will be added to the parent's children
165
165
  - `add_text` - yields `nil` and a `TextSettings`, which will be added to the parent's children
166
166
 
167
167
  E.g.
168
168
 
169
169
  ```ruby
170
- WhirledPeas.template do |template, template_settings|
171
- template_settings.bg_color = :blue
172
- template.add_grid do |grid, grid_settings|
173
- grid_settings.num_cols = 10
170
+ WhirledPeas.template do |composer, settings|
171
+ settings.bg_color = :blue
172
+ composer.add_grid do |composer, settings|
173
+ settings.num_cols = 10
174
174
  100.times do |i|
175
- grid.add_text { i }
175
+ composer.add_text { i }
176
176
  end
177
177
  end
178
178
  end
@@ -181,29 +181,27 @@ end
181
181
  The above template can also be broken down into more manageable methods, e.g.
182
182
 
183
183
  ```ruby
184
- def number_grid(grid, settings)
184
+ def number_grid(_composer, settings)
185
185
  settings.num_cols = 10
186
- 100.times do |i|
187
- grid.add_text { i }
188
- end
186
+ 100.times.map(&:itself)
189
187
  end
190
188
 
191
- WhirledPeas.template do |template, settings|
189
+ WhirledPeas.template do |composer, settings|
192
190
  settings.bg_color = :blue
193
- template.add_grid(&method(:number_grid))
191
+ composer.add_grid(&method(:number_grid))
194
192
  end
195
193
  ```
196
194
 
197
195
  Additionally, if no child element is explicitly added to a `GridElement`, but the block returns an array of strings or numbers, those will be converted to `TextElements` and added as children to the `GridElement`. For example, these are identical ways to create a grid of strings
198
196
 
199
197
  ```ruby
200
- template.add_grid do |g|
198
+ template.add_grid do |composer|
201
199
  100.times do |i|
202
- g.add_text { i }
200
+ composer.add_text { i }
203
201
  end
204
202
  end
205
203
 
206
- template.add_grid do |g|
204
+ template.add_grid do
207
205
  100.times.map(&:itself)
208
206
  end
209
207
  ```
@@ -211,51 +209,65 @@ end
211
209
  Similarly, if no child element is explicilty added to a `BoxElement`, but the block returns a string or number, that value will be converted to a `TextElement` and added as a child. For example, these are identical ways to create a box with string content
212
210
 
213
211
  ```ruby
214
- template.add_box do |b|
215
- b.add_text { "Hello!" }
212
+ template.add_box do |composer|
213
+ composer.add_text { "Hello!" }
216
214
  end
217
215
 
218
- template.add_box do |b|
216
+ template.add_box do
219
217
  "Hello!"
220
218
  end
221
219
  ```
222
220
 
223
221
  #### Settings
224
222
 
225
- Each element type has an associated settings type, which provide a custom set of options to format the output. Parent settings may be merged into child settings (assuming the child supports those settings)
223
+ Each element type has an associated settings type, which provide a custom set of options to format the output. Child settings will inherit from the parent, where applicable
226
224
  The available settigs are
227
225
 
228
- | Setting | Description | Default | Availability | Merged? |
229
- | ------------- | ------------------------------------------------------------------ | ------- | --------------------------------- | ------- |
230
- | `align` | Justifies the text (allowed values: `:left`, `:center`, `:right`) | `:left` | `Box`, `Grid`, `Text` | Yes |
231
- | `auto_margin` | Evenly distribute side margin (overrides left/right in `margin`) | `false` | `Box`, `Grid` | Yes |
232
- | `bg_color` | Background color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
233
- | `bold` | `true` makes the font bold | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
234
- | `border` | Set the border for the lements | none | `Box`, `Grid`, | Yes |
235
- | `color` | Foreground text color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
236
- | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | `Box` | Yes |
237
- | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | `Box`, `Grid` | Yes |
238
- | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | `Box`, `Grid` | Yes |
239
- | `title_font` | Font used to create "large" text (see [Large Text](#large-text)) | | `Text` |
240
- | `transpose` | Display grid elements top-to-bottom, then left-to-right | `false` | `Grid` | No |
241
- | `underline` | `true` underlines the font | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
242
- | `width` | Override the calculated with of an element | | `Box`, `Grid`, `Text` | No |
243
-
244
- ##### Margin and Padding
245
-
246
- Margin and padding settings allow for setting the spacing on each of the 4 sides of the element independently. The set these values, use
247
-
248
- - `clear_margin` - sets all margin values to 0
226
+ | Setting | Description | Default | Availability | Inherited |
227
+ | ------------ | ------------------------------------------------------------------------------- | ------- | --------------------- | -------------------- |
228
+ | `align` | Justifies the content (allowed values: `:left`, `:center`, `:right`) | `:left` | `Box`, `Grid` | Yes |
229
+ | `bg_color` | Background color (see [Colors](#colors)) | | `Box`, `Grid`, `Text` | Yes |
230
+ | `bold` | `true` makes the font bold | `false` | `Box`, `Grid`, `Text` | Yes |
231
+ | `border` | Set the border for the lements | none | `Box`, `Grid`, | Only style and color |
232
+ | `color` | Foreground text color (see [Colors](#colors)) | | `Box`, `Grid`, `Text` | Yes |
233
+ | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | `Box`, `Grid` | Yes |
234
+ | `height` | Override the calculated height of an element's content area | | `Box`, `Grid` | No |
235
+ | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | `Box`, `Grid` | No |
236
+ | `num_cols` | Number of columns in the grid (must be set!) | | `Grid` | No |
237
+ | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | `Box`, `Grid` | No |
238
+ | `position` | Set the (left, top) position of the element relative to parent content area | `0` | `Box`, `Grid` | No |
239
+ | `title_font` | Font used for "large" text (see [Large Text](#large-text), ignores `underline`) | | `Text` | No |
240
+ | `underline` | `true` underlines the font | `false` | `Box`, `Grid`, `Text` | Yes |
241
+ | `width` | Override the calculated width of an element's content area | | `Box`, `Grid` | No |
242
+
243
+ ##### Position
244
+
245
+ Position settings dictate the relative position from where the painter would have preferred to place the container. Negative numbers move the container left/up and positive numbers move it right/down. To set these values, use
246
+
247
+ - `set_position(left:, top:)`
248
+
249
+ ##### Margin
250
+
251
+ Margin settings dictate the spacing on the outside (i.e. outside of the border) of each of the 4 sides of the container independently. To set these values, use
252
+
249
253
  - `set_margin(left:, top:, right:, bottom:)`
250
- - `clear_padding` - sets all margin values to 0
254
+
255
+ Note: values cannot be negative
256
+
257
+ ##### Padding
258
+
259
+ Padding settings dictate the spacing on the inside (i.e. inside of the border) of each of the 4 sides of the container independently. To set these values, use
260
+
251
261
  - `set_padding(left:, top:, right:, bottom:)`
252
262
 
263
+ Note: values cannot be negative
264
+
253
265
  ##### Border
254
266
 
255
267
  The border settings consist of 6 boolean values (border are either width 1 or not shown), the 4 obvious values (`left`, `top`, `right`, and `bottom`) along with 2 other values for inner borders (`inner_horiz` and `inner_vert`) in a grid. A border also has a foreground color (defaults to `:white`) and a style. The background color is determined by the `bg_color` of the element. Border values can be set with
256
268
 
257
- - `clear_border` - sets all border positions to `false`
258
269
  - `set_border(left:, top:, right:, bottom:, inner_horiz:, inner_vert:, color:, style:)`
270
+ - `full_border(style:, color:)`
259
271
 
260
272
  Available border styles are
261
273
 
@@ -373,8 +385,13 @@ Note: when using a title font with WhirledPeas for the first time on a system, t
373
385
  class TemplateFactory
374
386
  def build(frame, args)
375
387
  set_state(frame, args)
376
- WhirledPeas.template do |t|
377
- t.add_box('Body', &method(:body))
388
+ WhirledPeas.template do |composer, settings|
389
+ settings.flow = :l2r
390
+ settings.align = :center
391
+
392
+ composer.add_box('Title', &method(:title))
393
+ composer.add_box('Sum', &method(:sum))
394
+ composer.add_grid('NumberGrid', &method(:number_grid))
378
395
  end
379
396
  end
380
397
 
@@ -388,34 +405,25 @@ class TemplateFactory
388
405
  @high = args[:high] if args.key?(:high)
389
406
  end
390
407
 
391
- def title(_elem, settings)
408
+ def title(_composer, settings)
392
409
  settings.underline = true
393
410
  "Pair Finder"
394
411
  end
395
412
 
396
- def sum(_elem, settings)
413
+ def sum(_composer, settings)
397
414
  settings.color = @frame == 'found-pair' ? :green : :red
398
415
  @sum ? "Sum: #{@sum}" : 'N/A'
399
416
  end
400
417
 
401
- def number_grid(elem, settings)
418
+ def number_grid(composer, settings)
402
419
  settings.full_border
403
420
  @numbers.each.with_index do |num, index|
404
- g.add_text do |_, settings|
421
+ composer.add_text do |_, settings|
405
422
  settings.bg_color = (@low == index || @high == index) ? :cyan : :white
406
423
  num
407
424
  end
408
425
  end
409
426
  end
410
-
411
- def body(elem, settings)
412
- settings.flow = :l2r
413
- settings.auto_margin = true
414
-
415
- elem.add_box('Title', &method(:title))
416
- elem.add_box('Sum', &method(:sum))
417
- elem.add_grid('NumberGrid', &method(:number_grid))
418
- end
419
427
  end
420
428
  ```
421
429
 
@@ -443,16 +451,31 @@ Displays a single frame for several seconds
443
451
  $ whirled_peas <config file> play_frame move '{"direction":"N"}'
444
452
  ```
445
453
 
446
- Adding the `--debug` flag will result in just printing out the template's debug information, e.g.
454
+ Adding the `--template` flag will result in printing out debug information for the template, e.g.
447
455
 
448
456
  ```
449
- $ whirled_peas <config file> play_frame move '{"direction":"N"}' --debug
450
- + TEMPLATE [WhirledPeas::UI::Template]
457
+ $ whirled_peas <config file> play_frame move '{"direction":"N"}' --template
458
+ + TEMPLATE [WhirledPeas::Template::BoxElement]
451
459
  - Settings
452
- WhirledPeas::UI::TemplateSettings
460
+ WhirledPeas::Settings::BoxSettings
453
461
  <default>
454
462
  - Children
455
- + TitleContainer [WhirledPeas::UI::BoxElement]
463
+ + TitleContainer [WhirledPeas::Template::BoxElement]
464
+ ...
465
+ ```
466
+
467
+ Adding the `--painter` flag will result in printing out debug information the painter (the rendered template), e.g.
468
+
469
+ ```
470
+ $ whirled_peas <config file> play_frame move '{"direction":"N"}' --painter
471
+ + TEMPLATE [WhirledPeas::Graphics::BoxPainter]
472
+ - Settings
473
+ WhirledPeas::Settings::BoxSettings
474
+ <default>
475
+ - Dimensions
476
+ - Canvas:
477
+ - Children
478
+ + TitleContainer [WhirledPeas::Graphics::BoxPainter]
456
479
  ...
457
480
  ```
458
481
 
@@ -483,6 +506,21 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
483
506
 
484
507
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
485
508
 
509
+ ### Testing
510
+
511
+ In addition to standard RSpec tests, WhirledPeas has custom tests for rendered templates. These files live in `screen_test/rendered`. Each ruby file is expected to define a class named `TemplateFactory` that responds to `#build(name, args)` returning a template (the standard template factory role). Each file should also be accompanied by a `.frame` file with the same base name. This file will contain the output of the rendered screen and is considered the correct output when running tests.
512
+
513
+ Note: viewing `.frame` files with `cat` works better than most other text editors.
514
+
515
+ The following rake tasks are provided to interact with the screen tests
516
+
517
+ - `screen_test` runs all screen tests in the `screen_test/rendered` directory
518
+ - `screen_test:debug[path/to/file.rb]` print the rendered template debug tree
519
+ - `screen_test:run[path/to/file.rb]` runs a single screen test
520
+ - `screen_test:save[path/to/file.rb]` saves the output generated by the template in the `.frame` file, overwriting any existing file
521
+ - `screen_test:view[path/to/file.rb]` views the output generated by the template
522
+ - `screen_test:update_all[path/to/file.rb]` interactively step through each pending or failed screen test to compare/set the expected output
523
+
486
524
  ## Contributing
487
525
 
488
526
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/whirled_peas. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/whirled_peas/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,6 +1,40 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ def screen_test(file, method)
7
+ raise ArgumentError, 'Missing argument: file' unless file
8
+
9
+ require 'bundler/setup'
10
+ require 'whirled_peas'
11
+ require_relative 'screen_test/screen_tester'
12
+
13
+ WhirledPeas::ScreenTester.new(file).send(method)
14
+ end
15
+
16
+ namespace :screen_test do
17
+ %i[debug run save view].each do |t|
18
+ task t, [:file] do |_, args|
19
+ screen_test(args[:file], t)
20
+ end
21
+ end
22
+
23
+ task :update_all do
24
+ require 'bundler/setup'
25
+ require 'whirled_peas'
26
+ require_relative 'screen_test/screen_tester'
27
+
28
+ WhirledPeas::ScreenTester.update_all
29
+ end
30
+ end
31
+
32
+ task :screen_test do
33
+ require 'bundler/setup'
34
+ require 'whirled_peas'
35
+ require_relative 'screen_test/screen_tester'
36
+
37
+ WhirledPeas::ScreenTester.run_all
38
+ end
39
+
40
+ task default: [:screen_test, :spec]
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def print_usage
4
+ puts "Usage: #{$0} <config file> [options]"
5
+ puts
6
+ puts 'options include'
7
+ puts ' --disable-screen Disable the screen (useful when printing debug statements)'
8
+ puts ' --painter Print the painter debug tree and exit'
9
+ puts ' --template Print the template debug tree and exit'
10
+ end
11
+
12
+ if !(1..2).include?(ARGV.length)
13
+ print_usage
14
+ exit(1)
15
+ elsif !File.exist?(ARGV.first)
16
+ puts "File not found: #{ARGV.first}"
17
+ print_usage
18
+ exit(1)
19
+ elsif ARGV.length == 2 && !%w[--disable-screen --template --painter].include?(ARGV[1])
20
+ puts "Unrecognized option: #{ARGV[1]}"
21
+ print_usage
22
+ exit(1)
23
+ end
24
+
25
+ require 'bundler/setup'
26
+ require 'whirled_peas'
27
+
28
+ if ARGV.length == 1
29
+ option = nil
30
+ else
31
+ option = ARGV[1].sub(/^--/, '').gsub(/-/, '_').to_sym
32
+ end
33
+
34
+ template_file = ARGV.first[0] == '/' ? ARGV.first : File.join(Dir.pwd, ARGV.first)
35
+ WhirledPeas.debug(template_file, option)
@@ -1,11 +1,12 @@
1
1
  require 'logger'
2
2
 
3
3
  require 'whirled_peas/errors'
4
-
5
4
  require 'whirled_peas/config'
5
+ require 'whirled_peas/debugger'
6
6
  require 'whirled_peas/frame'
7
+ require 'whirled_peas/graphics'
8
+ require 'whirled_peas/settings'
7
9
  require 'whirled_peas/template'
8
- require 'whirled_peas/ui'
9
10
  require 'whirled_peas/utils'
10
11
  require 'whirled_peas/version'
11
12
 
@@ -18,11 +19,12 @@ module WhirledPeas
18
19
  yield config
19
20
  end
20
21
 
21
- def self.template(&block)
22
- require 'whirled_peas/template/element'
22
+ def self.debug(config_file, option=nil)
23
+ Debugger.new(config_file, option).debug
24
+ end
23
25
 
24
- template = UI::Template.new
25
- yield template, template.settings
26
- template
26
+ def self.template(&block)
27
+ require 'whirled_peas/template/composer'
28
+ Template::Composer.build(&block)
27
29
  end
28
30
  end