report_print 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0d7f2a1582aea408d911f88210e1b8c8ed606ce89f7bf21a7c7c26f27bb6bb7
4
- data.tar.gz: dc9f17860c7ef6e576b06215ea6e8a5b1d605d2c7b6c115b8d951ad077b0d806
3
+ metadata.gz: 95d2ad3bb32255b708ff4f8b2e8f60e300cd40a1d7bab2e352ca1b355ddf8bad
4
+ data.tar.gz: 13740735a26e08b56e1f0d2e790524afd3ec73789465a65117f2f62555177220
5
5
  SHA512:
6
- metadata.gz: 30dde24a45f9e1207ec2bccdd747e5ffe74a197284226ec0d60d29cf94e56bf5b818ed63f632a3703746d13c0ee0b1b76a00af51dea2f6daf20430c2bd1c77a3
7
- data.tar.gz: 12847ec207fc9537d16464ab39a1f27d3c034b1fe26ee74320786f17670893e3653849694bd090a7294d09a98a30c041f9d88567c9e240cd893ba5bb45d5ae1e
6
+ metadata.gz: 87218676c7e05ef0ec0f7243dc2558da038c4abac79f21a9eee2df00e730545e5add08761195d40238303241b9181198bab19da7acef422e57656d00f5b86db3
7
+ data.tar.gz: 5b17164200cdbc4fbb24a39e5206368766bead5277126c81753be4d9cfdcdf52df202d857eda1e15bc28b39bae95cd7641c015e0fc8eae6301fc48e18eef6884
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ MIT No Attribution
2
+
3
+ Copyright 2026 Benoit Hiller
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.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18
+ SOFTWARE.
data/README.md CHANGED
@@ -26,6 +26,8 @@ require 'report_print'
26
26
  rp object
