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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ##
2
4
  # lib/skn_utils/configuration.rb
3
5
  #
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # ##
2
4
  # File: ./lib/skn_utils/core_extensions.rb --
3
5
  # -- from: Rails 4.1 ActiveSupport:lib/active_support/core_ext/object/blank.rb
4
6
  # -- Ref: https://6ftdan.com/allyourdev/2015/01/20/refinements-over-monkey-patching/
7
+ # -- Ref: https://medium.com/rubycademy/the-complete-guide-to-create-a-copy-of-an-object-in-ruby-part-ii-cd28a99d58d9
5
8
 
6
9
  module SknUtils
7
10
  module CoreObjectExtensions
@@ -51,6 +54,15 @@ module SknUtils
51
54
  def presence
52
55
  self if present?
53
56
  end
57
+
58
+ def duplicable?
59
+ true
60
+ end
61
+
62
+ def deep_dup
63
+ duplicable? ? dup : self
64
+ end
65
+
54
66
  end
55
67
 
56
68
  class ::NilClass
@@ -94,6 +106,10 @@ module SknUtils
94
106
  #
95
107
  # @return [true, false]
96
108
  alias_method :blank?, :empty?
109
+
110
+ def deep_dup
111
+ map(&:deep_dup)
112
+ end
97
113
  end
98
114
 
99
115
  class ::Hash
@@ -104,6 +120,19 @@ module SknUtils
104
120
  #
105
121
  # @return [true, false]
106
122
  alias_method :blank?, :empty?
123
+
124
+ def deep_dup
125
+ hash = dup
126
+ each_pair do |key, value|
127
+ if key.frozen? && ::String === key
128
+ hash[key] = value.deep_dup
129
+ else
130
+ hash.delete(key)
131
+ hash[key.deep_dup] = value.deep_dup
132
+ end
133
+ end
134
+ hash
135
+ end
107
136
  end
108
137
 
109
138
  class ::String
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module SknUtils
3
4
  class DottedHash < NestedResult
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # File: ./lib/skn_utils/env_string_handler.rb
2
4
  #
3
5
  # Wrapping a string in this class gives you a prettier way to test
