skn_utils 5.4.0 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
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