module Eco module API class UseCases class UnkownCase < Exception def initialize(msg = nil, case_name: nil, type: nil) msg ||= "Unkown case" msg += ". Case name '#{case_name}'" if case_name msg += ". Case type '#{type}'" if type super(msg) end end class AmbiguousCaseReference < Exception def initialize(msg = nil, case_name: nil) msg ||= "You must specify type when there are multiple cases with same name" msg += ". Case name '#{case_name}'" if case_name super(msg) end end include Enumerable def initialize() @usecases = {} @cache_init = false @cases_by_name = {} end def length count end def empty? count == 0 end def each(params: {}, &block) return to_enum(:each) unless block items.each(&block) end def items @usecases.values end def add(usecase) raise "Expected Eco::API::UseCases::UseCase object. Given: #{usecase}" if !usecase || !usecase.is_a?(Eco::API::UseCases::UseCase) name = usecase.name type = usecase.type puts "Warning: overriding '#{type.to_s}' case #{name}" if self.defined?(name, type: type) @cache_init = false @usecases[key(name, type)] = usecase usecase end def define(name, type:, &block) Eco::API::UseCases::UseCase.new(name, type: type, root: self, &block).tap do |usecase| add(usecase) end end def defined?(name, type: nil) return @usecases.key?(key(name, type)) if type name?(name) end def name?(name) !!by_name[name] end def names by_name.keys end def types(name) return nil if !name?(name) by_name[name].map { |usecase| usecase.type } end def case(name, type: nil) if type && target_case = @usecases[key(name, type)] return target_case elsif type raise UseCases::UnkownCase.new(case_name: name, type: type) end raise UseCases::UnkownCase.new(case_name: name, type: type) unless cases = by_name[name] raise UseCases::AmbiguousCaseReference.new(case_name: name) if cases.length > 1 cases.first end # merges cases overriding self for exisint parsers def merge(cases) return self if !cases raise "Expected a Eco::API::UseCases object. Given #{cases.class}" if !cases.is_a?(Eco::API::UseCases) cases_hash = cases.to_h @usecases.merge!(cases_hash) cases_hash.transform_values do |usecase| usecase.root = self end @cache_init = false self end protected def to_h @usecases end private def by_name init_caches @by_name end def init_caches return true if @cache_init @cache_init = true @by_name = @usecases.values.group_by { |usecase| usecase.name } end def key(name, type) name.to_s + type.to_s end def name(key) key.to_s.split(":").first end def type key.to_s.split(":").last&.to_sym end end end end require_relative 'usecases/base_case' require_relative 'usecases/default_case' require_relative 'usecases/use_case' require_relative 'usecases/use_case_chain' require_relative 'usecases/base_io' require_relative 'usecases/use_case_io' require_relative 'usecases/default_cases'