@@ -0,0 +1,34 @@
1
+ # ##
2
+ #
3
+ #
4
+ module SknUtils
5
+
6
+ class HttpProcessor
7
+
8
+ def self.call(command)
9
+ completion = false
10
+
11
+ response = Net::HTTP.start( command.uri.host,command.uri.port,
12
+ use_ssl: command.uri.scheme.eql?("https")
13
+ ) do |http|
14
+ http.open_timeout = 5 # in seconds, for internal http timeouts
15
+ http.read_timeout = 15 # in seconds
16
+ if command.uri.scheme.eql?("https")
17
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
18
+ end
19
+ http.request(command.request)
20
+ end
21
+
22
+ if ( response.kind_of?(Net::HTTPClientError) or response.kind_of?(Net::HTTPServerError) )
23
+ completion = SknFailure.call(response.code, response.message)
24
+ else
25
+ payload = command.json? ? JSON.load(response.body) : response.body
26
+ completion = SknSuccess.call(payload, response.class.name)
27
+ end
28
+
29
+ completion
30
+ rescue => exception
31
+ SknFailure.call(command.uri.request_uri, "#{exception.message}; #{exception.backtrace[0]}")
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,247 @@
1
+ # ##
2
+ #
3
+ # Ref: https://yukimotopress.github.io/http
4
+
5
+ module SknUtils
6
+ # #################################################
7
+ #
8
+ class CommandJSONPDelete
9
+ def self.call(options) # {full_url:,username:,userpass:,payload:,headers:}
10
+ new(options)
11
+ end
12
+
13
+ def json?
14
+ true
15
+ end
16
+
17
+ def uri
18
+ @_uri
19
+ end
20
+
21
+ def request
22
+ req = @_headers.nil? ? Net::HTTP::Delete.new(uri.request_uri) : Net::HTTP::Delete.new(uri.request_uri, @_headers) # Generate HTTPRequest object
23
+ req.basic_auth(@_username, @_userpass) if credentials?
24
+ req.content_type = 'application/json'
25
+ req.body = formatted_data
26
+ req
27
+ end
28
+
29
+ private
30
+
31
+ def initialize(opts={})
32
+ @_username = opts[:username]
33
+ @_userpass = opts[:userpass]
34
+ @_headers = opts[:headers]
35
+ @_uri = URI.parse( opts[:full_url])
36
+ @_data = opts[:payload]
37
+ end
38
+
39
+ def formatted_data
40
+ @_data.respond_to?(:to_json) ? @_data.to_json : @_data
41
+ end
42
+
43
+ def credentials?
44
+ !(@_username.nil? || @_userpass.nil?)
45
+ end
46
+ end
47
+
48
+ # #################################################
49
+ #
50
+ class CommandJSONPost
51
+ def self.call(options) # {full_url:,username:,userpass:,payload:,headers:}
52
+ new(options)
53
+ end
54
+
55
+ def json?
56
+ true
57
+ end
58
+
59
+ def uri
60
+ @_uri
61
+ end
62
+
63
+ def request
64
+ req = @_headers.nil? ? Net::HTTP::Post.new(uri.path) : Net::HTTP::Post.new(uri.path, @_headers) # Generate HTTPRequest object
65
+ req.basic_auth(@_username, @_userpass) if credentials?
66
+ req.content_type = 'application/json'
67
+ req.body = formatted_data
68
+ req
69
+ end
70
+
71
+ private
72
+
73
+ def initialize(opts={})
74
+ @_username = opts[:username]
75
+ @_userpass = opts[:userpass]
76
+ @_headers = opts[:headers]
77
+ @_uri = URI.parse( opts[:full_url])
78
+ @_data = opts[:payload]
79
+ end
80
+
81
+ def formatted_data
82
+ @_data.respond_to?(:to_json) ? @_data.to_json : @_data
83
+ end
84
+
85
+ def credentials?
86
+ !(@_username.nil? || @_userpass.nil?)
87
+ end
88
+ end
89
+
90
+
91
+ # #################################################
92
+ #
93
+ class CommandFORMPost
94
+ def self.call(options) # {full_url:,username:,userpass:,payload:,headers:}
95
+ new(options)
96
+ end
97
+
98
+ def json?
99
+ false
100
+ end
101
+
102
+ def uri
103
+ @_uri
104
+ end
105
+
106
+ def request
107
+ req = @_headers.nil? ? Net::HTTP::Post.new(uri.path) : Net::HTTP::Post.new(uri.path, @_headers) # Generate HTTPRequest object
108
+ req.basic_auth(@_username, @_userpass) if credentials?
109
+ req.content_type = 'application/x-www-form-urlencoded'
110
+ req.set_form_data(formatted_data)
111
+ req
112
+ end
113
+
114
+ private
115
+
116
+ def initialize(opts={})
117
+ @_username = opts[:username]
118
+ @_userpass = opts[:userpass]
119
+ @_headers = opts[:headers]
120
+ @_uri = URI.parse( opts[:full_url])
121
+ @_data = opts[:payload]
122
+ end
123
+
124
+ def formatted_data
125
+ @_data
126
+ end
127
+
128
+ def credentials?
129
+ !(@_username.nil? || @_userpass.nil?)
130
+ end
131
+ end
132
+
133
+
134
+ # #################################################
135
+ #
136
+ class CommandJSONGet
137
+ def self.call(options) # {full_url:,username:,userpass:,headers:}
138
+ new(options)
139
+ end
140
+
141
+ def json?
142
+ true
143
+ end
144
+
145
+ def uri
146
+ @_uri
147
+ end
148
+
149
+ def request
150
+ req = @_headers.nil? ? Net::HTTP::Get.new(uri.request_uri) : Net::HTTP::Get.new(uri.request_uri, @_headers) # Generate HTTPRequest object
151
+ req.basic_auth(@_username, @_userpass) if credentials?
152
+ req
153
+ end
154
+
155
+ private
156
+
157
+ def initialize(opts={})
158
+ @_username = opts[:username]
159
+ @_userpass = opts[:userpass]
160
+ @_headers = opts[:headers]
161
+ @_uri = URI.parse( opts[:full_url])
162
+ end
163
+
164
+ def credentials?
165
+ !(@_username.nil? || @_userpass.nil?)
166
+ end
167
+ end
168
+
169
+
170
+ # #################################################
171
+ #
172
+ class CommandJSONPut
173
+ def self.call(options) # {full_url:,username:,userpass:,payload:,headers:}
174
+ new(options)
175
+ end
176
+
177
+ def json?
178
+ true
179
+ end
180
+
181
+ def uri
182
+ @_uri
183
+ end
184
+
185
+ def request
186
+ req = @_headers.nil? ? Net::HTTP::Put.new(uri.path) : Net::HTTP::Put.new(uri.path, @_headers) # Generate HTTPRequest object
187
+ req.basic_auth(@_username, @_userpass) if credentials?
188
+ req.content_type = 'application/json'
189
+ req.body = formatted_data
190
+ req
191
+ end
192
+
193
+ private
194
+
195
+ def initialize(opts={})
196
+ @_username = opts[:username]
197
+ @_userpass = opts[:userpass]
198
+ @_headers = opts[:headers]
199
+ @_uri = URI.parse( opts[:full_url])
200
+ @_data = opts[:payload]
201
+ end
202
+
203
+ def formatted_data
204
+ @_data.respond_to?(:to_json) ? @_data.to_json : @_data
205
+ end
206
+
207
+ def credentials?
208
+ !(@_username.nil? || @_userpass.nil?)
209
+ end
210
+ end
211
+
212
+
213
+ # #################################################
214
+ #
215
+ class CommandFORMDelete
216
+ def self.call(options) # {full_url:,username:,userpass:}
217
+ new(options)
218
+ end
219
+
220
+ def json?
221
+ false
222
+ end
223
+
224
+ def uri
225
+ @_uri
226
+ end
227
+
228
+ def request
229
+ req = @_headers.nil? ? Net::HTTP::Delete.new(uri.request_uri) : Net::HTTP::Delete.new(uri.request_uri, @_headers) # Generate HTTPRequest object
230
+ req.basic_auth(@_username, @_userpass) if credentials?
231
+ req
232
+ end
233
+
234
+ private
235
+
236
+ def initialize(opts={})
237
+ @_username = opts[:username]
238
+ @_userpass = opts[:userpass]
239
+ @_headers = opts[:headers]
240
+ @_uri = URI.parse( opts[:full_url])
241
+ end
242
+
243
+ def credentials?
244
+ !(@_username.nil? || @_userpass.nil?)
245
+ end
246
+ end
247
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # <project.root>/lib/skn_utils/nested_result.rb
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  #
3
5
  # Ruby Notify like class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # lib/skn_utils/null_object.rb
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
 
