easy_monad 0.0.9 → 0.0.10
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 +4 -4
- data/lib/configuration.rb +30 -0
- data/lib/easy_monad.rb +23 -0
- data/lib/errors.rb +21 -0
- data/lib/modules/i18n.rb +11 -0
- data/lib/modules/logging.rb +62 -0
- data/lib/modules/params_sanitizer.rb +30 -0
- data/lib/operation.rb +95 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6f1c4f41cf83d60e4fc8ce5cfb32fe96045049f1a30a93bdcc977c1dcfd2323b
|
|
4
|
+
data.tar.gz: faec7d0b656d2d0d4c82a2156788c791ca3432a1cd4c0b8b3639f237c2b58abc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63f5ff5e17720c96320463956fd12f4b92d5017d8034280303537958db0ea05583320d5f5a89ea859fbc762d38e261fb741a2d494ddd57d3d7a3137bbe904815
|
|
7
|
+
data.tar.gz: 4f4b2e8e3ac21a33a092ddd949a0358b26a585f903f6a39383843658cc3c0974fc8db516907f993513c9ac9d381d8f7186421d28eaf1a3961c2799dfd2663a7c
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module EasyMonad
|
|
2
|
+
class Configuration
|
|
3
|
+
class << self
|
|
4
|
+
attr_accessor :logger,
|
|
5
|
+
:using_modules,
|
|
6
|
+
:filter_parameters,
|
|
7
|
+
:rails_environment,
|
|
8
|
+
:configured
|
|
9
|
+
|
|
10
|
+
def set_defaults
|
|
11
|
+
require 'logger'
|
|
12
|
+
|
|
13
|
+
@logger = ::Logger.new(STDOUT)
|
|
14
|
+
@using_modules = [:params_sanitizer, :logging, :i18n]
|
|
15
|
+
@filter_parameters = %w[
|
|
16
|
+
password
|
|
17
|
+
password_confirmation
|
|
18
|
+
secret
|
|
19
|
+
password_salt
|
|
20
|
+
]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def configure
|
|
24
|
+
yield self
|
|
25
|
+
|
|
26
|
+
@configured = true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/easy_monad.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'configuration'
|
|
2
|
+
|
|
3
|
+
require_relative 'modules/params_sanitizer'
|
|
4
|
+
require_relative 'modules/i18n'
|
|
5
|
+
require_relative 'modules/logging'
|
|
6
|
+
|
|
7
|
+
require_relative 'operation'
|
|
8
|
+
require_relative 'errors'
|
|
9
|
+
|
|
10
|
+
module EasyMonad
|
|
11
|
+
def self.str_to_const(str)
|
|
12
|
+
eval(str.split('_').map(&:capitalize).unshift('Modules::').join)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Configuration.rails_environment = !!defined?(Rails)
|
|
16
|
+
Configuration.set_defaults unless Configuration.configured
|
|
17
|
+
|
|
18
|
+
Configuration.using_modules.each do |mod|
|
|
19
|
+
raise ArgumentError, 'Included Module must be a Symbol!' unless mod.is_a?(Symbol)
|
|
20
|
+
|
|
21
|
+
Operation.include str_to_const(mod.to_s)
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/errors.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyMonad
|
|
4
|
+
class Errors < Hash
|
|
5
|
+
def add(key, value)
|
|
6
|
+
self[key] ||= value
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_a
|
|
10
|
+
map { |key, val| "#{key}: #{val}" }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
to_a.join(', ')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def only_messages
|
|
18
|
+
values.flatten.map { _1.delete(':') }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/modules/i18n.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'params_sanitizer'
|
|
4
|
+
|
|
5
|
+
module EasyMonad
|
|
6
|
+
module Modules
|
|
7
|
+
module Logging
|
|
8
|
+
def self.included(base)
|
|
9
|
+
base.singleton_class.prepend(ClassMethods)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def call(*, **)
|
|
14
|
+
operation = new(*, **)
|
|
15
|
+
|
|
16
|
+
operation.within_early_exit_block do
|
|
17
|
+
operation.memoize_start_time
|
|
18
|
+
operation.log_start(operation)
|
|
19
|
+
operation.call
|
|
20
|
+
operation.log_end(operation)
|
|
21
|
+
|
|
22
|
+
operation
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def log_start(operation)
|
|
28
|
+
logger.info "Operation #{operation.class.name} starts params: #{operation.params_for_logging(operation.params)}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def log_end(operation)
|
|
32
|
+
logger.info "Operation #{operation.class.name} ends. Took: #{duration_from_start_in_secs} sec, params: #{operation.params_for_logging(operation.params)}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def log_critical_error(operation)
|
|
36
|
+
logger.error "Operation #{operation.class.name} ends with error. Took: #{duration_from_start_in_secs} sec, params: #{operation.params_for_logging(operation.params)}, errors: #{operation.errors.to_a}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def log_error(operation)
|
|
40
|
+
logger.error "Operation #{operation.class.name} has errors: #{operation.errors.to_a} params: #{operation.params_for_logging(operation.params)}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def memoize_start_time
|
|
44
|
+
@start_time = cpu_clock_now
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def duration_from_start_in_secs
|
|
50
|
+
(cpu_clock_now - @start_time).floor(2)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def logger
|
|
54
|
+
@logger ||= Configuration.logger
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cpu_clock_now
|
|
58
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyMonad
|
|
4
|
+
module Modules
|
|
5
|
+
module ParamsSanitizer
|
|
6
|
+
def params_for_logging(params)
|
|
7
|
+
regex = /(#{filter_parameters.join('|')})":"([^"]*)"/
|
|
8
|
+
hashed_params(params).inspect.gsub(regex, '\1":"[FILTERED]"')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def hashed_params(params)
|
|
14
|
+
if Configuration.rails_environment
|
|
15
|
+
params.is_a?(ActionController::Parameters) ? params.to_unsafe_h : params.to_h
|
|
16
|
+
else
|
|
17
|
+
params.to_h
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def filter_parameters
|
|
22
|
+
if Configuration.rails_environment
|
|
23
|
+
Rails.configuration.filter_parameters += Configuration.filter_parameters
|
|
24
|
+
else
|
|
25
|
+
Configuration.filter_parameters
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/operation.rb
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyMonad
|
|
4
|
+
class Operation
|
|
5
|
+
attr_reader :params
|
|
6
|
+
attr_accessor :result, :errors
|
|
7
|
+
|
|
8
|
+
def initialize(params, errors = Errors.new)
|
|
9
|
+
@params = params
|
|
10
|
+
@errors = errors
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def call(*, **)
|
|
15
|
+
operation = new(*, **)
|
|
16
|
+
|
|
17
|
+
operation.within_early_exit_block do
|
|
18
|
+
operation.call
|
|
19
|
+
|
|
20
|
+
operation
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
alias [] call
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def result!
|
|
28
|
+
return result if success?
|
|
29
|
+
|
|
30
|
+
raise ProcessError, self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def failure?
|
|
34
|
+
errors.any?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def success?
|
|
38
|
+
errors.empty?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def within_early_exit_block(&)
|
|
42
|
+
catch(:critical, &)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def call
|
|
46
|
+
raise NotImplementedError, "You must implement #call by yourself!"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def join(other)
|
|
52
|
+
other.errors.each do |error, description|
|
|
53
|
+
error(error, description)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
other
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def strict_join!(other)
|
|
60
|
+
other.errors.each do |error, description|
|
|
61
|
+
critical_error!(error, description)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
other
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# stubs for Logging and ParamsSanitizer mudules
|
|
68
|
+
def log_error(_) = nil
|
|
69
|
+
def log_critical_error(_) = nil
|
|
70
|
+
def params_for_logging(params) = params
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def error(error, description = nil)
|
|
75
|
+
errors.add(error, description || 'Something went wrong')
|
|
76
|
+
log_error(self)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def critical_error!(error, description = nil)
|
|
80
|
+
errors.add(error, description || 'Something went wrong')
|
|
81
|
+
log_critical_error(self)
|
|
82
|
+
throw(:critical, self)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class ProcessError < StandardError
|
|
87
|
+
attr_reader :operation, :message
|
|
88
|
+
|
|
89
|
+
def initialize(operation)
|
|
90
|
+
super
|
|
91
|
+
@operation = operation
|
|
92
|
+
@message = "#{operation.class} Process Error"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: easy_monad
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- T.Zhuk
|
|
@@ -15,7 +15,14 @@ email:
|
|
|
15
15
|
executables: []
|
|
16
16
|
extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
|
18
|
-
files:
|
|
18
|
+
files:
|
|
19
|
+
- lib/configuration.rb
|
|
20
|
+
- lib/easy_monad.rb
|
|
21
|
+
- lib/errors.rb
|
|
22
|
+
- lib/modules/i18n.rb
|
|
23
|
+
- lib/modules/logging.rb
|
|
24
|
+
- lib/modules/params_sanitizer.rb
|
|
25
|
+
- lib/operation.rb
|
|
19
26
|
licenses:
|
|
20
27
|
- MIT
|
|
21
28
|
metadata:
|