hackmac 1.8.2 → 1.8.3

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.
@@ -1,12 +1,56 @@
1
1
  class Hackmac::Graph
2
+ # A terminal display class that manages a grid of colored cells with ANSI
3
+ # styling support
4
+ #
5
+ # The Display class provides functionality for creating and managing
6
+ # terminal-based visual displays It handles cell-level rendering with support
7
+ # for colors, background colors, and text styles The class maintains internal
8
+ # state for cursor position and formatting attributes while providing methods
9
+ # to manipulate individual cells and render complete display grids to the
10
+ # terminal
11
+ #
12
+ # @example
13
+ # display = Hackmac::Graph::Display.new(24, 80)
14
+ # # Creates a 24x80 character display grid for terminal rendering
2
15
  class Display
3
16
  ANSI = Term::ANSIColor
4
17
 
18
+ # A cell representation for terminal display with character, color,
19
+ # background color, and styling attributes
20
+ #
21
+ # The Cell class encapsulates the properties of a single character cell in
22
+ # a terminal display, including its visual characteristics such as the
23
+ # displayed character, text color, background color, and styling
24
+ # attributes. It provides methods to compare cells and convert them to
25
+ # their string representation with ANSI escape codes for terminal
26
+ # rendering.
5
27
  class Cell < Struct.new(:char, :color, :on_color, :styles)
28
+ # The == method compares two Cell objects for equality by their internal
29
+ # array representation
30
+ #
31
+ # This method checks if the current Cell instance is equal to another
32
+ # Cell instance by comparing their underlying array representations
33
+ # returned by to_a
34
+ #
35
+ # @param other [ Hackmac::Graph::Display::Cell ] the other Cell object to
36
+ # compare against
37
+ #
38
+ # @return [ Boolean ] true if both cells have identical char, color,
39
+ # on_color, and styles values, false otherwise
6
40
  def ==(other)
7
41
  to_a == other.to_a
8
42
  end
9
43
 
44
+ # The to_s method converts a Cell object into its string representation
45
+ # with ANSI styling
46
+ #
47
+ # This method constructs a formatted string that includes the cell's
48
+ # character along with its color, background color, and text style
49
+ # attributes using ANSI escape sequences. The resulting string is
50
+ # suitable for display in terminal environments that support ANSI colors.
51
+ #
52
+ # @return [ String ] a formatted string containing the cell's visual representation
53
+ # with appropriate ANSI styling codes for terminal rendering
10
54
  def to_s
11
55
  result = +''
12
56
  result << ANSI.color(color)
@@ -17,12 +61,34 @@ class Hackmac::Graph
17
61
  end
18
62
  end
19
63
 
64
+ # The initialize method sets up a Display instance by configuring its grid
65
+ # dimensions and initializing internal state
66
+ #
67
+ # This method creates a display grid with the specified number of lines and
68
+ # columns, establishing the boundaries for cell positioning. It initializes
69
+ # the internal ranges for lines and columns and performs an initial clear
70
+ # operation to set up the display buffer with default values
71
+ #
72
+ # @param lines [ Integer ] the number of lines (rows) in the display grid
73
+ # @param columns [ Integer ] the number of columns (characters per line) in
74
+ # the display grid
20
75
  def initialize(lines, columns)
21
76
  @lines_range = 1..lines
22
77
  @columns_range = 1..columns
23
78
  clear
24
79
  end
25
80
 
81
+ # The clear method resets the display state by initializing cursor
82
+ # position, color attributes, and cell contents to their default values
83
+ #
84
+ # This method prepares the terminal display for a fresh rendering by
85
+ # resetting internal tracking variables such as cursor coordinates, color
86
+ # settings, and text styles. It also reinitializes the two-dimensional
87
+ # array of Cell objects that represent the display grid, filling each cell
88
+ # with a space character and default styling attributes
89
+ #
90
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
91
+ # for method chaining
26
92
  def clear
27
93
  @x = 1
28
94
  @y = 1
@@ -38,6 +104,16 @@ class Hackmac::Graph
38
104
  reset
39
105
  end
40
106
 
107
+ # The reset method resets the display's color and style attributes to their
108
+ # default values
109
+ #
110
+ # This method reinitializes the internal color tracking variables to their
111
+ # default state, clearing any active styling and resetting the text color
112
+ # to white (15) and background color to black (0). It also clears all
113
+ # active text styles.
114
+ #
115
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
116
+ # for method chaining
41
117
  def reset
42
118
  @color = 15
43
119
  @on_color = 0
@@ -45,6 +121,15 @@ class Hackmac::Graph
45
121
  self
46
122
  end
47
123
 
