yuuki 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f43903b0871e192e128847cf0e772066dec93cfa0b882afb9ac53bb0dfbf3ca
4
- data.tar.gz: 1114888a7eb4a790792556ab6aa03b9ace4da9a15bd56201f8fdf98cf855df30
3
+ metadata.gz: 95e60a7be44a24d27a3340b1a0bf86df33927e32cd855dd9b99df4faa2bc1685
4
+ data.tar.gz: '055829249f336c32e1f88f73984bbd465c037ad6b6edb5a3e2bce68139b25976'
5
5
  SHA512:
6
- metadata.gz: 742ddbe4914aa114d780a8a5bdd6285ba04c6ca651fa23d62c995741b155a935c58742240eb51114f43c6ab82347ea1d457a92f40b63ae87324fbf81ae8073a7
7
- data.tar.gz: 6ae20a7613818d726fd3442a7057354355106656a42c45c9f8c8dcf1dd1eb8172905307f35b9559e7e15c4e3c0b4f60cfad74017ccd254edff93dabf8fab485f
6
+ metadata.gz: b44ff4617ffaaf0e18e0654d67113308518b04575bc74ced15b3afa1418c479e5a577fcbac30de3aa9ff32a6bdcf007c4669a742df0da03a5ce684f271936a58
7
+ data.tar.gz: 9decda81bcfc32138478d91015590d0da49734e7e3d246a87bc40101daa7691a883118f8ad09d889b94dd9ce225f286a40635c2f94a6b84d3b1035431c8064e5
data/.gitignore CHANGED
@@ -6,5 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
- /test/
10
9
  Gemfile.lock
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in yuuki.gemspec
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
- require "bundler/gem_tasks"
2
- task :default => :spec
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
- class Caller
5
- Runner = Struct.new(:method, :tags, :exclude, :threading, :priority)
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
- def self.require_dir(dir, recursive = false)
8
- Dir.glob(recursive ? "#{require_dir}/**/*.rb" : "#{require_dir}/*.rb"){|file| require file}
9
- end
12
+ def initialize(*instances)
13
+ @instances = Set.new
14
+ @threads = []
15
+ add(*instances)
16
+ end
10
17
 
11
- def initialize(*klass)
12
- @runners = []
13
- @threads = []
14
- add(*klass)
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
- def add(*klass)
18
- klass.each do |klass|
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
- def run(**args)
37
- run_internal(@runners.reject(&:exclude), args)
38
- end
31
+ # add @yuuki to the instance
32
+ instance.instance_variable_set(:@yuuki, self)
39
33
 
40
- def run_all(**args)
41
- run_internal(@runners, args)
42
- end
34
+ # regist
35
+ @instances << instance
36
+ end
37
+ end
43
38
 
44
- def run_class(*klass, **args)
45
- run_internal(@runners.select{|e| !e.exclude && klass.any?{|k| e.method.receiver.instance_of?(k)}}, args)
46
- end
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
- def run_class_all(*klass, **args)
49
- run_internal(@runners.select{|e| klass.any?{|k| e.method.receiver.instance_of?(k)}}, args)
50
- end
47
+ def run(**args, &block)
48
+ run_internal(runners, args, &block)
49
+ end
51
50
 
52
- def run_tag(*tags, **args)
53
- run_internal(@runners.select{|e| tags.any?{|t| e.tags.any?(t)}}, args)
54
- end
51
+ def run_select(proc_select, **args, &block)
52
+ run_internal(runners.select(&proc_select), args, &block)
53
+ end
55
54
 
56
- def run_select(**args)
57
- run_internal(@runners.select{|e| yield(e)}, args)
58
- end
55
+ def run_tag(*tags, **args, &block)
56
+ run_select(proc{|_method, meta| meta[:tags]&.intersect?(tags)}, **args, &block)
57
+ end
59
58
 
60
- def run_method(klass, method, **args)
61
- runners = klass ? @runners.select{|e| e.method.receiver.class == klass} : @runners
62
- runners.select!{|e| e.method.name == method} if method
63
- run_internal(runners, args)
64
- end
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
- def join
67
- @threads.each(&:join)
68
- end
68
+ def join
69
+ @threads.each(&:join)
70
+ @threads.select!(&:alive?)
71
+ end
69
72
 
