Module: Hexes

Defined in:
lib/hexes.rb

Overview

Hexes takes care of some console/view/IO work for Scryglass

Class Method Summary collapse

Class Method Details

.capture_io(char_limit: nil) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/hexes.rb', line 65

def self.capture_io(char_limit: nil)
  stdout_rescue do # Ensures that $stdout is reset no matter what
    temporary_io_channel = StringIO.new
    $stdout = temporary_io_channel
    Thread.abort_on_exception = true # So threads can return error text at all

    if char_limit
      background_output_thread = Thread.new { yield } # It's assumed that the
      #   yielded block will be printing something somewhat promptly.

      sleep 0.05 # Give it a head start (Sometimes makes a difference!)

      while temporary_io_channel.size < char_limit
        io_size = temporary_io_channel.size
        sleep 0.05
        new_io_size = temporary_io_channel.size
        break if new_io_size == io_size
      end
      background_output_thread.terminate
    else
      yield
    end

    temporary_io_channel.rewind
    captured_output = temporary_io_channel.read
    captured_output = captured_output.clip_at(char_limit) if char_limit

    captured_output
  end
end

.hide_db_outputsObject



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/hexes.rb', line 105

def self.hide_db_outputs
  necessary_constants = ['Logger', 'ActiveRecord::Base']
  necessary_constants_defined = necessary_constants.all?(&:constant_defined?)
  return yield unless necessary_constants_defined

  rails_logger_defined = 'Rails'.constant_defined? && !!Rails.try(:logger)

  ## These are purposefully preserved as global variables so retrieval, in
  ##   debugging or errored usage, is as easy as possible.
  $preserved_ar_base_logger = ActiveRecord::Base.logger.dup
  $preserved_rails_logger = Rails.logger.dup if rails_logger_defined

  begin
    ## Now we create an unused dump string to serve as the output
    ignored_output = StringIO.new
    ignored_log = Logger.new(ignored_output)
    ActiveRecord::Base.logger = ignored_log
    Rails.logger = ignored_log if rails_logger_defined

    yielded_return = yield
  rescue => e
    # `e` is raised again in the `ensure` after displays are safely reset.
  ensure
    ActiveRecord::Base.logger = $preserved_ar_base_logger
    Rails.logger = $preserved_rails_logger if rails_logger_defined
    raise e if e
  end

  yielded_return
end

.opacify_screen_string(screen_string) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/hexes.rb', line 26

def self.opacify_screen_string(screen_string)
  screen_height, screen_width = $stdout.winsize

  split_lines = screen_string.split("\n")
  rows_filled = split_lines.count

  blank_rows_at_bottom = [screen_height - rows_filled, 0].max

  # This takes all the unfilled spaces left after a newline, and makes them
  #   real spaces, so they'll overwrite whatever was there a second ago. Thus
  #   I don't have to worry about clearing the screen all the time, which was
  #   seemingly causing console chaff and some flickering.
  side_filled_string = split_lines.map do |line|
    margin_to_fill = screen_width - line.ansiless.length
    line + (' ' * margin_to_fill)
  end.join("\e[00m\n") # Also turns off ANSI text formatting at the end of
  #   each line, in case a formatted string had its "turn off formatting" code
  #   cut off from the end. (Reducing the need to end with one at all).

  blank_line = "\n" + (' ' * screen_width)

  side_filled_string + (blank_line * blank_rows_at_bottom)
end

.overwrite_screen(screen_string) ⇒ Object



96
97
98
99
100
101
102
103
# File 'lib/hexes.rb', line 96

def self.overwrite_screen(screen_string)
  csi = "\e["
  $stdout.write "#{csi}s" # Saves terminal cursor position
  $stdout.write "#{csi}1;1H" # Moves terminal cursor to top left corner

  $stdout.print "\r#{screen_string}"
  $stdout.write "#{csi}u" # Restores saved terminal cursor position
end

.simple_screen_slice(screen_string) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/hexes.rb', line 9

def self.simple_screen_slice(screen_string)
  screen_height, screen_width = $stdout.winsize

  split_lines = screen_string.split("\n")

  ## Here we cut down the (rectangular if opacified) display array in both
  ##   dimensions (into a smaller rectangle), as needed, to fit the view.
  sliced_lines = split_lines.map do |string|
    ansi_length = string.length - string.ansiless_length
    slice_length = screen_width + ansi_length
    string[0, slice_length]
  end
  sliced_list = sliced_lines[0, screen_height]

  sliced_list.join("\n")
end

.stdout_rescueObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/hexes.rb', line 50

def self.stdout_rescue
  @preserved_stdout_dup = $stdout.dup

  begin
    yielded_return = yield
  rescue => e
    # `e` is raised again in the `ensure` block after stdout is safely reset.
  ensure
    $stdout = @preserved_stdout_dup
    raise e if e
  end

  yielded_return
end