howzit 2.0.7 → 2.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +4 -343
- data/bin/howzit +101 -83
- data/howzit.gemspec +2 -0
- data/lib/howzit/buildnote.rb +170 -19
- data/lib/howzit/colors.rb +3 -0
- data/lib/howzit/config.rb +62 -7
- data/lib/howzit/console_logger.rb +39 -1
- data/lib/howzit/hash.rb +2 -2
- data/lib/howzit/prompt.rb +6 -5
- data/lib/howzit/stringutils.rb +1 -1
- data/lib/howzit/task.rb +1 -0
- data/lib/howzit/topic.rb +21 -4
- data/lib/howzit/util.rb +10 -5
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +13 -0
- data/spec/cli_spec.rb +27 -0
- data/spec/spec_helper.rb +1 -0
- metadata +32 -3
- data/lib/howzit/buildnotes.rb +0 -1252
data/howzit.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
|
31
31
|
spec.add_development_dependency 'rubocop', '~> 0.28'
|
32
32
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
33
|
+
spec.add_development_dependency 'cli-test', '~> 1.0'
|
33
34
|
spec.add_development_dependency 'simplecov', '~> 0.9'
|
34
35
|
# spec.add_development_dependency 'codecov', '~> 0.1'
|
35
36
|
spec.add_development_dependency 'fuubar', '~> 2.0'
|
@@ -40,5 +41,6 @@ Gem::Specification.new do |spec|
|
|
40
41
|
|
41
42
|
spec.add_runtime_dependency 'mdless', '~> 1.0', '>= 1.0.28'
|
42
43
|
spec.add_runtime_dependency 'tty-screen', '~> 0.8'
|
44
|
+
spec.add_runtime_dependency 'tty-box', '~> 0.7'
|
43
45
|
# spec.add_runtime_dependency 'tty-prompt', '~> 0.23'
|
44
46
|
end
|
data/lib/howzit/buildnote.rb
CHANGED
@@ -7,10 +7,27 @@ module Howzit
|
|
7
7
|
|
8
8
|
attr_reader :metadata, :title
|
9
9
|
|
10
|
+
##
|
11
|
+
## Initialize a build note
|
12
|
+
##
|
13
|
+
## @param file [String] The path to the build note file
|
14
|
+
## @param args [Array] additional args
|
15
|
+
##
|
10
16
|
def initialize(file: nil, args: [])
|
11
17
|
@topics = []
|
12
|
-
|
13
|
-
|
18
|
+
if note_file.nil?
|
19
|
+
res = Prompt.yn('No build notes file found, create one?', default: true)
|
20
|
+
|
21
|
+
create_note if res
|
22
|
+
Process.exit 0
|
23
|
+
end
|
24
|
+
content = Util.read_file(note_file)
|
25
|
+
if content.nil? || content.empty?
|
26
|
+
Howzit.console.error("{br}No content found in build note (#{note_file}){x}".c)
|
27
|
+
Process.exit 1
|
28
|
+
else
|
29
|
+
@metadata = content.split(/^#/)[0].strip.get_metadata
|
30
|
+
end
|
14
31
|
|
15
32
|
read_help(file)
|
16
33
|
end
|
@@ -19,14 +36,25 @@ module Howzit
|
|
19
36
|
puts "#<Howzit::BuildNote @topics=[#{@topics.count}]>"
|
20
37
|
end
|
21
38
|
|
39
|
+
##
|
40
|
+
## Public method to begin processing the build note based on command line options
|
41
|
+
##
|
22
42
|
def run
|
23
43
|
process
|
24
44
|
end
|
25
45
|
|
46
|
+
##
|
47
|
+
## Public method to open build note in editor
|
48
|
+
##
|
26
49
|
def edit
|
27
50
|
edit_note
|
28
51
|
end
|
29
52
|
|
53
|
+
##
|
54
|
+
## Find a topic based on a fuzzy match
|
55
|
+
##
|
56
|
+
## @param term [String] The search term
|
57
|
+
##
|
30
58
|
def find_topic(term)
|
31
59
|
@topics.filter do |topic|
|
32
60
|
rx = term.to_rx
|
@@ -34,11 +62,19 @@ module Howzit
|
|
34
62
|
end
|
35
63
|
end
|
36
64
|
|
65
|
+
##
|
66
|
+
## Call grep on all topics, filtering out those that don't match
|
67
|
+
##
|
68
|
+
## @param term [String] The search pattern
|
69
|
+
##
|
37
70
|
def grep(term)
|
38
71
|
@topics.filter { |topic| topic.grep(term) }
|
39
72
|
end
|
40
73
|
|
41
74
|
# Output a list of topic titles
|
75
|
+
#
|
76
|
+
# @return [String] formatted list of topics in build note
|
77
|
+
#
|
42
78
|
def list
|
43
79
|
output = []
|
44
80
|
output.push("{bg}Topics:{x}\n".c)
|
@@ -48,14 +84,32 @@ module Howzit
|
|
48
84
|
output.join("\n")
|
49
85
|
end
|
50
86
|
|
87
|
+
|
88
|
+
##
|
89
|
+
## Return an array of topic titles
|
90
|
+
##
|
91
|
+
## @return [Array] array of topic titles
|
92
|
+
##
|
51
93
|
def list_topics
|
52
94
|
@topics.map { |topic| topic.title }
|
53
95
|
end
|
54
96
|
|
97
|
+
##
|
98
|
+
## Return a list of topic titles suitable for shell completion
|
99
|
+
##
|
100
|
+
## @return [String] newline-separated list of topic titles
|
101
|
+
##
|
55
102
|
def list_completions
|
56
103
|
list_topics.join("\n")
|
57
104
|
end
|
58
105
|
|
106
|
+
##
|
107
|
+
## Return a list of topics containing @directives,
|
108
|
+
## suitable for shell completion
|
109
|
+
##
|
110
|
+
## @return [String] newline-separated list of topic
|
111
|
+
## titles
|
112
|
+
##
|
59
113
|
def list_runnable_completions
|
60
114
|
output = []
|
61
115
|
@topics.each do |topic|
|
@@ -64,6 +118,12 @@ module Howzit
|
|
64
118
|
output.join("\n")
|
65
119
|
end
|
66
120
|
|
121
|
+
##
|
122
|
+
## Return a formatted list of topics containing
|
123
|
+
## @directives suitable for console output
|
124
|
+
##
|
125
|
+
## @return [String] formatted list
|
126
|
+
##
|
67
127
|
def list_runnable
|
68
128
|
output = []
|
69
129
|
output.push(%({bg}"Runnable" Topics:{x}\n).c)
|
@@ -82,6 +142,11 @@ module Howzit
|
|
82
142
|
output.join("\n")
|
83
143
|
end
|
84
144
|
|
145
|
+
##
|
146
|
+
## Read the help file contents
|
147
|
+
##
|
148
|
+
## @param file [String] The filepath
|
149
|
+
##
|
85
150
|
def read_file(file)
|
86
151
|
read_help_file(file)
|
87
152
|
end
|
@@ -89,7 +154,7 @@ module Howzit
|
|
89
154
|
# Create a buildnotes skeleton
|
90
155
|
def create_note
|
91
156
|
trap('SIGINT') do
|
92
|
-
Howzit.console.info "\
|
157
|
+
Howzit.console.info "\nCancelled"
|
93
158
|
exit!
|
94
159
|
end
|
95
160
|
default = !$stdout.isatty || Howzit.options[:default]
|
@@ -210,19 +275,33 @@ module Howzit
|
|
210
275
|
buildnotes.reverse
|
211
276
|
end
|
212
277
|
|
213
|
-
|
214
|
-
|
278
|
+
##
|
279
|
+
## Test if the filename matches the conditions to be a build note
|
280
|
+
##
|
281
|
+
## @param filename [String] The filename to test
|
282
|
+
##
|
283
|
+
## @return [Boolean] true if filename passes test
|
284
|
+
##
|
285
|
+
def build_note?(filename)
|
286
|
+
return false if filename.downcase !~ /^(howzit[^.]*|build[^.]+)/
|
287
|
+
|
215
288
|
return false if Howzit.config.should_ignore(filename)
|
289
|
+
|
216
290
|
true
|
217
291
|
end
|
218
292
|
|
293
|
+
##
|
294
|
+
## Glob current directory for valid build note filenames
|
295
|
+
##
|
296
|
+
## @return [String] file path
|
297
|
+
##
|
219
298
|
def glob_note
|
220
299
|
filename = nil
|
221
300
|
# Check for a build note file in the current folder. Filename must start
|
222
301
|
# with "build" and have an extension of txt, md, or markdown.
|
223
302
|
|
224
303
|
Dir.glob('*.{txt,md,markdown}').each do |f|
|
225
|
-
if
|
304
|
+
if build_note?(f)
|
226
305
|
filename = f
|
227
306
|
break
|
228
307
|
end
|
@@ -230,6 +309,13 @@ module Howzit
|
|
230
309
|
filename
|
231
310
|
end
|
232
311
|
|
312
|
+
##
|
313
|
+
## Search for a valid build note, checking current
|
314
|
+
## directory, git top level directory, and parent
|
315
|
+
## directories
|
316
|
+
##
|
317
|
+
## @return [String] filepath
|
318
|
+
##
|
233
319
|
def find_note_file
|
234
320
|
filename = glob_note
|
235
321
|
|
@@ -251,6 +337,11 @@ module Howzit
|
|
251
337
|
File.expand_path(filename)
|
252
338
|
end
|
253
339
|
|
340
|
+
##
|
341
|
+
## Search upstream directories for build notes
|
342
|
+
##
|
343
|
+
## @return [Array] array of build note paths
|
344
|
+
##
|
254
345
|
def read_upstream
|
255
346
|
buildnotes = glob_upstream
|
256
347
|
|
@@ -261,16 +352,23 @@ module Howzit
|
|
261
352
|
topics_dict
|
262
353
|
end
|
263
354
|
|
355
|
+
##
|
356
|
+
## Test to ensure that any `required` metadata in a
|
357
|
+
## template is fulfilled by the build note
|
358
|
+
##
|
359
|
+
## @param template [String] The template to read
|
360
|
+
## from
|
361
|
+
##
|
264
362
|
def ensure_requirements(template)
|
265
|
-
t_leader =
|
363
|
+
t_leader = Util.read_file(template).split(/^#/)[0].strip
|
266
364
|
if t_leader.length > 0
|
267
365
|
t_meta = t_leader.get_metadata
|
268
366
|
if t_meta.key?('required')
|
269
367
|
required = t_meta['required'].strip.split(/\s*,\s*/)
|
270
368
|
required.each do |req|
|
271
369
|
unless @metadata.keys.include?(req.downcase)
|
272
|
-
Howzit.console.error %({
|
273
|
-
Howzit.console.error %({
|
370
|
+
Howzit.console.error %({bRw}ERROR:{xbr} Missing required metadata key from template '{bw}#{File.basename(template, '.md')}{xr}'{x}).c
|
371
|
+
Howzit.console.error %({br}Please define {by}#{req.downcase}{xr} in build notes{x}).c
|
274
372
|
Process.exit 1
|
275
373
|
end
|
276
374
|
end
|
@@ -278,6 +376,11 @@ module Howzit
|
|
278
376
|
end
|
279
377
|
end
|
280
378
|
|
379
|
+
##
|
380
|
+
## Read a list of topics from an included template
|
381
|
+
##
|
382
|
+
## @param content [String] The template contents
|
383
|
+
##
|
281
384
|
def get_template_topics(content)
|
282
385
|
leader = content.split(/^#/)[0].strip
|
283
386
|
|
@@ -325,12 +428,18 @@ module Howzit
|
|
325
428
|
template_topics
|
326
429
|
end
|
327
430
|
|
328
|
-
|
329
|
-
|
431
|
+
##
|
432
|
+
## Import the contents of a filename as new topics
|
433
|
+
##
|
434
|
+
## @param mtch [MatchData] the filename match from
|
435
|
+
## the include directive
|
436
|
+
##
|
437
|
+
def include_file(mtch)
|
438
|
+
file = File.expand_path(mtch[1])
|
330
439
|
|
331
|
-
return
|
440
|
+
return mtch[0] unless File.exist?(file)
|
332
441
|
|
333
|
-
content =
|
442
|
+
content = Util.read_file(file)
|
334
443
|
home = ENV['HOME']
|
335
444
|
short_path = File.dirname(file.sub(/^#{home}/, '~'))
|
336
445
|
prefix = "#{short_path}/#{File.basename(file)}:"
|
@@ -343,8 +452,13 @@ module Howzit
|
|
343
452
|
end
|
344
453
|
end
|
345
454
|
|
455
|
+
##
|
456
|
+
## Get the title of the build note (top level header)
|
457
|
+
##
|
458
|
+
## @param truncate [Integer] Truncate to width
|
459
|
+
##
|
346
460
|
def note_title(truncate = 0)
|
347
|
-
help =
|
461
|
+
help = Util.read_file(note_file)
|
348
462
|
title = help.match(/(?:^(\S.*?)(?=\n==)|^# ?(.*?)$)/)
|
349
463
|
title = if title
|
350
464
|
title[1].nil? ? title[2] : title[1]
|
@@ -355,13 +469,24 @@ module Howzit
|
|
355
469
|
title && truncate.positive? ? title.trunc(truncate) : title
|
356
470
|
end
|
357
471
|
|
358
|
-
# Read in the build notes file and output a hash of
|
472
|
+
# Read in the build notes file and output a hash of
|
473
|
+
# "Title" => contents
|
474
|
+
#
|
475
|
+
# @param path [String] The build note path
|
476
|
+
#
|
477
|
+
# @return [Array] array of Topics
|
478
|
+
#
|
359
479
|
def read_help_file(path = nil)
|
360
480
|
topics = []
|
361
481
|
|
362
482
|
filename = path.nil? ? note_file : path
|
363
483
|
|
364
|
-
help =
|
484
|
+
help = Util.read_file(filename)
|
485
|
+
|
486
|
+
if help.nil? || help.empty?
|
487
|
+
Howzit.console.error("{br}No content found in #{filename}{x}".c)
|
488
|
+
Process.exit 1
|
489
|
+
end
|
365
490
|
|
366
491
|
@title = note_title
|
367
492
|
|
@@ -401,6 +526,11 @@ module Howzit
|
|
401
526
|
topics
|
402
527
|
end
|
403
528
|
|
529
|
+
##
|
530
|
+
## Read build note and include upstream topics
|
531
|
+
##
|
532
|
+
## @param path [String] The build note path
|
533
|
+
##
|
404
534
|
def read_help(path = nil)
|
405
535
|
@topics = read_help_file(path)
|
406
536
|
return unless path.nil? && Howzit.options[:include_upstream]
|
@@ -410,8 +540,17 @@ module Howzit
|
|
410
540
|
upstream_topics.each do |topic|
|
411
541
|
@topics.push(topic) unless find_topic(title.sub(/^.+:/, '')).count.positive?
|
412
542
|
end
|
543
|
+
|
544
|
+
if note_file && @topics.empty?
|
545
|
+
Howzit.console.error("{br}Note file found but no topics detected in #{note_file}{x}".c)
|
546
|
+
Process.exit 1
|
547
|
+
end
|
548
|
+
|
413
549
|
end
|
414
550
|
|
551
|
+
##
|
552
|
+
## Open build note in editor
|
553
|
+
##
|
415
554
|
def edit_note
|
416
555
|
editor = Howzit.options.fetch(:editor, ENV['EDITOR'])
|
417
556
|
|
@@ -429,7 +568,16 @@ module Howzit
|
|
429
568
|
end
|
430
569
|
end
|
431
570
|
|
432
|
-
|
571
|
+
##
|
572
|
+
## Run or print a topic
|
573
|
+
##
|
574
|
+
## @param topic [Topic] The topic
|
575
|
+
## @param run [Boolean] execute directives if
|
576
|
+
## true
|
577
|
+
## @param single [Boolean] is being output as a
|
578
|
+
## single topic
|
579
|
+
##
|
580
|
+
def process_topic(topic, run, single: false)
|
433
581
|
new_topic = topic.dup
|
434
582
|
|
435
583
|
# Handle variable replacement
|
@@ -443,6 +591,9 @@ module Howzit
|
|
443
591
|
output.nil? ? '' : output.join("\n")
|
444
592
|
end
|
445
593
|
|
594
|
+
##
|
595
|
+
## Search and process the build note
|
596
|
+
##
|
446
597
|
def process
|
447
598
|
output = []
|
448
599
|
|
@@ -535,10 +686,10 @@ module Howzit
|
|
535
686
|
|
536
687
|
if !topic_matches.empty?
|
537
688
|
# If we found a match
|
538
|
-
topic_matches.each { |topic_match| output.push(process_topic(topic_match, Howzit.options[:run], true)) }
|
689
|
+
topic_matches.each { |topic_match| output.push(process_topic(topic_match, Howzit.options[:run], single: true)) }
|
539
690
|
else
|
540
691
|
# If there's no argument or no match found, output all
|
541
|
-
topics.each { |k| output.push(process_topic(k, false, false)) }
|
692
|
+
topics.each { |k| output.push(process_topic(k, false, single: false)) }
|
542
693
|
end
|
543
694
|
Howzit.options[:paginate] = false if Howzit.options[:run]
|
544
695
|
Util.show(output.join("\n").strip, Howzit.options)
|
data/lib/howzit/colors.rb
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
module Howzit
|
5
5
|
# Terminal output color functions.
|
6
6
|
module Color
|
7
|
+
# Regexp to match excape sequences
|
7
8
|
ESCAPE_REGEX = /(?<=\[)(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+(?=m)/.freeze
|
9
|
+
|
8
10
|
# All available color names. Available as methods and string extensions.
|
9
11
|
#
|
10
12
|
# @example Use a color as a method. Color reset will be added to end of string.
|
@@ -79,6 +81,7 @@ module Howzit
|
|
79
81
|
[:default, '0;39']
|
80
82
|
].map(&:freeze).freeze
|
81
83
|
|
84
|
+
# Array of attribute keys only
|
82
85
|
ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
|
83
86
|
|
84
87
|
# Returns true if Howzit::Color supports the +feature+.
|
data/lib/howzit/config.rb
CHANGED
@@ -3,6 +3,7 @@ module Howzit
|
|
3
3
|
class Config
|
4
4
|
attr_reader :options
|
5
5
|
|
6
|
+
# Configuration defaults
|
6
7
|
DEFAULTS = {
|
7
8
|
color: true,
|
8
9
|
config_editor: ENV['EDITOR'] || nil,
|
@@ -22,18 +23,31 @@ module Howzit
|
|
22
23
|
wrap: 0
|
23
24
|
}.deep_freeze
|
24
25
|
|
26
|
+
##
|
27
|
+
## Initialize a config object
|
28
|
+
##
|
25
29
|
def initialize
|
26
30
|
load_options
|
27
31
|
end
|
28
32
|
|
33
|
+
##
|
34
|
+
## Write a config to a file
|
35
|
+
##
|
36
|
+
## @param config The configuration
|
37
|
+
##
|
29
38
|
def write_config(config)
|
30
39
|
File.open(config_file, 'w') { |f| f.puts config.to_yaml }
|
31
40
|
end
|
32
41
|
|
42
|
+
##
|
43
|
+
## Test if a file should be ignored based on YAML file
|
44
|
+
##
|
45
|
+
## @param filename The filename to test
|
46
|
+
##
|
33
47
|
def should_ignore(filename)
|
34
48
|
return false unless File.exist?(ignore_file)
|
35
49
|
|
36
|
-
@ignore_patterns ||= YAML.safe_load(
|
50
|
+
@ignore_patterns ||= YAML.safe_load(Util.read_file(ignore_file))
|
37
51
|
|
38
52
|
ignore = false
|
39
53
|
|
@@ -47,16 +61,29 @@ module Howzit
|
|
47
61
|
ignore
|
48
62
|
end
|
49
63
|
|
64
|
+
##
|
65
|
+
## Find the template folder
|
66
|
+
##
|
67
|
+
## @return [String] path to template folder
|
68
|
+
##
|
50
69
|
def template_folder
|
51
70
|
File.join(config_dir, 'templates')
|
52
71
|
end
|
53
72
|
|
73
|
+
##
|
74
|
+
## Initiate the editor for the config
|
75
|
+
##
|
54
76
|
def editor
|
55
77
|
edit_config(DEFAULTS)
|
56
78
|
end
|
57
79
|
|
58
80
|
private
|
59
81
|
|
82
|
+
##
|
83
|
+
## Load command line options
|
84
|
+
##
|
85
|
+
## @return [Hash] options with command line flags merged in
|
86
|
+
##
|
60
87
|
def load_options
|
61
88
|
Color.coloring = $stdout.isatty
|
62
89
|
flags = {
|
@@ -77,40 +104,68 @@ module Howzit
|
|
77
104
|
@options = flags.merge(config)
|
78
105
|
end
|
79
106
|
|
107
|
+
##
|
108
|
+
## Get the config directory
|
109
|
+
##
|
110
|
+
## @return [String] path to config directory
|
111
|
+
##
|
80
112
|
def config_dir
|
81
113
|
File.expand_path(CONFIG_DIR)
|
82
114
|
end
|
83
115
|
|
116
|
+
##
|
117
|
+
## Get the config file
|
118
|
+
##
|
119
|
+
## @return [String] path to config file
|
120
|
+
##
|
84
121
|
def config_file
|
85
122
|
File.join(config_dir, CONFIG_FILE)
|
86
123
|
end
|
87
124
|
|
125
|
+
##
|
126
|
+
## Get the ignore config file
|
127
|
+
##
|
128
|
+
## @return [String] path to ignore config file
|
129
|
+
##
|
88
130
|
def ignore_file
|
89
131
|
File.join(config_dir, IGNORE_FILE)
|
90
132
|
end
|
91
133
|
|
92
|
-
|
134
|
+
##
|
135
|
+
## Create a new config file (and directory if needed)
|
136
|
+
##
|
137
|
+
## @param default [Hash] default configuration to write
|
138
|
+
##
|
139
|
+
def create_config(default)
|
93
140
|
unless File.directory?(config_dir)
|
94
|
-
Howzit.
|
141
|
+
Howzit::ConsoleLogger.new(1).info "Creating config directory at #{config_dir}"
|
95
142
|
FileUtils.mkdir_p(config_dir)
|
96
143
|
end
|
97
144
|
|
98
145
|
unless File.exist?(config_file)
|
99
|
-
Howzit.
|
100
|
-
write_config(
|
146
|
+
Howzit::ConsoleLogger.new(1).info "Writing fresh config file to #{config_file}"
|
147
|
+
write_config(default)
|
101
148
|
end
|
102
149
|
config_file
|
103
150
|
end
|
104
151
|
|
152
|
+
##
|
153
|
+
## Load the config file
|
154
|
+
##
|
155
|
+
## @return [Hash] configuration object
|
156
|
+
##
|
105
157
|
def load_config
|
106
158
|
file = create_config(DEFAULTS)
|
107
|
-
config = YAML.load(
|
159
|
+
config = YAML.load(Util.read_file(file))
|
108
160
|
newconfig = config ? DEFAULTS.merge(config) : DEFAULTS
|
109
161
|
write_config(newconfig)
|
110
162
|
newconfig.dup
|
111
163
|
end
|
112
164
|
|
113
|
-
|
165
|
+
##
|
166
|
+
## Open the config in an editor
|
167
|
+
##
|
168
|
+
def edit_config
|
114
169
|
editor = Howzit.options.fetch(:config_editor, ENV['EDITOR'])
|
115
170
|
|
116
171
|
raise 'No config_editor defined' if editor.nil?
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Available log levels
|
3
4
|
LOG_LEVELS = {
|
4
5
|
debug: 0,
|
5
6
|
info: 1,
|
@@ -12,30 +13,67 @@ module Howzit
|
|
12
13
|
class ConsoleLogger
|
13
14
|
attr_accessor :log_level
|
14
15
|
|
16
|
+
##
|
17
|
+
## Init the console logging object
|
18
|
+
##
|
19
|
+
## @param level [Integer] log level
|
20
|
+
##
|
15
21
|
def initialize(level = nil)
|
16
|
-
@log_level = level || Howzit.options[:log_level]
|
22
|
+
@log_level = level.to_i || Howzit.options[:log_level]
|
17
23
|
end
|
18
24
|
|
25
|
+
##
|
26
|
+
## Get the log level from options
|
27
|
+
##
|
28
|
+
## @return [Integer] log level
|
29
|
+
##
|
19
30
|
def reset_level
|
20
31
|
@log_level = Howzit.options[:log_level]
|
21
32
|
end
|
22
33
|
|
34
|
+
##
|
35
|
+
## Write a message to the console based on the urgency
|
36
|
+
## level and user's log level setting
|
37
|
+
##
|
38
|
+
## @param msg [String] The message
|
39
|
+
## @param level [Symbol] The level
|
40
|
+
##
|
23
41
|
def write(msg, level = :info)
|
24
42
|
$stderr.puts msg if LOG_LEVELS[level] >= @log_level
|
25
43
|
end
|
26
44
|
|
45
|
+
##
|
46
|
+
## Write a message at debug level
|
47
|
+
##
|
48
|
+
## @param msg The message
|
49
|
+
##
|
27
50
|
def debug(msg)
|
28
51
|
write msg, :debug
|
29
52
|
end
|
30
53
|
|
54
|
+
##
|
55
|
+
## Write a message at info level
|
56
|
+
##
|
57
|
+
## @param msg The message
|
58
|
+
##
|
31
59
|
def info(msg)
|
32
60
|
write msg, :info
|
33
61
|
end
|
34
62
|
|
63
|
+
##
|
64
|
+
## Write a message at warn level
|
65
|
+
##
|
66
|
+
## @param msg The message
|
67
|
+
##
|
35
68
|
def warn(msg)
|
36
69
|
write msg, :warn
|
37
70
|
end
|
38
71
|
|
72
|
+
##
|
73
|
+
## Write a message at error level
|
74
|
+
##
|
75
|
+
## @param msg The message
|
76
|
+
##
|
39
77
|
def error(msg)
|
40
78
|
write msg, :error
|
41
79
|
end
|
data/lib/howzit/hash.rb
CHANGED
@@ -41,7 +41,7 @@ class ::Hash
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def stringify_keys!
|
44
|
-
|
44
|
+
replace stringify_keys
|
45
45
|
end
|
46
46
|
|
47
47
|
# Turn all keys into symbols
|
@@ -50,6 +50,6 @@ class ::Hash
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def symbolize_keys!
|
53
|
-
|
53
|
+
replace symbolize_keys
|
54
54
|
end
|
55
55
|
end
|
data/lib/howzit/prompt.rb
CHANGED
@@ -8,14 +8,15 @@ module Howzit
|
|
8
8
|
return default unless $stdout.isatty
|
9
9
|
|
10
10
|
return default if Howzit.options[:default]
|
11
|
-
|
12
|
-
system 'stty cbreak'
|
11
|
+
tty_state = `stty -g`
|
12
|
+
system 'stty raw -echo cbreak isig'
|
13
13
|
yn = color_single_options(default ? %w[Y n] : %w[y N])
|
14
14
|
$stdout.syswrite "\e[1;37m#{prompt} #{yn}\e[1;37m? \e[0m"
|
15
15
|
res = $stdin.sysread 1
|
16
16
|
res.chomp!
|
17
17
|
puts
|
18
18
|
system 'stty cooked'
|
19
|
+
system "stty #{tty_state}"
|
19
20
|
res.empty? ? default : res =~ /y/i
|
20
21
|
end
|
21
22
|
|
@@ -24,12 +25,12 @@ module Howzit
|
|
24
25
|
choices.each do |choice|
|
25
26
|
case choice
|
26
27
|
when /[A-Z]/
|
27
|
-
out.push(Color.template("{
|
28
|
+
out.push(Color.template("{bw}#{choice}{x}"))
|
28
29
|
else
|
29
|
-
out.push(Color.template("{
|
30
|
+
out.push(Color.template("{dw}#{choice}{xg}"))
|
30
31
|
end
|
31
32
|
end
|
32
|
-
Color.template("{
|
33
|
+
Color.template("{xg}[#{out.join('/')}{xg}]{x}")
|
33
34
|
end
|
34
35
|
|
35
36
|
def options_list(matches)
|
data/lib/howzit/stringutils.rb
CHANGED