skn_utils 5.4.0 → 5.8.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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +2 -0
  3. data/README.md +223 -72
  4. data/_config.yml +4 -4
  5. data/bin/concurrent_test_block +54 -0
  6. data/bin/concurrent_test_grouped +45 -0
  7. data/bin/concurrent_test_procs +45 -0
  8. data/bin/concurrent_test_wrapped +49 -0
  9. data/lib/skn_container.rb +2 -1
  10. data/lib/skn_failure.rb +2 -0
  11. data/lib/skn_hash.rb +2 -0
  12. data/lib/skn_registry.rb +25 -5
  13. data/lib/skn_settings.rb +2 -0
  14. data/lib/skn_success.rb +2 -0
  15. data/lib/skn_utils.rb +13 -2
  16. data/lib/skn_utils/concurrent_jobs.rb +117 -0
  17. data/lib/skn_utils/configurable.rb +55 -6
  18. data/lib/skn_utils/configuration.rb +2 -0
  19. data/lib/skn_utils/core_extensions.rb +29 -0
  20. data/lib/skn_utils/dotted_hash.rb +1 -0
  21. data/lib/skn_utils/env_string_handler.rb +2 -0
  22. data/lib/skn_utils/http_processor.rb +34 -0
  23. data/lib/skn_utils/job_commands.rb +247 -0
  24. data/lib/skn_utils/nested_result.rb +2 -0
  25. data/lib/skn_utils/notifier_base.rb +2 -0
  26. data/lib/skn_utils/null_object.rb +2 -0
  27. data/lib/skn_utils/page_controls.rb +2 -0
  28. data/lib/skn_utils/result_bean.rb +2 -0
  29. data/lib/skn_utils/version.rb +3 -1
  30. data/lib/skn_utils/wrappable.rb +32 -0
  31. data/skn_utils.gemspec +27 -22
  32. data/spec/lib/skn_utils/concurrent_jobs_spec.rb +279 -0
  33. data/spec/lib/skn_utils/configurable_spec.rb +23 -36
  34. data/spec/lib/skn_utils/registry_spec.rb +22 -0
  35. data/spec/lib/skn_utils/wrappers_spec.rb +80 -0
  36. data/spec/spec_helper.rb +5 -0
  37. data/spec/support/configurables.rb +36 -0
  38. data/spec/support/xml_matchers.rb +121 -0
  39. metadata +71 -24
  40. data/README.rdoc +0 -379
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # file: concurrent_test_grouped
4
+ #
5
+
6
+ require 'bundler/setup'
7
+ require 'skn_utils'
8
+
9
+
10
+ # ##
11
+ # MainLine
12
+ # ##
13
+ #
14
+ begin
15
+ # CommandJSONPost, CommandFORMGet, CommandJSONGet,
16
+ # CommandJSONPut, CommandFORMDelete
17
+ commands = [
18
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/posts"),
19
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/comments"),
20
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/todos/1"),
21
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/users")
22
+ ]
23
+
24
+ # Initialize the queue with Async Workers by default
25
+ provider = SknUtils::ConcurrentJobs.call
26
+
27
+ # Populate WorkQueue
28
+ provider.register_jobs(commands, SknUtils::HttpProcessor) # mis-spelling these params result in an immediate exception (line 43 below)
29
+
30
+ # Execute WorkQueue
31
+ result = provider.render_jobs
32
+
33
+ if result.success?
34
+ puts "Success: true"
35
+ puts "Values: #{result.values}"
36
+ puts "Messages: #{result.messages}"
37
+ else
38
+ puts "Success: false - errors: #{result.messages.join(', ')}"
39
+ puts "Values: #{result.values}"
40
+ end
41
+
42
+ # result.values
43
+ rescue => e
44
+ $stderr.puts e.message, e.backtrace
45
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # file: concurrent_test_procs
4
+ #
5
+ require 'bundler/setup'
6
+ require 'skn_utils'
7
+
8
+
9
+ # ##
10
+ # MainLine
11
+ # ##
12
+ #
13
+ begin
14
+ # CommandJSONPost, CommandFORMGet, CommandJSONGet,
15
+ # CommandJSONPut, CommandFORMDelete
16
+ commands = [
17
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/posts"),
18
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/comments"),
19
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/todos/1"),
20
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/users")
21
+ ]
22
+
23
+ # Initialize the queue with Async Workers by default
24
+ provider = SknUtils::ConcurrentJobs.call
25
+
26
+ # Populate WorkQueue
27
+ work_proc = ->(cmd) { SknSuccess.(cmd.uri.request_uri, "Ok") } # mis-spelling these params result in [SknFailure, SknFailure, ...] results
28
+ provider.register_jobs(commands, work_proc)
29
+
30
+ # Execute WorkQueue
31
+ result = provider.render_jobs
32
+
33
+ if result.success?
34
+ puts "Success: true"
35
+ puts "Values: #{result.values}"
36
+ puts "Messages: #{result.messages}"
37
+ else
38
+ puts "Success: false - errors: #{result.messages.join(', ')}"
39
+ puts "Values: #{result.values}"
40
+ end
41
+
42
+ # result.values
43
+ rescue => e
44
+ $stderr.puts e.message, e.backtrace
45
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # file: concurrent_test_wrapped
4
+ #
5
+
6
+ require 'bundler/setup'
7
+ require 'skn_utils'
8
+
9
+
10
+ # ##
11
+ # MainLine
12
+ # ##
13
+ #
14
+ begin
15
+ # CommandJSONPost, CommandFORMGet, CommandJSONGet,
16
+ # CommandJSONPut, CommandFORMDelete
17
+ commands = [
18
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/posts"),
19
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/comments"),
20
+ SknUtils::CommandJSONGet.call(full_url: "https://jsonplaceholder.typicode.com/todos/1"),
21
+ SknUtils::CommandJSONGet.call(full_url: "http://jsonplaceholder.typicode.com/users")
22
+ ]
23
+
24
+ # Initialize the queue with Async Workers by default
25
+ provider = SknUtils::ConcurrentJobs.call
26
+
27
+ # Populate WorkQueue
28
+ commands.each do |command|
29
+ provider.register_job do
30
+ SknUtils::JobWrapper.call(command, SknUtils::HttpProcessor) # mis-spelling these params result in [nil, nil, ...] results
31
+ end
32
+ end
33
+
34
+ # Execute WorkQueue
35
+ result = provider.render_jobs
36
+
37
+ if result.success?
38
+ puts "Success: true"
39
+ puts "Values: #{result.values}"
40
+ puts "Messages: #{result.messages}"
41
+ else
42
+ puts "Success: false - errors: #{result.messages.join(', ')}"
43
+ puts "Values: #{result.values}"
44
+ end
45
+
46
+ # result.values
47
+ rescue => e
48
+ $stderr.puts e.message, e.backtrace
49
+ end
@@ -1,4 +1,5 @@
1
- # ##
1
+ # frozen_string_literal: true
2
+
2
3
  # ##
