console-glitter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/console-glitter.rb +152 -0
- data/lib/console-glitter/ansi.rb +148 -0
- data/lib/console-glitter/version.rb +3 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c6dc7f133fc08089409ca94c2faccc434cfadc80
|
4
|
+
data.tar.gz: e7ded778c22128e5378af28f24c1463cc8616aed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd4af9e20d868a6159feb8f728df53b9ff45e84524054690df857fc2adbb2c7b0a6392e044ab2fbf41107769a25196779d6f34b9a939f95b132b352857c1ecb2
|
7
|
+
data.tar.gz: 29da738fc607e8016e35cc67118957141174407bbfc82dbccf68af8d99a635808ae79ec24ba1b7144a97e4cd0572150b555d1b232aa97d91ae59e95d201438ee
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'console-glitter/version'
|
2
|
+
require 'console-glitter/ansi'
|
3
|
+
|
4
|
+
module ConsoleGlitter
|
5
|
+
module UI extend self
|
6
|
+
extend ANSI
|
7
|
+
# Public: Prompt user for input, allowing for a default answer and a list
|
8
|
+
# of valid responses to be provided.
|
9
|
+
#
|
10
|
+
# question - Query to be presented to the user.
|
11
|
+
# options - Hash containing arguments defining acceptable responses.
|
12
|
+
# (default: {}):
|
13
|
+
# :default_answer - String containing the default answer. If
|
14
|
+
# this is nil, a non-empty answer MUST be
|
15
|
+
# given.
|
16
|
+
# :allow_empty - Whether or not to allow empty responses.
|
17
|
+
# Unless explicitly allowed, empty answers
|
18
|
+
# will be rejected.
|
19
|
+
# :valid_answers - An Array containing all valid responses. If
|
20
|
+
# this is empty, any answer will be accepted
|
21
|
+
# (except empty answers as specified above).
|
22
|
+
#
|
23
|
+
# Returns a String containing the answer provided by the user.
|
24
|
+
def prompt(question, options = {})
|
25
|
+
default = options[:default_answer].to_s
|
26
|
+
allow_empty = options[:allow_empty]
|
27
|
+
valid = options[:valid_answers] || []
|
28
|
+
|
29
|
+
default_display = " [#{default.strip}]" unless default.empty?
|
30
|
+
question.strip!
|
31
|
+
|
32
|
+
answer = nil
|
33
|
+
while answer.nil?
|
34
|
+
print "#{question}#{default_display}> "
|
35
|
+
answer = $stdin.readline.strip
|
36
|
+
answer = default if answer.empty?
|
37
|
+
|
38
|
+
if answer.empty?
|
39
|
+
answer = nil unless allow_empty
|
40
|
+
elsif valid.any?
|
41
|
+
answer = nil unless valid.grep(answer).any?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
answer
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Wrap Console#prompt but accept only a Y/N response.
|
49
|
+
#
|
50
|
+
# question - String containing the question to present to the user.
|
51
|
+
# args - Hash containing arguments to control acceptable responses.
|
52
|
+
# (default: {}):
|
53
|
+
# :default_answer - String containing the default answer.
|
54
|
+
#
|
55
|
+
# Returns true or false corresponding to Y or N answer respectively.
|
56
|
+
def prompt_yn(question, args = {})
|
57
|
+
args[:valid_answers] = []
|
58
|
+
answer = nil
|
59
|
+
|
60
|
+
until answer =~ /^[yn]/i
|
61
|
+
answer = prompt(question, args)
|
62
|
+
end
|
63
|
+
|
64
|
+
/^n/i.match(answer).nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Render a "spinner" on the command line and yield to a block,
|
68
|
+
# reporting success if nothing is raised, or else reporting failure.
|
69
|
+
#
|
70
|
+
# message - Message to be displayed describing the task being evaluated.
|
71
|
+
# block - Block to be yielded to determine pass or fail.
|
72
|
+
#
|
73
|
+
# Returns the result of the yielded block if successful.
|
74
|
+
# Raises whatever is raised inside the yielded block.
|
75
|
+
def spinner(message, &block)
|
76
|
+
success = nil
|
77
|
+
result = nil
|
78
|
+
|
79
|
+
pre = "\r#{bold}#{white} [#{reset}"
|
80
|
+
post = "#{bold}#{white}] #{reset}#{message}"
|
81
|
+
pre_ok = "\r#{bold}#{white} [#{green} ok "
|
82
|
+
pre_fail = "\r#{bold}#{white} [#{red}fail"
|
83
|
+
|
84
|
+
thread = Thread.new do
|
85
|
+
step = 0
|
86
|
+
spin = [" ", ". ", ".. ", "... ", "....", " ...", " ..", " ."]
|
87
|
+
while success.nil?
|
88
|
+
print "#{pre}#{spin[step % 8]}#{post}"
|
89
|
+
step += 1
|
90
|
+
sleep 0.5
|
91
|
+
end
|
92
|
+
|
93
|
+
if success
|
94
|
+
print "#{pre_ok}#{post}\n"
|
95
|
+
else
|
96
|
+
print "#{pre_fail}#{post}\n"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
begin
|
101
|
+
result = yield
|
102
|
+
success = true
|
103
|
+
thread.join
|
104
|
+
return result
|
105
|
+
rescue
|
106
|
+
success = false
|
107
|
+
thread.join
|
108
|
+
raise
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: Generate a formatted, printable table.
|
113
|
+
#
|
114
|
+
# rows - An Array containing Hashes which contain desired options to
|
115
|
+
# display. (e.g. [{"col1" => "a", "col2" => "b"}])
|
116
|
+
# labels - Hash containing key-value pairs to label each key in options.
|
117
|
+
# (default: nil)
|
118
|
+
#
|
119
|
+
# Returns a String containing the grid.
|
120
|
+
# Raises ArgumentError if anything but an Array is passed as rows.
|
121
|
+
def build_grid(rows, labels = nil)
|
122
|
+
if labels.nil?
|
123
|
+
labels = rows[0].keys.reduce({}) { |c,e| c.merge({e => e}) }
|
124
|
+
end
|
125
|
+
|
126
|
+
keys = labels.keys
|
127
|
+
|
128
|
+
max_width = labels.reduce({}) do |c,e|
|
129
|
+
c.merge({e[0]=> ([labels] + rows).map { |r| r[e[0]].length }.max})
|
130
|
+
end
|
131
|
+
|
132
|
+
grid_rule = max_width.reduce('+') do |c,e|
|
133
|
+
c + ('-' * (e[1] + 2)) + '+'
|
134
|
+
end
|
135
|
+
grid_rule << "\n"
|
136
|
+
|
137
|
+
grid = grid_rule.dup
|
138
|
+
grid << keys.reduce('|') do |c,e|
|
139
|
+
c + " #{bold}% #{max_width[e]}s#{reset} |" % labels[e]
|
140
|
+
end
|
141
|
+
grid << "\n"
|
142
|
+
|
143
|
+
grid << rows.reduce(grid_rule) do |c,e|
|
144
|
+
content = keys.reduce('') do |s,k|
|
145
|
+
s + " % #{max_width[k]}s |" % e[k]
|
146
|
+
end
|
147
|
+
c + "|#{content}\n"
|
148
|
+
end
|
149
|
+
grid << grid_rule
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module ConsoleGlitter
|
2
|
+
module ANSI extend self
|
3
|
+
# Public: Return an appropriate escape sequence depending upon the current
|
4
|
+
# platform.
|
5
|
+
#
|
6
|
+
# sequence - Control code(s) to be escaped. Multiple codes may be chained,
|
7
|
+
# separated by ';'.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# ConsoleGlitter::ANSI.escape 0
|
12
|
+
# # => "\033[0m"
|
13
|
+
#
|
14
|
+
# Returns a String.
|
15
|
+
def escape(sequence)
|
16
|
+
RUBY_PLATFORM =~ /win/i ? '' : "\033[#{sequence}m"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Generate an escape sequence to set the foreground color to an
|
20
|
+
# approximation of a 4 or 8 bit per channel hex RGB color a la CSS.
|
21
|
+
#
|
22
|
+
# color - String containing hex digits describing the color to convert.
|
23
|
+
# May be 4 or 8 bits per channel (3 or 6 characters long,
|
24
|
+
# respectively).
|
25
|
+
#
|
26
|
+
# Examples
|
27
|
+
#
|
28
|
+
# ConsoleGlitter::ANSI.hex_color("00FFFF")
|
29
|
+
# # => "\033[38;5;51m"
|
30
|
+
# ConsoleGlitter::ANSI.hex_color("F0F")
|
31
|
+
# # => "\033[38;5;201m"
|
32
|
+
#
|
33
|
+
# Returns the appropriate escape code as a Fixnum.
|
34
|
+
def hex_color(color)
|
35
|
+
escape [38, 5, closest(color)].join(';')
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: Generate an escape sequence to set the bg color to an
|
39
|
+
# approximation of a 4 or 8 bit per channel hex RGB color a la CSS.
|
40
|
+
#
|
41
|
+
# color - String containing hex digits describing the color to convert.
|
42
|
+
# May be 4 or 8 bits per channel (3 or 6 characters long,
|
43
|
+
# respectively).
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# ConsoleGlitter::ANSI.bg_hex_color("00FFFF")
|
48
|
+
# # => "\033[38;5;51m"
|
49
|
+
# ConsoleGlitter::ANSI.bg_hex_color("F0F")
|
50
|
+
# # => "\033[38;5;201m"
|
51
|
+
#
|
52
|
+
# Returns the appropriate escape code as a Fixnum.
|
53
|
+
def bg_hex_color(color)
|
54
|
+
escape [48, 5, closest(color)].join(';')
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Internal: Allow on-the-fly definition of ANSI control sequences. Methods
|
60
|
+
# are created for convenience which will either wrap the result of a block
|
61
|
+
# in the tag specified and a reset tag, or else simply return the code in
|
62
|
+
# question.
|
63
|
+
#
|
64
|
+
# name - String or Symbol containing the name of the constant to be
|
65
|
+
# defined.
|
66
|
+
# code - ANSI escape code to be saved.
|
67
|
+
#
|
68
|
+
# Returns nothing.
|
69
|
+
#
|
70
|
+
# Signature
|
71
|
+
#
|
72
|
+
# <name>(block)
|
73
|
+
#
|
74
|
+
# name - Name specified.
|
75
|
+
# block - Optional block to be evaluated, the result of which will placed
|
76
|
+
# in between the escape code specified.
|
77
|
+
def ansi(name, code)
|
78
|
+
code = escape(code)
|
79
|
+
|
80
|
+
define_method(name.to_sym) do |&block|
|
81
|
+
if block
|
82
|
+
"#{code}#{block.call}#{reset}"
|
83
|
+
else
|
84
|
+
code
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Internal: Parse a string describing either a 4 or 8 bit-per-channel color
|
90
|
+
# (similar to CSS formatting), matching it with the closest approximation
|
91
|
+
# for 256 color mode.
|
92
|
+
#
|
93
|
+
# color - String containing hex digits describing the color to convert.
|
94
|
+
# May be 4 or 8 bits per channel (3 or 6 characters long,
|
95
|
+
# respectively).
|
96
|
+
#
|
97
|
+
# Examples
|
98
|
+
#
|
99
|
+
# ConsoleGlitter::ANSI.closest("00FFFF")
|
100
|
+
# # => 51
|
101
|
+
# ConsoleGlitter::ANSI.closest("F0F")
|
102
|
+
# # => 201
|
103
|
+
#
|
104
|
+
# Returns the appropriate escape code as a Fixnum.
|
105
|
+
def closest(color)
|
106
|
+
bpc = 4
|
107
|
+
bpc *= 2 if color.length > 3
|
108
|
+
color = color.to_i(16)
|
109
|
+
|
110
|
+
blue = color % (1 << bpc)
|
111
|
+
green = ((color - blue) % (1 << (bpc * 2))) >> bpc
|
112
|
+
red = (color - (blue + green)) >> (bpc * 2)
|
113
|
+
|
114
|
+
# 216 (6**3) colors are mapped in 256 color mode (40 colors are otherwise
|
115
|
+
# reserved for normal and bold standard colors from 0x00 to 0x0f in
|
116
|
+
# addition to a 24 color gradient from black to white from 0xe8 - 0xff.)
|
117
|
+
[blue,green,red].each_with_index.map do |c,i|
|
118
|
+
(c/(((1 << bpc)-1)/5)) * 6**i
|
119
|
+
end.
|
120
|
+
reduce(&:+) + 0x10
|
121
|
+
end
|
122
|
+
|
123
|
+
# Define most common ANSI sequences
|
124
|
+
ansi :reset, 0
|
125
|
+
ansi :bold, 1
|
126
|
+
ansi :faint, 2
|
127
|
+
ansi :underline, 4
|
128
|
+
ansi :blink, 5
|
129
|
+
|
130
|
+
ansi :black, 30
|
131
|
+
ansi :red, 31
|
132
|
+
ansi :green, 32
|
133
|
+
ansi :brown, 33
|
134
|
+
ansi :blue, 34
|
135
|
+
ansi :magenta, 35
|
136
|
+
ansi :cyan, 36
|
137
|
+
ansi :white, 37
|
138
|
+
|
139
|
+
ansi :bg_black, 40
|
140
|
+
ansi :bg_red, 41
|
141
|
+
ansi :bg_green, 42
|
142
|
+
ansi :bg_brown, 43
|
143
|
+
ansi :bg_blue, 44
|
144
|
+
ansi :bg_magenta, 45
|
145
|
+
ansi :bg_cyan, 46
|
146
|
+
ansi :bg_white, 47
|
147
|
+
end
|
148
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: console-glitter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Wuest
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Tools for building nice looking CLI applications
|
14
|
+
email: chris@chriswuest.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/console-glitter.rb
|
20
|
+
- lib/console-glitter/ansi.rb
|
21
|
+
- lib/console-glitter/version.rb
|
22
|
+
homepage: http://github.com/cwuest/console-glitter
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.0.5
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Tools for prettier CLI apps
|
46
|
+
test_files: []
|
47
|
+
has_rdoc:
|