Class: Inspec::UI

Inherits:
Object
  • Object
show all
Defined in:
lib/inspec/ui.rb,
lib/inspec/ui_table_helper.rb

Overview

Provides simple terminal UI interaction primitives for CLI commands and plugins.

Defined Under Namespace

Classes: TableHelper

Constant Summary collapse

ANSI_CODES =
{
  reset: "\e[0m",
  bold: "\e[1m",
  color: {
    red: "\e[38;5;9m", # 256-color light red
    green: "\e[38;5;41m",  # 256-color light green
    yellow: "\e[33m",
    cyan: "\e[36m",
    white: "\e[37m",
    grey: "\e[38;5;247m",  # 256-color medium grey
  },
}.freeze
GLYPHS =
{
  bullet: "", # BULLET, Unicode: U+2022, UTF-8: E2 80 A2
  check: "", #  HEAVY CHECK MARK, Unicode: U+2714, UTF-8: E2 9C 94
  swirl: "", # ANTICLOCKWISE OPEN CIRCLE ARROW, Unicode U+21BA, UTF-8: E2 86 BA
  script_x: "×", # MULTIPLICATION SIGN, Unicode: U+00D7, UTF-8: C3 97
  question: "?", # normal ASCII question mark
  em_dash: "", # BOX DRAWINGS LIGHT HORIZONTAL Unicode: U+2500, UTF-8: E2 94 80
  heavy_dash: "", # RING IN EQUAL TO, Unicode: U+2256, UTF-8: E2 89 96
  vertical_dash: "", # BOX DRAWINGS LIGHT VERTICAL, Unicode: U+2502, UTF-8: E2 94 82
  table_corner: "", # N-ARY CIRCLED DOT OPERATOR, Unicode: U+2A00, UTF-8: E2 A8 80
}.freeze
EXIT_NORMAL =
0
EXIT_USAGE_ERROR =
1
EXIT_PLUGIN_ERROR =
2
EXIT_FATAL_DEPRECATION =
3
EXIT_GEM_DEPENDENCY_LOAD_ERROR =
4
EXIT_BAD_SIGNATURE =
5
EXIT_SIGNATURE_REQUIRED =
6
EXIT_LICENSE_NOT_ACCEPTED =
172
EXIT_LICENSE_NOT_ENTITLED =
173
EXIT_LICENSE_NOT_SET =
174
EXIT_FAILED_TESTS =
100
EXIT_SKIPPED_TESTS =
101
EXIT_TERMINATED_BY_CTL_C =
130

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ UI

Returns a new instance of UI.



45
46
47
48
49
# File 'lib/inspec/ui.rb', line 45

def initialize(opts = {})
  @color = opts[:color].nil? ? true : opts[:color]
  @interactive = opts[:interactive].nil? ? $stdout.isatty : opts[:interactive]
  @io = opts[:io] || $stdout
end

Instance Attribute Details

#ioObject (readonly)

Returns the value of attribute io.



43
44
45
# File 'lib/inspec/ui.rb', line 43

def io
  @io
end

Instance Method Details

#bold(str, opts = { print: true }) ⇒ Object



72
73
74
75
# File 'lib/inspec/ui.rb', line 72

def bold(str, opts = { print: true })
  result = color? ? io.print(ANSI_CODES[:bold] + str.to_s + ANSI_CODES[:reset]) : str.to_s
  print_or_return(result, opts[:print])
end

#color?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/inspec/ui.rb', line 51

def color?
  @color
end

#emphasis(str, opts = { print: false }) ⇒ Object

#
High-Level formatting methods
#


88
89
90
# File 'lib/inspec/ui.rb', line 88

def emphasis(str, opts = { print: false })
  cyan(str, opts)
end

#error(str, opts = { print: true }) ⇒ Object

Issues a one-line message, with ‘ERROR: ’ prepended in bold red.



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/inspec/ui.rb', line 113

def error(str, opts = { print: true })
  str = str.dup.to_s
  result = ""
  result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:red] : ""
  result += "ERROR:"
  result += color? ? ANSI_CODES[:reset] : ""
  result += " "
  result += str
  result += "\n"
  print_or_return(result, opts[:print])
end

#exit(code_sym = :normal) ⇒ Object

#
Exit Codes
#


195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/inspec/ui.rb', line 195

def exit(code_sym = :normal)
  # If it's a number, give them a pass for now.
  if code_sym.is_a? Numeric
    code_int = code_sym
  else
    code_const = ("EXIT_" + code_sym.to_s.upcase).to_sym
    unless self.class.const_defined?(code_const)
      warning("Unrecognized exit constant #{code_const} - exit with code 1")
      exit(:usage_error)
    end
    code_int = self.class.const_get(code_const)
  end
  Kernel.exit(code_int)
