yuuki 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/Gemfile +2 -0
- data/README.md +22 -1
- data/Rakefile +12 -2
- data/lib/yuuki/caller.rb +128 -114
- data/lib/yuuki/error.rb +4 -2
- data/lib/yuuki/periodic.rb +61 -0
- data/lib/yuuki/runner.rb +43 -40
- data/lib/yuuki/version.rb +3 -1
- data/lib/yuuki.rb +3 -1
- data/yuuki.gemspec +23 -21
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95e60a7be44a24d27a3340b1a0bf86df33927e32cd855dd9b99df4faa2bc1685
|
4
|
+
data.tar.gz: '055829249f336c32e1f88f73984bbd465c037ad6b6edb5a3e2bce68139b25976'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b44ff4617ffaaf0e18e0654d67113308518b04575bc74ced15b3afa1418c479e5a577fcbac30de3aa9ff32a6bdcf007c4669a742df0da03a5ce684f271936a58
|
7
|
+
data.tar.gz: 9decda81bcfc32138478d91015590d0da49734e7e3d246a87bc40101daa7691a883118f8ad09d889b94dd9ce225f286a40635c2f94a6b84d3b1035431c8064e5
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -20,7 +20,28 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
```ruby
|
24
|
+
class HogeClass
|
25
|
+
add :a
|
26
|
+
def a
|
27
|
+
puts 'a'
|
28
|
+
end
|
29
|
+
|
30
|
+
add :b
|
31
|
+
tag :b, :tag_b
|
32
|
+
def b
|
33
|
+
puts 'b'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
yuuki = Yuuki::Caller.new(HogeClass)
|
38
|
+
yuuki.run
|
39
|
+
# a
|
40
|
+
# b
|
41
|
+
|
42
|
+
yuuki.run_tag(:tag_b)
|
43
|
+
# b
|
44
|
+
```
|
24
45
|
|
25
46
|
## Contributing
|
26
47
|
|
data/Rakefile
CHANGED
@@ -1,2 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: %i[test]
|
data/lib/yuuki/caller.rb
CHANGED
@@ -1,135 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
1
4
|
require 'yuuki/runner'
|
2
5
|
|
3
6
|
module Yuuki
|
4
|
-
|
5
|
-
|
7
|
+
class Caller
|
8
|
+
def self.require_dir(_dir, recursive: false)
|
9
|
+
Dir.glob(recursive ? "#{require_dir}/**/*.rb" : "#{require_dir}/*.rb"){|file| require file}
|
10
|
+
end
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
12
|
+
def initialize(*instances)
|
13
|
+
@instances = Set.new
|
14
|
+
@threads = []
|
15
|
+
add(*instances)
|
16
|
+
end
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
def add(*instances)
|
19
|
+
instances.each do |instance|
|
20
|
+
# create instance if class is given
|
21
|
+
if instance.is_a?(Class)
|
22
|
+
klass = instance
|
23
|
+
instance = instance.new
|
24
|
+
else
|
25
|
+
klass = instance.class
|
15
26
|
end
|
16
27
|
|
17
|
-
|
18
|
-
|
19
|
-
instance = klass.new
|
20
|
-
instance.instance_variable_set(:@caller, self)
|
21
|
-
info = klass.instance_variable_get(:@runner_info) || {}
|
22
|
-
methods = klass.public_instance_methods(false)
|
23
|
-
methods |= klass.instance_variable_get(:@runner_adds) || []
|
24
|
-
methods -= klass.instance_variable_get(:@runner_excepts) || []
|
25
|
-
@runners += methods.map do |method|
|
26
|
-
tags = info.dig(method, :tags) || []
|
27
|
-
exclude = !!info.dig(method, :exclude)
|
28
|
-
threading = !!info.dig(method, :threading)
|
29
|
-
priority = info.dig(method, :priority) || 0
|
30
|
-
Runner.new(instance.method(method), tags, exclude, threading, priority)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
@runners.sort_by!{|e| -e.priority}
|
34
|
-
end
|
28
|
+
# check the klass is extended
|
29
|
+
raise Yuuki::Error, 'Runner instance must be extend Yuuki::Runner' unless klass.singleton_class.include?(Yuuki::Runner)
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
31
|
+
# add @yuuki to the instance
|
32
|
+
instance.instance_variable_set(:@yuuki, self)
|
39
33
|
|
40
|
-
|
41
|
-
|
42
|
-
|
34
|
+
# regist
|
35
|
+
@instances << instance
|
36
|
+
end
|
37
|
+
end
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
def runners
|
40
|
+
list = @instances.flat_map do |instance|
|
41
|
+
methods = instance.class.instance_variable_get(:@yuuki_methods)
|
42
|
+
methods.select{|_sig, meta| meta[:enabled]}.map{|sig, meta| [instance.method(sig), meta]}
|
43
|
+
end
|
44
|
+
list.sort_by{|_method, meta| -(meta[:priority] || 0)}
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
def run(**args, &block)
|
48
|
+
run_internal(runners, args, &block)
|
49
|
+
end
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
def run_select(proc_select, **args, &block)
|
52
|
+
run_internal(runners.select(&proc_select), args, &block)
|
53
|
+
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
def run_tag(*tags, **args, &block)
|
56
|
+
run_select(proc{|_method, meta| meta[:tags]&.intersect?(tags)}, **args, &block)
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
def run_method(klass, method_sig, **args, &block)
|
60
|
+
select_proc = proc do |method, _meta|
|
61
|
+
flag_klass = klass ? method.receiver.instance_of?(klass) : true
|
62
|
+
flag_method = method_sig ? method.name == method_sig : true
|
63
|
+
flag_klass && flag_method
|
64
|
+
end
|
65
|
+
run_select(select_proc, **args, &block)
|
66
|
+
end
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
def join
|
69
|
+
@threads.each(&:join)
|
70
|
+
@threads.select!(&:alive?)
|
71
|
+
end
|
69
72
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
73
|
+
def alive?
|
74
|
+
@threads.select!(&:alive?)
|
75
|
+
!@threads.empty?
|
76
|
+
end
|
77
|
+
alias running? alive?
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def run_internal(runners, args, &block)
|
82
|
+
@threads.select!(&:alive?)
|
83
|
+
runners.each do |method, meta|
|
84
|
+
if meta[:thread]
|
85
|
+
thread = Thread.new(method, args, block) do |thread_method, thread_args, thread_block|
|
86
|
+
run_method_internal(thread_method, thread_args, &thread_block)
|
87
|
+
end
|
88
|
+
thread.priority = meta[:priority] || 0
|
89
|
+
@threads << thread
|
90
|
+
else
|
91
|
+
run_method_internal(method, args, &block)
|
88
92
|
end
|
93
|
+
end
|
94
|
+
end
|
89
95
|
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
96
|
+
def run_method_internal(method, args, &block)
|
97
|
+
params = method.parameters
|
98
|
+
return method[] if params.empty?
|
99
|
+
params_array = []
|
100
|
+
params_hash = {}
|
101
|
+
params_block = nil
|
102
|
+
nonspecified_last_opt = nil
|
103
|
+
params.each do |type, name|
|
104
|
+
case type
|
105
|
+
when :req
|
106
|
+
raise Yuuki::Error, "A required argument '#{name}' was not found on running #{method.owner}::#{method.name}" unless args.key?(name)
|
107
|
+
params_array << args[name]
|
108
|
+
when :opt
|
109
|
+
# if parameters do not contain the :opt argument, treat it as not specified
|
110
|
+
next nonspecified_last_opt = name unless args.key?(name)
|
111
|
+
if nonspecified_last_opt
|
112
|
+
# if there already exist non-specified :opt arguments, no more specified :opt argument is allowed
|
113
|
+
raise Yuuki::Error, "A required argument '#{nonspecified_last_opt}' was not found"\
|
114
|
+
" on running #{method.owner}::#{method.name}"" with optional argument '#{name}'"
|
115
|
+
end
|
116
|
+
params_array << args[name]
|
117
|
+
when :rest
|
118
|
+
next unless args.key?(name)
|
119
|
+
if nonspecified_last_opt
|
120
|
+
# if there already exist non-specified :opt arguments, the :rest argument cannot be handled
|
121
|
+
raise Yuuki::Error, "A required argument '#{nonspecified_last_opt}' not found"\
|
122
|
+
" on running #{method.owner}::#{method.name}"" with rest argument '#{name}'"
|
123
|
+
end
|
124
|
+
if args[name].respond_to?(:to_ary)
|
125
|
+
params_array += args[name]
|
126
|
+
else
|
127
|
+
params_array << args[name]
|
128
|
+
end
|
129
|
+
when :keyreq
|
130
|
+
raise Yuuki::Error, "A required key argument '#{name}' was not found on running #{method.owner}::#{method.name}" unless args.key?(name)
|
131
|
+
params_hash[name] = args[name]
|
132
|
+
when :key
|
133
|
+
params_hash[name] = args[name] if args.key?(name)
|
134
|
+
when :keyrest
|
135
|
+
next unless args.key?(name)
|
136
|
+
if args[name].respond_to?(:to_hash)
|
137
|
+
params_hash.merge!(args[name])
|
138
|
+
else
|
139
|
+
params_hash[name] = args[name]
|
140
|
+
end
|
141
|
+
when :block
|
142
|
+
params_block = args[name]
|
133
143
|
end
|
144
|
+
end
|
145
|
+
params_block = block unless params.any?{|type, _| type == :block}
|
146
|
+
params_hash.empty? ? method[*params_array, ¶ms_block] : method[*params_array, **params_hash, ¶ms_block]
|
134
147
|
end
|
148
|
+
end
|
135
149
|
end
|
data/lib/yuuki/error.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yuuki/caller'
|
4
|
+
require 'yuuki/runner'
|
5
|
+
|
6
|
+
module Yuuki
|
7
|
+
module Runner
|
8
|
+
# set interval to the method
|
9
|
+
def periodic(method, interval)
|
10
|
+
@yuuki_methods ||= {}
|
11
|
+
@yuuki_methods[method] ||= {}
|
12
|
+
@yuuki_methods[method][:periodic] = interval
|
13
|
+
end
|
14
|
+
|
15
|
+
# set whether the method run at the first time
|
16
|
+
def first_run(method, enabled: true)
|
17
|
+
@yuuki_methods ||= {}
|
18
|
+
@yuuki_methods[method] ||= {}
|
19
|
+
@yuuki_methods[method][:first_run] = enabled
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Yuuki
|
25
|
+
class PeriodicCaller < Caller
|
26
|
+
attr_reader :first_run, :current_time
|
27
|
+
|
28
|
+
def initialize(*instances)
|
29
|
+
super
|
30
|
+
@first_run = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_error(&block)
|
34
|
+
@on_error = block
|
35
|
+
end
|
36
|
+
|
37
|
+
def run(gmtoff = Time.now.gmtoff, **args, &block)
|
38
|
+
last_time = nil
|
39
|
+
loop do
|
40
|
+
@current_time = Time.now.to_f
|
41
|
+
begin
|
42
|
+
select_proc = proc do |_method, meta|
|
43
|
+
next true if @first_run && meta[:first_run]
|
44
|
+
next false unless meta[:periodic]
|
45
|
+
next false unless last_time
|
46
|
+
c = @current_time + gmtoff
|
47
|
+
l = last_time + gmtoff
|
48
|
+
next true if (l.div(meta[:periodic]) + 1) * meta[:periodic] <= c
|
49
|
+
end
|
50
|
+
run_select(select_proc, **args, &block)
|
51
|
+
rescue
|
52
|
+
@on_error ? @on_error[$!] : raise
|
53
|
+
end
|
54
|
+
@first_run = false
|
55
|
+
|
56
|
+
last_time = @current_time
|
57
|
+
((@current_time + 1).floor - Time.now.to_f).tap{|e| sleep e if e > 0}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/yuuki/runner.rb
CHANGED
@@ -1,48 +1,51 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class RunnerBase
|
5
|
-
class << self
|
6
|
-
private
|
7
|
-
|
8
|
-
def add(*methods)
|
9
|
-
@runner_adds ||= []
|
10
|
-
@runner_adds |= methods
|
11
|
-
end
|
3
|
+
require 'set'
|
12
4
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
module Yuuki
|
6
|
+
module Runner
|
7
|
+
# add method
|
8
|
+
def add(*methods)
|
9
|
+
@yuuki_methods ||= {}
|
10
|
+
methods.each do |method|
|
11
|
+
@yuuki_methods[method] ||= {}
|
12
|
+
@yuuki_methods[method][:enabled] = true
|
13
|
+
end
|
14
|
+
end
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
# delete method
|
17
|
+
def delete(*methods)
|
18
|
+
@yuuki_methods ||= {}
|
19
|
+
methods.each do |method|
|
20
|
+
@yuuki_methods[method] ||= {}
|
21
|
+
@yuuki_methods[method][:enabled] = false
|
22
|
+
end
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
# add tags to the method
|
26
|
+
def tag(method, *tags)
|
27
|
+
@yuuki_methods ||= {}
|
28
|
+
@yuuki_methods[method] ||= {}
|
29
|
+
@yuuki_methods[method][:tags] ||= Set.new
|
30
|
+
@yuuki_methods[method][:tags].merge(tags)
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
# enable threading to the method
|
34
|
+
def thread(*methods, enabled: true)
|
35
|
+
@yuuki_methods ||= {}
|
36
|
+
methods.each do |method|
|
37
|
+
@yuuki_methods[method] ||= {}
|
38
|
+
@yuuki_methods[method][:thread] = enabled
|
39
|
+
end
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
# set priority to the method
|
43
|
+
def priority(*methods, priority)
|
44
|
+
@yuuki_methods ||= {}
|
45
|
+
methods.each do |method|
|
46
|
+
@yuuki_methods[method] ||= {}
|
47
|
+
@yuuki_methods[method][:priority] = priority
|
48
|
+
end
|
47
49
|
end
|
50
|
+
end
|
48
51
|
end
|
data/lib/yuuki/version.rb
CHANGED
data/lib/yuuki.rb
CHANGED
data/yuuki.gemspec
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$:.unshift(lib) unless $:.include?(lib)
|
3
5
|
require 'yuuki/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |spec|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
spec.name = 'yuuki'
|
9
|
+
spec.version = Yuuki::VERSION
|
10
|
+
spec.authors = ['Ishotihadus']
|
11
|
+
spec.email = ['hanachan.pao@gmail.com']
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
spec.summary = 'A caller / runner framework for Ruby'
|
14
|
+
spec.description = 'A caller / runner framework for Ruby.'
|
15
|
+
spec.homepage = 'https://github.com/ishotihadus/yuuki'
|
16
|
+
spec.license = 'MIT'
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
`git ls-files -z`.split("\x0").reject
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject{|f| f.match(%r{^(test|spec|features)/})}
|
22
|
+
end
|
23
|
+
spec.bindir = 'exe'
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}){|f| File.basename(f)}
|
25
|
+
spec.require_paths = ['lib']
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
spec.add_development_dependency 'bundler'
|
28
|
+
spec.add_development_dependency 'pry'
|
29
|
+
spec.add_development_dependency 'rake'
|
28
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yuuki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ishotihadus
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/yuuki.rb
|
70
70
|
- lib/yuuki/caller.rb
|
71
71
|
- lib/yuuki/error.rb
|
72
|
+
- lib/yuuki/periodic.rb
|
72
73
|
- lib/yuuki/runner.rb
|
73
74
|
- lib/yuuki/version.rb
|
74
75
|
- yuuki.gemspec
|
@@ -76,7 +77,7 @@ homepage: https://github.com/ishotihadus/yuuki
|
|
76
77
|
licenses:
|
77
78
|
- MIT
|
78
79
|
metadata: {}
|
79
|
-
post_install_message:
|
80
|
+
post_install_message:
|
80
81
|
rdoc_options: []
|
81
82
|
require_paths:
|
82
83
|
- lib
|
@@ -91,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
92
|
- !ruby/object:Gem::Version
|
92
93
|
version: '0'
|
93
94
|
requirements: []
|
94
|
-
rubygems_version: 3.
|
95
|
-
signing_key:
|
95
|
+
rubygems_version: 3.3.3
|
96
|
+
signing_key:
|
96
97
|
specification_version: 4
|
97
98
|
summary: A caller / runner framework for Ruby
|
98
99
|
test_files: []
|