27
27
  ```
28
28
 
29
+ See the [full documentation](https://benoithiller.github.io/report_print/) for more details.
30
+
29
31
  ## Development
30
32
 
31
33
  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,2 @@
1
+ *.md
2
+ ../lib
@@ -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,167 @@
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
+
14
+ # All Numeric types
15
+ rp 1
16
+ rp 0.5
17
+ rp Float::INFINITY
18
+ rp 1i * 1i
19
+ rp Rational(2, 3)
20
+
21
+ # Constants
22
+ rp true
23
+ rp false
24
+ rp nil
25
+
26
+ Output:
27
+
28
+ <pre>
29
+ <span style="color:var(--code-blue)">:symbols<span style="color:var(--code-green)">
30
+ "strings"<span style="color:var(--code-purple)">
31
+ 1
32
+ 0.5
33
+ Infinity
34
+ (-1+0i)
35
+ (2/3)<span style="color:var(--code-blue)">
36
+ true
37
+ false
38
+ nil</span>
39
+ </pre>
40
+
41
+ ## `Object`
42
+
43
+ class A
44
+ def initialize
45
+ @name = self.class.name
46
+ end
47
+ end
48
+
49
+ class B < A
50
+ def initialize
51
+ super
52
+ @field = A.new
53
+ end
54
+ end
55
+
56
+ rp B.new
57
+
58
+ Output:
59
+
60
+ <pre>
61
+ <span style="color:var(--code-orange)">B</span> <span style="color:var(--code-gray)">0x2b0</span>
62
+ <span style="color:var(--code-cyan)">@name</span> = <span style="color:var(--code-green)">"B"</span>
63
+ <span style="color:var(--code-cyan)">@field</span> = <span style="color:var(--code-orange)">A</span> <span style="color:var(--code-gray)">0x2b8</span>
64
+ <span style="color:var(--code-cyan)">@name</span> = <span style="color:var(--code-green)">"A"</span>
65
+ <span style="color:var(--code-blue)">end
66
+ end</span>
67
+ </pre>
68
+
69
+ ## `Module`
70
+
71
+ rp Class
72
+
73
+ Output:
74
+
75
+ <pre>
76
+ <span style="color:var(--code-orange)">Class</span>
77
+ </pre>
78
+
79
+
80
+ ## `Array`
81
+
82
+ rp [1, "two", [[]]]
83
+
84
+ Output:
85
+
86
+ <pre>
87
+ [
88
+ <span style="color:var(--code-purple)">1</span>,
89
+ <span style="color:var(--code-green)">"two"</span>,
90
+ [
91
+ []
92
+ ]
93
+ ]</span>
94
+ </pre>
95
+
96
+ ## `Hash`
97
+
98
+ rp({
99
+ "one" => 1,
100
+ two: {
101
+ [1, 2] => {}
102
+ }
103
+ })
104
+
105
+ Output:
106
+
107
+ <pre>
108
+ {
109
+ <span style="color:var(--code-green)">"one"</span> => <span style="color:var(--code-purple)">1</span>,
110
+ <span style="color:var(--code-cyan)">two:</span> {
111
+ [
112
+ <span style="color:var(--code-purple)">1</span>,
113
+ <span style="color:var(--code-purple)">2</span>
114
+ ] => {}
115
+ }
116
+ }</span>
117
+ </pre>
118
+
119
+ ## `Set`
120
+
121
+ rp Set[1, "thing", Set[]]
122
+
123
+ Output:
124
+
125
+ <pre>
126
+ <span style="color:var(--code-orange)">Set</span>[
127
+ <span style="color:var(--code-purple)">1</span>,
128
+ <span style="color:var(--code-green)">"thing"</span>,
129
+ <span style="color:var(--code-orange)">Set</span>[]
130
+ ]</span>
131
+ </pre>
132
+
133
+ ## `Data`
134
+
135
+ Direction = Data.define(:x, :y)
136
+ Velocity = Data.define(:speed, :direction)
137
+
138
+ rp Velocity[100, Direction[0.6, 0.8]]
139
+
140
+ Output:
141
+
142
+ <pre>
143
+ <span style="color:var(--code-blue)">Velocity</span>[
144
+ <span style="color:var(--code-cyan)">speed</span>: <span style="color:var(--code-purple)">100</span>,
145
+ <span style="color:var(--code-cyan)">direction</span>: <span style="color:var(--code-blue)">Direction</span>[
146
+ <span style="color:var(--code-cyan)">x</span>: <span style="color:var(--code-purple)">0.6</span>,
147
+ <span style="color:var(--code-cyan)">y</span>: <span style="color:var(--code-purple)">0.8</span>
148
+ ]
149
+ ]</span>
150
+ </pre>
151
+
152
+ ## `Struct`
153
+
154
+ Player = Struct.new(:health, :mana)
155
+
156
+ rp Player.new(100, 200)
157
+
158
+ Output:
159
+
160
+ <pre>
161
+ <span style="color:var(--code-orange)">Player</span>( <span style="color:var(--code-gray)">0x298</span>
162
+ <span style="color:var(--code-cyan)">health</span>: <span style="color:var(--code-purple)">100</span>,
163
+ <span style="color:var(--code-cyan)">mana</span>: <span style="color:var(--code-purple)">200</span>
164
+ )</span>
165
+ </pre>
166
+
167
+ 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.
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,9 @@
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
+ rp object
data/lib/.document ADDED
@@ -0,0 +1,2 @@
1
+ report_print/printer.rb
2
+ report_print/dsl.rb
@@ -13,7 +13,7 @@ end
13
13
 
14
14
  class ::Module < ::Object
15
15
  def report_print(rp)
16
- rp.write(name.short_class_name)
16
+ rp.write(short_class_name, color: :bright_yellow)
17
17
  end
18
18
  end
19
19
 
@@ -96,8 +96,11 @@ class ::Data < ::Object
96
96
  end
97
97
  rp.multiline(after: "]", separator: ",") do
98
98
  self.to_h.each do |name, value|
99
- rp.inline(": ") do
100
- rp.write(name, color: :bright_cyan)
99
+ rp.inline(" ") do
100
+ rp.inline("") do
101
+ rp.write(name, color: :bright_cyan)
102
+ rp.write(":")
103
+ end
101
104
  rp.rp(value)
102
105
  end
103
106
  end
@@ -320,27 +320,6 @@ module ReportPrint
320
320
 
321
321
  private
322
322
 
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
323
  def break_line
345
324
  @output.write("\n")
346
325
  @output.write(" " * @state.indent)
@@ -1,3 +1,3 @@
1
1
  module ReportPrint
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/report_print.rb CHANGED
@@ -6,5 +6,4 @@ require_relative "report_print/dsl"
6
6
 
7
7
  module ReportPrint; end
8
8
 
9
- # :enddoc:
10
9
  Kernel.prepend(ReportPrint::Dsl)
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.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benoit Hiller
@@ -23,17 +23,30 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '3.1'
26
- description: 'A hybrid between PrettyPrint and AwesomePrint/AmazingPrint. Providing
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
+ == Usage
32
+
33
+ require 'report_print'
34
+
35
+ rp object
30
36
  email:
31
37
  - benoit.hiller@gmail.com
32
38
  executables: []
33
39
  extensions: []
34
40
  extra_rdoc_files: []
35
41
  files:
42
+ - LICENSE
36
43
  - README.md
44
+ - doc/.document
45
+ - doc/Customization.md
46
+ - doc/Formatters.md
47
+ - doc/overview.md
48
+ - gem_description.rdoc
49
+ - lib/.document
37
50
  - lib/report_print.rb
38
51
  - lib/report_print/core_extensions.rb
39
52
  - lib/report_print/dsl.rb
@@ -41,7 +54,8 @@ files:
41
54
  - lib/report_print/refinements.rb
42
55
  - lib/report_print/version.rb
43
56
  homepage: https://github.com/BenoitHiller/report_print
44
- licenses: []
57
+ licenses:
58
+ - MIT-0
45
59
  metadata:
46
60
  allowed_push_host: https://rubygems.org
47
61
  homepage_uri: https://github.com/BenoitHiller/report_print
@@ -60,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
74
  - !ruby/object:Gem::Version
61
75
  version: '0'
62
76
  requirements: []
63
- rubygems_version: 4.0.10
77
+ rubygems_version: 4.0.16
64
78
  specification_version: 4
65
79
  summary: A hybrid between PrettyPrint and AwesomePrint/AmazingPrint
66
80
  test_files: []