lib/make_menu/menu.rb in make_menu-0.1.1 vs lib/make_menu/menu.rb in make_menu-1.0.0
- old
+ new
@@ -1,173 +1,133 @@
# frozen_string_literal: true
+require_relative 'builder'
require_relative 'menu_item_group'
-require_relative 'color_string'
-require_relative 'text_table'
+require_relative 'text/table'
+require_relative 'console/prompter'
module MakeMenu
# This class builds and displays a number-selection menu from a Makefile
# then prompts for a number and executes the target.
class Menu
- # @param [String] makefile Makefile name
def initialize(makefile)
+ @makefile = makefile
+
@groups = []
@items = []
- build makefile
+
+ @options = {
+ group_title_color: :underline,
+ clear_screen: true,
+ pause_on_success: false
+ }
+ @highlights = {}
+ @header = nil
end
- attr_reader :groups, :items
+ attr_reader :makefile, :groups, :items, :options, :highlights
- # Display menu and prompt for command
- # rubocop:disable Metrics/MethodLength
def run
- running = true
+ yield self if block_given?
- while running
+ Builder.build(makefile, self)
+
+ loop do
system 'clear' if clear_screen?
display_header
- puts colorize(TextTable.new(groups).to_s)
+ puts colorize(MakeMenu::Text::Table.new(groups).to_s)
puts
- puts 'Press ENTER to quit'.align(:center).bold
+ puts 'Press ESC to quit'.align(:center).bold
puts
- print 'Select option: '.align(:center)
- running = false unless execute_option(gets.strip)
- end
+ prompt = 'Select option: '.align(:center)
- puts
-
- system 'clear' if clear_screen?
- end
-
- # rubocop:enable Metrics/MethodLength
-
- # Display the company logo and the status bar (if set)
- def display_header
- puts formatted_logo if logo
- end
-
- private
-
- # Build a menu from the specified Makefile
- # @param [String] makefile Filename
- # rubocop:disable Metrics/MethodLength
- def build(makefile)
- File.open(makefile, 'r') do |file|
- option_number = 1
- current_group = nil
-
- file.each_line do |line|
- if line.start_with? '###'
- # Group header
- group_title = line.gsub(/###\s+/, '').strip
- current_group = MenuItemGroup.new(group_title.color(group_title_color))
- groups << current_group
-
- elsif line.match(/^[a-zA-Z_-]+:.*?## .*$$/)
- # Menu item
- target = line.split(':').first.strip
- description = line.split('##').last.strip
-
- # Target 'menu' should not appear
- next if target == 'menu'
-
- unless current_group
- current_group = MenuItemGroup.new('Commands'.color(group_title_color))
- groups << current_group
- end
-
- items << current_group.add_item(
- MenuItem.new(option_number, target, description)
- )
-
- option_number += 1
- end
- end
-
- if option_number == 1
+ begin
+ execute_option(MakeMenu::Console::Prompter.prompt(prompt).strip)
puts
- puts 'No annotated targets found!'.red.bold
- puts
- puts 'Expecting something like this....'
- puts " #{'my_target:'.cyan} #{'## Do some things'.yellow}"
- puts
- exit 1
+ rescue MakeMenu::Console::Prompter::PressedEscape
+ break
end
end
- rescue Errno::ENOENT => _e
puts
- puts 'No Makefile!'.red.bold
- puts
- puts "File '#{makefile}' could not be found.".yellow
- puts
- exit 1
+
+ system 'clear' if clear_screen?
end
- # rubocop:enable Metrics/MethodLength
-
- # Execute the selected menu item
- # @param [String] selected Value entered by user
- # @return [Boolean] False to signify that menu should exit
def execute_option(selected)
- return false if selected.empty?
-
selected = selected.to_i
items.each do |item|
next unless item.option_number == selected
system 'clear' if clear_screen?
+
item.execute
- return true
- end
- true
+ if pause_on_success?
+ puts "\nPress ENTER to continue....".dark
+ gets
+ end
+ end
end
- # Apply word colorings
- # @param [String] string
- # @return [String]
- def colorize(string)
- return string unless Object.const_defined?("#{self.class.name}::HIGHLIGHTS")
-
- Object.const_get("#{self.class.name}::HIGHLIGHTS").each do |word, color|
- case color
- when Array
- color.each { |c| string.gsub!(word, word.send(c)) }
- else
- string.gsub!(word, word.send(color))
- end
+ def display_header
+ if @header
+ @header.call
+ else
+ logo = " #{Dir.pwd.split('/').last.upcase} ".invert.bold.to_s
+ puts "\n#{logo.align(:center)}\n \n"
end
- string
end
- # Center each line of the logo across the screen
- def formatted_logo
- logo.split("\n")
- .map { |line| line.align(:center) }
- .join("\n")
+ def options
+ @options.merge!(yield) if block_given?
+ @options
end
- # Get the menu logo from the LOGO constant
- def logo
- return "\n#{" #{Dir.pwd.split('/').last} ".light_yellow_bg.black.bold}\n \n" unless Object.const_defined?("#{self.class.name}::LOGO")
+ def highlights
+ @highlights.merge!(yield) if block_given?
+ @highlights
+ end
- Object.const_get("#{self.class.name}::LOGO")
+ def header(&block)
+ @header = block
end
- protected
+ def add_group(group)
+ groups << group
+ group
+ end
- # @return [Symbol,Array[Symbol]] Color for group title
+ def add_item(item)
+ items << item
+ item
+ end
+
def group_title_color
- %i[yellow bold]
+ options[:group_title_color]
end
- # Clear screen before and after each command
def clear_screen?
- true
+ options[:clear_screen]
+ end
+
+ def pause_on_success?
+ options[:pause_on_success]
+ end
+
+ def colorize(text)
+ highlights.each do |word, color|
+ case color
+ when Array
+ color.each { |c| text.gsub!(word, word.send(c)) }
+ else
+ text.gsub!(word, word.send(color))
+ end
+ end
+ text
end
end
end