kaicho 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.5
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in kaicho.gemspec
6
+ gemspec
@@ -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
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Kaicho
2
+ VERSION = "0.1.0"
3
+ 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: []