3
4
  # SknContainer
4
5
  # - Key/Value Container where keys and/or values can be any valid Ruby Class, Proc, Instance, or object.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ##
2
4
  # Bad Result
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  #
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ##
2
4
  # SknRegistry
3
5
  # - Key/Value Container where keys and/or values can be any valid Ruby Class, Proc, Instance, or object.
@@ -71,9 +73,8 @@ class SknRegistry < Concurrent::Hash
71
73
  attr_reader :item, :options
72
74
 
73
75
  def initialize(item, options = {})
74
- @item, @options = item, {
75
- call: item.is_a?(::Proc)
76
- }.merge(options)
76
+ @item = item
77
+ @options = { call: item.is_a?(::Proc) }.merge(options)
77
78
  end
78
79
 
79
80
  # Determine if call is required, without changing original values
@@ -94,18 +95,19 @@ class SknRegistry < Concurrent::Hash
94
95
  def initialize(&block)
95
96
  super
96
97
  block.call(self) if block_given?
98
+ @__substitutes = {}
97
99
  end
98
100
 
99
101
  # public instance methods
100
102
  def register(key, contents = nil, options = {}, &block)
101
103
  if block_given?
102
104
  item = block
103
- options = contents if contents.is_a?(::Hash)
105
+ options.merge!(contents) if contents.is_a?(::Hash)
104
106
  else
105
107
  item = contents
106
108
  end
107
109
 
108
- self[key] = Content.new(item, options)
110
+ self.store( key, Content.new(item, options) )
109
111
 
110
112
  self # enable chaining
111
113
  end
@@ -114,4 +116,22 @@ class SknRegistry < Concurrent::Hash
114
116
  self[key]&.call(render_proc)
115
117
  end
116
118
 
119
+ def register_mock(key, contents = nil, options = {}, &block)
120
+ if member?(key)
121
+ @__substitutes.store(key, self.delete(key) )
122
+ end
123
+
124
+ register(key, contents, options, &block)
125
+ end
126
+ alias_method :substitute, :register_mock
127
+
128
+ def unregister_mocks!
129
+ @__substitutes.keys.each do |k|
130
+ self[k] = @__substitutes.delete(k)
131
+ end
132
+
133
+ nil
134
+ end
135
+ alias_method :restore!, :unregister_mocks!
136
+
117
137
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # Initialize:
3
5
  # SknSettings.load_config_basename!('some_name')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ##
2
4
  # Good Result
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
 
2
4
  require "skn_utils/version"
3
5
  require 'psych'
@@ -8,9 +10,12 @@ require 'time'
8
10
  require 'concurrent'
9
11
  unless defined?(Rails)
