lib/yuuki/caller.rb in yuuki-0.1.7 vs lib/yuuki/caller.rb in yuuki-0.1.8

- old
+ new

@@ -1,41 +1,49 @@ # frozen_string_literal: true require 'set' require 'yuuki/runner' +require 'yoshinon' module Yuuki class Caller # requires all the rb files in the given directory # @param [String] require_dir directory # @param [Boolean] recursive def self.require_dir(require_dir, recursive: false) - Dir.glob(recursive ? "#{require_dir}/**/*.rb" : "#{require_dir}/*.rb"){|file| require file} + Dir.glob(recursive ? "#{require_dir}/**/*.rb" : "#{require_dir}/*.rb").sort.each {|file| require file} end # @param [Object] instances - def initialize(*instances) + def initialize(*instances, use_yoshinon: true) @instances = Set.new @threads = [] add(*instances) + @use_yoshinon = use_yoshinon end # adds instances to yuuki # @param [Object] instances def add(*instances) instances.each do |instance| # create instance if class is given if instance.is_a?(Class) klass = instance # check the klass is extended - raise Yuuki::Error, 'Runner instance must be extend Yuuki::Runner' unless klass.singleton_class.include?(Yuuki::Runner) + unless klass.singleton_class.include?(Yuuki::Runner) + raise Yuuki::Error, 'Runner instance must be extend Yuuki::Runner' + end + instance = instance.allocate instance.instance_variable_set(:@yuuki, self) instance.send(:initialize) else # check the klass is extended - raise Yuuki::Error, 'Runner instance must be extend Yuuki::Runner' unless instance.class.singleton_class.include?(Yuuki::Runner) + unless instance.class.singleton_class.include?(Yuuki::Runner) + raise Yuuki::Error, 'Runner instance must be extend Yuuki::Runner' + end + # add @yuuki to the instance instance.instance_variable_set(:@yuuki, self) end # regist @@ -46,23 +54,23 @@ # returns runners # @return [Array<[Method, Hash<Symbol, Object>]>] def runners list = @instances.flat_map do |instance| methods = instance.class.instance_variable_get(:@yuuki_methods) - methods.select{|_sig, meta| meta[:enabled]}.map{|sig, meta| [instance.method(sig), meta]} + methods.select {|_sig, meta| meta[:enabled]}.map {|sig, meta| [instance.method(sig), meta]} end - list.sort_by{|_method, meta| -(meta[:priority] || 0)} + list.sort_by {|_method, meta| -(meta[:priority] || 0)} end # returns all tags defined as Set def tags tags = @instances.flat_map do |instance| methods = instance.class.instance_variable_get(:@yuuki_methods) - methods.select{|_sig, meta| meta[:enabled]}.flat_map{|_sig, meta| meta[:tags]} + methods.select {|_sig, meta| meta[:enabled]}.flat_map {|_sig, meta| meta[:tags]} end ret = Set.new - tags.each{|e| ret += e if e} + tags.each {|e| ret += e if e} ret end # runs all methods # @param [Object] args arguments @@ -88,13 +96,14 @@ def run_tag(*tags, **args, &block) t = self.tags tags.each do |e| next if t.include?(e) raise Yuuki::Error, "tag `#{e}` is not associated" unless @ignore_tag_error + warn "Yuuki Warning: tag `#{e}` is not associated" end - run_select(proc{|_method, meta| meta[:tags]&.intersect?(tags)}, **args, &block) + run_select(proc {|_method, meta| meta[:tags]&.intersect?(tags)}, **args, &block) end # runs the specific method # @param [Class, nil] klass # @param [Symbol, nil] method_sig method name @@ -140,30 +149,37 @@ end def run_method_internal(method, args, &block) params = method.parameters return method[] if params.empty? + + yoshinon = Yoshinon.lock if @use_yoshinon params_array = [] params_hash = {} params_block = nil nonspecified_last_opt = nil params.each do |type, name| case type when :req - raise Yuuki::Error, "A required argument '#{name}' was not found on running #{method.owner}::#{method.name}" unless args.key?(name) + unless args.key?(name) + raise Yuuki::Error, "A required argument '#{name}' was not found on running #{method.owner}::#{method.name}" + end + params_array << args[name] when :opt # if parameters do not contain the :opt argument, treat it as not specified next nonspecified_last_opt = name unless args.key?(name) + if nonspecified_last_opt # if there already exist non-specified :opt arguments, no more specified :opt argument is allowed raise Yuuki::Error, "A required argument '#{nonspecified_last_opt}' was not found"\ " on running #{method.owner}::#{method.name}"" with optional argument '#{name}'" end params_array << args[name] when :rest next unless args.key?(name) + if nonspecified_last_opt # if there already exist non-specified :opt arguments, the :rest argument cannot be handled raise Yuuki::Error, "A required argument '#{nonspecified_last_opt}' not found"\ " on running #{method.owner}::#{method.name}"" with rest argument '#{name}'" end @@ -171,25 +187,32 @@ params_array += args[name] else params_array << args[name] end when :keyreq - raise Yuuki::Error, "A required key argument '#{name}' was not found on running #{method.owner}::#{method.name}" unless args.key?(name) + unless args.key?(name) + raise Yuuki::Error, + "A required key argument '#{name}' was not found on running #{method.owner}::#{method.name}" + end + params_hash[name] = args[name] when :key params_hash[name] = args[name] if args.key?(name) when :keyrest next unless args.key?(name) + if args[name].respond_to?(:to_hash) params_hash.merge!(args[name]) else params_hash[name] = args[name] end when :block params_block = args[name] end end - params_block = block unless params.any?{|type, _| type == :block} + params_block = block unless params.any? {|type, _| type == :block} params_hash.empty? ? method[*params_array, &params_block] : method[*params_array, **params_hash, &params_block] end + ensure + yoshinon&.unlock if @use_yoshinon end end