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.
@@ -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: []