scryglass 1.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e64cacb2e1c0e588ffa8554c9203f73a5aa11f565454f0e7e190328b18acaaa8
4
- data.tar.gz: 4435413405197c4dbf03a80bff4632b29cf09d44b0f53de45894ea426c858091
3
+ metadata.gz: 69ff16003c6e5b4ceb6e93e9c5f9ee8aed269b50954db3869963fdf9ab64215b
4
+ data.tar.gz: 6d5c2f92d50b86a1e837033646b7793ee08e5115df98c47c2772775132875337
5
5
  SHA512:
6
- metadata.gz: 2d9081ae5876b542f6c17e792f7a02b12f832a128644e3334c0c6b819dc076fb1a8e60f77e9c02e65032e67e2be52fae38f7ba8b0d38fdfced2bac95469b4ff0
7
- data.tar.gz: adbc658b799af3c4167d132de38d3225db3efaba3e95b39251352b0b8360169419db654605fd88314ccbfce80ce3a78d9cb87c02ff55559ce42a483d086848cf
6
+ metadata.gz: 2f76204b2d6a0e67901e5cee79c5b4a1dcbe7fd08bf03c289cc95268b6e562d86bc49804f215a476e2239a7dfa388e66771c2ad1b1206b23b0b16aeee00607a1
7
+ data.tar.gz: 25171585025b50992b202bff43a881715a11cb7e48c0cfef522281357ea9d2de0de2b584446ba36d979fce45eba7509b69531118f98ce55d3b02c03c5534129e
Binary file
data/.irbrc ADDED
@@ -0,0 +1,9 @@
1
+ Scryglass.load
2
+
3
+ def th
4
+ Scryglass.test_hash
5
+ end
6
+
7
+ def dh
8
+ Scryglass.demo_hash
9
+ end
@@ -7,6 +7,109 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## Added
11
+
12
+ ## Changed
13
+
14
+ ## Fixed
15
+
16
+ ## [2.0.2] - 2020-01-14
17
+
18
+ ## Added
19
+
20
+ ## Changed
21
+
22
+ - Added a default character limit to the method_showcase_for lens to speed it up (Some AR objects have over 1000 methods).
23
+
24
+ ## Fixed
25
+
26
+ ## [2.0.1] - 2020-01-13
27
+
28
+ ## Changed
29
+
30
+ - The named-an-object message now stays for 3 seconds instead of 2.
31
+
32
+ ## Fixed
33
+
34
+ - Typo in spec.description in scryglass.gemspec.
35
+ - Negative sign error on method_showcase_for while calculating padding for very long method names.
36
+
37
+ ## [2.0.0] - 2021-01-13
38
+
39
+ ## Added
40
+
41
+ - Turned on ANSI formatted/colored support with AnsiSliceStringRefinement.
42
+ - Added 'AmazingPrint' lens (colored) and gem.
43
+ - Added color formatting to (beta) method_showcase_for.
44
+ - Added "Smart Open" command 'o', which attempts to create sub-rows of the (next) most helpful type.
45
+ - README and help screen now point out that holding SHIFT will increase up/down step distance.
46
+ - Bottom and right edges of screen now indicate, with dots, when there is more beyond the view's edge.
47
+ - Added the VIM home row keybindings `h`/`j`/`k`/`l` as optional arrow keys.
48
+ - Now if the scry session hits an error, it will first ensure the error and console prompt appear below the present screen.
49
+ - Can now press `=` to give a console instance variable name to current objects without leaving scry session.
50
+ - Added popup messages for when the user attempts to create sub-rows for the current row and no sub-items are found.
51
+ - Added tab functionality to manage multiple scry session tabs for easy reference and comparison.
52
+ - Scryglass version now shows up in top right corner of the tree view when the header has no values to track.
53
+ - Improved and enabled 'Method Showcase' lens by default.
54
+ - Added `[<]`/`[>]` key reminders to Lens View.
55
+
56
+ ## Changed
57
+
58
+ - Changed user_signal timeout period from 0.1sec to 0.3sec to reduce number of coincidentally dropped inputs.
59
+ - Changed AnsiSliceStringRefinement syntax even closer to 'string'[args] (supporting [i, l] syntax).
60
+ - Changed the keys for switching subject type and lens from `L`/`l` to `<`/`>` (To make room for vim h/j/k/l keybindings)
61
+ - Expanded list of "Patient Actions" which won't beep even if that procedure (sometimes user input) took longer than 4 seconds.
62
+ - Improved popup messages QOL (they now stack properly and don't make the user wait for them to disappear).
63
+ - Removed `scry_resume` command; bare `scry` now always resumes last session even if the current console receiver isn't `main`.
64
+ - Made help screen key text blue.
65
+
66
+ ## Fixed
67
+
68
+ - Some more fixes to support (BETA) method_showcase_for:
69
+ - Added method_source gem.
70
+ - Now requiring lens_helper.
71
+ - Changed method to be callable externally
72
+ - Extra view margin no longer producible at far end of ANSI strings
73
+ - Escape true newlines returned by objects with unexpected `.inspect` results, which otherwise messes up the display.
74
+ - Cursor indicators ( `(`/`@`/`·` ) can no longer stall or error on exceptional objects; they now show up as `X` if they error or take too long (0.05s).
75
+ - When quitting from the help screen, cursor and prompt are now set all the way at the bottom of the display, rather than where the content ends on the current *non-help* panel.
76
+
77
+ ## [1.1.0] - 2020-09-21
78
+
79
+ ## Added
80
+
81
+ - Added ability to distinguish genuine escape key presses, and added escape key functionality.
82
+ - Added ability (AnsiSliceStringRefinement) to slice strings while effectively maintaining their ANSI formatting, as our eyes would expect.
83
+ - Added some dynamic header items to Tree View that track the following:
84
+ - Multiple targets count and message
85
+ - Last search text (what will be searched again by hitting 'n')
86
+ - Number-to-move, if digits are typed
87
+ - ('?' controls reminder now only displays when header is otherwise empty)
88
+
89
+ ## Changed
90
+
91
+ - Now inputs check and screen redraws every 0.1 seconds even without user keypresses.
92
+ - (ArrayFitToRefinement now allows non-plural array counts)
93
+
94
+ ## Removed
95
+
96
+ - Temporarily removed record/playback functionality
97
+ - Removed all dependency on activesupport
98
+
99
+ ## Fixed
100
+
101
+ - Fixed issue where shrinking the console screen size enough would create a visual glitch until one of the boundary-resizing commands was received.
102
+
103
+ ## [1.0.1] - 2020-09-18
104
+
105
+ ### Added
106
+
107
+ - Added `require 'stringio'` for StringIO
108
+
109
+ ### Removed
110
+
111
+ - Removed development_dependency 'io-console'
112
+
10
113
  ## [1.0.0] - 2020-09-18
11
114
 
12
115
  ### Added
@@ -1,33 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scryglass (1.0.0)
4
+ scryglass (2.0.2)
5
+ amazing_print
6
+ binding_of_caller
7
+ method_source
5
8
 
6
9
  GEM
7
10
  remote: https://rubygems.org/
8
11
  specs:
9
- activesupport (5.2.4.4)
10
- concurrent-ruby (~> 1.0, >= 1.0.2)
11
- i18n (>= 0.7, < 2)
12
- minitest (~> 5.1)
13
- tzinfo (~> 1.1)
14
- concurrent-ruby (1.1.7)
15
- i18n (1.8.5)
16
- concurrent-ruby (~> 1.0)
17
- io-console (0.5.6)
18
- minitest (5.14.2)
12
+ amazing_print (1.2.1)
13
+ binding_of_caller (0.8.0)
14
+ debug_inspector (>= 0.0.1)
15
+ coderay (1.1.3)
16
+ debug_inspector (0.0.3)
17
+ interception (0.5)
18
+ method_source (1.0.0)
19
+ pry (0.13.1)
20
+ coderay (~> 1.1)
21
+ method_source (~> 1.0)
22
+ pry-rescue (1.5.2)
23
+ interception (>= 0.5)
24
+ pry (>= 0.12.0)
19
25
  rake (12.3.3)
20
- thread_safe (0.3.6)
21
- tzinfo (1.2.7)
22
- thread_safe (~> 0.1)
23
26
 
24
27
  PLATFORMS
25
28
  ruby
26
29
 
27
30
  DEPENDENCIES
28
- activesupport (~> 5.0)
29
31
  bundler (~> 2.1)
30
- io-console
32
+ pry-rescue
31
33
  rake (~> 12.0)
32
34
  scryglass!
33
35
 
data/README.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 🔮 Scryglass
2
+
3
+ Scryglass is a ruby console tool for visualizing and actively exploring objects (large, nested, interrelated, or unfamiliar). You can navigate nested arrays, hashes, instance variables, ActiveRecord
4
+ relations, and unknown Enumerable types like an expandable/collapsable file tree in an intuitive UI.
5
+
6
+ Objects and child objects can also be inspected through a variety of display lenses, returned directly to the console, and more!
7
+
8
+ `scry` is quick to use and useful for both experienced developers and those very new to ruby, rails, or coding.
9
+ It facilitates:
10
+ - Debugging/Investigating
11
+ - Education, learning the structure of objects and their relationships
12
+ - Comparing/Scanning sub-items in an Enumerable (e.g. Person.first.library_records.scry)
13
+
14
+
1
15
  # Table of Contents
2
16
 
3
17
  [🔮 Scryglass Intro Summary](#-scryglass)
@@ -18,18 +32,6 @@
18
32
  - [Miscellaneous Troubleshooting Notes](#miscellaneous-troubleshooting-notes)
19
33
  - [Contributing](#contributing)
20
34
 
21
- # 🔮 Scryglass
22
-
23
- Scryglass is a ruby console tool for visualizing and actively exploring objects (large, nested, interrelated, or unfamiliar). You can navigate nested arrays, hashes, instance variables, ActiveRecord
24
- relations, and unknown Enumerable types like an expandable/collapsable file tree in an intuitive UI.
25
-
26
- Objects and child objects can also be inspected through a variety of display lenses, returned directly to the console, and more!
27
-
28
- `scry` is quick to use and useful for both experienced developers and those very new to ruby, rails, or coding.
29
- It facilitates:
30
- - Debugging/Investigating
31
- - Education, learning the structure of objects and their relationships
32
- - Comparing/Scanning sub-items in an Enumerable (e.g. Person.first.library_records.scry)
33
35
 
34
36
  ## ⚡️ tl;dr SUPER Quick Start
35
37
 
@@ -58,7 +60,7 @@ $ gem install scryglass
58
60
  ```
59
61
  ## Enabling Scryglass
60
62
 
61
- For the `scry` method syntax to work as cleanly as it does, Scryglass needs to add the method to the Kernel module. While this is safe, it was safest to have this only happen on a console session basis. To enable the `scry` method, call `Scryglass.load`. Thus, to automatically enable Scryglass when opening a console, you add one of the following lines to your `./irbrc` (and `./pryrc` for rails or pry sessions):
63
+ For the `scry` method syntax to work as cleanly as it does, Scryglass needs to add the method to the Kernel module. While this is safe, it was safest to have this only happen on a console session basis. To enable the `scry` method, call `Scryglass.load`. Thus, to automatically enable Scryglass when opening a console, you add one of the following lines to your `./.irbrc` (and `./.pryrc` for rails or pry sessions):
62
64
  ```ruby
63
65
  Scryglass.load
64
66
  ```
@@ -85,9 +87,6 @@ To start a Scry Session, call:
85
87
  **A note about passing an argument without parentheses:**
86
88
  > The arg syntax (`scry my_object`) will get confused if it's given a hash direcly (`scry {a: [1, 2] }`), thinking you're trying to pass a block, unless you use parentheses (`scry({a: [1, 2] })`).
87
89
 
88
- **A note about using the resume session command, while in a pry:**
89
- > The straight resume command, the bare `scry`, relies on the assumption that the method receiver is `main`. When your console is a pry in some other code, `self` is no longer `main`, but some other object, and so you are actually calling `scry` on that, overwriting your previous session. If you still want to resume session in that context, you can use `scry_resume`.
90
-
91
90
  ## Basic Usage
92
91
 
93
92
  Use the arrow keys to move around and open/close known Enumerable types! Hit `'?'` to view all the controls and learn how to do much much more.
@@ -128,40 +127,47 @@ The cursor, movable by arrow keys, is represented by a straight line (`–––
128
127
  | `––––` | ...no secret contents |
129
128
  | `(–––` | ...a non-empty Enumerable of an unknown type (openable with `'('`) |
130
129
  | `–@––` | ...instance variables on the object (openable with `'@'`) |
131
- | `(@––` | ...both! ***Generally* instance variables yield more sub-items with more info.** |
130
+ | `––·–` | ...ActiveRecord associations (openable with `'.'`) |
131
+ | `(@·–` | ...all three! (Note: ***Generally* IVs yield more sub-items with more info than using `'('`).** |
132
132
 
133
- ActiveRecord objects are no secret; you can press `'.'` on them to build their AR Association sub-items.
133
+ An `X` in place of any of these characters indicates an error or a timeout (if the "counting" process takes longer than 0.05 seconds)
134
134
 
135
135
  A single `•` will mark the presence of user-added rows when they are hidden.
136
136
 
137
137
  ### Waiting!
138
138
  Scryglass has two features to make wait time a little easier:
139
- - If any process takes longer than 4 seconds between you pressing a key and the process completing, it **makes a beep sound!** This means if something seems like it might take a bit, you can switch to another tab or window without worry, and it will tell you when to check back.
139
+ - If any process (with a couple exceptions for user input) takes longer than 4 seconds between you pressing a key and the process completing, it **makes a beep sound!** This means if something seems like it might take a bit, you can switch to another tab or window without worry, and it will tell you when to check back.
140
140
  - While there are no time estimates (for a number of reasons), many subprocesses are linked to a **progress bar**, which will display at the bottom of the screen. If multiple nested processes are running one within another, the progress bar will divide itself into parts to show each process. The leftmost bar is the base level iteration task.
141
141
 
142
142
  ## In-Depth Control Rundown
143
143
 
144
- | Key | Help Screen Snippet | Verbose Description |
144
+ | Key | Help_Screen_Snippet | Verbose Description |
145
145
  |:---:|---------------------|---------------------|
146
146
  | `?` | Press '?' for controls | `?` will cycle through the help panels, then back to the scry session. |
147
147
  | `q` | Quit Scry | Exits the scry session, returning nil. The cursor (and exit message) is then placed below the last line console line with content in order to take up no more space than needed. |
148
- | `UP`/`DOWN` | Navigate (You can type a number first) | Moves the cursor one step upward or downward in the tree view (this can be done while in lens view). If a number (of any number of digits) is typed out before pressing `UP` or `DOWN`, then the cursor will move that many steps in that direction. If the number of steps goes past the edge of the list, the cursor will sit safely at that edge. |
149
- | `RIGHT` | Expand current or selected row(s) | If any rows are *selected* this attempts to expand all of them, and will expand the ones it can. If none are selected, then it will attempt to expand the current row where the cursor is. If the current row has preexisting sub-items, but they are hidden because the current ro is collapsed, this will reveal them in the tree view. |
148
+ | `UP`/`DOWN` | Navigate (To move further, type a number first or use SHIFT) | Moves the cursor one step upward or downward in the tree view (this can be done while in lens view). If a number (of any number of digits) is typed out before pressing `UP` or `DOWN`, then the cursor will move that many steps in that direction. If `SHIFT` is held while pressing, then the cursor will move 12 steps in that direction. If the number of steps goes past the edge of the list, the cursor will sit safely at that edge. |
149
+ | `RIGHT` | Expand current or selected row(s) | If any rows are *selected* this attempts to expand all of them, and will expand the ones it can. If none are selected, then it will attempt to expand the current row where the cursor is. If the current row has preexisting sub-items, but they are hidden because the current row is collapsed, this will reveal them in the tree view. |
150
150
  | `LEFT` | Collapse current or selected row(s) | If any rows are *selected* this attempts to collapse all of them, and will collapse the ones it can. If none are selected, then it will attempt to collapse the current row where the cursor is. If the current row either has no sub-items or is already collapsed, this action will collapse its parent row instead and place the cursor there. |
151
+ | `h`/`j`/`k`/`l` | (These keys on the home row can also serve as arrow keys) | This is for those familiar with VIM keybindings! Shift speeds up k/j to 12 steps just the same as UP/DOWN. |
151
152
  | `ENTER` | Close Scry, returning current or selected object(s) (Key or Value) | Returns the subject object (based on current subject type, :value or :key) of the current item, or, if any items are selected (`->`), it returns all of those in an array. The order matches the order in which they were marked as selected. In the case of \| and \*, the order of the array will be top to bottom. If the current Subject Type (toggled by `L`) is :key, rows without "keys" will return `nil`. |
152
153
  | `SPACEBAR` | Toggle Lens View | Switches between Tree View and Lens View. This will not change the view position of the lens view, but the view position of the tree view will still follow the cursor if the cursor moves while in lens view. |
153
- | `l` | Cycle through lens types | Cycles through the different lens types in the lens view. These all take the current row, at either the "key" or the "value" object depending on the current subject type (toggled by `L`), and display a string of it, transformed through that particular lens. New lenses can be written in the config. |
154
- | `L` | Toggle subject (Key/Value of row) | This change is only perceptible in the lens view, but does also change which objects are returned by `ENTER`. Any objects without "keys" will return nil for their :key if they don't have one. |
155
- | `w`/`a`/`s`/`d` | Move view window (ALT increases speed) | The W/A/S/D keys form a second set of arrow keys for moving around the "screen" through which you view the tree view and the lens view, when the contents don't all fit on the screen at once. They move 5 cells in the specificied direction, or 50 if ALT is held before pressing. Can be held down for continuous movement. |
154
+ | `>` | Cycle through lens types | Cycles through the different lens types in the lens view. These all take the current row, at either the "key" or the "value" object depending on the current subject type (toggled by `L`), and display a string of it, transformed through that particular lens. New lenses can be written in the config. |
155
+ | `<` | Toggle subject (Key/Value of row) | This change is only perceptible in the lens view, but does also change which objects are returned by `ENTER`. Any objects without "keys" will return nil for their :key if they don't have one. |
156
+ | `w`/`a`/`s`/`d` | Move view window (ALT increases speed) | The W/A/S/D keys form a second set of arrow keys for moving around the "screen" through which you view the tree view and the lens view, when the contents don't all fit on the screen at once. They move 5 cells in the specified direction, or 50 if ALT is held before pressing. Can be held down for continuous movement. |
156
157
  | `0` | Reset view location (Press again: reset cursor) | This resets/zeros the current view (tree or lens). If you are in the tree view, and the view is in the zero (top left) position, then this will instead move the cursor there. |
157
158
  | `@` | Build instance variable sub-rows for current or selected row(s) | Identifies all instance variables on the object (or value of a key-value pair) of the current or selected rows. Then these instance variables are turned into a list of keys, called on the original object, and then paired with the resulting objects. Known Enumerables are recursively navigable as always. |
158
- | `.` | Build ActiveRecord association sub-rows for current or selected row(s) | If the `ActiveRecord` constant is not defined by the system, this will do nothing. If it is, this will navigate the reflections of the the class of the object (or value of a key-value pair) in order to find its AR Associations and turn them into key-value sub-items. Note: With the default configuration, the way it uses reflections *purposefully ignores `:through` relations and `scope`d relations (e.g. the extraneous `CURRENT_phone_numbers`).* |
159
+ | `.` | Build ActiveRecord association sub-rows for current or selected row(s) | If the `ActiveRecord` constant is not defined by the system, this will do nothing. If it is, this will navigate the reflections of the the class of the object (or value of a key-value pair) in order to find its AR Associations and turn them into key-value sub-items. Note: With the default configuration, the way it uses reflections *purposefully ignores `:through` relations and `scope`d relations (e.g. the extraneous `CURRENT_phone_numbers`).* Note: The `·` cursor indicator does not take the time to traverse all reflections, nor account for all configured filters. It's possible that `.` will produce no sub-rows despite the indicator. |
159
160
  | `(` | Attempt to smart-build sub-rows for current or selected row(s), if Enumerable. Usually '@' is preferable | Attempts a "smart reading" of the object (or value of a key-value pair) of the current or selected rows. If the object is an Enumerable, it will attempt to parse it into sub-items. if the object has keys, it will be parsed as key-value pairs like a hash, otherwise singular objects like an array. This can sometimes create sub-items that would otherwise be more neatly accesible under a single instance variable if instance variables are built instead, so default to trying that first. |
161
+ | `o` | Quick Open: builds the most likely helpful sub-rows ( '.' \|\| '@' \|\| '(' ) | "Quick Open" first tries opening AR Associations. If none are produced, it tries for instance variables. If none are produced, it attempts to open as it would an unknown Enumerable type. Can be pressed repeatedly to produce all types of sub-rows. |
160
162
  | `*` | Select/Deselect ALL rows | This includes hidden rows. If all rows are already selected, they will be unselected, regardless of how they became selected. |
161
163
  | `\|` | Select/Deselect every sibling row under the same parent row | If all siblings under that parent row are already selected, they will be unselected, regardless of how they became selected. |
162
164
  | `-` | Select/Deselect current row | If these objects are later returned, the order in which they were selected will determine their order in the returned array. |
165
+ | `Tab` | Change session tab (to the right) (`Shift`+`Tab` moves left) | Changes which scry session is the current one, and brings up the tab bar for a couple seconds. |
166
+ | `Q` | Close current session tab | Permanently exits the current session tab, but keeps scry running if another tab remains. Switches one tab to left if there is one.
163
167
  | `/` | Begin a text search (in tree view) | Begins a case-sensitive regex search of all items, in a loop, starting with just below the current row. For a matching object to be found, the search must match its *truncated sample string in tree view* (regardless of what is on or off screen) (it must match either the key or the value, not the full line they create) (known enumerable types, like `[•••]`, may count as a match if they contain the string in the backend). |
164
168
  | `n` | Move to next search result | Will, using the most recent search entry, move the cursor on to the next match downward, cycling through all rows. This follows the same matching rules as the original search. |
169
+ | `=` | Open prompt to type a console handle for current or selected row(s) | Gets text from user (not including the '@') and saves the current subject, or array of selected row(s) subjects, under that instance variable name. These variables live in the console itself: the binding of wherever `scry` was called. Care is taken not to allow them to conflict with preexisting IV names or method names. Note: But still, if you are prying inside an object/context, your IVs will be defined on that object. Note: If you switch from one pry context to another and then back, your first pry's instance variables will be there despite not being listed in the IV outro message. |
170
+ | `Esc` | Resets selection, last search, and number-to-move. (or returns to Tree View) | (Essentially, clears the values represented in the Tree View header if you're in the Tree View; otherwise it returns you to the Tree View) |
165
171
 
166
172
  ## Configuration / Customization (all optional)
167
173
 
@@ -187,18 +193,28 @@ Scryglass.configure do |config|
187
193
  ## UX
188
194
  # config.cursor_tracking = [:flexible_range, :dead_center][0] # Default: [0]
189
195
  # config.lenses = [ # Custom lenses can easily be added as name+lambda hashes! Or comment some out to turn them off.
196
+ # { name: 'Amazing Print (`ap`)',
197
+ # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { ap o } } }, # This has colors!
190
198
  # { name: 'Pretty Print (`pp`)',
191
199
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { pp o } } },
192
200
  # { name: 'Inspect (`.inspect`)',
193
201
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o.inspect } } },
194
202
  # { name: 'Yaml Print (`y`)',