124
+ # The each method iterates over all cells in the display grid
125
+ #
126
+ # This method provides an iterator interface for accessing each cell in the
127
+ # terminal display grid by yielding the row, column, and cell object for
128
+ # each position in the grid
129
+ #
130
+ # @yield [ y, x, cell ] yields the row coordinate, column coordinate, and cell object
131
+ #
132
+ # @return [ Enumerator ] an enumerator that allows iteration over all cells in the grid
48
133
  def each(&block)
49
134
  Enumerator.new do |enum|
50
135
  @lines_range.each do |y|
@@ -55,6 +140,20 @@ class Hackmac::Graph
55
140
  end.each(&block)
56
141
  end
57
142
 
143
+ # The - method calculates the difference between two display states by
144
+ # comparing their cells and returns a string of ANSI escape sequences that
145
+ # represent only the changes
146
+ #
147
+ # This method takes another Display instance and compares it with the
148
+ # current display state to identify which cells have changed. It generates
149
+ # a minimal set of ANSI cursor movement and character output commands to
150
+ # redraw only the portions of the display that have changed, making
151
+ # terminal updates more efficient
152
+ #
153
+ # @param old [ Hackmac::Graph::Display ] the previous display state to compare against
154
+ #
155
+ # @return [ String ] a string containing ANSI escape sequences for
156
+ # rendering only the changed cells
58
157
  def -(old)
59
158
  dimensions != old.dimensions and raise ArgumentError,
60
159
  "old dimensions #{old.dimensions.inspect} don't match #{dimensions.inspect}"
@@ -67,32 +166,94 @@ class Hackmac::Graph
67
166
  result
68
167
  end
69
168
 
169
+ # The to_s method generates a string representation of the display by
170
+ # iterating over all cells and constructing a formatted terminal output
171
+ # with ANSI escape sequences for positioning and styling
172
+ #
173
+ # @return [ String ] a complete terminal display string with all cells
174
+ # rendered using their visual attributes and positioned according to
175
+ # their coordinates in the grid
70
176
  def to_s
71
177
  each.inject(ANSI.clear_screen) do |s, (y, x, c)|
72
178
  s << ANSI.move_to(y, x) << c.to_s
73
179
  end
74
180
  end
75
181
 
182
+ # The inspect method returns a string representation of the display object
183
+ # that includes its class name along with the dimensions of the display
184
+ # grid
185
+ #
186
+ # @return [ String ] a formatted string containing the class name and
187
+ # display dimensions in the format "#<ClassName: columns×lines>"
76
188
  def inspect
77
189
  "#<#{self.class}: #{columns}×#{lines}>"
78
190
  end
79
191
 
192
+ # The x reader method provides access to the x attribute that was set
193
+ # during object initialization.
194
+ #
195
+ # This method returns the value of the x instance variable, which typically
196
+ # represents the horizontal coordinate or position within the display grid.
197
+ #
198
+ # @return [ Integer ] the x coordinate value stored in the instance variable
80
199
  attr_reader :x
81
200
 
201
+ # The y reader method provides access to the y attribute that was set
202
+ # during object initialization.
203
+ #
204
+ # This method returns the value of the y instance variable, which typically
205
+ # represents the vertical coordinate or position within the display grid.
206
+ #
207
+ # @return [ Integer ] the y coordinate value stored in the instance variable
82
208
  attr_reader :y
83
209
 
210
+ # The lines method returns the number of lines in the display
211
+ #
212
+ # This method provides access to the vertical dimension of the graphical
213
+ # display by returning the total number of rows available for rendering
214
+ # content
215
+ #
216
+ # @return [ Integer ] the number of lines (rows) in the display object
84
217
  def lines
85
218
  @lines_range.end
86
219
  end
87
220
 
221
+ # The columns method returns the number of columns in the display
222
+ #
223
+ # This method provides access to the horizontal dimension of the graphical
224
+ # display by returning the total number of columns available for rendering
225
+ # content
226
+ #
227
+ # @return [ Integer ] the number of columns (characters per line) in the
228
+ # display object
88
229
  def columns
89
230
  @columns_range.end
90
231
  end
91
232
 
233
+ # The dimensions method returns the size dimensions of the display grid
234
+ #
235
+ # This method provides access to the display's rectangular dimensions by
236
+ # returning an array containing the number of lines (height) and columns (width)
237
+ # that define the terminal display area
238
+ #
239
+ # @return [ Array<Integer> ] an array where the first element is the number of lines
240
+ # and the second element is the number of columns in the display grid
92
241
  def dimensions
93
242
  [ lines, columns ]
94
243
  end
95
244
 
245
+ # The styled method sets the text styles for subsequent character output
246
+ #
247
+ # This method configures the styling attributes that will be applied to
248
+ # characters written to the display, such as bold, italic, underline,
249
+ # and other text formatting options. It validates that all provided style
250
+ # names are recognized before applying them.
251
+ #
252
+ # @param s [ Array<Symbol> ] an array of style symbols to apply
253
+ #
254
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for method chaining
255
+ #
256
+ # @raise [ ArgumentError ] raised when any of the provided style symbols is not recognized
96
257
  def styled(*s)