10
12
  begin
13
+ require "uri"
14
+ require "net/http"
15
+ require 'net/https'
11
16
  require 'deep_merge'
12
17
  rescue LoadError => e
13
- puts e.message
18
+ $stderr.puts e.message, e.backtrace
14
19
  end
15
20
  end
16
21
  require 'skn_utils/core_extensions'
@@ -25,6 +30,11 @@ require 'skn_utils/null_object'
25
30
  require 'skn_utils/notifier_base'
26
31
  require 'skn_utils/configuration'
27
32
  require 'skn_utils/configurable'
33
+ require 'skn_utils/wrappable'
34
+
35
+ require "skn_utils/job_commands"
36
+ require "skn_utils/http_processor"
37
+ require "skn_utils/concurrent_jobs"
28
38
 
29
39
  require 'skn_hash'
30
40
  require 'skn_registry'
@@ -48,7 +58,7 @@ module SknUtils
48
58
  [SknFailure, SknFailure].any? {|o| res.kind_of?(o) } ? res : SknSuccess.( res )
49
59
 
50
60
  rescue StandardError, ScriptError => error
51
- puts "#{retry_count} - #{error.class.name}:#{error.message}"
61
+ $stderr.puts "#{retry_count} - #{error.class.name}:#{error.message}"
52
62
  if retry_count <= attempts
53
63
  retry_count+= 1
54
64
  sleep(pause_between)
@@ -86,3 +96,4 @@ module SknUtils
86
96
  end
87
97
 
88
98
  end
99
+
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+ # ##
3
+ #
4
+ #
5
+ # See JobCommands, HttpProcessor, ...
6
+ # See ./bin/par_test_[block|grouped|wrapped] examples
7
+ #
8
+
9
+ module SknUtils
10
+
11
+ class SyncWorker
12
+ def initialize(&blk)
13
+ @blk = blk
14
+ end
15
+
16
+ def call
17
+ @blk.call
18
+ rescue => ex
19
+ failures = ex.backtrace.map {|x| x.split("/").last }.join(",")
20
+ SknFailure.(ex.class.name, { cause: ex.message, backtrace: failures})
21
+ end
22
+ end
23
+
24
+ class AsyncWorker
25
+ def initialize(&blk)
26
+ @blk = Concurrent::Promise.execute(&blk)
27
+ end
28
+
29
+ def call
30
+ @blk.value
31
+ rescue => ex
32
+ failures = ex.backtrace.map {|x| x.split("/").last }.join(",")
33
+ SknFailure.(ex.class.name, { cause: ex.message, backtrace: failures})
34
+ end
35
+ end
36
+
37
+ class Result
38
+ def initialize(merged)
39
+ @merged = merged
40
+ end
41
+
42
+ def success?
43
+ @merged.all?(&:success) rescue false
44
+ end
45
+
46
+ def messages
47
+ @merged.map(&:message)&.compact rescue []
48
+ end
49
+
50
+ def values
51
+ @merged
52
+ end
53
+ end
54
+
55
+ class CallableWrapperJob
56
+ def self.call(callable, command)
57
+ callable.call(command)
58
+ rescue => ex
59
+ failures = ex.backtrace.map {|x| x.split("/").last }.join(",")
60
+ SknFailure.(ex.class.name, { cause: ex.message, backtrace: failures})
61
+ end
62
+ end
63
+ class JobWrapper
64
+ def self.call(command, callable)
65
+ callable.call(command)
66
+ rescue => ex
67
+ failures = ex.backtrace.map {|x| x.split("/").last }.join(",")
68
+ SknFailure.(ex.class.name, { cause: ex.message, backtrace: failures})
69
+ end
70
+ end
71
+
72
+ class ConcurrentJobs
73
+ attr_reader :elapsed_time_string
74
+
75
+ def self.call(async: true)
76
+ worker = async ? AsyncWorker : SyncWorker
77
+ new(worker: worker)
78
+ end
79
+
80
+ def initialize(worker:)
81
+ @worker = worker
82
+ @workers = []
83
+ end
84
+
85
+ # commands: array of command objects related to callable
86
+ # callable: callable class or proc, ex:SknUtils::HttpProcessor
87
+ # callable must return SknSuccess || SknFailure
88
+ def register_jobs(commands, callable)
89
+ commands.each do |command|
90
+ register_job do
91
+ JobWrapper.call(command,callable)
92
+ end
93
+ end
94
+ end
95
+
96
+ def register_job(&blk)
97
+ @workers << @worker.new(&blk)
98
+ end
99
+
100
+ def render_jobs
101
+ stime = SknUtils.duration
102
+ merged = @workers.each_with_object([]) do |worker, acc|
103
+ begin
104
+ res = worker.call
105
+ acc.push( res.nil? ? SknFailure.("Unknown", {cause: "Nil Return Value to render Jobs", backtrace: []}) : res )
106
+ rescue => ex
107
+ failures = ex.backtrace.map {|x| x.split("/").last }.join(",")
108
+ acc.push SknFailure.(ex.class.name, { cause: ex.message, backtrace: failures})
109
+ end
110
+ end
111
+ @elapsed_time_string = SknUtils.duration(stime)
112
+ Result.new(merged)
113
+ rescue => e
114
+ Result.new(merged || [])
115
+ end
116
+ end
117
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # File: <gem-root>/lib/skn_utils/configurable.rb
3
5
  # Ref: https://www.toptal.com/ruby/ruby-dsl-metaprogramming-guide