2
4
  module SknUtils
3
5
  class PageControls < NestedResult
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
 
2
4
  module SknUtils
3
5
  class ResultBean < NestedResult
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A better way to say it
2
4
  module SknUtils
3
5
  class Version
4
6
  MAJOR = 5
5
- MINOR = 4
7
+ MINOR = 8
6
8
  PATCH = 0
7
9
 
8
10
  def self.to_s
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ##
4
+ #
5
+ # Ref: https://blog.appsignal.com/2018/10/02/ruby-magic-class-level-instance-variables.html
6
+
7
+ module SknUtils
8
+
9
+ module Wrappable
10
+ def wrap(mod)
11
+ wrappers << mod
12
+ end
13
+
14
+ def wrappers
15
+ @wrappers ||= []
16
+ end
17
+
18
+ def inherited_wrappers
19
+ ancestors
20
+ .grep(Wrappable)
21
+ .reverse
22
+ .flat_map(&:wrappers)
23
+ end
24
+
25
+ def new(*arguments, &block)
26
+ instance = allocate
27
+ inherited_wrappers.each { |mod|instance.singleton_class.include(mod) }
28
+ instance.send(:initialize, *arguments, &block)
29
+ instance
30
+ end
31
+ end
32
+ end
@@ -1,44 +1,49 @@
1
+ # frozen_string_literal: true
1
2
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'skn_utils/version'
3
+
4
+ require_relative 'lib/skn_utils/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'skn_utils'
8
8
  spec.version = SknUtils::VERSION
