whirled_peas 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 85262725d00d4055dceb88c2672afc6a7f5027626a3038998706b5d8e2d1a3aa
4
+ data.tar.gz: 15bc9278fd2945d0ea5cf6a5436ba11e00724e71f128ec487f5569c3689bfaeb
5
+ SHA512:
6
+ metadata.gz: 7270704f5ff2adc5d225dd7c612f489a968c9d5efc2fef399b65a8ad7320fcad2920ec355645f961744577df740efbfcf4947f477e13224702764bf64931a52b
7
+ data.tar.gz: a46f83016c3038275fccc907894c0ea7fc3ce0553c5da343d77fbfbbdf9f619ca169346e11b5862cf502e7785372a750a0ab668bfffb3198b1d529a75cd198a5
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ Gemfile.lock
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.6
6
+ before_install: gem install bundler -v 2.1.4
File without changes
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at collier@apartmentlist.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in whirled_peas.gemspec
4
+ gemspec
5
+
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec', '~> 3.0'
8
+ gem 'pry-byebug'
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Tom Collier
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,331 @@
1
+ # WhirledPeas
2
+
3
+ Visualize your code's execution with Whirled Peas!
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'whirled_peas'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install whirled_peas
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'whirled_peas'
25
+
26
+ class TemplateFactory
27
+ def build(frame, args)
28
+ WhirledPeas.template do |body|
29
+ body.add_box do |_, settings|
30
+ settings.underline = true
31
+ "Hello #{args['name']}"
32
+ end
33
+ # ...
34
+ end
35
+ end
36
+ end
37
+
38
+ class Driver
39
+ def start(producer)
40
+ producer.send('starting', args: { 'name' => 'World' })
41
+ # ...
42
+ end
43
+ end
44
+
45
+ WhirledPeas.start(Driver.new, TemplateFactory.new)
46
+ ```
47
+
48
+ A Whirled Peas application consists of two pieces
49
+
50
+ 1. The driver, which emits lightweight frame events
51
+ 1. The template factory, which builds templates to convert frame events from the driver into terminal graphics
52
+
53
+ ### Driver
54
+
55
+ The driver is the application code to be visualized. This is typically a lightweight wrapper around an existing application that conforms to the signature below.
56
+
57
+ ```ruby
58
+ # Start the application and pass frame events to the producer to be rendered by the UI
59
+ #
60
+ # @param producer [Producer] frame producer that sends events to the UI
61
+ def start(producer)
62
+ # application code here
63
+ end
64
+ ```
65
+
66
+ The producer provides a single method
67
+
68
+ ```ruby
69
+ # Send frame events to the UI
70
+ #
71
+ # @param name [String] application defined name for the frame. The template factory will be provided this name
72
+ # @param duration [Number] time in seconds this frame should be displayed for (defaults to 1 frame)
73
+ # @param args [Hash] key value pairs to send as arguments to the template factory, these values will be
74
+ # serialized/deserialized
75
+ def send(name, duration:, args:)
76
+ # implementation
77
+ end
78
+ ```
79
+
80
+ #### Example
81
+
82
+ Simple application that loads a set of numbers and looks for a pair that adds up to 1,000
83
+
84
+ ```ruby
85
+ class Driver
86
+ def start(producer)
87
+ numbers = File.readlines('/path/to/numbers.txt').map(&:to_i)
88
+ producer.send('load-numbers', duration: 3, args: { numbers: numbers })
89
+ numbers.sort!
90
+ producer.send('sort-numbers', duration: 3, args: { numbers: numbers })
91
+ low = 0
92
+ high = numbers.length - 1
93
+ while low < high
94
+ sum = numbers[low] + numbers[high]
95
+ if sum == 1000
96
+ producer.send('found-pair', duration: 5, args: { low: low, high: high, sum: sum })
97
+ return
98
+ elsif sum < 1000
99
+ producer.send('too-low', args: { low: low, high: high, sum: sum })
100
+ low += 1
101
+ else
102
+ producer.send('too-high', args: { low: low, high: high, sum: sum })
103
+ high -= 1
104
+ end
105
+ end
106
+ producer.send('no-solution', duration: 5)
107
+ end
108
+ end
109
+ ```
110
+
111
+ ### Template Factory
112
+
113
+ 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.
114
+
115
+ #### Building Blocks
116
+
117
+ 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.
118
+
119
+ A `ComposableElement` provides the following methods to add child elements
120
+
121
+ - `add_box` - yields a `ComposableElement` and a `BoxSettings`, which will be added to the parent's children
122
+ - `add_grid` - yields a `ComposableElement` and a `GridSettings`, which will be added to the parent's children
123
+ - `add_text` - yields `nil` and a `TextSettings`, which will be added to the parent's children
124
+
125
+ 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
126
+
127
+ ```ruby
128
+ template.add_grid do |g|
129
+ 100.times do |i|
130
+ g.add_text { i.to_s }
131
+ end
132
+ end
133
+
134
+ template.add_grid do |g|
135
+ 100.times.map(&:to_s)
136
+ end
137
+ ```
138
+
139
+ 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
140
+
141
+ ```ruby
142
+ template.add_box do |b|
143
+ b.add_text { "Hello!" }
144
+ end
145
+
146
+ template.add_box do |b|
147
+ "Hello!"
148
+ end
149
+ ```
150
+
151
+ #### Settings
152
+
153
+ 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)
154
+ The available settigs are
155
+
156
+ | Setting | Description | Default | Availability | Merged? |
157
+ | ------------- | ------------------------------------------------------------------ | ------- | --------------------------------- | ------- |
158
+ | `align` | Justifies the text (allowed values: `:left`, `:center`, `:right`) | `:left` | `Box`, `Grid`, `Text` | Yes |
159
+ | `auto_margin` | Evenly distribute side margin (overrides left/right in `margin`) | `false` | `Box`, `Grid` | Yes |
160
+ | `bg_color` | Background color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
161
+ | `bold` | `true` makes the font bold | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
162
+ | `border` | Set the border for the lements | none | `Box`, `Grid`, | Yes |
163
+ | `color` | Foreground text color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
164
+ | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | `Box` | Yes |
165
+ | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | `Box`, `Grid` | Yes |
166
+ | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | `Box`, `Grid` | Yes |
167
+ | `transpose` | Display grid elements top-to-bottom, then left-to-right | `false` | `Grid` | No |
168
+ | `underline` | `true` underlines the font | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
169
+ | `width` | Override the calculated with of an element | | `Box`, `Grid`, `Text` | No |
170
+
171
+ ##### Margin and Padding
172
+
173
+ Margin and padding settings allow for setting the spacing on each of the 4 sides of the element independently. The set these values, use
174
+
175
+ - `set_margin(left:, top:, right:, bottom:)`
176
+ - `set_padding(left:, top:, right:, bottom:)`
177
+
178
+ Any argument value not provided will result in that value being 0.
179
+
180
+ ##### Border
181
+
182
+ 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
183
+
184
+ - `set_border(left:, top:, right:, bottom:, inner_horiz:, inner_vert:, color:, style:)`
185
+
186
+ Available border styles are
187
+
188
+ - `:bold` (default)
189
+
190
+ ```
191
+ ┏━━┳━━┓
192
+ ┃ ┃ ┃
193
+ ┣━━╋━━┫
194
+ ┃ ┃ ┃
195
+ ┗━━┻━━┛
196
+ ```
197
+
198
+ - `:double`
199
+
200
+ ```
201
+ ╔══╦══╗
202
+ ║ ║ ║
203
+ ╠══╬══╣
204
+ ║ ║ ║
205
+ ╚══╩══╝
206
+ ```
207
+
208
+ - `:soft`
209
+
210
+ ```
211
+ ╭──┬──╮
212
+ │ │ │
213
+ ├──┼──┤
214
+ │ │ │
215
+ ╰──┴──╯
216
+ ```
217
+
218
+ ##### Display Flow
219
+
220
+ Child elements can flow in one of 4 directions
221
+
222
+ - `:l2r` left-to-right
223
+
224
+ ```
225
+ [child 1] [child 2] ... [child N]
226
+ ```
227
+
228
+ - `:r2l` right-to-left
229
+
230
+ ```
231
+ [child N] [child N - 1] ... [child 1]
232
+ ```
233
+
234
+ - `:t2b` top-to-bottom
235
+
236
+ ```
237
+ [child 1]
238
+ [child 2]
239
+ ...
240
+ [child N]
241
+ ```
242
+
243
+ - `:b2t` bottom-to-top
244
+
245
+ ```
246
+ [child N]
247
+ [child N - 1]
248
+ ...
249
+ [child 1]
250
+ ```
251
+
252
+ ##### Colors
253
+
254
+ Below is the list of available colors (for both foreground and background)
255
+
256
+ - `:black`
257
+ - `:blue`
258
+ - `:cyan`
259
+ - `:gray`
260
+ - `:green`
261
+ - `:magenta`
262
+ - `:red`
263
+ - `:white`
264
+ - `:yellow`
265
+
266
+ Many of these also have a "bright" option:
267
+
268
+ - `:bright_blue`
269
+ - `:bright_cyan`
270
+ - `:bright_green`
271
+ - `:bright_magenta`
272
+ - `:bright_red`
273
+ - `:bright_yellow`
274
+
275
+ ### Example
276
+
277
+ ```ruby
278
+ class TemplateFactory
279
+ def initialize
280
+ @numbers = []
281
+ end
282
+
283
+ def build(name, args)
284
+ @numbers = args['numbers'] if args.key?('numbers')
285
+
286
+ WhirledPeas.template do |t|
287
+ t.add_box do |body, settings|
288
+ settings.flow = :l2r
289
+ settings.auto_margin = true
290
+ body.add_box do |title, settings|
291
+ settings.underline = true
292
+ "Pair Finder"
293
+ end
294
+ body.add_box do |_, settings|
295
+ settings.color = name == 'found-pair' ? :green : :red
296
+ args.key?('sum') ? "Sum: #{args['sum']}" : 'N/A'
297
+ end
298
+ body.add_grid do |g, settings|
299
+ settings.full_border
300
+ @numbers.each.with_index do |num, index|
301
+ is_low = args.key?('low') && args['low'] == index
302
+ is_high = args.key?('high') && args['high'] == index
303
+ g.add_text do |_, settings|
304
+ settings.bg_color = (is_low || is_high) ? :cyan : :white
305
+ num.to_s
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ ```
314
+
315
+ ## Development
316
+
317
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
318
+
319
+ 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).
320
+
321
+ ## Contributing
322
+
323
+ 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).
324
+
325
+ ## License
326
+
327
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
328
+
329
+ ## Code of Conduct
330
+
331
+ Everyone interacting in the WhirledPeas project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/whirled_peas/blob/master/CODE_OF_CONDUCT.md).