195
- # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { y o } } }, # OR: `puts o.to_yaml`
203
+ # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { require 'yaml' ; y o } } }, # OR: `puts o.to_yaml`
196
204
  # { name: 'Puts (`puts`)',
197
205
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o } } },
198
- # # { name: 'Method Showcase', # Not included by default
199
- # # lambda: ->(o) { Scryglass::LensHelper.method_showcase_for(o) } },
206
+ # { name: 'Method Showcase',
207
+ # lambda: ->(o) { Scryglass::LensHelper.method_showcase_for(o, char_limit: 20_000) } },
200
208
  # ]
201
209
 
210
+ ## AmazingPrint defaults, if the user has not set their own:
211
+ # AmazingPrint.defaults ||= {
212
+ # index: false, # (Don't display array indices).
213
+ # raw: true, # (Recursively format instance variables).
214
+ # }
215
+ # See https://github.com/amazing-print/amazing_print
216
+
217
+
202
218
  ## Building ActiveRecord association sub-rows:
203
219
  # config.include_empty_associations = true # Default: true
204
220
  # config.include_through_associations = false # Default: false
@@ -12,16 +12,26 @@ Scryglass.configure do |config|
12
12
  # config.lenses = [ # Custom lenses can easily be added as name+lambda hashes! Or comment some out to turn them off.
