ko 0.1.0 → 0.1.2
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/.overcommit.yml +4 -0
- data/.rspec +1 -1
- data/.rubocop.yml +40 -3
- data/.tool-versions +2 -0
- data/Gemfile +11 -4
- data/Gemfile.lock +141 -0
- data/README.md +2 -2
- data/Rakefile +1 -1
- data/exe/ko +28 -0
- data/lib/ko/application.rb +26 -0
- data/lib/ko/children.rb +28 -0
- data/lib/ko/object.rb +72 -0
- data/lib/ko/signals/connection.rb +32 -0
- data/lib/ko/signals/signal.rb +53 -0
- data/lib/ko/signals/validator.rb +43 -0
- data/lib/ko/signals.rb +53 -0
- data/lib/ko/version.rb +2 -2
- data/lib/ko.rb +26 -2
- metadata +61 -9
- data/sig/ko.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3e23069fa6e3d507cacf8baae87633f6537cb5254a9cd465b8e372519c0e0704
|
|
4
|
+
data.tar.gz: e33170f4510c249229a33d33c9fdca7a2d54375240976618d9e0aa026c28a318
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b6c6b37d7ec073ff85c9b444e3e764b547dea1b1959db64b05a2603d70b9b50a44742879bc5e5a6b938a76520cfa6879faf0b291e1c985245abdc632c1e62ec
|
|
7
|
+
data.tar.gz: be5a5b7165da862a6f9482961185ee83845a335a69d0e648b367050c69ffe1abb7492e1124a6b99eaa5548f38fcf8463aab8f1bae7a23045fc0f5c38c4c9ad99
|
data/.overcommit.yml
ADDED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
TargetRubyVersion: 2
|
|
2
|
+
TargetRubyVersion: 3.2
|
|
3
|
+
NewCops: enable
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
|
|
6
|
+
require:
|
|
7
|
+
- rubocop-performance
|
|
8
|
+
- rubocop-rspec
|
|
9
|
+
|
|
10
|
+
Layout/LineLength:
|
|
11
|
+
Max: 120
|
|
12
|
+
Exclude:
|
|
13
|
+
- spec/**/*_spec.rb
|
|
14
|
+
|
|
15
|
+
Metrics/BlockLength:
|
|
16
|
+
Exclude:
|
|
17
|
+
- spec/**/*_spec.rb
|
|
18
|
+
- "*.gemspec"
|
|
19
|
+
|
|
20
|
+
Metrics/MethodLength:
|
|
21
|
+
Max: 10
|
|
22
|
+
|
|
23
|
+
RSpec/NamedSubject:
|
|
24
|
+
Enabled: false
|
|
3
25
|
|
|
4
26
|
Style/StringLiterals:
|
|
5
27
|
Enabled: true
|
|
@@ -9,5 +31,20 @@ Style/StringLiteralsInInterpolation:
|
|
|
9
31
|
Enabled: true
|
|
10
32
|
EnforcedStyle: double_quotes
|
|
11
33
|
|
|
12
|
-
|
|
13
|
-
|
|
34
|
+
Style/Documentation:
|
|
35
|
+
Enabled: false
|
|
36
|
+
|
|
37
|
+
Style/SymbolArray:
|
|
38
|
+
EnforcedStyle: brackets
|
|
39
|
+
|
|
40
|
+
Style/WordArray:
|
|
41
|
+
EnforcedStyle: brackets
|
|
42
|
+
|
|
43
|
+
Style/NumberedParametersLimit:
|
|
44
|
+
Max: 2
|
|
45
|
+
|
|
46
|
+
RSpec/EmptyExampleGroup:
|
|
47
|
+
AutoCorrect: false
|
|
48
|
+
|
|
49
|
+
RSpec/NestedGroups:
|
|
50
|
+
Max: 5
|
data/.tool-versions
ADDED
data/Gemfile
CHANGED
|
@@ -5,8 +5,15 @@ source "https://rubygems.org"
|
|
|
5
5
|
# Specify your gem's dependencies in ko.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
group :development, :test do
|
|
9
|
+
gem "overcommit", require: false
|
|
10
|
+
gem "rake", require: false
|
|
11
|
+
gem "rspec", require: false
|
|
12
|
+
gem "rubocop", require: false
|
|
13
|
+
gem "rubocop-performance", require: false
|
|
14
|
+
gem "rubocop-rspec", require: false
|
|
15
|
+
gem "simplecov", require: false
|
|
16
|
+
gem "solargraph", require: false
|
|
9
17
|
|
|
10
|
-
gem "rspec"
|
|
11
|
-
|
|
12
|
-
gem "rubocop", "~> 1.21"
|
|
18
|
+
gem "async-rspec"
|
|
19
|
+
end
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
ko (0.1.2)
|
|
5
|
+
async (~> 2.5.0)
|
|
6
|
+
binding_of_caller (~> 1.0.0)
|
|
7
|
+
zeitwerk (~> 2.6.0)
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
ast (2.4.2)
|
|
13
|
+
async (2.5.0)
|
|
14
|
+
console (~> 1.10)
|
|
15
|
+
io-event (~> 1.1)
|
|
16
|
+
timers (~> 4.1)
|
|
17
|
+
async-rspec (1.16.1)
|
|
18
|
+
rspec (~> 3.0)
|
|
19
|
+
rspec-files (~> 1.0)
|
|
20
|
+
rspec-memory (~> 1.0)
|
|
21
|
+
backport (1.2.0)
|
|
22
|
+
benchmark (0.2.1)
|
|
23
|
+
binding_of_caller (1.0.0)
|
|
24
|
+
debug_inspector (>= 0.0.1)
|
|
25
|
+
childprocess (4.1.0)
|
|
26
|
+
console (1.16.2)
|
|
27
|
+
fiber-local
|
|
28
|
+
debug_inspector (1.1.0)
|
|
29
|
+
diff-lcs (1.5.0)
|
|
30
|
+
docile (1.4.0)
|
|
31
|
+
e2mmap (0.1.0)
|
|
32
|
+
fiber-local (1.0.0)
|
|
33
|
+
iniparse (1.5.0)
|
|
34
|
+
io-event (1.1.7)
|
|
35
|
+
jaro_winkler (1.5.4)
|
|
36
|
+
json (2.6.3)
|
|
37
|
+
kramdown (2.4.0)
|
|
38
|
+
rexml
|
|
39
|
+
kramdown-parser-gfm (1.1.0)
|
|
40
|
+
kramdown (~> 2.0)
|
|
41
|
+
nokogiri (1.14.2-x86_64-linux)
|
|
42
|
+
racc (~> 1.4)
|
|
43
|
+
overcommit (0.60.0)
|
|
44
|
+
childprocess (>= 0.6.3, < 5)
|
|
45
|
+
iniparse (~> 1.4)
|
|
46
|
+
rexml (~> 3.2)
|
|
47
|
+
parallel (1.22.1)
|
|
48
|
+
parser (3.2.1.0)
|
|
49
|
+
ast (~> 2.4.1)
|
|
50
|
+
racc (1.6.2)
|
|
51
|
+
rainbow (3.1.1)
|
|
52
|
+
rake (13.0.6)
|
|
53
|
+
regexp_parser (2.7.0)
|
|
54
|
+
reverse_markdown (2.1.1)
|
|
55
|
+
nokogiri
|
|
56
|
+
rexml (3.2.5)
|
|
57
|
+
rspec (3.12.0)
|
|
58
|
+
rspec-core (~> 3.12.0)
|
|
59
|
+
rspec-expectations (~> 3.12.0)
|
|
60
|
+
rspec-mocks (~> 3.12.0)
|
|
61
|
+
rspec-core (3.12.1)
|
|
62
|
+
rspec-support (~> 3.12.0)
|
|
63
|
+
rspec-expectations (3.12.2)
|
|
64
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
65
|
+
rspec-support (~> 3.12.0)
|
|
66
|
+
rspec-files (1.1.3)
|
|
67
|
+
rspec (~> 3.0)
|
|
68
|
+
rspec-memory (1.0.3)
|
|
69
|
+
rspec (~> 3.0)
|
|
70
|
+
rspec-mocks (3.12.3)
|
|
71
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
72
|
+
rspec-support (~> 3.12.0)
|
|
73
|
+
rspec-support (3.12.0)
|
|
74
|
+
rubocop (1.46.0)
|
|
75
|
+
json (~> 2.3)
|
|
76
|
+
parallel (~> 1.10)
|
|
77
|
+
parser (>= 3.2.0.0)
|
|
78
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
79
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
80
|
+
rexml (>= 3.2.5, < 4.0)
|
|
81
|
+
rubocop-ast (>= 1.26.0, < 2.0)
|
|
82
|
+
ruby-progressbar (~> 1.7)
|
|
83
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
84
|
+
rubocop-ast (1.26.0)
|
|
85
|
+
parser (>= 3.2.1.0)
|
|
86
|
+
rubocop-capybara (2.17.1)
|
|
87
|
+
rubocop (~> 1.41)
|
|
88
|
+
rubocop-performance (1.16.0)
|
|
89
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
90
|
+
rubocop-ast (>= 0.4.0)
|
|
91
|
+
rubocop-rspec (2.19.0)
|
|
92
|
+
rubocop (~> 1.33)
|
|
93
|
+
rubocop-capybara (~> 2.17)
|
|
94
|
+
ruby-progressbar (1.11.0)
|
|
95
|
+
simplecov (0.22.0)
|
|
96
|
+
docile (~> 1.1)
|
|
97
|
+
simplecov-html (~> 0.11)
|
|
98
|
+
simplecov_json_formatter (~> 0.1)
|
|
99
|
+
simplecov-html (0.12.3)
|
|
100
|
+
simplecov_json_formatter (0.1.4)
|
|
101
|
+
solargraph (0.48.0)
|
|
102
|
+
backport (~> 1.2)
|
|
103
|
+
benchmark
|
|
104
|
+
bundler (>= 1.17.2)
|
|
105
|
+
diff-lcs (~> 1.4)
|
|
106
|
+
e2mmap
|
|
107
|
+
jaro_winkler (~> 1.5)
|
|
108
|
+
kramdown (~> 2.3)
|
|
109
|
+
kramdown-parser-gfm (~> 1.1)
|
|
110
|
+
parser (~> 3.0)
|
|
111
|
+
reverse_markdown (>= 1.0.5, < 3)
|
|
112
|
+
rubocop (>= 0.52)
|
|
113
|
+
thor (~> 1.0)
|
|
114
|
+
tilt (~> 2.0)
|
|
115
|
+
yard (~> 0.9, >= 0.9.24)
|
|
116
|
+
thor (1.2.1)
|
|
117
|
+
tilt (2.1.0)
|
|
118
|
+
timers (4.3.5)
|
|
119
|
+
unicode-display_width (2.4.2)
|
|
120
|
+
webrick (1.7.0)
|
|
121
|
+
yard (0.9.28)
|
|
122
|
+
webrick (~> 1.7.0)
|
|
123
|
+
zeitwerk (2.6.7)
|
|
124
|
+
|
|
125
|
+
PLATFORMS
|
|
126
|
+
x86_64-linux
|
|
127
|
+
|
|
128
|
+
DEPENDENCIES
|
|
129
|
+
async-rspec
|
|
130
|
+
ko!
|
|
131
|
+
overcommit
|
|
132
|
+
rake
|
|
133
|
+
rspec
|
|
134
|
+
rubocop
|
|
135
|
+
rubocop-performance
|
|
136
|
+
rubocop-rspec
|
|
137
|
+
simplecov
|
|
138
|
+
solargraph
|
|
139
|
+
|
|
140
|
+
BUNDLED WITH
|
|
141
|
+
2.4.6
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# KO
|
|
2
2
|
|
|
3
3
|
TODO: Delete this and the text below, and describe your gem
|
|
4
4
|
|
|
@@ -36,4 +36,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
36
36
|
|
|
37
37
|
## Code of Conduct
|
|
38
38
|
|
|
39
|
-
Everyone interacting in the
|
|
39
|
+
Everyone interacting in the KO project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ko/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
data/exe/ko
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "ko"
|
|
5
|
+
|
|
6
|
+
class MyApplication < KO::Application
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class MyObject < KO::Object
|
|
10
|
+
signal :something
|
|
11
|
+
|
|
12
|
+
# def on_ready do
|
|
13
|
+
# pp("Ready #{id}")
|
|
14
|
+
# end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
MyApplication[] do
|
|
18
|
+
x = MyObject["first"] do
|
|
19
|
+
signal :blah
|
|
20
|
+
|
|
21
|
+
MyObject["second"]
|
|
22
|
+
|
|
23
|
+
on_ready do
|
|
24
|
+
pp("Ready #{id}")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
t = MyObject["third"]
|
|
28
|
+
t.parent = x
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
pp MyApplication.instance
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
class Application < Object
|
|
5
|
+
# rubocop:disable Style/GlobalVars
|
|
6
|
+
class << self
|
|
7
|
+
def instance = $_KO_APP
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(id: nil)
|
|
11
|
+
begin
|
|
12
|
+
super(id: id || "app")
|
|
13
|
+
rescue InvalidParent
|
|
14
|
+
@parent = nil
|
|
15
|
+
end
|
|
16
|
+
raise AlreadyIitialized if $_KO_APP
|
|
17
|
+
|
|
18
|
+
$_KO_APP = self
|
|
19
|
+
end
|
|
20
|
+
# rubocop:enable Style/GlobalVars
|
|
21
|
+
|
|
22
|
+
def parent=(_obj)
|
|
23
|
+
raise KO::InvalidParent, "KO::Application cannot have a parent"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/ko/children.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
class Children
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@store = Set.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# TODO: use index
|
|
12
|
+
def [](id) = @store.find { _1.id == id }
|
|
13
|
+
|
|
14
|
+
def add(obj) = @store << obj
|
|
15
|
+
|
|
16
|
+
def remove(obj)
|
|
17
|
+
raise UnknownChildError unless @store.include?(obj)
|
|
18
|
+
|
|
19
|
+
@store.delete(obj)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def inspect = to_a.inspect
|
|
23
|
+
def pretty_inspect = to_a.pretty_inspect
|
|
24
|
+
|
|
25
|
+
def each(...) = @store.each(...)
|
|
26
|
+
def count(...) = @store.count(...)
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/ko/object.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
class Object
|
|
5
|
+
extend Signals
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def [](id = nil, &)
|
|
9
|
+
new(id:).tap do |obj|
|
|
10
|
+
obj.instance_exec(&) if block_given?
|
|
11
|
+
obj.ready.emit
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :id, :parent
|
|
17
|
+
|
|
18
|
+
signal :ready
|
|
19
|
+
|
|
20
|
+
def initialize(id: nil)
|
|
21
|
+
@id = id
|
|
22
|
+
self.parent = find_parent
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def children = @children ||= Children.new
|
|
26
|
+
|
|
27
|
+
def parent=(obj)
|
|
28
|
+
raise KO::InvalidParent unless can_be_parent?(obj)
|
|
29
|
+
|
|
30
|
+
parent&.remove_child(self)
|
|
31
|
+
@parent = obj
|
|
32
|
+
parent.add_child(self)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add_child(obj)
|
|
36
|
+
obj.parent = self if obj.parent != self
|
|
37
|
+
|
|
38
|
+
children.add(obj)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def remove_child(obj) = children.remove(obj)
|
|
42
|
+
|
|
43
|
+
def [](id) = children[id]
|
|
44
|
+
|
|
45
|
+
def app
|
|
46
|
+
@app ||= begin
|
|
47
|
+
obj = self
|
|
48
|
+
obj = obj.parent until obj.parent.nil?
|
|
49
|
+
obj
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def inspect
|
|
54
|
+
id_str = id.nil? ? "" : "[#{id.inspect}]"
|
|
55
|
+
"#<#{self.class}#{id_str} signals=#{signals.count} properties=0 children=#{children.count}>"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def find_parent
|
|
61
|
+
binding.callers[2..].each do |caller|
|
|
62
|
+
obj = caller.receiver
|
|
63
|
+
return obj if can_be_parent?(obj)
|
|
64
|
+
end
|
|
65
|
+
raise KO::InvalidParent
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def can_be_parent?(obj)
|
|
69
|
+
obj.is_a?(KO::Object) && obj != self
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
module Signals
|
|
5
|
+
class Connection
|
|
6
|
+
attr_reader :callable, :mode, :signal
|
|
7
|
+
|
|
8
|
+
def initialize(callable, signal, mode:, one_shot:)
|
|
9
|
+
Validator.new(signal).validate_callable_type!(callable)
|
|
10
|
+
|
|
11
|
+
@callable = callable
|
|
12
|
+
@signal = signal
|
|
13
|
+
@mode = mode
|
|
14
|
+
@one_shot = one_shot
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def one_shot? = @one_shot
|
|
18
|
+
|
|
19
|
+
def call(*args, force_direct: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
20
|
+
return @callable.call(*args) if @callable.is_a?(Method) || @callable.is_a?(Signal)
|
|
21
|
+
|
|
22
|
+
@callable.send(signal.receiver_name, *args)
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
warn(e)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def disconnect
|
|
28
|
+
@signal.disconnect(@callable)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
module Signals
|
|
5
|
+
class Signal
|
|
6
|
+
attr_reader :name, :arg_types, :connections
|
|
7
|
+
|
|
8
|
+
def initialize(name, arg_types)
|
|
9
|
+
@name = name
|
|
10
|
+
@arg_types = arg_types
|
|
11
|
+
|
|
12
|
+
@validator = Validator.new(self)
|
|
13
|
+
@connections = {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def dup = super().tap { _1.connections.clear }
|
|
17
|
+
|
|
18
|
+
def receiver_name = "on_#{name}".to_sym
|
|
19
|
+
|
|
20
|
+
# Only 3 ways to connect:
|
|
21
|
+
# some_object.some_signal.connect(receiver) -> receiver#on_some_signal
|
|
22
|
+
# some_object.some_signal.connect(receiver.method(:do_something)) -> receiver#do_something
|
|
23
|
+
# some_object.some_signal.connect(receiver.another_signal) -> emits receiver#another_signal
|
|
24
|
+
# Blocks, Procs and Lambda are not supported on purpose
|
|
25
|
+
def connect(callable = nil, mode: :direct, one_shot: false)
|
|
26
|
+
@validator.validate_callable!(callable)
|
|
27
|
+
|
|
28
|
+
Connection.new(callable, self, mode:, one_shot:).tap { @connections[callable] = _1 }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def disconnect(callable)
|
|
32
|
+
raise ArgumentError, "given callable is not connected to this signal" if @connections.delete(callable).nil?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def emit(*args)
|
|
36
|
+
@validator.validate_args!(args)
|
|
37
|
+
notify_subscribers(args)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def inspect = "#<#{self.class}[#{name.inspect}] connections=#{@connections.count}>"
|
|
41
|
+
|
|
42
|
+
def call(...) = emit(...)
|
|
43
|
+
|
|
44
|
+
def notify_subscribers(args)
|
|
45
|
+
@connections.values.shuffle.each do |connection|
|
|
46
|
+
connection.call(*args)
|
|
47
|
+
ensure
|
|
48
|
+
connection.disconnect if connection.one_shot?
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
module Signals
|
|
5
|
+
class Validator
|
|
6
|
+
def initialize(signal)
|
|
7
|
+
@signal = signal
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate_args!(args)
|
|
11
|
+
types = args.map(&:class)
|
|
12
|
+
|
|
13
|
+
return if types.count == @signal.arg_types.count && types_match?(types)
|
|
14
|
+
|
|
15
|
+
raise KO::EmitError, "expected args: #{@signal.arg_types}. given: #{types}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate_callable!(callable)
|
|
19
|
+
callable = validate_callable_type!(callable)
|
|
20
|
+
validate_signal_arity!(callable) if callable.is_a?(Signal)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate_callable_type!(callable)
|
|
24
|
+
return callable if callable.is_a?(Signal) || callable.is_a?(Method)
|
|
25
|
+
|
|
26
|
+
return callable.method(@signal.receiver_name) if callable.respond_to?(@signal.receiver_name)
|
|
27
|
+
|
|
28
|
+
raise ArgumentError, "callable must be a Signal, a Method, or must respond to #{@signal.receiver_name}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def types_match?(types) = types.each.with_index.all? { _1.ancestors.include?(@signal.arg_types[_2]) }
|
|
34
|
+
|
|
35
|
+
def validate_signal_arity!(signal)
|
|
36
|
+
return if signal.arg_types == @signal.arg_types
|
|
37
|
+
|
|
38
|
+
raise ArgumentError,
|
|
39
|
+
"target signal must have same type signature. Expected: #{@signal.arg_types}. given: #{signal.arg_types}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/ko/signals.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KO
|
|
4
|
+
module Signals
|
|
5
|
+
module InstanceMethods
|
|
6
|
+
# TODO: write me!
|
|
7
|
+
def respond_to_missing?(name, include_private = false); end
|
|
8
|
+
|
|
9
|
+
def method_missing(name, *args, **params, &)
|
|
10
|
+
sigs = signals.each.with_object({}) { |(_k, v), acc| acc[v.receiver_name] = v }
|
|
11
|
+
super unless sigs.include?(name)
|
|
12
|
+
|
|
13
|
+
define_singleton_method(name, &)
|
|
14
|
+
|
|
15
|
+
sigs[name].connect(self)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def signals = @signals ||= self.class.signals.transform_values(&:dup)
|
|
21
|
+
|
|
22
|
+
def emit(name, *args) = send(name).call(*args)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module AddSignal
|
|
26
|
+
def signal(name, *arg_types)
|
|
27
|
+
signals[name.to_sym] = Signal.new(name, arg_types)
|
|
28
|
+
|
|
29
|
+
d = respond_to?(:define_method) ? :define_method : :define_singleton_method
|
|
30
|
+
send(d, name) { signals[name.to_sym] }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
def extended(base)
|
|
36
|
+
base.include(InstanceMethods)
|
|
37
|
+
base.extend(AddSignal)
|
|
38
|
+
base.include(AddSignal)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# def method_added(name)
|
|
43
|
+
# pp([self, name])
|
|
44
|
+
# end
|
|
45
|
+
|
|
46
|
+
def inherited(child)
|
|
47
|
+
super(child)
|
|
48
|
+
child.signals.merge!(signals)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def signals = @signals ||= {}
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/ko/version.rb
CHANGED
data/lib/ko.rb
CHANGED
|
@@ -2,7 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "ko/version"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
require "zeitwerk"
|
|
6
|
+
|
|
7
|
+
require "binding_of_caller"
|
|
8
|
+
|
|
9
|
+
loader = Zeitwerk::Loader.for_gem
|
|
10
|
+
loader.inflector.inflect(
|
|
11
|
+
"ko" => "KO"
|
|
12
|
+
)
|
|
13
|
+
loader.setup
|
|
14
|
+
|
|
15
|
+
module KO
|
|
6
16
|
class Error < StandardError; end
|
|
7
|
-
|
|
17
|
+
|
|
18
|
+
class InvalidParent < Error
|
|
19
|
+
def initialize(msg = "only KO::Object can be a parent for KO::Object")
|
|
20
|
+
super(msg)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class AlreadyIitialized < Error
|
|
25
|
+
def initialize
|
|
26
|
+
super("KO is already initialized: only one instance of KO::Application must exist")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class UnknownChildError < Error; end
|
|
31
|
+
class EmitError < Error; end
|
|
8
32
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,57 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ko
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gleb Sinyavskiy
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-04-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2023-04-09 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: async
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 2.5.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 2.5.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: binding_of_caller
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 1.0.0
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 1.0.0
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: zeitwerk
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 2.6.0
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 2.6.0
|
|
13
55
|
description: KO
|
|
14
56
|
email:
|
|
15
57
|
- zhulik.gleb@gmail.com
|
|
@@ -18,23 +60,33 @@ executables:
|
|
|
18
60
|
extensions: []
|
|
19
61
|
extra_rdoc_files: []
|
|
20
62
|
files:
|
|
63
|
+
- ".overcommit.yml"
|
|
21
64
|
- ".rspec"
|
|
22
65
|
- ".rubocop.yml"
|
|
66
|
+
- ".tool-versions"
|
|
23
67
|
- CODE_OF_CONDUCT.md
|
|
24
68
|
- Gemfile
|
|
69
|
+
- Gemfile.lock
|
|
25
70
|
- LICENSE.txt
|
|
26
71
|
- README.md
|
|
27
72
|
- Rakefile
|
|
28
73
|
- exe/ko
|
|
29
74
|
- lib/ko.rb
|
|
75
|
+
- lib/ko/application.rb
|
|
76
|
+
- lib/ko/children.rb
|
|
77
|
+
- lib/ko/object.rb
|
|
78
|
+
- lib/ko/signals.rb
|
|
79
|
+
- lib/ko/signals/connection.rb
|
|
80
|
+
- lib/ko/signals/signal.rb
|
|
81
|
+
- lib/ko/signals/validator.rb
|
|
30
82
|
- lib/ko/version.rb
|
|
31
|
-
- sig/ko.rbs
|
|
32
83
|
homepage: https://github.com/zhulik/ko
|
|
33
84
|
licenses:
|
|
34
85
|
- MIT
|
|
35
86
|
metadata:
|
|
36
87
|
homepage_uri: https://github.com/zhulik/ko
|
|
37
|
-
|
|
88
|
+
rubygems_mfa_required: 'true'
|
|
89
|
+
post_install_message:
|
|
38
90
|
rdoc_options: []
|
|
39
91
|
require_paths:
|
|
40
92
|
- lib
|
|
@@ -42,15 +94,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
42
94
|
requirements:
|
|
43
95
|
- - ">="
|
|
44
96
|
- !ruby/object:Gem::Version
|
|
45
|
-
version: 2.
|
|
97
|
+
version: 3.2.0
|
|
46
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
99
|
requirements:
|
|
48
100
|
- - ">="
|
|
49
101
|
- !ruby/object:Gem::Version
|
|
50
102
|
version: '0'
|
|
51
103
|
requirements: []
|
|
52
|
-
rubygems_version: 3.4.
|
|
53
|
-
signing_key:
|
|
104
|
+
rubygems_version: 3.4.10
|
|
105
|
+
signing_key:
|
|
54
106
|
specification_version: 4
|
|
55
107
|
summary: KO
|
|
56
108
|
test_files: []
|
data/sig/ko.rbs
DELETED