Class: Yuuki::Caller
- Inherits:
-
Object
- Object
- Yuuki::Caller
- Defined in:
- lib/yuuki/caller.rb,
sig/yuuki/caller.rbs
Direct Known Subclasses
Class Method Summary collapse
Instance Method Summary collapse
- #add(*instances) ⇒ void
- #alive? ⇒ Boolean (also: #running?)
-
#initialize(*instances, use_yoshinon: true) ⇒ Caller
constructor
A new instance of Caller.
- #join ⇒ void
-
#methods ⇒ Array[runner_entry]
NOTE: intentionally shadows Object#methods; returns [Method, meta] pairs sorted by priority (highest first).
- #run(*tags, **args, &block) ⇒ void
- #run_internal(runners, args, &block) ⇒ void
-
#run_method_internal(method, args, &block) ⇒ void
Maps the args hash onto the method's parameters by name.
- #run_select(selector, **args, &block) ⇒ void
Constructor Details
#initialize(*instances, use_yoshinon: true) ⇒ Caller
Returns a new instance of Caller.
13 14 15 16 17 18 |
# File 'lib/yuuki/caller.rb', line 13 def initialize(*instances, use_yoshinon: true) @instances = Set.new @threads = [] add(*instances) @use_yoshinon = use_yoshinon end |
Class Method Details
.require_dir(require_dir, recursive: false) ⇒ void
This method returns an undefined value.
9 10 11 |
# File 'lib/yuuki/caller.rb', line 9 def self.require_dir(require_dir, recursive: false) Dir.glob(recursive ? "#{require_dir}/**/*.rb" : "#{require_dir}/*.rb").each { |file| require file } end |
Instance Method Details
#add(*instances) ⇒ void
This method returns an undefined value.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/yuuki/caller.rb', line 20 def add(*instances) instances.each do |instance| if instance.is_a?(Class) klass = instance raise Yuuki::Error, 'Runner instance must be inherit Yuuki::Runner' unless klass < Yuuki::Runner # allocate + explicit initialize so that @yuuki is already set when # the runner's #initialize runs instance = instance.allocate instance.instance_variable_set(:@yuuki, self) instance.send(:initialize) else raise Yuuki::Error, 'Runner instance must be inherit Yuuki::Runner' unless instance.is_a?(Yuuki::Runner) instance.instance_variable_set(:@yuuki, self) end @instances << instance end end |
#alive? ⇒ Boolean Also known as: running?
67 68 69 70 |
# File 'lib/yuuki/caller.rb', line 67 def alive? @threads.select!(&:alive?) !@threads.empty? end |
#join ⇒ void
This method returns an undefined value.
62 63 64 65 |
# File 'lib/yuuki/caller.rb', line 62 def join @threads.each(&:join) @threads.select!(&:alive?) end |
#methods ⇒ Array[runner_entry]
NOTE: intentionally shadows Object#methods; returns [Method, meta] pairs sorted by priority (highest first)
42 43 44 45 46 47 48 49 |
# File 'lib/yuuki/caller.rb', line 42 def methods list = @instances.flat_map do |instance| methods = instance.class.yuuki_methods methods.map { |sig, | [instance.method(sig), ] } end list.sort_by! { |_method, | -([:priority] || 0) } list end |
#run(*tags, **args, &block) ⇒ void
This method returns an undefined value.
51 52 53 54 55 56 |
# File 'lib/yuuki/caller.rb', line 51 def run(*, **args, &block) selector = proc do |_method, | [:tags] && !([:tags] & ).empty? end run_select(selector, **args, &block) end |
#run_internal(runners, args, &block) ⇒ void
This method returns an undefined value.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/yuuki/caller.rb', line 75 def run_internal(runners, args, &block) @threads.select!(&:alive?) runners.each do |method, | if [:thread] thread = Thread.new(method, args, block) do |thread_method, thread_args, thread_block| run_method_internal(thread_method, thread_args, &thread_block) end thread.priority = [:priority] || 0 @threads << thread else run_method_internal(method, args, &block) end end end |
#run_method_internal(method, args, &block) ⇒ void
This method returns an undefined value.
Maps the args hash onto the method's parameters by name. Positional optionals can only be filled left-to-right: once one is unspecified, passing any later :opt/:rest argument is an error (nonspecified_last_opt).
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/yuuki/caller.rb', line 93 def run_method_internal(method, args, &block) yoshinon = Yoshinon.lock if @use_yoshinon params = method.parameters return method[&block] if params.empty? params_array = [] params_hash = {} params_block = nil nonspecified_last_opt = nil params.each do |type, name| case type when :req 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 if args[name].respond_to?(:to_ary) params_array += args[name] else params_array << args[name] end when :keyreq 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] if args.key?(name) end end # fall back to the block passed to run unless one was explicitly given via args params_block = block unless params.any? { |type, name| type == :block && args.key?(name) } params_hash.empty? ? method[*params_array, ¶ms_block] : method[*params_array, **params_hash, ¶ms_block] ensure yoshinon&.unlock end |
#run_select(selector, **args, &block) ⇒ void
This method returns an undefined value.
58 59 60 |
# File 'lib/yuuki/caller.rb', line 58 def run_select(selector, **args, &block) run_internal(methods.select(&selector), args, &block) end |