13
13
  # { name: 'Pretty Print (`pp`)',
14
14
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { pp o } } },
15
+ # { name: 'Amazing Print (`ap`)',
16
+ # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { ap o } } }, # This has colors!
15
17
  # { name: 'Inspect (`.inspect`)',
16
18
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o.inspect } } },
17
19
  # { name: 'Yaml Print (`y`)',
18
- # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { y o } } }, # OR: `puts o.to_yaml`
20
+ # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { require 'yaml' ; y o } } }, # OR: `puts o.to_yaml`
19
21
  # { name: 'Puts (`puts`)',
20
22
  # lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o } } },
21
- # # { name: 'Method Showcase', # Not included by default
22
- # # lambda: ->(o) { Scryglass::LensHelper.method_showcase_for(o) } },
23
+ # { name: 'Method Showcase',
24
+ # lambda: ->(o) { Scryglass::LensHelper.method_showcase_for(o, char_limit: 20_000) } },
23
25
  # ]
24
26
 
27
+ ## AmazingPrint defaults, if the user has not set their own:
28
+ # AmazingPrint.defaults ||= {
29
+ # index: false, # (Don't display array indices).
30
+ # raw: true, # (Recursively format instance variables).
31
+ # }
32
+ # See https://github.com/amazing-print/amazing_print
33
+
34
+
25
35
  ## Building ActiveRecord association sub-rows:
