Class: ReportPrint::Printer

Inherits:
Object show all
Defined in:
lib/report_print/printer.rb

Overview

The class of the printer instances provided to Object#report_print methods.

Defined Under Namespace

Classes: State

Instance Method Summary collapse

Constructor Details

#initialize(output = $>, color: :auto) ⇒ Printer

Returns a new printer object writing to the specified output.

Intended only for internal use. See Dsl#rp for more details.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/report_print/printer.rb', line 32

def initialize(output = $>, color: :auto)
  @output = output
  if color == :auto
    # Ignore block performing runtime type check.
    # steep:ignore:start
    color = output.respond_to?(:tty?) && output.tty?
    # steep:ignore:end
  end
  @rainbow = Rainbow::Wrapper.new(color)

  @seen = ::Set.new
  @state = State[
    mode: :multiline,
    indent: 0,
    separator: "",
    inline_separator: "",
    next_inline_separator: nil,
    after: nil,
    start_of_line: false,
    start_of_block: true
  ]
end

Instance Method Details

#color(input, *values) ⇒ Object

Wrap the provided input string in a Rainbow::Presenter and color it using Rainbow::Presenter#color passing the provided values.

This uses a Rainbow::Wrapper instantiated by the Printer which uses the user specified settings for whether color printing is enabled.

Additionally if values is a single symbol matching /bright_(\w+)/, then it will first apply the specified color, then apply Rainbow::Presenter#bright to the output.

Thus the following are equivalent:

rp.color("string", :bright_blue)
rp.color("string", :blue).bright


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/report_print/printer.rb', line 86

def color(input, *values)
  wrapped = @rainbow.wrap(input.to_s)
  case values
  in [Symbol => name]
    if (matches = name.match(/bright_(\w+)/))
      wrapped.color(matches[1].to_sym).bright
    else
      wrapped.color(name)
    end
  in []
    wrapped
  else
    wrapped.color(*values)
  end
end

#inline(inline_separator = :inherit, &block) ⇒ Object

Define a block which prints each item on the same line separated by inline_separator.

If called inside another #inline block, it only customize the separator between the elements printed within the block.

If no inline_separator is specified, then the inline_separator of the containing inline block will be used, or "" if there is no containing inline block.

If you want to reset the separator to the empty value you will thus need to pass nil or "".



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/report_print/printer.rb', line 115

def inline(inline_separator = :inherit, &block)
  if inline_separator == :inherit
    inline_separator = @state.inline_separator
  end
  result = with_state(mode: :inline, inline_separator:, &block)
  if @state.inline?
    set_state(
      start_of_line: @state.start_of_line && result.start_of_line,
      start_of_block: @state.start_of_block && result.start_of_block
    )
    if @state.next_inline_separator != result.next_inline_separator
      # If the inner inline state is requesting a separator, then that
      # means we should request the current separator instead.
      set_state(next_inline_separator: @state.inline_separator)
    end
  else
    set_state(
      start_of_block: @state.start_of_block && result.start_of_block
    )
  end
end

#multiline(separator: nil, after: nil, after_empty: true, indent: 2, &block) ⇒ Object

Define a block which prints each item or #inline block on a separate line.

Accepts the following options:

  • separator: a separator to print before each newline, or :inherit to use the separator of the containing multiline block.
  • after: a string to print after the end of the block.
  • after_empty: if true, print after: even when nothing was written inside the block.
  • indent: the number of spaces to increase the indent by inside the block.


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/report_print/printer.rb', line 148

def multiline(
  separator: nil,
  after: nil,
  after_empty: true,
  indent: 2,
  &block
)
  if separator == :inherit
    separator = @state.separator
  end

  result = with_state(
    mode: :multiline,
    start_of_line: true,
    start_of_block: true,
    indent: @state.indent + indent,
    next_inline_separator: nil,
    separator:,
    &block
  )

  set_state(
    start_of_block: @state.start_of_block && result.start_of_block
  )

  did_write = !result.start_of_block

  if did_write || after_empty
    unless after.nil?
      if did_write
        break_line
      end
      @output.write(after)
      set_state(start_of_block: false)

      did_write = true
    end
  end

  if did_write
    if @state.inline?
      set_state(next_inline_separator: @state.inline_separator)
    else
      # This is to cleanup the special case handling of the outermost state.
      # Likely this would be more clear with an explicit flag.
      set_state(start_of_line: true)
    end
  end
end

#rp(object) ⇒ Object

Print an object using its Object#report_print method.

Note: if an argument is provided which does not inherit from Object, then "BasicObject" will be printed.



60
61
62
63
64
65
66
67
# File 'lib/report_print/printer.rb', line 60

def rp(object)
  case object
  when Object
    object.report_print(self)
  else
    write("BasicObject", color: :bright_yellow)
  end
end

#unless_seen(object) ⇒ Object



312
313
314
315
316
317
318
319
# File 'lib/report_print/printer.rb', line 312

def unless_seen(object)
  if @seen.include?(object.__id__)
    write_header(object)
  else
    @seen.add(object.__id__)
    yield
  end
end

#write(*strings, color: nil) ⇒ Object

Write out the provided strings given the current printer state.

If color: is provided it will be interpreted the same as in the case where #color is given a singular argument.

When multiple strings are provided, they will be rendered as if they were first concatenated into a single string, as in IO#write. Meaning no separators or line breaks will be rendered between them.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/report_print/printer.rb', line 207

def write(*strings, color: nil)
  if @state.start_of_line
    unless @state.start_of_block
      @output.write(@state.separator)
    end
    break_line
  elsif @state.next_inline_separator
    @output.write(@state.next_inline_separator)
  end

  if color
    strings = strings.map do |string|
      self.color(string, color)
    end
  end

  @output.write(*strings)

  if @state.inline?
    set_state(
      start_of_line: false,
      start_of_block: false,
      next_inline_separator: @state.inline_separator
    )
  else
    set_state(
      start_of_block: false,
      start_of_line: true
    )
  end
end

#write_header(object, write_id: true) ⇒ Object

Write the class name and the object id joined with a space.


Object 0xabcd1234


247
248
249
250
251
252
253
254
# File 'lib/report_print/printer.rb', line 247

def write_header(object, write_id: true)
  inline(" ") do
    write(object.class.short_class_name, color: :bright_yellow)
    if write_id
      write_object_id(object)
    end
  end
end

#write_instance_variables(object, variables = :all) ⇒ Object

Write out the instance variables of an object.

If an array of symbols is provided as variables, only those will be considered, otherwise all variables returned by Object#instance_variables will be used.

class Example
  def new(value)
    @value = value
    @string = value.to_s
  end
end

rp.write_instance_variables(Example.new(1))
rp.write_instance_variables(Example.new(:two), [:@value])

Output:


@value = 1
@string = "1"
@value = :two


298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/report_print/printer.rb', line 298

def write_instance_variables(object, variables = :all)
  if variables == :all
    variables = object.instance_variables
  end

  variables.each do |name|
    inline(" ") do
      write(name, color: :bright_cyan)
      write("=")
      rp(object.instance_variable_get(name))
    end
  end
end

#write_object_id(object) ⇒ Object

Write the id of the object as hex.


0xabcd1234


262
263
264
# File 'lib/report_print/printer.rb', line 262

def write_object_id(object)
  write(sprintf("%#x", object.__id__), color: :bright_black)
end