9
9
  spec.author = 'James Scott Jr'
10
10
  spec.email = 'skoona@gmail.com'
11
- spec.summary = <<-EOF
12
- SknUtils contains a small collection of Ruby utilities, the first being a NestedResult a key/value container.
13
- EOF
14
-
15
- spec.description = <<-EOF
16
- The intent of the NestedResult class is to be a container for data values composed of key/value pairs,
17
- with easy access to its contents, and on-demand transformation back to the hash (#to_hash).
11
+ spec.summary = <<-DESC
12
+ Ruby utilities for dependency injection/lookup, class customizations, and dot.notion access over nested hashes.
13
+ DESC
14
+ spec.description = <<-DESC
15
+ Value containers supporting nested dot.notation access over hashes, and utilities offering dependency injection/lookup, and
16
+ language extensions support running in a non-rails environment. Plus, examples of null objects, class customization,
17
+ and concurrent processing.
18
18
 
19
19
  Review the RSpec tests, and or review the README for more details.
20
- EOF
21
- spec.post_install_message = <<-EOF
20
+ DESC
21
+
22
+ spec.post_install_message = <<-DESC
22
23
  This version includes modified versions of SknUtils::ResultBean, SknUtils::PageControls classes, which inherit from
23
24
  SknUtils::NestedResult class. SknUtils::NestedResult replaces those original classes and consolidates their function.
24
- EOF
25
+ DESC
26
+
25
27
  spec.homepage = "https://github.com/skoona/skn_utils"
26
28
  spec.license = "MIT"
27
29
  spec.platform = Gem::Platform::RUBY
28
- spec.files = `git ls-files -z`.split("\x0")
30
+ spec.files = `git ls-files -z`.split("\x0")
29
31
  spec.executables = []
30
- spec.test_files = spec.files.grep(%r{^(spec)/})
31
- spec.require_paths = ['lib']
32
+ spec.test_files = spec.files.grep(%r{^(spec)/})
33
+ spec.require_paths = %w[lib]
34
+ spec.extra_rdoc_files = Dir["README.md", "CODE_OF_CONDUCT.md", "LICENSE"]
32
35
 
33
36
  spec.add_runtime_dependency 'deep_merge', '~> 1'
34
37
  spec.add_runtime_dependency 'concurrent-ruby', '~> 1'
35
38
  spec.add_runtime_dependency 'thor', '~> 0'
36
39
 
37
- spec.add_development_dependency "bundler", "~> 1"
38
- spec.add_development_dependency "rake", "~> 10"
39
- spec.add_development_dependency "rspec", '~> 3'
40
- spec.add_development_dependency "pry", "~> 0"
41
- spec.add_development_dependency "simplecov", "~> 0"
42
- spec.add_development_dependency 'benchmark-ips', '~> 2'
40
+ spec.add_development_dependency "bundler", ">= 1"
41
+ spec.add_development_dependency "rake", ">= 12.3.3"
42
+ spec.add_development_dependency "rspec", '>= 3'
43
+ spec.add_development_dependency "pry", ">= 0"
44
+ spec.add_development_dependency "pry-coolline"
45
+ spec.add_development_dependency "simplecov", ">= 0"
46
+ spec.add_development_dependency 'benchmark-ips', '>= 2'
47
+ spec.add_development_dependency 'webmock'
43
48
 
44
49
  end