require 'thor' module Eco module Common class MetaThor < Thor INPUT_OPTION = "input" INPUT_SYM = :input INPUT_KEY = "json" CUSTOM_HELP_MAPPINGS = ["?", "help"] ALL_HELP_MAPPINGS = ::Thor::HELP_MAPPINGS + CUSTOM_HELP_MAPPINGS class_option :input, type: :hash, default: {json: nil}, required: false, desc: "--input=json:STRING" class_option :pipe, type: :boolean, default: false, required: false, desc: "--pipe subcommand" class << self def start(given_args = ARGV, config = {}) config[:shell] ||= Thor::Base.shell.new CommandGroup.new(given_args).map do |unit| args = unit.args {|args| parse_custom_help(args)} input = unit.input&.as_option result = dispatch(nil, args.dup, input, config) exit if help?(args) unit.output = Value.new(result) end end # @note: it allows to use `help` at the end (alias: `?`) # If there is custom help at the end of the current command, # normalize custom help to native `help` and switch last # and second last arguments def parse_custom_help(args) return args unless custom_help?(args&.last) # move from custom to native help if args.length > 1 # switch args last and second last position args.insert(args.length - 2, "help").pop else args[0] = "help" end args end def custom_help?(value) CUSTOM_HELP_MAPPINGS.include?(value) end def help?(value) case value when String ALL_HELP_MAPPINGS.include?(value) when Symbol help?(value.to_s) when Array value.any? { |v| help?(v) } when Hash value.keys.any? { |k| help?(v) } else "what? #{value}" end end end protected no_commands do def input?(options) options && (options.key?(INPUT_OPTION) || options.key?(INPUT_KEY) || options.key?(Value::KEY_OPTION) ) end def input(value) case when value.is_a?(Value) value.value when value.is_a?(String) input(JSON.parse(value)) when value.is_a?(Hash) case when value.key?(Value::KEY_OPTION) Value.to_value(value) when value.key?(INPUT_OPTION) input(value[INPUT_OPTION]) when value.key?(INPUT_SYM) input(value[INPUT_SYM]) when value.key?(INPUT_KEY) val = value[INPUT_KEY] JSON.parse(val) unless val.is_a?(Hash) else value end else value end end end end end end require_relative 'meta_thor/pipe' require_relative 'meta_thor/command_unit' require_relative 'meta_thor/command_group' require_relative 'meta_thor/value' require_relative 'meta_thor/thor' #require_relative 'metha_thor/input' #require_relative 'metha_thor/input_multi'