@@ -25,7 +27,7 @@ module SknUtils
25
27
  # end
26
28
  #
27
29
  #################
28
- # During Definition
30
+ # -or- During Definition
29
31
  #################
30
32
  # class MyApp
31
33
  # include SknUtils::Configurable.with(:app_id, :title, :cookie_name, {root_enable: true})
@@ -36,6 +38,7 @@ module SknUtils
36
38
  # cookie_name { "#{app_id}_session" }
37
39
  # end
38
40
  #
41
+ # # these are the root_enable default settings
39
42
  # self.logger = Logger.new
40
43
  # self.env = ENV.fetch('RACK_ENV', 'development')
41
44
  # self.root = Dir.pwd
@@ -56,6 +59,11 @@ module SknUtils
56
59
  # - env = string value from RACK_ENV
57
60
  # - registry = SknRegistry instance
58
61
  # - logger = Assigned Logger instance
62
+ # - romDB = var for Rom-DB if used or Any Platform Database
63
+ # - metadata = platform metadata container
64
+ # - userdata = user area
65
+ # - metrics = platform metrics container
66
+ # - ...
59
67
  # #with(*user_attrs, enable_root: true|false) - defaults to enable of Main Class Attrs
60
68
  # ##
61
69
  # User-Defined Attrs
@@ -65,9 +73,9 @@ module SknUtils
65
73
 
66
74
  module Configurable
67
75
 
68
- def self.with(*attrs, **options)
76
+ def self.with(*config_attrs, **root_options)
69
77
  _not_provided = Object.new
70
- _app_main = options.empty? || options.values.any?{|v| v == true}
78
+ _root_options = root_options.empty? || root_options.values.any?{|v| v == true}
71
79
 
72
80
  # Define the config class/module methods
73
81
  config_class = Class.new do
@@ -79,7 +87,7 @@ module SknUtils
79
87
  instance_variable_set("@#{attr}", val)
80
88
  end
81
89
 
82
- attrs.each do |attr|
90
+ config_attrs.each do |attr|
83
91
  define_method attr do |value = _not_provided, &block|
84
92
  if value === _not_provided && block.nil?
85
93
  result = instance_variable_get("@#{attr}")
@@ -90,7 +98,7 @@ module SknUtils
90
98
  end
91
99
  end
92
100
 
93
- attr_writer *attrs
101
+ attr_writer *config_attrs
94
102
  end
95
103
 
96
104
  # Define the runtime access methods
@@ -101,7 +109,7 @@ module SknUtils
101
109
  def configure(&block)
102
110
  config.instance_eval(&block)
103
111
  end
104
- if _app_main
112
+ if _root_options
105
113
  # Enable Rails<Like>.env and Rails.logger like feature:
106
114
  # - MyClass.env.production? or MyClass.logger or MyClass.root
107
115
  def registry
@@ -128,6 +136,38 @@ module SknUtils
128
136
  def logger=(obj)
129
137
  @__logger = obj
130
138
  end
139
+
140
+ # Any Platform Database
141
+ def romDB
142
+ @__db ||= nil
143
+ end
144
+ def romDB(obj)
145
+ @__db = obj
146
+ end
147
+
148
+ # Maybe Platform Metadata
149
+ def metadata
150
+ @__metadata ||= nil
151
+ end
152
+ def metadata=(obj)
153
+ @__metadata = obj
154
+ end
155
+
156
+ # Userdata container for any use
157
+ def userdata
158
+ @__userdata ||= nil
159
+ end
160
+ def userdata=(obj)
161
+ @__userdata = obj
162
+ end
163
+
164
+ # Metrics container for any use
165
+ def metrics
166
+ @__metrics ||= nil
167
+ end
168
+ def metrics=(obj)
169
+ @__metrics = obj
170
+ end
131
171
  end
132
172
  end
133
173
 
@@ -142,3 +182,12 @@ module SknUtils
142
182
 
143
183
  end # end module
144
184
  end # End module
185
+
186
+ #
187
+ # def [](key)
188
+ # @internal_var[key]
189
+ # end
190
+ #
191
+ # def []=(key, value)
192
+ # @internal_var[key] = value
193
+ # end