end

#headline(str, opts = { print: true }) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/inspec/ui.rb', line 92

def headline(str, opts = { print: true })
  str = str.dup.to_s
  if str.length < 76
    dash_length = 80 - str.length - 4 # 4 spaces
    dash_length /= 2
  else
    dash_length = 0
  end

  result = "\n"
  result += " " + (color? ? GLYPHS[:em_dash] : "-") * dash_length + " "
  result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:white] : ""
  result += str
  result += color? ? ANSI_CODES[:reset] : ""
  result += " " + (color? ? GLYPHS[:em_dash] : "-") * dash_length + " "
  result += "\n\n"

  print_or_return(result, opts[:print])
end

#interactive?Boolean

#
Interactivity
#

Returns:

  • (Boolean)


213
214
215
# File 'lib/inspec/ui.rb', line 213

def interactive?
  @interactive
end

#line(opts = { print: true }) ⇒ Object

Draws a horizontal line.



139
140
141
142
143
144
145
146
# File 'lib/inspec/ui.rb', line 139

def line(opts = { print: true })
  if color?
    result = ANSI_CODES[:bold] + GLYPHS[:heavy_dash] * 80 + ANSI_CODES[:reset] + "\n"
  else
    result = "-" * 80 + "\n"
  end
  print_or_return(result, opts[:print])
end

#line_with_width(width = 80, opts = { print: true }) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/inspec/ui.rb', line 148

def line_with_width(width = 80, opts = { print: true } )
  if color?
    result = ANSI_CODES[:bold] + GLYPHS[:heavy_dash] * width + ANSI_CODES[:reset] + "\n"
  else
    result = "-" * width + "\n"
  end
  print_or_return(result, opts[:print])
end

#list_item(str, opts = { print: true }) ⇒ Object

Makes a bullet point.



158
159
160
161
162
# File 'lib/inspec/ui.rb', line 158

def list_item(str, opts = { print: true })
  bullet = color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:white] + GLYPHS[:bullet] + ANSI_CODES[:reset] : "*"
  result = " " + bullet + " " + str.to_s + "\n"
  print_or_return(result, opts[:print])
end

#plain(str, opts = { print: true }) ⇒ Object

#
Low-level formatting methods
#


64
65
66
# File 'lib/inspec/ui.rb', line 64

def plain(str, opts = { print: true })
  print_or_return(str.to_s, opts[:print])
end

#plain_line(str = "", opts = { print: true }) ⇒ Object



68
69
70
# File 'lib/inspec/ui.rb', line 68

def plain_line(str = "", opts = { print: true })
  print_or_return(str.to_s + "\n", opts[:print])
end


55
56
57
58
# File 'lib/inspec/ui.rb', line 55

def print_or_return(str, print_flag)
  io.print(str) if print_flag
  str
end

#promptObject

This simply returns a TTY::Prompt object, gated on interactivity being enabled.



218
219
220
221
222
223
224
225
226
# File 'lib/inspec/ui.rb', line 218

def prompt
  unless interactive?
    raise Inspec::UserInteractionRequired, "Somthing is trying to ask the user a question, but interactivity is disabled."
  end

  require "tty-prompt"

  @prompt ||= TTY::Prompt.new
end

#table(opts = { print: true }) {|the_table| ... } ⇒ Object

Makes a table. Call with a block; block arg will be a TTY::Table object, with an extension for setting the header. Typical use: ui.table do |t|

 t.header = ['Name', 'Rank', 'Cereal Number']
 t << ['Crunch', 'Captain', 1]
 t << ['', '', 1]
end

Yields:

  • (the_table)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/inspec/ui.rb', line 172

def table(opts = { print: true })
  require "inspec/ui_table_helper"

  the_table = TableHelper.new
  yield(the_table)

  colorizer = proc do |data, row, _col|
    if color? && row == 0
      ANSI_CODES[:bold] + ANSI_CODES[:color][:white] + data.to_s + ANSI_CODES[:reset]
    else
      data
    end
  end
  render_mode = color? ? :unicode : :ascii
  padding = [0, 1, 0, 1] # T R B L
  result = the_table.render(render_mode, filter: colorizer, padding: padding) + "\n"
  print_or_return(result, opts[:print])
end

#warning(str, opts = { print: true }) ⇒ Object

Issues a one-line message, with ‘WARNING: ’ prepended in bold yellow.



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/inspec/ui.rb', line 126

def warning(str, opts = { print: true })
  str = str.dup.to_s
  result = ""
  result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:yellow] : ""
  result += "WARNING:"
  result += color? ? ANSI_CODES[:reset] : ""
  result += " "
  result += str
  result += "\n"
  print_or_return(result, opts[:print])
end