Class: Bauk::Utils::BaseParser
- Includes:
- Log
- Defined in:
- lib/bauk/utils/base_parser.rb
Overview
This class wraps optparse and provides come common functionality. Common functionality includes:
-
Logging levels
The basic functionality can be invoked with calls to #order!
It also enables sub-options to be passed into the initializer with the following options:
-
info : A string line that gets displayed explaining the sub-command
-
opts : Any options pertaining to this sub-command lineage
-
action : The lambda to execute on action called
-
aliases : List of alternative names to go down this route
-
… : Any further keys are treated as extra sub-options
The sub-command functionality can be invoked with calls to #parse
Instance Method Summary collapse
-
#available_actions ⇒ Object
Lists available child actions based on the current @action_chain.
-
#common_opts(opts) ⇒ Object
Passes common options to opts.
-
#custom_opts(opts) ⇒ Object
Passes the user-defined options to opts.
-
#initialize(actions = {}) ⇒ BaseParser
constructor
Accepts a hash of actions.
- #order(*args) ⇒ Object
- #order!(*args) ⇒ Object
-
#parse(args = nil, map = {}) ⇒ Object
The order of execution is: 1.
Methods included from Log
check_level, create, #decrease_logging, decrease_logging, increase_logging, #increase_logging, #log, log_level, #log_level=, logger_name, loggers, set_log_level, #test_logging, #title
Constructor Details
#initialize(actions = {}) ⇒ BaseParser
Accepts a hash of actions. E.g:
BaseParser.new({
opts: lambda do |opts|
# opts.on ...
end,
sub_action_a: {
aliases: %i[a action_a],
info: 'Please choose me!',
opts: lambda do |opts|
# Only accesible if 'sub_action_a' chosen
end,
action: ->() { function_call() },
sub_action_a_sub: {
# Only accessible after sub_action_a called
}
}
})
Alternatively the top-level opts can be passed in as a block:
BaseParser.new() do |opts|
# opts.on ...
end
Options penetrate down the sub-command chain so the parent command options can be called from child commands. These can however be overwritten by child options.
47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/bauk/utils/base_parser.rb', line 47 def initialize(actions = {}) # :yields: opts @actions = actions # To store action map @action_chain = [] # To stop chain of actions called @config ||= {} # To store the config required for the accelerator if block_given? && actions[:opts] raise 'Cannot pass a block and set the main opts : They are the same' elsif block_given? actions[:opts] = Proc.new end initialize_parser end |
Instance Method Details
#available_actions ⇒ Object
Lists available child actions based on the current @action_chain
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/bauk/utils/base_parser.rb', line 112 def available_actions # Put *'s if this has an action ret = "#{program_name} - Available actions (--help for more info):\n".dup max = 0 ca = current_action only_child_actions: true ca.each_key { |key| max = key.length if key.length > max } ca.each_key do |a| if ca[a].is_a? Hash ret << (ca[a][:action] ? ' * ' : ' - ') # If it has an action, use * bullets ret << format("%-#{max}s : ", a) # Add the name ret << "<#{ca[a][:aliases].join(',')}> " if ca[a][:aliases]&.is_a?(Array) ret << ca[a][:info] if ca[a][:info]&.is_a?(String) ret << "\n" # Add a newline else ret << format(" * %-#{max}s\n", a) end end ret end |
#common_opts(opts) ⇒ Object
Passes common options to opts
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/bauk/utils/base_parser.rb', line 141 def common_opts(opts) opts.separator '' opts.separator 'Common options:' opts.on('-v', '--verbose [[CLASS=]LEVEL]', 'Set/Increase verbosity level') do |v| type = '' if v =~ /=/ type, v = v.split('=') v = Integer(v) elsif v =~ /^[0-9]*$/ v = v.to_i elsif v =~ /./ type = v v = nil end if v Bauk::Utils::Log.set_log_level(v, type) else Bauk::Utils::Log.increase_logging(type) end end end |
#custom_opts(opts) ⇒ Object
Passes the user-defined options to opts
164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/bauk/utils/base_parser.rb', line 164 def custom_opts(opts) # TODO: allow opts to just pass in a hash reference and a symbol list name = program_name child_actions: false actions = { name => @actions } [name, *@action_chain].each do |a| actions = actions[a] next unless actions[:opts] opts.separator '' opts.separator "#{a.capitalize} options:" actions[:opts].call(opts) end end |
#order(*args) ⇒ Object
132 133 134 |
# File 'lib/bauk/utils/base_parser.rb', line 132 def order(*args) @parser.order(*args) end |
#order!(*args) ⇒ Object
136 137 138 |
# File 'lib/bauk/utils/base_parser.rb', line 136 def order!(*args) @parser.order!(*args) end |
#parse(args = nil, map = {}) ⇒ Object
The order of execution is:
-
Any extra options are evaluated
-
The command action is executed if present
-
Parse is called again if there are sub-commands
Options:
- args
-
args to parse. Defaults to ARGV.
- map
-
optional hash at end with the following values:
-
parse_children: false # To not parse arguments after an action, before executing it
-
continue: true # Used internally. Set this to continue parsing from gathered action chain. Used as this function loops
-
continue_on_error: true # Set this to true to not return 3 on invalid/no action provided
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/bauk/utils/base_parser.rb', line 70 def parse(args = nil, map = {}) args ||= ARGV @action_chain = [] unless map[:continue] order!(args) # Build up action chain action_name = args.shift action = next_action(action_name) if action_name if action_name if action.is_a? Hash initialize_parser # First get any extra opts order!(args) unless map[:parse_children] == false # Then run this action action[:action].call if action[:action].respond_to?(:call) # Then continue down into sub-actions parse(args, { continue: true }.merge(map)) elsif action.respond_to? :call # First get any trailing args order!(args) # This is the end of the chain, call the sub and finish action.call elsif action.nil? puts "Invalid action: #{action_name}" puts available_actions exit 3 unless map[:continue_on_error] else raise 'Invalid action: Needs to be a Hash or block' end elsif !current_action(only_child_actions: true).empty? # If there are sub-actions that were not called, inform the user of these puts available_actions exit 3 unless map[:continue_on_error] end unless args.empty? puts "Unknown args: #{args}" exit 3 unless map[:continue_on_error] end end |