26
36
  # config.include_empty_associations = true # Default: true
27
37
  # config.include_through_associations = false # Default: false
@@ -107,7 +107,7 @@ module Hexes
107
107
  necessary_constants_defined = necessary_constants.all?(&:constant_defined?)
108
108
  return yield unless necessary_constants_defined
109
109
 
110
- rails_logger_defined = 'Rails'.constant_defined? && Rails.try(:logger).present?
110
+ rails_logger_defined = 'Rails'.constant_defined? && !!Rails.try(:logger)
111
111
 
112
112
  ## These are purposefully preserved as global variables so retrieval, in
113
113
  ## debugging or errored usage, is as easy as possible.
@@ -7,5 +7,150 @@ module AnsilessStringRefinement
7
7
  def ansiless_length
8
8
  ansiless.length
9
9
  end
10
+
11
+ ## Splits string into characters, with each ANSI escape code being its own
12
+ ## grouped item, like so:
13
+ ## irb> "PLAIN\e[32mCOLOR\e[0mPLAIN".ansi_string_breakout
14
+ ## => ["P", "L", "A", "I", "N", "\e[32m", "C", "O", "L", "O", "R",
15
+ ## "\e[0m", "P", "L", "A", "I", "N"]
16
+ def ansi_string_breakout
17
+ breakout_array = []
18
+ working_self = self.dup
19
+
20
+ while working_self[0]
21
+ if (working_self =~ /\e\[[\d\;]*m/) == 0 # if begins with
22
+ end_of_escape_code = (working_self.index('m'))
23
+ leading_escape_code = working_self[0..end_of_escape_code]
24
+ breakout_array << leading_escape_code
25
+ working_self = working_self[(end_of_escape_code + 1)..-1]
26
+ else
27
+ leading_character = working_self[0]
28
+ breakout_array << leading_character
29
+ working_self = working_self[1..-1]
30
+ end
31
+ end
32
+
33
+ breakout_array
34
+ end
35
+
36
+ def is_ansi_escape_code?
37
+ (self =~ /^\e\[[\d\;]*m$/) == 0
38
+ end
39
+
40
+ ## Returns the indexed character of the real string, determined by the index
41
+ ## given in reference to its ANSIless display form. e.g.:
42
+ ## > s = "\e[31mTEST\e[00m"
43
+ ## > puts s
44
+ ## TEST
45
+ ## > s.ansiless_pick(1) = 'y'
46
+ ## > s
47
+ ## => "\e[31mTyST\e[00m"
48
+ def ansiless_pick(given_index)
49
+ ansiless_self = self.ansiless
50
+
51
+ return nil if ansiless_self[given_index].nil?
52
+
53
+ given_index = (given_index + ansiless_self.length) if given_index.negative?
54
+
55
+ mock_index = 0 # A scanning index that *doesn't* count ANSI codes
56
+ real_index = 0 # A scanning index that *does* count ANSI codes
57
+
58
+ ansi_string_array = ansi_string_breakout
59
+
60
+ until mock_index == given_index
61
+ while ansi_string_array.first.is_ansi_escape_code?
62
+ real_index += (ansi_string_array.shift.length)
63
+ end
64
+
65
+ ansi_string_array.shift
66
+
67
+ while ansi_string_array.first.is_ansi_escape_code?
68
+ real_index += (ansi_string_array.shift.length)
69
+ end
70
+
71
+ mock_index += 1
72
+ real_index += 1
73
+ end
74
+
75
+ self[real_index]
76
+ end
77
+
78
+ ## Like ansiless_pick, but it can set that found string character instead
79
+ def ansiless_set!(given_index, string)
80
+ raise ArgumentError, 'First argument must be an Integer' unless given_index.is_a?(Integer)
81
+ raise ArgumentError, 'Second argument must be a String' unless string.is_a?(String)
82
+
83
+ ansiless_self = self.ansiless
84
+
85
+ return nil if ansiless_self[given_index].nil?
86
+
87
+ given_index = (given_index + ansiless_self.length) if given_index.negative?
88
+
89
+
90
+ new_string = string.to_s
91
+
92
+ mock_index = 0 # A scanning index that *doesn't* count ANSI codes
93
+ real_index = 0 # A scanning index that *does* count ANSI codes
94
+
95
+ ansi_string_array = ansi_string_breakout
96
+
97
+ until mock_index == given_index
98
+ while ansi_string_array.first.is_ansi_escape_code?
99
+ real_index += (ansi_string_array.shift.length)
100
+ end
101
+
102
+ ansi_string_array.shift
103
+
104
+ while ansi_string_array.first.is_ansi_escape_code?
105
+ real_index += (ansi_string_array.shift.length)
106
+ end
107
+
108
+ mock_index += 1
109
+ real_index += 1
110
+ end
111
+
112
+ self[real_index] = new_string
113
+ end
114
+
115
+ def ansi_slice(arg1, arg2 = nil) # i.e. like 'test'[0..2] and 'test'[2, 1]
116
+ unless (arg1.is_a?(Range) && arg2.nil?) ||
117
+ (arg1.is_a?(Integer) && arg2.is_a?(Integer))
118
+ raise ArgumentError, 'ansi_slice takes either a single Range ' \
119
+ 'or two integers (index and length) as its arguments.'
120
+ end
121
+
122
+ target_range = arg1.is_a?(Range) ? arg1 : (arg1...(arg1 + arg2))
123
+
124
+ if target_range.min.negative? || target_range.max.negative?
125
+ raise ArgumentError, 'Range must be entirely positive!'
126
+ end
127
+
128
+ args = [arg1, arg2].compact
129
+ return self[*args] if (self =~ /\e\[[\d\;]*m/).nil? # No work need be done
130
+
131
+ ## And here we match the normal `:[]` behavior outside of boundaries, e.g:
132
+ ## irb> 'TEST'[4..9]
133
+ ## => ""
134
+ ## irb> 'TEST'[5..9]
135
+ ## => nil
136
+ return nil if target_range.min > self.ansiless_length
137
+
138
+ mock_index = 0 # A scanning index that *doesn't* count ANSI codes
139
+ result_string_array = []
140
+
141
+ ansi_string_breakout.each do |char|
142
+ char_is_ansi_escape_code = char.is_ansi_escape_code?
143
+ within_target_range =
144
+ target_range.include?(mock_index)
145
+
146
+ if within_target_range || char_is_ansi_escape_code
147
+ result_string_array << char
148
+ end
149
+
150
+ mock_index += 1 unless char_is_ansi_escape_code
151
+ end
152
+
153
+ result_string_array.join('')
154
+ end
10
155
  end
11
156
  end