97
258
  if nope = s.find { !style?(_1) }
98
259
  raise ArgumentError, "#{nope} is not a style"
@@ -101,6 +262,20 @@ class Hackmac::Graph
101
262
  self
102
263
  end
103
264
 
265
+ # The at method sets the cursor position within the display grid
266
+ #
267
+ # This method updates the internal y and x coordinates to the specified position,
268
+ # validating that the coordinates fall within the defined grid boundaries before
269
+ # making the change. It enables subsequent character output operations to occur
270
+ # at the designated location.
271
+ #
272
+ # @param y [ Integer ] the vertical coordinate to move the cursor to
273
+ # @param x [ Integer ] the horizontal coordinate to move the cursor to
274
+ #
275
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for method chaining
276
+ #
277
+ # @raise [ ArgumentError ] raised when the y coordinate is outside the valid lines range
278
+ # @raise [ ArgumentError ] raised when the x coordinate is outside the valid columns range
104
279
  def at(y, x)
105
280
  @lines_range.include?(y) or
106
281
  raise ArgumentError, "y #{y} out of lines range #@lines_range"
@@ -110,6 +285,19 @@ class Hackmac::Graph
110
285
  self
111
286
  end
112
287
 
288
+ # The put method assigns a character to the current cursor position in the
289
+ # display grid
290
+ #
291
+ # This method stores a character cell at the current vertical and
292
+ # horizontal coordinates within the terminal display grid. It validates
293
+ # that the input is a single character before assigning it, ensuring that
294
+ # only valid characters are placed in the grid.
295
+ #
296
+ # @param char [ String ] the single character to be placed at the current cursor position
297
+ #
298
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow for method chaining
299
+ #
300
+ # @raise [ ArgumentError ] raised when the provided character is not a single character
113
301
  def put(char)
114
302
  char.size == 1 or
115
303
  raise ArgumentError, "#{char} is not single character"
@@ -117,6 +305,18 @@ class Hackmac::Graph
117
305
  self
118
306
  end
119
307
 
308
+ # The write method outputs a string character by character within the
309
+ # display grid
310
+ #
311
+ # This method takes a string and writes it to the current cursor position
312
+ # in the terminal display, advancing the cursor position after each
313
+ # character is written. It handles line wrapping by stopping when reaching
314
+ # the end of the row.
315
+ #
316
+ # @param string [ String ] the string to be written to the display
317
+ #
318
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
319
+ # for method chaining
120
320
  def write(string)
121
321
  string.each_char do |char|
122
322
  put(char)
@@ -129,39 +329,135 @@ class Hackmac::Graph
129
329
  self
130
330
  end
131
331
 
332
+ # The top method moves the cursor position to the first line of the current
333
+ # column
334
+ #
335
+ # This method sets the vertical cursor coordinate to the first line while
336
+ # preserving the current horizontal position It is useful for positioning
337
+ # text at the top of the current column in terminal displays
338
+ #
339
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for
340
+ # method chaining
341
+ #
132
342
  def top
133
343
  at(1, x)
134
344
  end
135
345
 
346
+ # The bottom method moves the cursor position to the last line of the
347
+ # current column
348
+ #
349
+ # This method sets the vertical cursor coordinate to the last line while
350
+ # preserving the current horizontal position. It is useful for positioning
351
+ # text at the bottom of the current column in terminal displays.
352
+ #
353
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for
354
+ # method chaining
136
355
  def bottom
137
356
  at(lines, x)
138
357
  end
139
358
 
359
+ # The left method moves the cursor position to the first column of the
360
+ # current line
361
+ #
362
+ # This method sets the horizontal cursor coordinate to the first column while
363
+ # preserving the current vertical position. It is useful for positioning text
364
+ # at the beginning of the current line in terminal displays
365
+ #
366
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for
367
+ # method chaining
140
368
  def left
141
369
  at(y, 1)
142
370
  end
143
371
 
372
+ # The right method moves the cursor position to the last column of the
373
+ # current line
374
+ #
375
+ # This method sets the horizontal cursor coordinate to the final column
376
+ # while maintaining the current vertical position. It is useful for
377
+ # positioning text at the end of the current line in terminal displays
378
+ #
379
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for
380
+ # method chaining
144
381
  def right
145
382
  at(y, columns)
146
383
  end
147
384
 
385
+ # The centered method moves the cursor position to the center of the
386
+ # display grid
387
+ #
388
+ # This method calculates the midpoint coordinates of the terminal display
389
+ # grid and positions the cursor at that location, making it convenient for
390
+ # centering text or other content within the available terminal space
391
+ #
392
+ # @return [ Hackmac::Graph::Display ] returns the Display instance for
393
+ # method chaining
148
394
  def centered