70
- def alive?
71
- @threads.any?(&:alive?)
72
- end
73
- alias running? alive?
74
-
75
- private
76
-
77
- def run_internal(runners, args)
78
- runners.each do |runner|
79
- if runner.threading
80
- @threads << Thread.new(runner.method, args) do |method, args|
81
- run_method_internal(method, args)
82
- end
83
- else
84
- run_method_internal(runner.method, args)
85
- end
86
- end
87
- @threads.select!(&:alive?)
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
- def run_method_internal(method, args)
91
- params = method.parameters
92
- return method[] if params.size == 0
93
- params_array = []
94
- params_hash = {}
95
- params_block = nil
96
- nonspecified_last_opt = nil
97
- params.each do |type, name|
98
- case type
99
- when :req
100
- raise Yuuki::Error.new("A required argument '#{name}' was not found on running #{method.owner}::#{method.name}") unless args.key?(name)
101
- params_array << args[name]
102
- when :opt
103
- next nonspecified_last_opt = name unless args.key?(name)
104
- raise Yuuki::Error.new("A required argument '#{nonspecified_last_opt}' was not found"\
105
- " on running #{method.owner}::#{method.name}"" with optional argument '#{name}'") if nonspecified_last_opt
106
- params_array << args[name]
107
- when :rest
108
- next unless args.key?(name)
109
- raise Yuuki::Error.new("A required argument '#{nonspecified_last_opt}' not found"\
110
- " on running #{method.owner}::#{method.name}"" with rest argument '#{name}'") if nonspecified_last_opt
111
- if args[name].respond_to?(:to_ary)
112
- params_array += args[name]
113
- else
114
- params_array << args[name]
115
- end
116
- when :keyreq
117
- raise Yuuki::Error.new("A required key argument '#{name}' was not found on running #{method.owner}::#{method.name}") unless args.key?(name)
118
- params_hash[name] = args[name]
119
- when :key
120
- params_hash[name] = args[name] if args.key?(name)
121
- when :keyrest
122
- next unless args.key?(name)
123
- if args[name].respond_to?(:to_hash)
124
- params_hash.merge!(args[name])
125
- else
126
- params_hash[name] = args[name]
127
- end
128
- when :block
129
- params_block = args[name]
130
- end
131
- end
132
- params_hash.empty? ? method[*params_array, &params_block] : method[*params_array, **params_hash, &params_block]
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, &params_block] : method[*params_array, **params_hash, &params_block]
134
147
  end
148
+ end
135
149
  end
data/lib/yuuki/error.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Yuuki
2
- class Error < StandardError
3
- end
4
+ class Error < StandardError
5
+ end
4
6
  end
@@ -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
- require 'yuuki/error'
1
+ # frozen_string_literal: true
2
2
 
3
- module Yuuki
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
- def delete(*methods)
14
- @runner_excepts ||= []
15
- @runner_excepts |= methods
16
- end
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
- def tag(method, *tags)
19
- @runner_info ||= {}
20
- @runner_info[method] ||= {}
21
- @runner_info[method][:tags] ||= []
22
- @runner_info[method][:tags] |= tags
23
- end
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
- def exclude(*methods)
26
- @runner_info ||= {}
27
- methods.each do |method|
28
- @runner_info[method] ||= {}
29
- @runner_info[method][:exclude] = true
30
- end
31
- end
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
- def threading(*methods)
34
- @runner_info ||= {}
35
- methods.each do |method|
36
- @runner_info[method] ||= {}
37
- @runner_info[method][:threading] = true
38
- end
39
- end
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
- def priority(method, priority)
42
- @runner_info ||= {}
43
- @runner_info[method] ||= {}
44
- @runner_info[method][:priority] = priority
45
- end
46
- end
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Yuuki
2
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
3
5
  end
data/lib/yuuki.rb CHANGED
@@ -1,4 +1,6 @@
1
- require 'yuuki/runner'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'yuuki/caller'
3
4
  require 'yuuki/error'
5
+ require 'yuuki/runner'
4
6
  require 'yuuki/version'
data/yuuki.gemspec CHANGED
@@ -1,28 +1,30 @@
1
- lib = File.expand_path('../lib', __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
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
- spec.name = 'yuuki'
7
- spec.version = Yuuki::VERSION
8
- spec.authors = ['Ishotihadus']
9
- spec.email = ['hanachan.pao@gmail.com']
8
+ spec.name = 'yuuki'
9
+ spec.version = Yuuki::VERSION
10
+ spec.authors = ['Ishotihadus']
11
+ spec.email = ['hanachan.pao@gmail.com']
10
12
 
11
- spec.summary = 'A caller / runner framework for Ruby'
12
- spec.description = 'A caller / runner framework for Ruby.'
13
- spec.homepage = 'https://github.com/ishotihadus/yuuki'
14
- spec.license = 'MIT'
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
- # Specify which files should be added to the gem when it is released.
17
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
- end
21
- spec.bindir = 'exe'
22
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
- spec.require_paths = ['lib']
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
- spec.add_development_dependency 'bundler'
26
- spec.add_development_dependency 'rake'
27
- spec.add_development_dependency 'pry'
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.0
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: 2019-03-16 00:00:00.000000000 Z
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: rake
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: pry
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.0.1
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: []