module SknUtils

##

See JobCommands, HttpProcessor, … See ./bin/par_test_ examples

File: <gem-root>/lib/skn_utils/configurable.rb

Ref: https://www.toptal.com/ruby/ruby-dsl-metaprogramming-guide

## lib/skn_utils/configuration.rb

@see SknSettings

Filepath Targets:


<prepend-somefile> config/settings.yml config/settings/#{environment}.yml config/environments/#{environment}.yml

config/settings.local.yml config/settings/#{environment}.local.yml config/environments/#{environment}.local.yml <append-somefile>

Public API


load_config_basename!(environment_name) config_path!(config_root) load_and_set_settings(ordered_list_of_files)

- Alias: reload_from_files(ordered_list_of_files)

reload!() setting_files(config_root, environment_name) add_source!(file_path_or_hash) prepend_source!(file_path_or_hash)


SknSettings setup: class << (SknSetting = SknUtils::Configuration.new( ENV )); end

## File: ./lib/skn_utils/core_extensions.rb – – from: Rails 4.1 ActiveSupport:lib/active_support/core_ext/object/blank.rb – Ref: 6ftdan.com/allyourdev/2015/01/20/refinements-over-monkey-patching/ – Ref: medium.com/rubycademy/the-complete-guide-to-create-a-copy-of-an-object-in-ruby-part-ii-cd28a99d58d9

File: ./lib/skn_utils/env_string_handler.rb

Wrapping a string in this class gives you a prettier way to test for equality. The value returned by Rails.env is wrapped in a StringInquirer object so instead of calling this:

Rails.env == 'production'
SknSettings.env == 'production'

you can call this:

Rails.env.production?
SknSettings.env.productcion?

Create a EnvStringHandler to support: SknSettings.env.development? Yes, its YAML trick in config/settings.yml

 ...
 env: !ruby/string:SknUtils::EnvStringHandler <%= ENV['RACK_ENV'] %>
root: !ruby/string:SknUtils::EnvStringHandler <%= Dir.pwd %>
 ...

#

##

Ref: yukimotopress.github.io/http

<project.root>/lib/skn_utils/nested_result.rb

SknUtils::NestedResult Value Container/Class for Ruby with Indifferent Hash and/or Dot.notation access

Description:

Creates an Object with attribute methods for dot.notation and hash.notation access for each hash input key/value pair.

If the key's value is an hash itself, it will become an NestedResult Object.
if the key's value is an Array of Hashes, each hash element of the Array will
   become an Object; non-hash object are left as-is
if the key's value is an Array of Arrays-of- Hash/Object, each hash element of each Array will
   become an Object; non-hash object are left as-is.  This array of array of arrays
   goes on to the end.

Transforms entire input hash contents into dot.notation and hash.notation accessible key/value pairs.
  - hash
  - array of hashes
  - non hash element values are not modified,
    whether in an array or the basic value in a key/value pair

The ability of the resulting Object to be YAML/Psych'ed, or Marshaled(dump/load) is preserved

Transforms entire input hash contents into dot.notation accessible object

- hash
- array of hashes
- non hash element values are not modified, whether in an array or the basic value in a key/value pair

This module provides

Simple Initialization Pattern

person = SknUtils::NestedResult.new( {name: "Bob", title: {day: 'Analyst', night: 'Fireman'}} )

Serializers:

person.to_hash
  => {name: 'Bob', title: {day: 'Analyst', night: 'Fireman'}}
person.to_json
  => "{\"name\":\"Bob\", \"title\":{\"day\":\"Analyst\", \"night\":\"Fireman\"}}"

Dynamic addition of new key/values after initialization

person.address = 'Fort Wayne Indiana'
person.address
  => 'Fort Wayne Indiana'

dot.notation feature for all instance variables

person.title.day
  => "Analyst"
person.name = "James"
  => "James"

InDifferent String/Symbol hash feature for all instance variables

person['title']['day']
  => "Analyst"
person['name'] = "James"
  => "James"
person[:name]
  => "James"
person[:name] = "Bob"
  => "Bob"

Supports <attr>? predicate method patterns, and delete_field(:attr) method

example:
  person.title.night?
    => true                    true or false, like obj.name.present?
  person.delete_field(:name)   only first/root level attributes can be deleted
    => 'Bob'                   returns last value of deleted key
  person.name_not_found
    => NoMethodFound           raises exception if key is not found

Exporting hash from any key starting point

person.hash_from(:name)
  => {name: 'Bob'}            the entire hash tree from that starting point

Advanced Methods

#to_hash                          - returns copy of input hash
#to_json(*args)                   - converts input hash into JSON
#keys                             - returns the first-level keys of input hash
#delete_field(attr_sym)           - removes attribute/key and returns it's former value
#hash_from(starting_attr_sym)     - (Protected Method) returns remaining hash starting from key provided

Known Issues

Ruby Notify like class

Ref: ozone.wordpress.com/category/programming/metaprogramming/

Listeners implement:

def attribute_changed(attr, old, new)
  ...
end

lib/skn_utils/null_object.rb

A better way to say it

##

Ref: blog.appsignal.com/2018/10/02/ruby-magic-class-level-instance-variables.html

Constants

VERSION

Public Class Methods

as_human_size(number) click to toggle source

## SknUtils.as_human_size(12345) #=> 12 KB

# File lib/skn_utils.rb, line 76
def self.as_human_size(number)
  units = %W(Bytes KB MB GB TB PB EB)
  num = number.to_f
  if number < 1001
    num = number
    exp = 0
  else
    max_exp  = units.size - 1
    exp = ( Math.log( num ) / Math.log( 1024 ) ).round
    exp = max_exp  if exp > max_exp
    num /= 1024 ** exp
  end
  ((num > 9 || num.modulo(1) < 0.1) ? '%d %s' : '%.1f %s') % [num, units[exp]]
end
catch_exceptions(retries=3, pause_between=3) { || ... } click to toggle source

Random Utils Retries block up to :retries times with a :pause_between, and returns Success/Failure object – return SknSuccess | SknFailure response object

# File lib/skn_utils.rb, line 52
def self.catch_exceptions(retries=3, pause_between=3, &block)
  retry_count ||= 1
  attempts = retries
  begin

    res = yield
    [SknFailure, SknFailure].any? {|o| res.kind_of?(o) } ? res : SknSuccess.( res )

  rescue StandardError, ScriptError => error
    $stderr.puts "#{retry_count} - #{error.class.name}:#{error.message}"
    if retry_count <= attempts
      retry_count+= 1
      sleep(pause_between)
      retry
    else
      SknFailure.( "RETRY ATTEMPTS FAILED - #{error.class.name}:#{error.message}", error.backtrace[0..5].to_s )
    end
  end
end
duration(start_time=nil) click to toggle source

call without to get start time call with start_time to get duration string

# File lib/skn_utils.rb, line 93
def self.duration(start_time=nil)
  start_time.nil? ? Process.clock_gettime(Process::CLOCK_MONOTONIC) :
      "%3.3f seconds" % (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time)
end
nullable?(value) click to toggle source
# File lib/skn_utils/null_object.rb, line 27
def self.nullable?(value)
  value.nil? ? NullObject.new : value
end