howzit 2.0.6 → 2.0.9

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.
@@ -10,7 +10,7 @@ module Howzit
10
10
  def initialize(file: nil, args: [])
11
11
  @topics = []
12
12
  create_note if note_file.nil?
13
- @metadata = IO.read(note_file).split(/^#/)[0].strip.get_metadata
13
+ @metadata = Util.read_file(note_file).split(/^#/)[0].strip.get_metadata
14
14
 
15
15
  read_help(file)
16
16
  end
@@ -89,7 +89,7 @@ module Howzit
89
89
  # Create a buildnotes skeleton
90
90
  def create_note
91
91
  trap('SIGINT') do
92
- warn "\nCanceled"
92
+ Howzit.console.info "\nCancelled"
93
93
  exit!
94
94
  end
95
95
  default = !$stdout.isatty || Howzit.options[:default]
@@ -210,9 +210,11 @@ module Howzit
210
210
  buildnotes.reverse
211
211
  end
212
212
 
213
- def is_build_notes(filename)
214
- return false if filename.downcase !~ /(^howzit[^.]*|build[^.]+)/
213
+ def build_note?(filename)
214
+ return false if filename.downcase !~ /^(howzit[^.]*|build[^.]+)/
215
+
215
216
  return false if Howzit.config.should_ignore(filename)
217
+
216
218
  true
217
219
  end
218
220
 
@@ -222,7 +224,7 @@ module Howzit
222
224
  # with "build" and have an extension of txt, md, or markdown.
223
225
 
224
226
  Dir.glob('*.{txt,md,markdown}').each do |f|
225
- if is_build_notes(f)
227
+ if build_note?(f)
226
228
  filename = f
227
229
  break
228
230
  end
@@ -262,15 +264,15 @@ module Howzit
262
264
  end
263
265
 
264
266
  def ensure_requirements(template)
265
- t_leader = IO.read(template).split(/^#/)[0].strip
267
+ t_leader = Util.read_file(template).split(/^#/)[0].strip
266
268
  if t_leader.length > 0
267
269
  t_meta = t_leader.get_metadata
268
270
  if t_meta.key?('required')
269
271
  required = t_meta['required'].strip.split(/\s*,\s*/)
270
272
  required.each do |req|
271
273
  unless @metadata.keys.include?(req.downcase)
272
- warn %({xr}ERROR: Missing required metadata key from template '{bw}#{File.basename(template, '.md')}{xr}'{x}).c
273
- warn %({xr}Please define {by}#{req.downcase}{xr} in build notes{x}).c
274
+ Howzit.console.error %({xr}ERROR: Missing required metadata key from template '{bw}#{File.basename(template, '.md')}{xr}'{x}).c
275
+ Howzit.console.error %({xr}Please define {by}#{req.downcase}{xr} in build notes{x}).c
274
276
  Process.exit 1
275
277
  end
276
278
  end
@@ -330,7 +332,7 @@ module Howzit
330
332
 
331
333
  return m[0] unless File.exist?(file)
332
334
 
333
- content = IO.read(file)
335
+ content = Util.read_file(file)
334
336
  home = ENV['HOME']
335
337
  short_path = File.dirname(file.sub(/^#{home}/, '~'))
336
338
  prefix = "#{short_path}/#{File.basename(file)}:"
@@ -344,7 +346,7 @@ module Howzit
344
346
  end
345
347
 
346
348
  def note_title(truncate = 0)
347
- help = IO.read(note_file).strip
349
+ help = Util.read_file(note_file)
348
350
  title = help.match(/(?:^(\S.*?)(?=\n==)|^# ?(.*?)$)/)
349
351
  title = if title
350
352
  title[1].nil? ? title[2] : title[1]
@@ -361,7 +363,7 @@ module Howzit
361
363
 
362
364
  filename = path.nil? ? note_file : path
363
365
 
364
- help = IO.read(filename)
366
+ help = Util.read_file(filename)
365
367
 
366
368
  @title = note_title
367
369
 
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(IO.read(ignore_file))
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
- def create_config(d)
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
- warn "Creating config directory at #{config_dir}"
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
- warn "Writing fresh config file to #{config_file}"
100
- write_config(d)
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(IO.read(file))
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
- def edit_config(d)
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?
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ LOG_LEVELS = {
4
+ debug: 0,
5
+ info: 1,
6
+ warn: 2,
7
+ error: 3
8
+ }.deep_freeze
9
+
10
+ module Howzit
11
+ # Console logging
12
+ class ConsoleLogger
13
+ attr_accessor :log_level
14
+
15
+ ##
16
+ ## Init the console logging object
17
+ ##
18
+ ## @param level [Integer] log level
19
+ ##
20
+ def initialize(level = nil)
21
+ @log_level = level.to_i || Howzit.options[:log_level]
22
+ end
23
+
24
+ ##
25
+ ## Get the log level from options
26
+ ##
27
+ ## @return [Integer] log level
28
+ ##
29
+ def reset_level
30
+ @log_level = Howzit.options[:log_level]
31
+ end
32
+
33
+ ##
34
+ ## Write a message to the console based on the urgency
35
+ ## level and user's log level setting
36
+ ##
37
+ ## @param msg [String] The message
38
+ ## @param level [Symbol] The level
39
+ ##
40
+ def write(msg, level = :info)
41
+ $stderr.puts msg if LOG_LEVELS[level] >= @log_level
42
+ end
43
+
44
+ ##
45
+ ## Write a message at debug level
46
+ ##
47
+ ## @param msg The message
48
+ ##
49
+ def debug(msg)
50
+ write msg, :debug
51
+ end
52
+
53
+ ##
54
+ ## Write a message at info level
55
+ ##
56
+ ## @param msg The message
57
+ ##
58
+ def info(msg)
59
+ write msg, :info
60
+ end
61
+
62
+ ##
63
+ ## Write a message at warn level
64
+ ##
65
+ ## @param msg The message
66
+ ##
67
+ def warn(msg)
68
+ write msg, :warn
69
+ end
70
+
71
+ ##
72
+ ## Write a message at error level
73
+ ##
74
+ ## @param msg The message
75
+ ##
76
+ def error(msg)
77
+ write msg, :error
78
+ end
79
+ end
80
+ 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("{bg}#{choice}{xg}"))
28
+ out.push(Color.template("{bw}#{choice}{x}"))
28
29
  else
29
- out.push(Color.template("{w}#{choice}"))
30
+ out.push(Color.template("{dw}#{choice}{xg}"))
30
31
  end
31
32
  end
32
- Color.template("{g}[#{out.join('/')}{g}]{x}")
33
+ Color.template("{xg}[#{out.join('/')}{xg}]{x}")
33
34
  end
34
35
 
35
36
  def options_list(matches)
@@ -54,7 +55,7 @@ module Howzit
54
55
  ]
55
56
  res = `echo #{Shellwords.escape(matches.join("\n"))} | fzf #{settings.join(' ')}`.strip
56
57
  if res.nil? || res.empty?
57
- warn 'Cancelled'
58
+ Howzit.console.info 'Cancelled'
58
59
  Process.exit 0
59
60
  end
60
61
  return res.split(/\n/)
@@ -147,7 +147,7 @@ module Howzit
147
147
 
148
148
  def extract_metadata
149
149
  if File.exist?(self)
150
- leader = IO.read(self).split(/^#/)[0].strip
150
+ leader = Util.read_file(self).split(/^#/)[0].strip
151
151
  leader.length > 0 ? leader.get_metadata : {}
152
152
  else
153
153
  {}
data/lib/howzit/task.rb CHANGED
@@ -13,6 +13,10 @@ module Howzit
13
13
  @default = default
14
14
  end
15
15
 
16
+ def inspect
17
+ %(<#Howzit::Task @type=:#{@type} @title="#{@title}" @block?=#{@action.split(/\n/).count > 1}>)
18
+ end
19
+
16
20
  def to_s
17
21
  @title
18
22
  end
data/lib/howzit/topic.rb CHANGED
@@ -9,6 +9,12 @@ module Howzit
9
9
 
10
10
  attr_reader :title, :tasks, :prereqs, :postreqs
11
11
 
12
+ ##
13
+ ## Initialize a topic object
14
+ ##
15
+ ## @param title [String] The topic title
16
+ ## @param content [String] The raw topic content
17
+ ##
12
18
  def initialize(title, content)
13
19
  @title = title
14
20
  @content = content
@@ -17,18 +23,29 @@ module Howzit
17
23
  @tasks = gather_tasks
18
24
  end
19
25
 
26
+ ##
27
+ ## Search title and contents for a pattern
28
+ ##
29
+ ## @param term [String] the search pattern
30
+ ##
20
31
  def grep(term)
21
32
  @title =~ /#{term}/i || @content =~ /#{term}/i
22
33
  end
23
34
 
24
- # Handle run command, execute directives
35
+ # Handle run command, execute directives in topic
25
36
  def run(nested: false)
26
37
  output = []
27
38
  tasks = 0
39
+ cols = begin
40
+ TTY::Screen.columns > 60 ? 60 : TTY::Screen.columns
41
+ rescue StandardError
42
+ 60
43
+ end
44
+
28
45
  if @tasks.count.positive?
29
46
  unless @prereqs.empty?
30
- puts @prereqs.join("\n\n")
31
- res = Prompt.yn('This topic has prerequisites, have they been met?', default: true)
47
+ puts TTY::Box.frame("{by}#{@prereqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols)
48
+ res = Prompt.yn('Have the above prerequisites been met?', default: true)
32
49
  Process.exit 1 unless res
33
50
 
34
51
  end
@@ -42,7 +59,7 @@ module Howzit
42
59
  end
43
60
 
44
61
  if task.type == :block
45
- warn "{bg}Running block {bw}#{title}{x}".c if Howzit.options[:log_level] < 2
62
+ Howzit.console.info "{bg}Running block {bw}#{title}{x}".c if Howzit.options[:log_level] < 2
46
63
  block = task.action
47
64
  script = Tempfile.new('howzit_script')
48
65
  begin
@@ -81,11 +98,11 @@ module Howzit
81
98
  end
82
99
  end
83
100
  else
84
- warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
101
+ Howzit.console.warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
85
102
  end
86
103
  output.push("{bm}Ran #{tasks} #{tasks == 1 ? 'task' : 'tasks'}{x}".c) if Howzit.options[:log_level] < 2 && !nested
87
104
 
88
- puts postreqs.join("\n\n") unless postreqs.empty?
105
+ puts TTY::Box.frame("{bw}#{@postreqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols) unless @postreqs.empty?
89
106
 
90
107
  output
91
108
  end
@@ -95,21 +112,21 @@ module Howzit
95
112
  out = "{bg}Copying {bw}#{string}".c
96
113
  case os
97
114
  when /darwin.*/i
98
- warn "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
115
+ $stderr.puts "#{out} (macOS){x}".c if Howzit.options[:log_level].zero?
99
116
  `echo #{Shellwords.escape(string)}'\\c'|pbcopy`
100
117
  when /mingw|mswin/i
101
- warn "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
118
+ $stderr.puts "#{out} (Windows){x}".c if Howzit.options[:log_level].zero?
102
119
  `echo #{Shellwords.escape(string)} | clip`
103
120
  else
104
121
  if 'xsel'.available?
105
- warn "#{out} (Linux, xsel){x}".c if Howzit.options[:log_level] < 2
122
+ $stderr.puts "#{out} (Linux, xsel){x}".c if Howzit.options[:log_level].zero?
106
123
  `echo #{Shellwords.escape(string)}'\\c'|xsel -i`
107
124
  elsif 'xclip'.available?
108
- warn "#{out} (Linux, xclip){x}".c if Howzit.options[:log_level] < 2
125
+ $stderr.puts "#{out} (Linux, xclip){x}".c if Howzit.options[:log_level].zero?
109
126
  `echo #{Shellwords.escape(string)}'\\c'|xclip -i`
110
127
  else
111
- warn out if Howzit.options[:log_level] < 2
112
- warn 'Unable to determine executable for clipboard.'
128
+ $stderr.puts out if Howzit.options[:log_level].zero?
129
+ $stderr.puts 'Unable to determine executable for clipboard.'
113
130
  end
114
131
  end
115
132
  end
@@ -119,18 +136,18 @@ module Howzit
119
136
  out = "{bg}Opening {bw}#{command}".c
120
137
  case os
121
138
  when /darwin.*/i
122
- warn "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
139
+ Howzit.console.debug "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
123
140
  `open #{Shellwords.escape(command)}`
124
141
  when /mingw|mswin/i
125
- warn "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
142
+ Howzit.console.debug "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
126
143
  `start #{Shellwords.escape(command)}`
127
144
  else
128
145
  if 'xdg-open'.available?
129
- warn "#{out} (Linux){x}".c if Howzit.options[:log_level] < 2
146
+ Howzit.console.debug "#{out} (Linux){x}".c if Howzit.options[:log_level] < 2
130
147
  `xdg-open #{Shellwords.escape(command)}`
131
148
  else
132
- warn out if Howzit.options[:log_level] < 2
133
- warn 'Unable to determine executable for `open`.'
149
+ Howzit.console.debug out if Howzit.options[:log_level] < 2
150
+ Howzit.console.debug 'Unable to determine executable for `open`.'
134
151
  end
135
152
  end
136
153
  end
data/lib/howzit/util.rb CHANGED
@@ -1,21 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Howzit
4
+ # Util class
2
5
  module Util
3
6
  class << self
7
+ def read_file(path)
8
+ IO.read(path).force_encoding('utf-8').strip
9
+ end
10
+
4
11
  def valid_command?(command)
5
12
  cmd = command.split(' ')[0]
6
13
  command_exist?(cmd)
7
14
  end
8
-
15
+
9
16
  def command_exist?(command)
10
17
  exts = ENV.fetch('PATHEXT', '').split(::File::PATH_SEPARATOR)
11
18
  if Pathname.new(command).absolute?
12
- ::File.exist?(command) ||
13
- exts.any? { |ext| ::File.exist?("#{command}#{ext}") }
19
+ ::File.exist?(command) || exts.any? { |ext| ::File.exist?("#{command}#{ext}") }
14
20
  else
15
21
  ENV.fetch('PATH', '').split(::File::PATH_SEPARATOR).any? do |dir|
16
22
  file = ::File.join(dir, command)
17
- ::File.exist?(file) ||
18
- exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
23
+ ::File.exist?(file) || exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
19
24
  end
20
25
  end
21
26
  end
@@ -40,7 +45,7 @@ module Howzit
40
45
  if hl.available?
41
46
  Howzit.options[:highlighter]
42
47
  else
43
- warn Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
48
+ Howzit.console.error Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
44
49
  Howzit.options[:highlighter] = 'auto'
45
50
  which_highlighter
46
51
  end
@@ -78,7 +83,7 @@ module Howzit
78
83
  if pg.available?
79
84
  Howzit.options[:pager]
80
85
  else
81
- warn Color.template("{Rw}Error:{xbw} Specified pager (#{Howzit.options[:pager]}) not found, switching to auto")
86
+ Howzit.console.error Color.template("{Rw}Error:{xbw} Specified pager (#{Howzit.options[:pager]}) not found, switching to auto")
82
87
  Howzit.options[:pager] = 'auto'
83
88
  which_pager
84
89
  end
@@ -104,7 +109,7 @@ module Howzit
104
109
  begin
105
110
  exec(pager)
106
111
  rescue SystemCallError => e
107
- @log.error(e)
112
+ Howzit.console.error(e)
108
113
  exit 1
109
114
  end
110
115
  end
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.0.6'
6
+ VERSION = '2.0.9'
7
7
  end
data/lib/howzit.rb CHANGED
@@ -5,8 +5,9 @@ require_relative 'howzit/prompt'
5
5
  require_relative 'howzit/colors'
6
6
  require_relative 'howzit/stringutils'
7
7
 
8
- require_relative 'howzit/util'
9
8
  require_relative 'howzit/hash'
9
+ require_relative 'howzit/console_logger'
10
+ require_relative 'howzit/util'
10
11
  require_relative 'howzit/config'
11
12
  require_relative 'howzit/task'
12
13
  require_relative 'howzit/topic'
@@ -20,6 +21,7 @@ require 'tempfile'
20
21
  require 'yaml'
21
22
 
22
23
  require 'tty/screen'
24
+ require 'tty/box'
23
25
  # require 'tty/prompt'
24
26
 
25
27
  CONFIG_DIR = '~/.config/howzit'
@@ -29,6 +31,7 @@ MATCHING_OPTIONS = %w[partial exact fuzzy beginswith].freeze
29
31
  MULTIPLE_OPTIONS = %w[first best all choose].freeze
30
32
  HEADER_FORMAT_OPTIONS = %w[border block].freeze
31
33
 
34
+ # Main module for howzit
32
35
  module Howzit
33
36
  class << self
34
37
  attr_accessor :arguments, :cli_args
@@ -52,5 +55,9 @@ module Howzit
52
55
  def buildnote
53
56
  @buildnote ||= BuildNote.new
54
57
  end
58
+
59
+ def console
60
+ @console ||= Howzit::ConsoleLogger.new(options[:log_level])
61
+ end
55
62
  end
56
63
  end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # https://github.com/thoiberg/cli-test
6
+ describe 'CLI' do
7
+ include CliTest
8
+
9
+ it 'executes successfully' do
10
+ execute_script('bin/howzit', use_bundler: true)
11
+ expect(last_execution).to be_successful
12
+ end
13
+
14
+ it 'lists available topics' do
15
+ execute_script('bin/howzit', use_bundler: true, args: %w[-L])
16
+ expect(last_execution).to be_successful
17
+ expect(last_execution.stdout).to match(/Topic Balogna/)
18
+ expect(last_execution.stdout.split(/\n/).count).to eq 3
19
+ end
20
+
21
+ it 'lists available tasks' do
22
+ execute_script('bin/howzit', use_bundler: true, args: %w[-T])
23
+ expect(last_execution).to be_successful
24
+ expect(last_execution.stdout).to match(/Topic Balogna/)
25
+ expect(last_execution.stdout.split(/\n/).count).to eq 2
26
+ end
27
+ end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,7 @@
10
10
  # end
11
11
 
12
12
  require 'howzit'
13
+ require 'cli-test'
13
14
 
14
15
  RSpec.configure do |c|
15
16
  c.expect_with(:rspec) { |e| e.syntax = :expect }