149
395
  at(lines / 2, columns / 2)
150
396
  end
151
397
 
398
+ # The write_centered method positions the cursor at the horizontal center
399
+ # of the display grid and writes a string there
400
+ #
401
+ # This method calculates the starting column position needed to center the
402
+ # given string within the current display width, moves the cursor to that
403
+ # position, and then writes the string character by character.
404
+ # It is useful for creating centered text output in terminal displays.
405
+ #
406
+ # @param string [ String ] the text string to be written and centered on
407
+ # the current line
408
+ #
409
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
410
+ # for method chaining
152
411
  def write_centered(string)
153
412
  at(@y, (columns - string.size) / 2).write(string)
154
413
  end
155
414
 
415
+ # The get method retrieves the cell object at the current cursor position
416
+ #
417
+ # This method accesses the internal two-dimensional array of Cell objects
418
+ # using the current vertical and horizontal cursor coordinates to return
419
+ # the specific cell that is currently pointed to by the cursor
420
+ #
421
+ # @return [ Hackmac::Graph::Display::Cell ] the cell object at the current
422
+ # cursor position
156
423
  def get
157
424
  @cells[@y - 1][@x - 1]
158
425
  end
159
426
 
427
+ # The color method sets the text color attribute for subsequent character
428
+ # output
429
+ #
430
+ # This method configures the color that will be applied to characters
431
+ # written to the display by updating the internal color tracking variable
432
+ # with a validated color attribute value
433
+ #
434
+ # @param color [ Integer ] the color index to set for subsequent text output
435
+ #
436
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
437
+ # for method chaining
438
+ #
439
+ # @raise [ ArgumentError ] raised when the provided color value is not a
440
+ # valid color attribute
160
441
  def color(color)
161
442
  @color = attribute!(color)
162
443
  self
163
444
  end
164
445
 
446
+ # The on_color method sets the background color attribute for subsequent
447
+ # character output
448
+ #
449
+ # This method configures the background color that will be applied to
450
+ # characters written to the display by updating the internal on_color
451
+ # tracking variable with a validated color attribute value
452
+ #
453
+ # @param on_color [ Integer ] the background color index to set for
454
+ # subsequent text output
455
+ #
456
+ # @return [ Hackmac::Graph::Display ] returns the Display instance to allow
457
+ # for method chaining
458
+ #
459
+ # @raise [ ArgumentError ] raised when the provided color value is not a
460
+ # valid color attribute
165
461
  def on_color(on_color)
166
462
  @on_color = attribute!(on_color)
167
463
  self
@@ -169,6 +465,17 @@ class Hackmac::Graph
169
465
 
170
466
  private
171
467
 
468
+ # The style? method checks whether a given symbol is a valid text styling
469
+ # attribute
470
+ #
471
+ # This method verifies if the provided symbol corresponds to one of the
472
+ # supported text styles that can be applied to terminal output, such as
473
+ # bold, italic, underline, and other formatting options
474
+ #
475
+ # @param s [ Symbol ] the symbol to check against the list of valid styles
476
+ #
477
+ # @return [ Boolean ] true if the symbol is a recognized text style, false
478
+ # otherwise
172
479
  def style?(s)
173
480
  [
174
481
  :bold,
@@ -187,10 +494,34 @@ class Hackmac::Graph
187
494
  ].member?(s)
188
495
  end
189
496
 
497
+ # The attribute? method checks if a given value is a valid ANSI color
498
+ # attribute
499
+ #
500
+ # This method validates whether the provided input corresponds to a
501
+ # recognized ANSI color attribute within the Term::ANSIColor::Attribute
502
+ # namespace
503
+ #
504
+ # @param a [ Object ] the value to check against valid ANSI attributes
505
+ #
506
+ # @return [ Object, nil ] the attribute if valid, nil otherwise
190
507
  def attribute?(a)
191
508
  Term::ANSIColor::Attribute[a]
192
509
  end
193
510
 
511
+ # The attribute! method validates a given value against known ANSI color
512
+ # attributes and raises an error if invalid
513
+ #
514
+ # This method serves as a validation wrapper around the attribute? method,
515
+ # ensuring that a provided value is a recognized ANSI color attribute. If
516
+ # the validation fails, it raises an ArgumentError with a descriptive
517
+ # message indicating which value was not accepted
518
+ #
519
+ # @param a [ Object ] the value to validate as an ANSI color attribute
520
+ #
521
+ # @return [ Object ] returns the validated attribute if it passes validation
522
+ #
523
+ # @raise [ ArgumentError ] raised when the provided value is not recognized
524
+ # as a valid ANSI color attribute
194
525
  def attribute!(a)
195
526
  attribute?(a) or
196
527
  raise ArgumentError, "#{a.inspect} is not a color attribute"