kaicho 0.1.0
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/README.md +31 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/kaicho.gemspec +27 -0
- data/lib/kaicho.rb +230 -0
- data/lib/kaicho/version.rb +3 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fb83b5885137a7bf2c5f7356781218603fff10efd4ff45f2d3279ba9e9df9c03
|
4
|
+
data.tar.gz: a16eb9fb31003ce0030e3520d7825a34e76d27f3bc68ef481f1b705d894e1ce9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 16b18fd50f9585ca9654244efbf784f45d250f3bad1e915a97631d84ad43c2f2da29ec5ca5aea414997db4187d3cc1e886dddb46d62785a4ec8b994680eaaaac
|
7
|
+
data.tar.gz: ccf475fcdceda0ffd6b15ee90d30ea06d8db64d059a6f6be6e1b8b665c1dec9ff1b56d5ab1d815e92272f87bc26bd72bf7a6b591ce010407d9a8f3c061d92fb8
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Kaicho
|
2
|
+
|
3
|
+
Kaicho is the boss for your resources. It handles keeping everything up to
|
4
|
+
date.
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
class Fruits
|
8
|
+
include Kaicho
|
9
|
+
|
10
|
+
def intialize
|
11
|
+
def_resource :apples, accessor: :both { @apples || 0 }
|
12
|
+
def_resource :oranges, accessor: :both { @oranges || 0 }
|
13
|
+
def_resource :total, depend: { apples: :fail, oranges: :fail } do
|
14
|
+
puts "computing total"
|
15
|
+
@apples + @oranges
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
f = Fruits.new
|
21
|
+
f.apples #=> 0
|
22
|
+
f.apples += 1 #=> 1
|
23
|
+
computing total
|
24
|
+
f.oranges = 10 #=> 10
|
25
|
+
computing total
|
26
|
+
f.total #=> 11
|
27
|
+
f.oranges = 2
|
28
|
+
computing total
|
29
|
+
f.total #=> 13
|
30
|
+
f.total #=> 13
|
31
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "kaicho"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/kaicho.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "kaicho/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "kaicho"
|
7
|
+
spec.version = Kaicho::VERSION
|
8
|
+
spec.authors = ["Stone Tickle"]
|
9
|
+
spec.email = ["lattis@mochiro.moe"]
|
10
|
+
|
11
|
+
spec.summary = "a resource manager"
|
12
|
+
spec.homepage = "https://github.com/annacrombie/kaicho"
|
13
|
+
|
14
|
+
# Specify which files should be added to the gem when it is released.
|
15
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
16
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
17
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
end
|
19
|
+
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
end
|
data/lib/kaicho.rb
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
require "kaicho/version"
|
2
|
+
|
3
|
+
# Kaicho is a module that assists in a class's resource management.
|
4
|
+
# It enables you to chain resources together. Each resource when changed
|
5
|
+
# will update all of its dependants. Additionally, if you try to access a
|
6
|
+
# resource which has not been initialized, it will update itself along with
|
7
|
+
# all resources it depends on.
|
8
|
+
#
|
9
|
+
# This is useful if you have a class with many instance variables that all
|
10
|
+
# form a dependancy tree. For instance:
|
11
|
+
#
|
12
|
+
# ```
|
13
|
+
# class Fruits
|
14
|
+
# include Kaicho
|
15
|
+
#
|
16
|
+
# def intialize
|
17
|
+
# def_resource :apples, accessor: :both { @apples || 0 }
|
18
|
+
# def_resource :oranges, accessor: :both { @oranges || 0 }
|
19
|
+
# def_resource :total, depend: { apples: :fail, oranges: :fail } do
|
20
|
+
# puts "computing total"
|
21
|
+
# @apples + @oranges
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# f = Fruits.new
|
27
|
+
# f.apples #=> 0
|
28
|
+
# f.apples += 1 #=> 1
|
29
|
+
# computing total
|
30
|
+
# f.oranges = 10 #=> 10
|
31
|
+
# computing total
|
32
|
+
# f.total #=> 11
|
33
|
+
# f.oranges = 2
|
34
|
+
# computing total
|
35
|
+
# f.total #=> 13
|
36
|
+
# f.total #=> 13
|
37
|
+
# ```
|
38
|
+
module Kaicho
|
39
|
+
# adds trigger(s) which can be used to trigger updates of resources
|
40
|
+
# who have the trigger set
|
41
|
+
#
|
42
|
+
# @param t a list of symbols to be used as triggers
|
43
|
+
def add_triggers(*t)
|
44
|
+
@triggers ||= []
|
45
|
+
@triggers += t.map(&:to_sym)
|
46
|
+
end
|
47
|
+
|
48
|
+
# makes both an attr_reader and an attr_writer for the `dname`
|
49
|
+
#
|
50
|
+
# @param dname the resource to create accessors for
|
51
|
+
# @param share the owner of the shared variable
|
52
|
+
def attr_accessor(dname, share: nil)
|
53
|
+
attr_reader(dname, share: nil)
|
54
|
+
attr_writer(dname, share: nil)
|
55
|
+
end
|
56
|
+
|
57
|
+
# builds an attr_reader for a resource which functions just like a typical
|
58
|
+
# attr_reader but will update the resource if it hasn't been accessed
|
59
|
+
# before.
|
60
|
+
#
|
61
|
+
# @param dname the resource that will be accessed
|
62
|
+
# @param share the owner of the shared variable
|
63
|
+
def attr_reader(dname, share: nil)
|
64
|
+
read = share.nil? ? -> { instance_variable_get(:"@#{dname}") }
|
65
|
+
: -> { share.class_variable_get(:"@@#{dname}") }
|
66
|
+
define_singleton_method(dname) do
|
67
|
+
update_resource(dname) unless @resources[dname][:udid].positive?
|
68
|
+
read.call
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# builds an attr_writer for a resource which functions just like a typical
|
73
|
+
# attr_writer but will update the resource's dependants when it is called.
|
74
|
+
#
|
75
|
+
# @param dname the resource that will be accessed
|
76
|
+
# @param share the owner of the shared variable
|
77
|
+
def attr_writer(dname, share: nil)
|
78
|
+
write = share.nil? ? -> (v) { instance_variable_set(:"@#{dname}", v) }
|
79
|
+
: -> (v) { share.class_variable_set(:"@@#{dname}", v) }
|
80
|
+
define_singleton_method(:"#{dname}=") do |v|
|
81
|
+
write.call(v)
|
82
|
+
update_dependants(dname)
|
83
|
+
v
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_type(expected, got)
|
88
|
+
unless expected === got
|
89
|
+
raise TypeError.new("expected #{expected.name} got #{got}:#{got.class.name}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# define a resource
|
94
|
+
#
|
95
|
+
# @param dname the name of the resource
|
96
|
+
# @param depends a hash of dependants with the format
|
97
|
+
# { dependant_name: :update_action }
|
98
|
+
# where update_action is the action that
|
99
|
+
# is taken when this resource is updated.
|
100
|
+
# update_action can be one of
|
101
|
+
# :
|
102
|
+
def def_resource(dname,
|
103
|
+
depends: {},
|
104
|
+
triggers: [],
|
105
|
+
overwrite: false,
|
106
|
+
share: nil,
|
107
|
+
accessor: :read,
|
108
|
+
&block)
|
109
|
+
@resources ||= {}
|
110
|
+
|
111
|
+
check_type(Symbol, dname)
|
112
|
+
check_type(Hash, depends)
|
113
|
+
check_type(Array, triggers)
|
114
|
+
|
115
|
+
return if @resources.key?(dname) && !overwrite
|
116
|
+
|
117
|
+
add_triggers # initialize @triggers to []
|
118
|
+
triggers.each do |t|
|
119
|
+
raise ArgumentError.new("invalid trigger ':#{t}'") unless @triggers.include?(t)
|
120
|
+
end
|
121
|
+
|
122
|
+
depends.map =
|
123
|
+
case depends
|
124
|
+
when Array
|
125
|
+
depends.map { |d| [d, :keep] }.to_h
|
126
|
+
when Hash
|
127
|
+
depends
|
128
|
+
else
|
129
|
+
{ depends => :keep }
|
130
|
+
end
|
131
|
+
|
132
|
+
Zashoku.log.warn(self) { "overwriting resource #{dname}" } if @resources.key?(dname)
|
133
|
+
Zashoku.log.info(self) { "defining resource #{dname}" }
|
134
|
+
@resources.merge!(
|
135
|
+
dname => {
|
136
|
+
depends: depends,
|
137
|
+
proc: block,
|
138
|
+
udid: -1,
|
139
|
+
triggers: triggers & (@triggers || []),
|
140
|
+
share: share,
|
141
|
+
varname: share.nil? ? "@#{dname}" : "@@#{dname}"
|
142
|
+
}
|
143
|
+
)
|
144
|
+
|
145
|
+
case accessor
|
146
|
+
when :read, :r
|
147
|
+
attr_reader(dname, share: share)
|
148
|
+
when :write, :w
|
149
|
+
attr_writer(dname, share: share)
|
150
|
+
when :both, :rw
|
151
|
+
attr_accessor(dname, share: share)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def resource_defined?(dname)
|
156
|
+
return instance_variable_defined?("@#{dname}") unless @resources.key?(dname)
|
157
|
+
|
158
|
+
if @resources[dname][:share].nil?
|
159
|
+
instance_variable_defined?(@resources[dname][:varname])
|
160
|
+
else
|
161
|
+
@resources[dname][:share].class_variable_defined?(@resources[dname][:varname])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def update_resource(dname, udid=nil)
|
166
|
+
raise "no such resource #{dname}" unless @resources.key?(dname)
|
167
|
+
|
168
|
+
Zashoku.log.debug(self) { "not updating #{dname}" } if @resources[dname][:udid] == udid
|
169
|
+
|
170
|
+
return if @resources[dname][:udid] == udid
|
171
|
+
|
172
|
+
Zashoku.log.debug(self) { "updating resource #{dname} #{udid}" }
|
173
|
+
|
174
|
+
udid ||= rand
|
175
|
+
|
176
|
+
return unless update_requisites(dname, udid)
|
177
|
+
|
178
|
+
result = @resources[dname][:proc].call
|
179
|
+
|
180
|
+
if @resources[dname][:share].nil?
|
181
|
+
instance_variable_set(@resources[dname][:varname], result)
|
182
|
+
else
|
183
|
+
@resources[dname][:share].class_variable_set(@resources[dname][:varname], result)
|
184
|
+
end
|
185
|
+
|
186
|
+
@resources[dname][:udid] = udid
|
187
|
+
|
188
|
+
update_dependants(dname, udid)
|
189
|
+
end
|
190
|
+
|
191
|
+
def update_requisites(dname, udid=nil)
|
192
|
+
udid ||= rand
|
193
|
+
@resources[dname][:depends].each do |d, o|
|
194
|
+
case o
|
195
|
+
when :update
|
196
|
+
update_resource(d, udid)
|
197
|
+
when :keep
|
198
|
+
update_resource(d, udid) unless resource_defined?(d)
|
199
|
+
when :fail
|
200
|
+
unless resource_defined?(d)
|
201
|
+
Zashoku.log.debug(self) { "update resource #{dname} failing on #{d}" }
|
202
|
+
return false
|
203
|
+
end
|
204
|
+
when :force
|
205
|
+
update_resource(d, udid)
|
206
|
+
else
|
207
|
+
raise "option #{o} not understood for #{d} while updating #{dname}"
|
208
|
+
end
|
209
|
+
true
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def update_dependants(dname, udid=nil)
|
214
|
+
udid ||= rand
|
215
|
+
Zashoku.log.debug(self) { "updating dependants for #{dname}" }
|
216
|
+
dependants = @resources.select { |_,v| v[:depends].include?(dname) && v[:udid] != udid }
|
217
|
+
dependants.each { |d,_| update_resource(d, udid) }
|
218
|
+
end
|
219
|
+
|
220
|
+
def trigger_resources(trigger)
|
221
|
+
udid = rand
|
222
|
+
res = @resources.select { |_,v| v[:triggers].include?(trigger) }
|
223
|
+
res.each { |r,_| update_resource(r, udid) }
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_all_resources
|
227
|
+
udid = rand
|
228
|
+
@resources.keys.each { |d| update_resource(d, udid) }
|
229
|
+
end
|
230
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kaicho
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stone Tickle
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- lattis@mochiro.moe
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/setup
|
70
|
+
- kaicho.gemspec
|
71
|
+
- lib/kaicho.rb
|
72
|
+
- lib/kaicho/version.rb
|
73
|
+
homepage: https://github.com/annacrombie/kaicho
|
74
|
+
licenses: []
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.7.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: a resource manager
|
96
|
+
test_files: []
|