statize 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1419b6b991c36e435ce8282dad28ef1a3d65a04862963058b4ed41bddcd955f9
4
+ data.tar.gz: a561f07330b9cf9a7247f43f81f97db72f8372b82dc9e4bf47a319aa5489f4b2
5
+ SHA512:
6
+ metadata.gz: 5e027e8e4da7e11f9cd557d517a61fa72eec2c18d1434fd1237775e5deb1d173a8da2ffdc2b1895a3db19dd6d64c114cc1ba76d0cf7dc17633e47244adf4347b
7
+ data.tar.gz: 2b7949d5edbab65bb53d8e78ef12ec519b618d33a9dd03e1ef722d29dadfcbefcd907408343ab993dd7034e5b8bd09b923dccd7d4760efe4bb4d7ec453741c7e
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in statize.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ statize (0.1.0)
5
+ teLogger
6
+ toolrack
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ base58 (0.2.3)
12
+ devops_assist (0.3.1)
13
+ git_cli
14
+ git_cli_prompt
15
+ gvcs
16
+ teLogger
17
+ toolrack
18
+ tty-prompt
19
+ diff-lcs (1.5.0)
20
+ git_cli (0.10.0)
21
+ gvcs
22
+ ptools (~> 1.4.0)
23
+ teLogger
24
+ toolrack
25
+ git_cli_prompt (0.3.1)
26
+ teLogger
27
+ toolrack
28
+ tty-prompt
29
+ gvcs (0.1.0)
30
+ pastel (0.8.0)
31
+ tty-color (~> 0.5)
32
+ ptools (1.4.2)
33
+ rake (13.0.6)
34
+ rspec (3.12.0)
35
+ rspec-core (~> 3.12.0)
36
+ rspec-expectations (~> 3.12.0)
37
+ rspec-mocks (~> 3.12.0)
38
+ rspec-core (3.12.0)
39
+ rspec-support (~> 3.12.0)
40
+ rspec-expectations (3.12.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.12.0)
43
+ rspec-mocks (3.12.0)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.12.0)
46
+ rspec-support (3.12.0)
47
+ teLogger (0.2.0)
48
+ toolrack (0.19.1)
49
+ base58
50
+ tty-color (0.6.0)
51
+ tty-cursor (0.7.1)
52
+ tty-prompt (0.23.1)
53
+ pastel (~> 0.8)
54
+ tty-reader (~> 0.8)
55
+ tty-reader (0.9.0)
56
+ tty-cursor (~> 0.7)
57
+ tty-screen (~> 0.8)
58
+ wisper (~> 2.0)
59
+ tty-screen (0.8.1)
60
+ wisper (2.0.1)
61
+
62
+ PLATFORMS
63
+ x86_64-linux
64
+
65
+ DEPENDENCIES
66
+ devops_assist
67
+ rake (~> 13.0)
68
+ rspec (~> 3.0)
69
+ statize!
70
+
71
+ BUNDLED WITH
72
+ 2.2.28
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Statize
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/statize`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'statize'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install statize
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/statize.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'devops_assist'
9
+
10
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "statize"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Statize
4
+ VERSION = "0.1.0"
5
+ end
data/lib/statize.rb ADDED
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+ require 'toolrack'
3
+ require 'teLogger'
4
+
5
+ require_relative "statize/version"
6
+
7
+ module Statize
8
+ class Error < StandardError; end
9
+ class InvalidState < StandardError; end
10
+ class InvalidStateForEvent < StandardError; end
11
+ class UserHalt < StandardError; end
12
+ class InvalidEvent < StandardError; end
13
+ class DuplicatedKey < StandardError; end
14
+
15
+ include TR::CondUtils
16
+
17
+ include TeLogger::TeLogHelper
18
+ teLogger_tag :statize
19
+
20
+ # class methods start here
21
+ module ClassMethods
22
+
23
+ def stateful(opts = { }, &block)
24
+ @ops = { } if @ops.nil?
25
+ ops = {
26
+ initial_state: :open,
27
+ state_attr_name: "state",
28
+ }
29
+
30
+ @profile = opts[:profile] || :default
31
+
32
+ #opts.delete(:profile)
33
+
34
+ ops.merge!(opts) if not opts.nil? and opts.is_a?(Hash)
35
+
36
+ @ops[@profile] = { }
37
+ @ops[@profile].merge!(ops)
38
+
39
+ if block
40
+ class_eval(&block)
41
+ end
42
+
43
+ end
44
+
45
+ # definition of event
46
+ # Using global parameter @profile during definition
47
+ def event(evt, *args, &block)
48
+
49
+ evt = evt.to_sym
50
+ add_event_block(@profile, evt, &block)
51
+
52
+ args.first.each do |fromSt, toSt|
53
+ fromSt = fromSt.to_sym
54
+ toSt = toSt.to_sym
55
+ add_state_events(@profile,fromSt, evt)
56
+ add_state_transition(@profile, fromSt, toSt)
57
+ add_event_states(@profile, evt, fromSt, toSt)
58
+ add_profile_states(@profile, fromSt, toSt)
59
+ end
60
+
61
+ end
62
+
63
+ def state_meaning(ops)
64
+ raise Error, "Hash expected" if not ops.is_a?(Hash)
65
+ ops.each do |k,v|
66
+ add_state_meaning(@profile, k, v)
67
+ add_meaning_states(@profile, v, k)
68
+ end
69
+ end
70
+
71
+ def state_attr_name(prof = :default)
72
+ @ops[prof][:state_attr_name].to_s.freeze
73
+ end
74
+
75
+ def initial_state(prof = :default)
76
+ @ops[prof][:initial_state].to_s.freeze
77
+ end
78
+
79
+ def states_table(prof = :default)
80
+ _states_transfer_table(prof).freeze
81
+ end
82
+
83
+ def state_events_table(prof = :default)
84
+ _state_events_table(prof).freeze
85
+ end
86
+
87
+ def event_states_table(prof = :default)
88
+ _event_states_table(prof).freeze
89
+ end
90
+
91
+ def event_block_table(prof = :default)
92
+ _event_block_table(prof).freeze
93
+ end
94
+
95
+ def profile_states_list(prof = :default)
96
+ _profile_states_list(prof).freeze
97
+ end
98
+
99
+ def state_meaning_table(prof = :default)
100
+ _state_meaning_table(prof).freeze
101
+ end
102
+
103
+ def meaning_states_table(prof = :default)
104
+ _meaning_states_table(prof).freeze
105
+ end
106
+
107
+ def state_profiles
108
+ @ops.keys.freeze
109
+ end
110
+
111
+ private
112
+ # keep possible next states
113
+ def add_state_transition(prof, from, to)
114
+ _states_transfer_table(prof)[from] = [] if _states_transfer_table(prof)[from].nil?
115
+ # ok to keep single relationship as this table hold the possible next states,
116
+ # which is possible duplicate but different event
117
+ _states_transfer_table(prof)[from] << to if not _states_transfer_table(prof)[from].include?(to)
118
+ end
119
+
120
+ # map state (current state) to possible events
121
+ def add_state_events(prof, from, evt)
122
+ _state_events_table(prof)[from] = [] if _state_events_table(prof)[from].nil?
123
+ _state_events_table(prof)[from] << evt
124
+ end
125
+
126
+ # keep complete event, from and to state
127
+ def add_event_states(prof, evt, fromSt, toSt)
128
+ _event_states_table(prof)[evt] = {} if _event_states_table(prof)[evt].nil?
129
+ _event_states_table(prof)[evt][fromSt] = toSt
130
+ end
131
+
132
+ # map event to block
133
+ def add_event_block(prof, evt, &block)
134
+ _event_block_table(prof)[evt] = block if block
135
+ end
136
+
137
+ def add_profile_states(prof, *st)
138
+ st.each do |s|
139
+ _profile_states_list(prof) << s if not _profile_states_list(prof).include?(s)
140
+ end
141
+ end
142
+
143
+ def add_state_meaning(prof, state, meaning)
144
+ val = _state_meaning_table[state]
145
+ raise DuplicatedKey, "State '#{state}' has already given meaning '#{val}'" if not val.nil?
146
+ _state_meaning_table[state] = meaning
147
+ end
148
+
149
+ def add_meaning_states(prof, meaning, state)
150
+ _meaning_states_table(prof)[meaning] = [] if _meaning_states_table(prof)[meaning].nil?
151
+ _meaning_states_table(prof)[meaning] << state if not _meaning_states_table(prof)[meaning].include?(state)
152
+ end
153
+
154
+ def _states_transfer_table(prof = :default)
155
+ @ops[prof][:state_transfer] = {} if @ops[prof][:state_transfer].nil?
156
+ @ops[prof][:state_transfer]
157
+ end
158
+
159
+ def _state_events_table(prof = :default)
160
+ @ops[prof][:state_events] = {} if @ops[prof][:state_events].nil?
161
+ @ops[prof][:state_events]
162
+ end
163
+
164
+ def _event_states_table(prof = :default)
165
+ @ops[prof][:event_states] = {} if @ops[prof][:event_states].nil?
166
+ @ops[prof][:event_states]
167
+ end
168
+
169
+ def _event_block_table(prof = :default)
170
+ @ops[prof][:event_block_table] = {} if @ops[prof][:event_block_table].nil?
171
+ @ops[prof][:event_block_table]
172
+ end
173
+
174
+ def _profile_states_list(prof = :default)
175
+ @ops[prof][:states] = [] if @ops[prof][:states].nil?
176
+ @ops[prof][:states]
177
+ end
178
+
179
+ def _state_meaning_table(prof = :default)
180
+ @ops[prof][:state_meaning] = {} if @ops[prof][:state_meaning].nil?
181
+ @ops[prof][:state_meaning]
182
+ end
183
+
184
+ def _meaning_states_table(prof = :default)
185
+ @ops[prof][:meaning_states] = {} if @ops[prof][:meaning_states].nil?
186
+ @ops[prof][:meaning_states]
187
+ end
188
+
189
+ end
190
+ def self.included(klass)
191
+ klass.extend(ClassMethods)
192
+ end
193
+ # end class methods
194
+
195
+
196
+ #
197
+ # instance methods
198
+ #
199
+ def init_state(prof = :default)
200
+ prof = prof.to_sym if not prof.nil?
201
+ set_active_state_profile(prof)
202
+ update_state(self.class.initial_state(prof))
203
+ end
204
+
205
+ def activate_state_profile(prof)
206
+ prof = prof.to_sym if not prof.nil?
207
+ set_active_state_profile(prof)
208
+ end
209
+
210
+ def at_initial_state?
211
+ current_state == self.class.initial_state(active_state_profile)
212
+ end
213
+
214
+ def next_states
215
+ st = current_state
216
+ if not_empty?(st)
217
+ self.class.states_table(active_state_profile)[st.to_sym].map { |e| e.to_s }
218
+ else
219
+ []
220
+ end
221
+ end
222
+
223
+ def all_states
224
+ self.class.profile_states_list(active_state_profile).map { |s| s.to_s }
225
+ end
226
+
227
+ def apply_state(st)
228
+
229
+ case st
230
+ when Symbol
231
+ sst = st
232
+ else
233
+ sst = st.to_sym
234
+ end
235
+
236
+ if next_states.include?(sst.to_s)
237
+ update_state(sst)
238
+ true
239
+ else
240
+ false
241
+ end
242
+ end
243
+ def apply_state!(st)
244
+ res = apply_state(st)
245
+ raise InvalidState, "Given new state '#{st}' is not valid" if not res
246
+ end
247
+
248
+
249
+ def next_events
250
+ se = self.class.state_events_table(active_state_profile)
251
+ cst = current_state
252
+ res = se[cst.to_sym]
253
+ # res == nil will happened if it is at the end of the event chain
254
+ res = [] if res.nil?
255
+ res
256
+ end
257
+
258
+ def trigger_event(evt, &block)
259
+ evt = evt.to_sym if not evt.nil?
260
+ cst = current_state
261
+ if not_empty?(cst)
262
+ cst = cst.to_sym
263
+ tbl = self.class.event_states_table(active_state_profile)[evt]
264
+
265
+ raise InvalidEvent, "Event '#{evt}' not registered under profile '#{active_state_profile}'" if tbl.nil?
266
+
267
+ # current state not tie to from state of this event
268
+ raise InvalidStateForEvent, "Current state '#{cst}' is not register to event '#{evt}'" if not tbl.keys.include?(cst)
269
+
270
+ destSt = tbl[cst]
271
+ raise InvalidStateForEvent, "New state transition from current state '#{cst}' due to event '#{evt}' is empty" if is_empty?(destSt)
272
+
273
+ evtBlock = self.class.event_block_table(active_state_profile)[evt]
274
+ update = true
275
+
276
+ update = evtBlock.call(action: :before, profile: active_state_profile, event: evt, from_state: cst, to_state: destSt, target: self) if not evtBlock.nil?
277
+ update = true if is_empty?(update) or not_bool?(update)
278
+
279
+ if update
280
+ apply_state(destSt)
281
+ evtBlock.call(action: :after, profile: active_state_profile, event: evt, from_state: cst, to_state: destSt, target: self) if not evtBlock.nil?
282
+ block.call(action: :after, profile: active_state_profile, event: evt, from_state: cst, to_state: destSt, target: self) if block
283
+ else
284
+ teLogger.error "Event '#{evt}' triggered but block returned false. Status not updated to '#{destSt}'"
285
+ raise UserHalt,"Event '#{evt}' triggered but block returned false. Status not updated to '#{destSt}'"
286
+ end
287
+
288
+ else
289
+ # current state is empty!
290
+ end
291
+ end
292
+
293
+ def current_state
294
+ if has_rattr?(self.class.state_attr_name(active_state_profile))
295
+ self.send("#{self.class.state_attr_name(active_state_profile)}")
296
+ else
297
+ nil
298
+ end
299
+ end
300
+
301
+ def state_profiles
302
+ self.class.state_profiles
303
+ end
304
+
305
+ def current_state_meaning
306
+ cst = current_state
307
+ smt = self.class.state_meaning_table(active_state_profile)
308
+ meaning = smt[cst.to_sym]
309
+ if meaning.nil?
310
+ :not_defined
311
+ else
312
+ meaning
313
+ end
314
+ end
315
+
316
+ def states_of_meaning(meaning)
317
+ res = self.class.meaning_states_table(active_state_profile)[meaning]
318
+ if not res.nil?
319
+ res
320
+ else
321
+ []
322
+ end
323
+ end
324
+
325
+ private
326
+ def has_wattr?(key)
327
+ self.respond_to?("#{key}=".to_sym)
328
+ end
329
+ def has_rattr?(key)
330
+ self.respond_to?("#{key}".to_sym)
331
+ end
332
+
333
+ def update_state(st)
334
+ if has_wattr?(self.class.state_attr_name(active_state_profile))
335
+ self.send("#{self.class.state_attr_name(active_state_profile)}=", st.to_s)
336
+ end
337
+ end
338
+
339
+ def active_state_profile
340
+ @aprof = :default if is_empty?(@aprof)
341
+ @aprof
342
+ end
343
+
344
+ def set_active_state_profile(val)
345
+ @aprof = val
346
+ end
347
+
348
+ # instance methods
349
+
350
+ end
data/statize.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/statize/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "statize"
7
+ spec.version = Statize::VERSION
8
+ spec.authors = ["Chris"]
9
+ spec.email = ["chris@antrapol.com"]
10
+
11
+ spec.summary = ""
12
+ spec.description = ""
13
+ spec.homepage = ""
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+ #spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
17
+
18
+ #spec.metadata["homepage_uri"] = spec.homepage
19
+ #spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
20
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency 'toolrack'
34
+ spec.add_dependency 'teLogger'
35
+
36
+ spec.add_development_dependency 'devops_assist'
37
+
38
+ # Uncomment to register a new dependency of your gem
39
+ # spec.add_dependency "example-gem", "~> 1.0"
40
+
41
+ # For more information and examples about making a new gem, checkout our
42
+ # guide at: https://bundler.io/guides/creating_gem.html
43
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: statize
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: toolrack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: teLogger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: devops_assist
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: ''
56
+ email:
57
+ - chris@antrapol.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rspec"
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - README.md
66
+ - Rakefile
67
+ - bin/console
68
+ - bin/setup
69
+ - lib/statize.rb
70
+ - lib/statize/version.rb
71
+ - statize.gemspec
72
+ homepage: ''
73
+ licenses: []
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.4.0
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.2.22
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: ''
94
+ test_files: []