module Eco class CLI class Config class UseCases include Eco::CLI::Config::Help attr_reader :core_config class CaseConfig < Struct.new(:cases_config, :option, :type, :description, :casename, :callback) def add_option(arg, desc = nil, &block) core_config.options_set.add(arg, desc, namespace: option, &block) self end private def core_config cases_config.core_config end end class ActiveCase < Struct.new(:index, :option, :callback) end def initialize(core_config:) @core_config = core_config @linked_cases = {} end # @return [String] summary of the use cases. def help(refine: nil) refinement = refine.is_a?(String)? " (containing: '#{refine}')" : "" ["The following are the available use cases#{refinement}:"].yield_self do |lines| max_len = keys_max_len(@linked_cases.keys) @linked_cases.keys.sort.select do |key| refine.is_a?(String) && key.include?(refine) end.each do |option_case| lines << help_line(option_case, @linked_cases[option_case].description, max_len) end lines end.join("\n") end # Integrates a usecase to the command line. # @param option_case [String] the command line option to invoke the usecase. # @param type [Symbol] the type of usecase. # @param desc [String] description of the case. # @param case_name [String, nil] the name of the usecase as defined. def add(option_case, type, desc = nil, case_name: nil) Eco::API::UseCases::UseCase.validate_type(type) unless callback = block_given?? Proc.new : nil raise "You must specify a valid 'case_name' when no block is provided" unless case_name raise "'case_name' expected to be a String. Given: #{case_name.class}" unless case_name.is_a?(String) end puts "Overriding case config '#{option_case}'" if @linked_cases.key?(option_case) @linked_cases[option_case] = CaseConfig.new(self, option_case, type, desc, case_name, callback) end # Scopes/identifies which usecases are being invoked from the command line # @note # - this method will sort the active usecases by the position they hold in the command line # @param io [Eco::API::UseCases::BaseIO] the input/output object # @return [Hash] where keys are cases and values a `Hash` with `option` String and `callback` def active(io:) validate_io!(io) return @active_cases unless !@active_cases @active_cases = @linked_cases.each_with_object({}) do |(option_case, data), active_cases| next nil unless SCR.get_arg(option_case) if usecase = get_usecase(io: io, data: data) index = SCR.get_arg_index(option_case) active_cases[usecase] = ActiveCase.new(index, option_case, data.callback) end end.sort_by {|c, d| d.index}.to_h end def process(io:) validate_io!(io) processed = false active(io: io).each do |usecase, data| raise "Something went wrong when scoping active cases" unless data processed = true io = case_io(io: io, usecase: usecase) # some usecases have a callback to collect the parameters data.callback&.call(*io.params) io = usecase.launch(io: io) end processed end private # Gets a `UseCaseIO` def case_io(io:, usecase:) validate_io!(io) case io when Eco::API::UseCases::UseCaseIO io.chain(usecase: usecase) when Eco::API::UseCases::BaseIO params = io.params(keyed: true, all: true).merge(usecase: usecase) Eco::API::UseCases::UseCaseIO.new(**params) end end def get_usecase(io:, data:) usecase = if case_name = data.casename io.session.usecases.case(case_name, type: data.type) end usecase ||= if callback = data.callback # identify/retrieve usecase via callback params = io.params(keyed: true).merge(type: data.type) io = io.new(**params, validate: false) callback.call(*io.params).tap do |usecase| unless usecase.is_a?(Eco::API::UseCases::UseCase) msg = "When adding a usecase, without specifying 'case_name:', " msg += "the block that integrates usecase for cli option '#{data.option}'" msg += " must return an Eco::API::UseCases::UseCase object. It returns #{usecase.class}" raise msg end end end end def validate_io!(io) unless io && io.is_a?(Eco::API::UseCases::BaseIO) raise "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}" end end end end end end