howzit 2.0.7 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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