report_print 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -1
- data/doc/.document +2 -0
- data/doc/Customization.md +150 -0
- data/doc/Formatters.md +185 -0
- data/doc/overview.md +84 -0
- data/gem_description.rdoc +5 -0
- data/lib/.document +3 -0
- data/lib/report_print/api.rb +61 -0
- data/lib/report_print/core_extensions.rb +93 -17
- data/lib/report_print/dsl.rb +2 -0
- data/lib/report_print/printer.rb +32 -45
- data/lib/report_print/refinements.rb +0 -9
- data/lib/report_print/scoped_options.rb +21 -0
- data/lib/report_print/version.rb +1 -1
- data/lib/report_print.rb +5 -4
- metadata +16 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6bc69172badef1f367d722882bf9dfc8dcaffb66926811cc37ddebcffac68a8
|
|
4
|
+
data.tar.gz: 1fdb2ce8ed7441c34f6cc792480fc9b7ad614c0d26204cf237ada5c52f9969bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b701bc0e9ac1896140001a39967d96ea4acc369fc7ae8a619a0e62035aa16ace37dcebcb6757abb5f0d3deb93be1e1f8381b31cc90c1e7aadd4a687cbcec0bec
|
|
7
|
+
data.tar.gz: 74c6fb521894a4f14591d5d0e23f1b941c04b5209fe9dfb880b35f84041a27c6f917aee484e6402ec555e466fd5a6e3fb582ba60c3ad1432b452f1385c7b4baa
|
data/README.md
CHANGED
|
@@ -23,9 +23,33 @@ gem install report_print
|
|
|
23
23
|
```ruby
|
|
24
24
|
require 'report_print'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
class Example
|
|
27
|
+
def initialize
|
|
28
|
+
@foo = { a: [1,2,3] }
|
|
29
|
+
@bar = Object.new
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
rp Example.new
|
|
27
34
|
```
|
|
28
35
|
|
|
36
|
+
Output:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
Example 0x378
|
|
40
|
+
@foo = {
|
|
41
|
+
a: [
|
|
42
|
+
1,
|
|
43
|
+
2,
|
|
44
|
+
3
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
@bar = Object 0x3a8
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
See the [full documentation](https://benoithiller.github.io/report_print/) for more details.
|
|
52
|
+
|
|
29
53
|
## Development
|
|
30
54
|
|
|
31
55
|
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.
|
data/doc/.document
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Customization
|
|
2
|
+
|
|
3
|
+
To set up customized printing for your own classes, you need to define the `report_print` instance method.
|
|
4
|
+
|
|
5
|
+
When you then go to print the object, the method you defined will be called passing in a ReportPrint::Printer instance that you can use to print things.
|
|
6
|
+
|
|
7
|
+
The printer is composed of the following 4 methods:
|
|
8
|
+
|
|
9
|
+
* ReportPrint::Printer#multiline
|
|
10
|
+
* ReportPrint::Printer#inline
|
|
11
|
+
* ReportPrint::Printer#write
|
|
12
|
+
* ReportPrint::Printer#rp
|
|
13
|
+
|
|
14
|
+
The `multiline` and `inline` methods modify the behaviour of the `write` method to enable you to specify how elements are joined and lines are separated.
|
|
15
|
+
|
|
16
|
+
The `rp` method simply calls the `report_print` method of the specified object passing in the printer.
|
|
17
|
+
|
|
18
|
+
## `multiline`
|
|
19
|
+
|
|
20
|
+
The `multiline` method creates a new multiline context and executes the provided block within it, resetting the printer context back at the end of the block.
|
|
21
|
+
|
|
22
|
+
Inside a multiline context each call to `write` will write its output on a new line indented as per the current indent level.
|
|
23
|
+
|
|
24
|
+
If you specify a `separator` for the multiline context, then that will be written before the newline on every line except the first line of the multiline context.
|
|
25
|
+
|
|
26
|
+
At the end of a multiline context the content of `after` is written into the outer context, unless `after_empty` is false and nothing was written inside the context.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
class ::Array < ::Object
|
|
32
|
+
def report_print(rp)
|
|
33
|
+
rp.write("[")
|
|
34
|
+
rp.multiline(after: "]", separator: ",") do
|
|
35
|
+
to_a.each do |item|
|
|
36
|
+
rp.rp(item)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
In this example we also see the outline of the common pattern intended for when you are putting delimiters around a block. You write the opening token manually, but rely on the `after:` keyword argument to write the closing token.
|
|
44
|
+
|
|
45
|
+
The value passed to `after:` will be written without any separator before it. This pattern allows us to do the above safely without wrapping things in an extra `inline` block to prevent a separator being placed before the `"]"`.
|
|
46
|
+
|
|
47
|
+
## `inline`
|
|
48
|
+
|
|
49
|
+
The `inline` method creates a new inline context and executes the provided block within it, resetting the printer context back at the end of the block.
|
|
50
|
+
|
|
51
|
+
When an inline context is placed within a multiline context we will say that it defines a `line`.
|
|
52
|
+
|
|
53
|
+
For each line the first call to `write` behaves the same as one in the containing multiline context.
|
|
54
|
+
|
|
55
|
+
Within an inline context the `inline_separator` defines a sequence to be written between two writes in that context.
|
|
56
|
+
|
|
57
|
+
When inline contexts are nested the rules are applied such that all of the writes within a child context are treated as one write for the purposes of joining.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
rp.inline("+") do
|
|
63
|
+
rp.inline("-") do
|
|
64
|
+
rp.write(1)
|
|
65
|
+
end
|
|
66
|
+
rp.inline("/") do
|
|
67
|
+
rp.write(2)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# => "1+2"
|
|
72
|
+
|
|
73
|
+
rp.inline("+") do
|
|
74
|
+
rp.inline("-") do
|
|
75
|
+
rp.write(1)
|
|
76
|
+
rp.write(2)
|
|
77
|
+
end
|
|
78
|
+
rp.inline("/") do
|
|
79
|
+
rp.write(3)
|
|
80
|
+
rp.write(4)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# => "1-2+3/4"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Writing Defensively
|
|
88
|
+
|
|
89
|
+
When creating a `report_print` method it is very important to be explicit about how you want the text to be written.
|
|
90
|
+
|
|
91
|
+
**You cannot safely assume anything about the outer context.**
|
|
92
|
+
|
|
93
|
+
Thus if you want items to be rendered on the same line you always need to enclose them in an `inline` context. Same goes for multiple lines and a multiline context.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
# Bad: assumes that it is in an inline context with a blank inline_separator
|
|
99
|
+
def report_print(rp)
|
|
100
|
+
rp.write("Item")
|
|
101
|
+
rp.write("[")
|
|
102
|
+
rp.multiline(after: "]", separator: ",") do
|
|
103
|
+
each do |sub_item|
|
|
104
|
+
rp.rp(sub_item)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Good: sets up an inline context
|
|
110
|
+
def report_print(rp)
|
|
111
|
+
rp.inline("") do
|
|
112
|
+
rp.write("Item")
|
|
113
|
+
rp.write("[")
|
|
114
|
+
rp.multiline(after: "]", separator: ",") do
|
|
115
|
+
each do |sub_item|
|
|
116
|
+
rp.rp(sub_item)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Only use Separators for Separators
|
|
124
|
+
|
|
125
|
+
Separators are only written between two writes, so you probably don't want to use them for some things that feel like separators but don't have that same property.
|
|
126
|
+
|
|
127
|
+
For example:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
class Assignment
|
|
131
|
+
# Bad: if @rhs is empty we probably still want to render an =.
|
|
132
|
+
# Otherwise users won't be able to tell that it is an assignment being
|
|
133
|
+
# printed.
|
|
134
|
+
def report_print(rp)
|
|
135
|
+
rp.inline(" = ") do
|
|
136
|
+
rp.rp(@lhs)
|
|
137
|
+
rp.rp(@rhs) if @rhs
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Better
|
|
142
|
+
def report_print(rp)
|
|
143
|
+
rp.inline(" ") do
|
|
144
|
+
rp.rp(@lhs)
|
|
145
|
+
rp.write("=")
|
|
146
|
+
rp.rp(@rhs) if @rhs
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
```
|
data/doc/Formatters.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Formatters
|
|
2
|
+
|
|
3
|
+
The following formatter implementation are provided by default.
|
|
4
|
+
|
|
5
|
+
They are implemented by adding the `report_print` method onto the specified class, and so will be inherited as expected and can be overwritten as needed.
|
|
6
|
+
|
|
7
|
+
## Simple Values
|
|
8
|
+
|
|
9
|
+
A number of simple value types are configured to produce colorized versions of their `inspect` output.
|
|
10
|
+
|
|
11
|
+
rp :symbols
|
|
12
|
+
rp "strings"
|
|
13
|
+
rp /regex/
|
|
14
|
+
|
|
15
|
+
# All Numeric types
|
|
16
|
+
rp 1
|
|
17
|
+
rp 0.5
|
|
18
|
+
rp Float::INFINITY
|
|
19
|
+
rp 1i * 1i
|
|
20
|
+
rp Rational(2, 3)
|
|
21
|
+
|
|
22
|
+
# Constants
|
|
23
|
+
rp true
|
|
24
|
+
rp false
|
|
25
|
+
rp nil
|
|
26
|
+
|
|
27
|
+
Output:
|
|
28
|
+
|
|
29
|
+
<pre>
|
|
30
|
+
<span style="color:var(--code-blue)">:symbols<span style="color:var(--code-green)">
|
|
31
|
+
"strings"<span style="color:var(--code-orange)">
|
|
32
|
+
/regex/<span style="color:var(--code-purple)">
|
|
33
|
+
1
|
|
34
|
+
0.5
|
|
35
|
+
Infinity
|
|
36
|
+
(-1+0i)
|
|
37
|
+
(2/3)<span style="color:var(--code-blue)">
|
|
38
|
+
true
|
|
39
|
+
false
|
|
40
|
+
nil</span>
|
|
41
|
+
</pre>
|
|
42
|
+
|
|
43
|
+
## `Object`
|
|
44
|
+
|
|
45
|
+
class A
|
|
46
|
+
def initialize
|
|
47
|
+
@name = self.class.name
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class B < A
|
|
52
|
+
def initialize
|
|
53
|
+
super
|
|
54
|
+
@field = A.new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
rp B.new
|
|
59
|
+
|
|
60
|
+
Output:
|
|
61
|
+
|
|
62
|
+
<pre>
|
|
63
|
+
<span style="color:var(--code-orange)">B</span> <span style="color:var(--code-gray)">0x2b0</span>
|
|
64
|
+
<span style="color:var(--code-cyan)">@name</span> = <span style="color:var(--code-green)">"B"</span>
|
|
65
|
+
<span style="color:var(--code-cyan)">@field</span> = <span style="color:var(--code-orange)">A</span> <span style="color:var(--code-gray)">0x2b8</span>
|
|
66
|
+
<span style="color:var(--code-cyan)">@name</span> = <span style="color:var(--code-green)">"A"</span>
|
|
67
|
+
<span style="color:var(--code-blue)">end
|
|
68
|
+
end</span>
|
|
69
|
+
</pre>
|
|
70
|
+
|
|
71
|
+
## `Module`
|
|
72
|
+
|
|
73
|
+
rp Class
|
|
74
|
+
|
|
75
|
+
Output:
|
|
76
|
+
|
|
77
|
+
<pre>
|
|
78
|
+
<span style="color:var(--code-orange)">Class</span>
|
|
79
|
+
</pre>
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## `Array`
|
|
83
|
+
|
|
84
|
+
rp [1, "two", [[]]]
|
|
85
|
+
|
|
86
|
+
Output:
|
|
87
|
+
|
|
88
|
+
<pre>
|
|
89
|
+
[
|
|
90
|
+
<span style="color:var(--code-purple)">1</span>,
|
|
91
|
+
<span style="color:var(--code-green)">"two"</span>,
|
|
92
|
+
[
|
|
93
|
+
[]
|
|
94
|
+
]
|
|
95
|
+
]</span>
|
|
96
|
+
</pre>
|
|
97
|
+
|
|
98
|
+
## `Hash`
|
|
99
|
+
|
|
100
|
+
rp({
|
|
101
|
+
"one" => 1,
|
|
102
|
+
two: {
|
|
103
|
+
[1, 2] => {}
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
Output:
|
|
108
|
+
|
|
109
|
+
<pre>
|
|
110
|
+
{
|
|
111
|
+
<span style="color:var(--code-green)">"one"</span> => <span style="color:var(--code-purple)">1</span>,
|
|
112
|
+
<span style="color:var(--code-cyan)">two:</span> {
|
|
113
|
+
[
|
|
114
|
+
<span style="color:var(--code-purple)">1</span>,
|
|
115
|
+
<span style="color:var(--code-purple)">2</span>
|
|
116
|
+
] => {}
|
|
117
|
+
}
|
|
118
|
+
}</span>
|
|
119
|
+
</pre>
|
|
120
|
+
|
|
121
|
+
## `Set`
|
|
122
|
+
|
|
123
|
+
rp Set[1, "thing", Set[]]
|
|
124
|
+
|
|
125
|
+
Output:
|
|
126
|
+
|
|
127
|
+
<pre>
|
|
128
|
+
<span style="color:var(--code-orange)">Set</span>[
|
|
129
|
+
<span style="color:var(--code-purple)">1</span>,
|
|
130
|
+
<span style="color:var(--code-green)">"thing"</span>,
|
|
131
|
+
<span style="color:var(--code-orange)">Set</span>[]
|
|
132
|
+
]</span>
|
|
133
|
+
</pre>
|
|
134
|
+
|
|
135
|
+
## `Data`
|
|
136
|
+
|
|
137
|
+
Direction = Data.define(:x, :y)
|
|
138
|
+
Velocity = Data.define(:speed, :direction)
|
|
139
|
+
|
|
140
|
+
rp Velocity[100, Direction[0.6, 0.8]]
|
|
141
|
+
|
|
142
|
+
Output:
|
|
143
|
+
|
|
144
|
+
<pre>
|
|
145
|
+
<span style="color:var(--code-blue)">Velocity</span>[
|
|
146
|
+
<span style="color:var(--code-cyan)">speed</span>: <span style="color:var(--code-purple)">100</span>,
|
|
147
|
+
<span style="color:var(--code-cyan)">direction</span>: <span style="color:var(--code-blue)">Direction</span>[
|
|
148
|
+
<span style="color:var(--code-cyan)">x</span>: <span style="color:var(--code-purple)">0.6</span>,
|
|
149
|
+
<span style="color:var(--code-cyan)">y</span>: <span style="color:var(--code-purple)">0.8</span>
|
|
150
|
+
]
|
|
151
|
+
]</span>
|
|
152
|
+
</pre>
|
|
153
|
+
|
|
154
|
+
## `Struct`
|
|
155
|
+
|
|
156
|
+
Player = Struct.new(:health, :mana)
|
|
157
|
+
|
|
158
|
+
rp Player.new(100, 200)
|
|
159
|
+
|
|
160
|
+
Output:
|
|
161
|
+
|
|
162
|
+
<pre>
|
|
163
|
+
<span style="color:var(--code-orange)">Player</span>( <span style="color:var(--code-gray)">0x298</span>
|
|
164
|
+
<span style="color:var(--code-cyan)">health</span>: <span style="color:var(--code-purple)">100</span>,
|
|
165
|
+
<span style="color:var(--code-cyan)">mana</span>: <span style="color:var(--code-purple)">200</span>
|
|
166
|
+
)</span>
|
|
167
|
+
</pre>
|
|
168
|
+
|
|
169
|
+
Note that the object id is included for `Struct` but not for `Data` as the latter is a flyweight while the former is essentially an ordinary class.
|
|
170
|
+
|
|
171
|
+
## `Range` and `ArithmeticSequence`
|
|
172
|
+
|
|
173
|
+
rp(1..10)
|
|
174
|
+
rp(..10)
|
|
175
|
+
rp((1...10).step(2))
|
|
176
|
+
rp("a".."z")
|
|
177
|
+
|
|
178
|
+
Output:
|
|
179
|
+
|
|
180
|
+
<pre>
|
|
181
|
+
(<span style="color:var(--code-purple)">1</span>..<span style="color:var(--code-purple)">10</span>)
|
|
182
|
+
(..<span style="color:var(--code-purple)">10</span>)
|
|
183
|
+
(<span style="color:var(--code-purple)">1</span>...<span style="color:var(--code-purple)">10</span>).step(<span style="color:var(--code-purple)">2</span>)
|
|
184
|
+
(<span style="color:var(--code-green)">"a"</span>..<span style="color:var(--code-green)">"z"</span>)</span>
|
|
185
|
+
</pre>
|
data/doc/overview.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
A hybrid between PrettyPrint and AwesomePrint/AmazingPrint. Providing you both a stylish readable default, and the ability to customize it as needed.
|
|
2
|
+
|
|
3
|
+
The name ReportPrint comes from the desire to output detailed reports of the program state at a given point in time, rather than merely inspecting an object.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
require 'report_print'
|
|
8
|
+
|
|
9
|
+
class Example
|
|
10
|
+
def initialize
|
|
11
|
+
@foo = { a: [1,2,3] }
|
|
12
|
+
@bar = Object.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
rp Example.new
|
|
17
|
+
|
|
18
|
+
Output:
|
|
19
|
+
|
|
20
|
+
<pre>
|
|
21
|
+
<span style="color:var(--code-orange)">Example</span> <span style="color:var(--code-gray)">0x2a0</span>
|
|
22
|
+
<span style="color:var(--code-cyan)">@foo</span> = {
|
|
23
|
+
<span style="color:var(--code-cyan)">a:</span> [
|
|
24
|
+
<span style="color:var(--code-purple)">1</span>,
|
|
25
|
+
<span style="color:var(--code-purple)">2</span>,
|
|
26
|
+
<span style="color:var(--code-purple)">3</span>
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
<span style="color:var(--code-cyan)">@bar</span> = <span style="color:var(--code-orange)">Object</span> <span style="color:var(--code-gray)">0x2a8<span style="color:var(--code-blue)">
|
|
30
|
+
end</span>
|
|
31
|
+
</pre>
|
|
32
|
+
|
|
33
|
+
See ReportPrint::Dsl#rp for the documentation of the global `rp` method.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
ReportPrint comes with custom printers for the following standard library classes:
|
|
38
|
+
|
|
39
|
+
* `Object`
|
|
40
|
+
* `Module`
|
|
41
|
+
* `Array`
|
|
42
|
+
* `Hash`
|
|
43
|
+
* `Set`
|
|
44
|
+
* `Data`
|
|
45
|
+
* `Struct`
|
|
46
|
+
|
|
47
|
+
In addition it will produce colorized `inspect` output for the following classes:
|
|
48
|
+
|
|
49
|
+
* `Symbol`
|
|
50
|
+
* `String`
|
|
51
|
+
* `Numeric`
|
|
52
|
+
* `TrueClass`
|
|
53
|
+
* `FalseClass`
|
|
54
|
+
* `NilClass`
|
|
55
|
+
|
|
56
|
+
See the page on Formatters for examples of each.
|
|
57
|
+
|
|
58
|
+
### Customization
|
|
59
|
+
|
|
60
|
+
Similarly to PrettyPrint you can define the `report_print` method on a class to customize the rendering of instances of that class.
|
|
61
|
+
|
|
62
|
+
class Production
|
|
63
|
+
attr_accessor :left, :right
|
|
64
|
+
|
|
65
|
+
def report_print(rp)
|
|
66
|
+
rp.inline(" ") do
|
|
67
|
+
rp.rp(left)
|
|
68
|
+
rp.write("=>")
|
|
69
|
+
right.each do |token|
|
|
70
|
+
rp.rp(token)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
See Customization for a guide on how to use the various methods provided by the `rp` object above.
|
|
77
|
+
|
|
78
|
+
See ReportPrint::Printer for the API documentation of printer object.
|
|
79
|
+
|
|
80
|
+
### Design
|
|
81
|
+
|
|
82
|
+
The printed output intentionally avoids the standard inspect format of `#<Object:0x000078c7430fd6c8>` in favour of relying primarily on line breaks and indentation to delimit the start and end of objects.
|
|
83
|
+
|
|
84
|
+
Similarly a conscious choice was made not to attempt any kind of midline alignment like `ap` does. Midline alignment may sometimes be pretty but it pays a substantial readability penalty for it.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
A hybrid between PrettyPrint and AwesomePrint/AmazingPrint. Providing you both a stylish readable default, and the ability to customize it as needed.
|
|
2
|
+
|
|
3
|
+
The name ReportPrint comes from the desire to output detailed reports of the program state at a given point in time, rather than merely inspecting an object.
|
|
4
|
+
|
|
5
|
+
After requiring simply use the global `rp` method to print objects like you do with `pp` or `ap`.
|
data/lib/.document
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module ReportPrint
|
|
2
|
+
##
|
|
3
|
+
# These are the extensions that are included into the Module class that
|
|
4
|
+
# enabled you to customize the behaviour of ReportPrint for your own classes.
|
|
5
|
+
module Api
|
|
6
|
+
##
|
|
7
|
+
# Defines options used by the printer when printing instances of the
|
|
8
|
+
# current class.
|
|
9
|
+
#
|
|
10
|
+
# The currently supported options are:
|
|
11
|
+
#
|
|
12
|
+
# * `detect_cycles:` whether instances of this class should display just a
|
|
13
|
+
# header and id when printed multiple times by the same report print
|
|
14
|
+
# command.
|
|
15
|
+
# <br>
|
|
16
|
+
# Defaults to `true` except for in the case of the simple value types and
|
|
17
|
+
# Data classes.
|
|
18
|
+
# * `color:` the color value to apply when using #report_print_inspect!.
|
|
19
|
+
# <br>
|
|
20
|
+
# Defaults to `nil`.
|
|
21
|
+
#
|
|
22
|
+
# #### Example Usage
|
|
23
|
+
#
|
|
24
|
+
# ```
|
|
25
|
+
# class WithColor
|
|
26
|
+
# report_print_options(color: :bright_blue)
|
|
27
|
+
# report_print_inspect!
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# class CustomContainer
|
|
31
|
+
# report_print_options(detect_cycles: false)
|
|
32
|
+
# end
|
|
33
|
+
# ```
|
|
34
|
+
#
|
|
35
|
+
# #### Option Loading
|
|
36
|
+
#
|
|
37
|
+
# Setting any value to `nil` means: take the global value if it is defined.
|
|
38
|
+
#
|
|
39
|
+
# When ReportPrint fetches options for a given class it first fetches the
|
|
40
|
+
# superclass options (recursively), then it merges the options for the
|
|
41
|
+
# current class on top.
|
|
42
|
+
#
|
|
43
|
+
# After which it compacts the options (removing the nils) and merges them
|
|
44
|
+
# on top of any global options. Where the global options are currently
|
|
45
|
+
# specified by calling `ReportPrint.report_print_options`.
|
|
46
|
+
def report_print_options(**kwargs)
|
|
47
|
+
@report_print_options = (@report_print_options || {}).merge(kwargs)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Helper that defines a `report_print` method which calls `inspect` and
|
|
52
|
+
# applies the `color:` specified in #report_print_options.
|
|
53
|
+
def report_print_inspect!
|
|
54
|
+
define_method(:report_print) do |rp|
|
|
55
|
+
rp.write(inspect, color: rp.options_for(self)[:color])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Module.prepend(ReportPrint::Api)
|
|
@@ -1,47 +1,114 @@
|
|
|
1
1
|
using ReportPrint::Refinements
|
|
2
2
|
|
|
3
|
-
class ::
|
|
3
|
+
class ::Module < ::Object
|
|
4
4
|
def report_print(rp)
|
|
5
|
-
rp.
|
|
6
|
-
rp.write_header(self)
|
|
7
|
-
rp.multiline(after: rp.color("end", :bright_blue), after_empty: false) do
|
|
8
|
-
rp.write_instance_variables(self)
|
|
9
|
-
end
|
|
10
|
-
end
|
|
5
|
+
rp.write(short_class_name, color: :bright_yellow)
|
|
11
6
|
end
|
|
12
7
|
end
|
|
13
8
|
|
|
14
|
-
class ::
|
|
9
|
+
class ::Object < ::BasicObject
|
|
10
|
+
report_print_options(detect_cycles: true)
|
|
11
|
+
|
|
15
12
|
def report_print(rp)
|
|
16
|
-
rp.
|
|
13
|
+
rp.write_header(self)
|
|
14
|
+
rp.multiline(after: rp.color("end", :bright_blue), after_empty: false) do
|
|
15
|
+
rp.write_instance_variables(self)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def report_print_cycle(rp)
|
|
20
|
+
rp.write_header(self)
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
class ::Symbol < ::Object
|
|
21
|
-
|
|
25
|
+
report_print_options(color: :bright_blue, detect_cycles: false)
|
|
26
|
+
report_print_inspect!
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
class ::TrueClass < ::Object
|
|
25
|
-
|
|
30
|
+
report_print_options(color: :bright_blue, detect_cycles: false)
|
|
31
|
+
report_print_inspect!
|
|
26
32
|
end
|
|
27
33
|
|
|
28
34
|
class ::FalseClass < ::Object
|
|
29
|
-
|
|
35
|
+
report_print_options(color: :bright_blue, detect_cycles: false)
|
|
36
|
+
report_print_inspect!
|
|
30
37
|
end
|
|
31
38
|
|
|
32
39
|
class ::Numeric < ::Object
|
|
33
|
-
|
|
40
|
+
report_print_options(color: :bright_magenta, detect_cycles: false)
|
|
41
|
+
report_print_inspect!
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
class ::String < ::Object
|
|
37
|
-
|
|
45
|
+
report_print_options(color: :bright_green, detect_cycles: false)
|
|
46
|
+
report_print_inspect!
|
|
38
47
|
end
|
|
39
48
|
|
|
40
49
|
class ::NilClass < ::Object
|
|
41
|
-
|
|
50
|
+
report_print_options(color: :bright_blue, detect_cycles: false)
|
|
51
|
+
report_print_inspect!
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class ::Regexp < ::Object
|
|
55
|
+
report_print_options(color: :yellow, detect_cycles: false)
|
|
56
|
+
report_print_inspect!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class ::Range < ::Object
|
|
60
|
+
report_print_options(detect_cycles: false)
|
|
61
|
+
|
|
62
|
+
def report_print(rp)
|
|
63
|
+
first = self.first rescue nil
|
|
64
|
+
last = self.last rescue nil
|
|
65
|
+
|
|
66
|
+
rp.inline("") do
|
|
67
|
+
rp.write("(")
|
|
68
|
+
unless first.nil?
|
|
69
|
+
rp.rp(first)
|
|
70
|
+
end
|
|
71
|
+
rp.write("..")
|
|
72
|
+
if exclude_end?
|
|
73
|
+
rp.write(".")
|
|
74
|
+
end
|
|
75
|
+
unless last.nil?
|
|
76
|
+
rp.rp(last)
|
|
77
|
+
end
|
|
78
|
+
rp.write(")")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class ::Enumerator::ArithmeticSequence ::Enumerator
|
|
84
|
+
report_print_options(detect_cycles: false)
|
|
85
|
+
|
|
86
|
+
def report_print(rp)
|
|
87
|
+
rp.inline("") do
|
|
88
|
+
rp.write("(")
|
|
89
|
+
unless self.begin.nil?
|
|
90
|
+
rp.rp(self.begin)
|
|
91
|
+
end
|
|
92
|
+
rp.write("..")
|
|
93
|
+
if exclude_end?
|
|
94
|
+
rp.write(".")
|
|
95
|
+
end
|
|
96
|
+
unless self.end.nil?
|
|
97
|
+
rp.rp(self.end)
|
|
98
|
+
end
|
|
99
|
+
rp.write(")")
|
|
100
|
+
unless step == 1
|
|
101
|
+
rp.write(".step(")
|
|
102
|
+
rp.rp(step)
|
|
103
|
+
rp.write(")")
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
42
107
|
end
|
|
43
108
|
|
|
44
109
|
class ::Array < ::Object
|
|
110
|
+
report_print_options(detect_cycles: false)
|
|
111
|
+
|
|
45
112
|
def report_print(rp)
|
|
46
113
|
rp.write("[")
|
|
47
114
|
rp.multiline(after: "]", separator: ",") do
|
|
@@ -53,6 +120,8 @@ class ::Array < ::Object
|
|
|
53
120
|
end
|
|
54
121
|
|
|
55
122
|
class ::Hash < ::Object
|
|
123
|
+
report_print_options(detect_cycles: false)
|
|
124
|
+
|
|
56
125
|
def report_print(rp)
|
|
57
126
|
rp.write("{")
|
|
58
127
|
rp.multiline(after: "}", separator: ",") do
|
|
@@ -74,6 +143,8 @@ class ::Hash < ::Object
|
|
|
74
143
|
end
|
|
75
144
|
|
|
76
145
|
class ::Set < ::Object
|
|
146
|
+
report_print_options(detect_cycles: false)
|
|
147
|
+
|
|
77
148
|
def report_print(rp)
|
|
78
149
|
rp.inline("") do
|
|
79
150
|
rp.write("Set", color: :yellow)
|
|
@@ -88,6 +159,8 @@ class ::Set < ::Object
|
|
|
88
159
|
end
|
|
89
160
|
|
|
90
161
|
class ::Data < ::Object
|
|
162
|
+
report_print_options(detect_cycles: false)
|
|
163
|
+
|
|
91
164
|
def report_print(rp)
|
|
92
165
|
name = self.class.short_class_name
|
|
93
166
|
rp.inline("") do
|
|
@@ -96,8 +169,11 @@ class ::Data < ::Object
|
|
|
96
169
|
end
|
|
97
170
|
rp.multiline(after: "]", separator: ",") do
|
|
98
171
|
self.to_h.each do |name, value|
|
|
99
|
-
rp.inline("
|
|
100
|
-
rp.
|
|
172
|
+
rp.inline(" ") do
|
|
173
|
+
rp.inline("") do
|
|
174
|
+
rp.write(name, color: :bright_cyan)
|
|
175
|
+
rp.write(":")
|
|
176
|
+
end
|
|
101
177
|
rp.rp(value)
|
|
102
178
|
end
|
|
103
179
|
end
|
data/lib/report_print/dsl.rb
CHANGED
data/lib/report_print/printer.rb
CHANGED
|
@@ -13,16 +13,12 @@ module ReportPrint
|
|
|
13
13
|
:next_inline_separator,
|
|
14
14
|
:after,
|
|
15
15
|
:start_of_line,
|
|
16
|
-
:start_of_block
|
|
16
|
+
:start_of_block,
|
|
17
|
+
:start_of_output
|
|
17
18
|
) do
|
|
18
|
-
# Ruby type checking can't really handle this type of dynamic programming
|
|
19
|
-
# very well yet, so we just skip type checking here as there is only the
|
|
20
|
-
# one short function.
|
|
21
|
-
# steep:ignore:start
|
|
22
19
|
def inline?
|
|
23
20
|
mode == :inline
|
|
24
21
|
end
|
|
25
|
-
# steep:ignore:end
|
|
26
22
|
end
|
|
27
23
|
|
|
28
24
|
##
|
|
@@ -32,10 +28,7 @@ module ReportPrint
|
|
|
32
28
|
def initialize(output = $>, color: :auto)
|
|
33
29
|
@output = output
|
|
34
30
|
if color == :auto
|
|
35
|
-
# Ignore block performing runtime type check.
|
|
36
|
-
# steep:ignore:start
|
|
37
31
|
color = output.respond_to?(:tty?) && output.tty?
|
|
38
|
-
# steep:ignore:end
|
|
39
32
|
end
|
|
40
33
|
@rainbow = Rainbow::Wrapper.new(color)
|
|
41
34
|
|
|
@@ -47,9 +40,12 @@ module ReportPrint
|
|
|
47
40
|
inline_separator: "",
|
|
48
41
|
next_inline_separator: nil,
|
|
49
42
|
after: nil,
|
|
50
|
-
start_of_line:
|
|
51
|
-
start_of_block: true
|
|
43
|
+
start_of_line: true,
|
|
44
|
+
start_of_block: true,
|
|
45
|
+
start_of_output: true
|
|
52
46
|
]
|
|
47
|
+
|
|
48
|
+
@options = ScopedOptions.new(ReportPrint.report_print_options)
|
|
53
49
|
end
|
|
54
50
|
|
|
55
51
|
##
|
|
@@ -60,7 +56,14 @@ module ReportPrint
|
|
|
60
56
|
def rp(object)
|
|
61
57
|
case object
|
|
62
58
|
when Object
|
|
63
|
-
object.
|
|
59
|
+
if @seen.include?(object.__id__)
|
|
60
|
+
object.report_print_cycle(self)
|
|
61
|
+
else
|
|
62
|
+
if options_for(object)[:detect_cycles]
|
|
63
|
+
@seen.add(object.__id__)
|
|
64
|
+
end
|
|
65
|
+
object.report_print(self)
|
|
66
|
+
end
|
|
64
67
|
else
|
|
65
68
|
write("BasicObject", color: :bright_yellow)
|
|
66
69
|
end
|
|
@@ -120,7 +123,8 @@ module ReportPrint
|
|
|
120
123
|
if @state.inline?
|
|
121
124
|
set_state(
|
|
122
125
|
start_of_line: @state.start_of_line && result.start_of_line,
|
|
123
|
-
start_of_block: @state.start_of_block && result.start_of_block
|
|
126
|
+
start_of_block: @state.start_of_block && result.start_of_block,
|
|
127
|
+
start_of_output: @state.start_of_output && result.start_of_output
|
|
124
128
|
)
|
|
125
129
|
if @state.next_inline_separator != result.next_inline_separator
|
|
126
130
|
# If the inner inline state is requesting a separator, then that
|
|
@@ -129,7 +133,8 @@ module ReportPrint
|
|
|
129
133
|
end
|
|
130
134
|
else
|
|
131
135
|
set_state(
|
|
132
|
-
start_of_block: @state.start_of_block && result.start_of_block
|
|
136
|
+
start_of_block: @state.start_of_block && result.start_of_block,
|
|
137
|
+
start_of_output: @state.start_of_output && result.start_of_output
|
|
133
138
|
)
|
|
134
139
|
end
|
|
135
140
|
end
|
|
@@ -167,7 +172,8 @@ module ReportPrint
|
|
|
167
172
|
)
|
|
168
173
|
|
|
169
174
|
set_state(
|
|
170
|
-
start_of_block: @state.start_of_block && result.start_of_block
|
|
175
|
+
start_of_block: @state.start_of_block && result.start_of_block,
|
|
176
|
+
start_of_output: @state.start_of_output && result.start_of_output
|
|
171
177
|
)
|
|
172
178
|
|
|
173
179
|
did_write = !result.start_of_block
|
|
@@ -205,7 +211,7 @@ module ReportPrint
|
|
|
205
211
|
# first concatenated into a single string, as in `IO#write`. Meaning no
|
|
206
212
|
# separators or line breaks will be rendered between them.
|
|
207
213
|
def write(*strings, color: nil)
|
|
208
|
-
if @state.start_of_line
|
|
214
|
+
if @state.start_of_line && !@state.start_of_output
|
|
209
215
|
unless @state.start_of_block
|
|
210
216
|
@output.write(@state.separator)
|
|
211
217
|
end
|
|
@@ -226,12 +232,14 @@ module ReportPrint
|
|
|
226
232
|
set_state(
|
|
227
233
|
start_of_line: false,
|
|
228
234
|
start_of_block: false,
|
|
235
|
+
start_of_output: false,
|
|
229
236
|
next_inline_separator: @state.inline_separator
|
|
230
237
|
)
|
|
231
238
|
else
|
|
232
239
|
set_state(
|
|
233
240
|
start_of_block: false,
|
|
234
|
-
start_of_line: true
|
|
241
|
+
start_of_line: true,
|
|
242
|
+
start_of_output: false
|
|
235
243
|
)
|
|
236
244
|
end
|
|
237
245
|
end
|
|
@@ -309,38 +317,17 @@ module ReportPrint
|
|
|
309
317
|
end
|
|
310
318
|
end
|
|
311
319
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
320
|
+
##
|
|
321
|
+
# Fetch the options which are set for the class of `object`.
|
|
322
|
+
#
|
|
323
|
+
# See Api#report_print_options for more details about the available
|
|
324
|
+
# options.
|
|
325
|
+
def options_for(object)
|
|
326
|
+
@options.options_for(object.class)
|
|
319
327
|
end
|
|
320
328
|
|
|
321
329
|
private
|
|
322
330
|
|
|
323
|
-
def write_after(value)
|
|
324
|
-
if @state.start_of_line
|
|
325
|
-
break_line
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
@output.write(value)
|
|
329
|
-
|
|
330
|
-
if @state.inline?
|
|
331
|
-
set_state(
|
|
332
|
-
start_of_line: false,
|
|
333
|
-
start_of_block: false,
|
|
334
|
-
next_inline_separator: @state.inline_separator
|
|
335
|
-
)
|
|
336
|
-
else
|
|
337
|
-
set_state(
|
|
338
|
-
start_of_block: false,
|
|
339
|
-
start_of_line: true
|
|
340
|
-
)
|
|
341
|
-
end
|
|
342
|
-
end
|
|
343
|
-
|
|
344
331
|
def break_line
|
|
345
332
|
@output.write("\n")
|
|
346
333
|
@output.write(" " * @state.indent)
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
module ReportPrint
|
|
2
2
|
module Refinements
|
|
3
|
-
refine Object.singleton_class do
|
|
4
|
-
def report_print_inspect!(color: nil)
|
|
5
|
-
define_method(:report_print) do |rp|
|
|
6
|
-
# @type self: Object
|
|
7
|
-
rp.write(inspect, color:)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
3
|
refine Module do
|
|
13
4
|
def short_class_name
|
|
14
5
|
name.sub(/^.*::/, "")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module ReportPrint
|
|
2
|
+
class ScopedOptions
|
|
3
|
+
def initialize(global_options)
|
|
4
|
+
@global_options = global_options
|
|
5
|
+
@cache = {
|
|
6
|
+
Object => Object.report_print_options,
|
|
7
|
+
BasicObject => {}
|
|
8
|
+
}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def options_for(klass)
|
|
12
|
+
@global_options.merge(self_options_for(klass).compact)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private def self_options_for(klass)
|
|
16
|
+
@cache[klass] ||= (
|
|
17
|
+
self_options_for(klass.superclass).merge(klass.report_print_options)
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/report_print/version.rb
CHANGED
data/lib/report_print.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
require_relative "report_print/version"
|
|
2
2
|
require_relative "report_print/refinements"
|
|
3
|
+
require_relative "report_print/api"
|
|
4
|
+
require_relative "report_print/scoped_options"
|
|
3
5
|
require_relative "report_print/printer"
|
|
4
6
|
require_relative "report_print/core_extensions"
|
|
5
7
|
require_relative "report_print/dsl"
|
|
6
8
|
|
|
7
|
-
module ReportPrint
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Kernel.prepend(ReportPrint::Dsl)
|
|
9
|
+
module ReportPrint
|
|
10
|
+
@report_print_options = {}
|
|
11
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: report_print
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Benoit Hiller
|
|
@@ -23,10 +23,12 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '3.1'
|
|
26
|
-
description:
|
|
27
|
-
you both a stylish readable default, and the ability to customize it as needed.
|
|
26
|
+
description: |
|
|
27
|
+
A hybrid between PrettyPrint and AwesomePrint/AmazingPrint. Providing you both a stylish readable default, and the ability to customize it as needed.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
The name ReportPrint comes from the desire to output detailed reports of the program state at a given point in time, rather than merely inspecting an object.
|
|
30
|
+
|
|
31
|
+
After requiring simply use the global `rp` method to print objects like you do with `pp` or `ap`.
|
|
30
32
|
email:
|
|
31
33
|
- benoit.hiller@gmail.com
|
|
32
34
|
executables: []
|
|
@@ -35,18 +37,26 @@ extra_rdoc_files: []
|
|
|
35
37
|
files:
|
|
36
38
|
- LICENSE
|
|
37
39
|
- README.md
|
|
40
|
+
- doc/.document
|
|
41
|
+
- doc/Customization.md
|
|
42
|
+
- doc/Formatters.md
|
|
43
|
+
- doc/overview.md
|
|
44
|
+
- gem_description.rdoc
|
|
45
|
+
- lib/.document
|
|
38
46
|
- lib/report_print.rb
|
|
47
|
+
- lib/report_print/api.rb
|
|
39
48
|
- lib/report_print/core_extensions.rb
|
|
40
49
|
- lib/report_print/dsl.rb
|
|
41
50
|
- lib/report_print/printer.rb
|
|
42
51
|
- lib/report_print/refinements.rb
|
|
52
|
+
- lib/report_print/scoped_options.rb
|
|
43
53
|
- lib/report_print/version.rb
|
|
44
|
-
homepage: https://github.
|
|
54
|
+
homepage: https://benoithiller.github.io/report_print/
|
|
45
55
|
licenses:
|
|
46
56
|
- MIT-0
|
|
47
57
|
metadata:
|
|
48
58
|
allowed_push_host: https://rubygems.org
|
|
49
|
-
homepage_uri: https://github.
|
|
59
|
+
homepage_uri: https://benoithiller.github.io/report_print/
|
|
50
60
|
source_code_uri: https://github.com/BenoitHiller/report_print
|
|
51
61
|
rdoc_options: []
|
|
52
62
|
require_paths:
|