cmdx 0.1.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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +64 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +132 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +76 -0
  10. data/Rakefile +12 -0
  11. data/docs/basics/call.md +31 -0
  12. data/docs/basics/context.md +67 -0
  13. data/docs/basics/run.md +34 -0
  14. data/docs/basics/setup.md +32 -0
  15. data/docs/batch.md +53 -0
  16. data/docs/configuration.md +57 -0
  17. data/docs/example.md +82 -0
  18. data/docs/getting_started.md +47 -0
  19. data/docs/hooks.md +59 -0
  20. data/docs/interruptions/exceptions.md +29 -0
  21. data/docs/interruptions/faults.md +89 -0
  22. data/docs/interruptions/halt.md +80 -0
  23. data/docs/logging.md +102 -0
  24. data/docs/outcomes/result.md +17 -0
  25. data/docs/outcomes/states.md +31 -0
  26. data/docs/outcomes/statuses.md +33 -0
  27. data/docs/parameters/coercions.md +52 -0
  28. data/docs/parameters/defaults.md +47 -0
  29. data/docs/parameters/definitions.md +123 -0
  30. data/docs/parameters/namespacing.md +57 -0
  31. data/docs/parameters/validations.md +312 -0
  32. data/docs/tips_and_tricks.md +79 -0
  33. data/lib/cmdx/.DS_Store +0 -0
  34. data/lib/cmdx/batch.rb +43 -0
  35. data/lib/cmdx/coercions/array.rb +15 -0
  36. data/lib/cmdx/coercions/big_decimal.rb +23 -0
  37. data/lib/cmdx/coercions/boolean.rb +27 -0
  38. data/lib/cmdx/coercions/complex.rb +21 -0
  39. data/lib/cmdx/coercions/date.rb +26 -0
  40. data/lib/cmdx/coercions/date_time.rb +26 -0
  41. data/lib/cmdx/coercions/float.rb +21 -0
  42. data/lib/cmdx/coercions/hash.rb +31 -0
  43. data/lib/cmdx/coercions/integer.rb +21 -0
  44. data/lib/cmdx/coercions/rational.rb +21 -0
  45. data/lib/cmdx/coercions/string.rb +15 -0
  46. data/lib/cmdx/coercions/time.rb +26 -0
  47. data/lib/cmdx/coercions/virtual.rb +15 -0
  48. data/lib/cmdx/configuration.rb +25 -0
  49. data/lib/cmdx/context.rb +15 -0
  50. data/lib/cmdx/core_ext/hash.rb +36 -0
  51. data/lib/cmdx/core_ext/module.rb +48 -0
  52. data/lib/cmdx/core_ext/object.rb +55 -0
  53. data/lib/cmdx/error.rb +23 -0
  54. data/lib/cmdx/errors.rb +92 -0
  55. data/lib/cmdx/fault.rb +47 -0
  56. data/lib/cmdx/faults.rb +11 -0
  57. data/lib/cmdx/immutator.rb +21 -0
  58. data/lib/cmdx/lazy_struct.rb +79 -0
  59. data/lib/cmdx/log_formatters/json.rb +13 -0
  60. data/lib/cmdx/log_formatters/key_value.rb +13 -0
  61. data/lib/cmdx/log_formatters/line.rb +14 -0
  62. data/lib/cmdx/log_formatters/logstash.rb +18 -0
  63. data/lib/cmdx/log_formatters/raw.rb +13 -0
  64. data/lib/cmdx/logger.rb +16 -0
  65. data/lib/cmdx/parameter.rb +101 -0
  66. data/lib/cmdx/parameter_inspector.rb +23 -0
  67. data/lib/cmdx/parameter_serializer.rb +20 -0
  68. data/lib/cmdx/parameter_validator.rb +19 -0
  69. data/lib/cmdx/parameter_value.rb +136 -0
  70. data/lib/cmdx/parameters.rb +34 -0
  71. data/lib/cmdx/parameters_inspector.rb +13 -0
  72. data/lib/cmdx/parameters_serializer.rb +13 -0
  73. data/lib/cmdx/railtie.rb +32 -0
  74. data/lib/cmdx/result.rb +170 -0
  75. data/lib/cmdx/result_inspector.rb +31 -0
  76. data/lib/cmdx/result_logger.rb +22 -0
  77. data/lib/cmdx/result_serializer.rb +38 -0
  78. data/lib/cmdx/run.rb +33 -0
  79. data/lib/cmdx/run_inspector.rb +21 -0
  80. data/lib/cmdx/run_serializer.rb +16 -0
  81. data/lib/cmdx/task.rb +151 -0
  82. data/lib/cmdx/task_hook.rb +18 -0
  83. data/lib/cmdx/utils/datetime_formatter.rb +17 -0
  84. data/lib/cmdx/utils/method_name.rb +24 -0
  85. data/lib/cmdx/utils/runtime.rb +19 -0
  86. data/lib/cmdx/validators/custom.rb +20 -0
  87. data/lib/cmdx/validators/exclusion.rb +51 -0
  88. data/lib/cmdx/validators/format.rb +27 -0
  89. data/lib/cmdx/validators/inclusion.rb +51 -0
  90. data/lib/cmdx/validators/length.rb +114 -0
  91. data/lib/cmdx/validators/numeric.rb +114 -0
  92. data/lib/cmdx/validators/presence.rb +27 -0
  93. data/lib/cmdx/version.rb +7 -0
  94. data/lib/cmdx.rb +80 -0
  95. data/lib/generators/cmdx/batch_generator.rb +30 -0
  96. data/lib/generators/cmdx/install_generator.rb +15 -0
  97. data/lib/generators/cmdx/task_generator.rb +30 -0
  98. data/lib/generators/cmdx/templates/batch.rb.tt +7 -0
  99. data/lib/generators/cmdx/templates/install.rb +23 -0
  100. data/lib/generators/cmdx/templates/task.rb.tt +9 -0
  101. data/lib/locales/en.yml +36 -0
  102. data/lib/locales/es.yml +36 -0
  103. metadata +288 -0
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module Validators
5
+ module Numeric
6
+
7
+ extend self
8
+
9
+ def call(value, options = {})
10
+ case options[:numeric]
11
+ in { within: within }
12
+ raise_within_validation_error!(within.begin, within.end, options) unless within.cover?(value)
13
+ in { not_within: not_within }
14
+ raise_not_within_validation_error!(not_within.begin, not_within.end, options) if not_within.cover?(value)
15
+ in { in: yn }
16
+ raise_within_validation_error!(yn.begin, yn.end, options) unless yn.cover?(value)
17
+ in { not_in: not_in }
18
+ raise_not_within_validation_error!(not_in.begin, not_in.end, options) if not_in.cover?(value)
19
+ in { min: min, max: max }
20
+ raise_within_validation_error!(min, max, options) unless value.between?(min, max)
21
+ in { min: min }
22
+ raise_min_validation_error!(min, options) unless min <= value
23
+ in { max: max }
24
+ raise_max_validation_error!(max, options) unless value <= max
25
+ in { is: is }
26
+ raise_is_validation_error!(is, options) unless value == is
27
+ in { is_not: is_not }
28
+ raise_is_not_validation_error!(is_not, options) if value == is_not
29
+ else
30
+ raise ArgumentError, "no known numeric validator options given"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def raise_within_validation_error!(min, max, options)
37
+ message = options.dig(:numeric, :within_message) ||
38
+ options.dig(:numeric, :in_message) ||
39
+ options.dig(:numeric, :message)
40
+ message %= { min:, max: } unless message.nil?
41
+
42
+ raise ValidationError, message || I18n.t(
43
+ "cmdx.validators.numeric.within",
44
+ min:,
45
+ max:,
46
+ default: "must be within #{min} and #{max}"
47
+ )
48
+ end
49
+
50
+ def raise_not_within_validation_error!(min, max, options)
51
+ message = options.dig(:numeric, :not_within_message) ||
52
+ options.dig(:numeric, :not_in_message) ||
53
+ options.dig(:numeric, :message)
54
+ message %= { min:, max: } unless message.nil?
55
+
56
+ raise ValidationError, message || I18n.t(
57
+ "cmdx.validators.numeric.not_within",
58
+ min:,
59
+ max:,
60
+ default: "must not be within #{min} and #{max}"
61
+ )
62
+ end
63
+
64
+ def raise_min_validation_error!(min, options)
65
+ message = options.dig(:numeric, :min_message) ||
66
+ options.dig(:numeric, :message)
67
+ message %= { min: } unless message.nil?
68
+
69
+ raise ValidationError, message || I18n.t(
70
+ "cmdx.validators.numeric.min",
71
+ min:,
72
+ default: "must be at least #{min}"
73
+ )
74
+ end
75
+
76
+ def raise_max_validation_error!(max, options)
77
+ message = options.dig(:numeric, :max_message) ||
78
+ options.dig(:numeric, :message)
79
+ message %= { max: } unless message.nil?
80
+
81
+ raise ValidationError, message || I18n.t(
82
+ "cmdx.validators.numeric.max",
83
+ max:,
84
+ default: "must be at most #{max}"
85
+ )
86
+ end
87
+
88
+ def raise_is_validation_error!(is, options)
89
+ message = options.dig(:numeric, :is_message) ||
90
+ options.dig(:numeric, :message)
91
+ message %= { is: } unless message.nil?
92
+
93
+ raise ValidationError, message || I18n.t(
94
+ "cmdx.validators.numeric.is",
95
+ is:,
96
+ default: "must be #{is}"
97
+ )
98
+ end
99
+
100
+ def raise_is_not_validation_error!(is_not, options)
101
+ message = options.dig(:numeric, :is_not_message) ||
102
+ options.dig(:numeric, :message)
103
+ message %= { is_not: } unless message.nil?
104
+
105
+ raise ValidationError, message || I18n.t(
106
+ "cmdx.validators.numeric.is_not",
107
+ is_not:,
108
+ default: "must not be #{is_not}"
109
+ )
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module Validators
5
+ module Presence
6
+
7
+ module_function
8
+
9
+ def call(value, options = {})
10
+ return if if value.is_a?(String)
11
+ /\S/.match?(value)
12
+ elsif value.respond_to?(:empty?)
13
+ !value.empty?
14
+ else
15
+ !value.nil?
16
+ end
17
+
18
+ message = options.dig(:presence, :message) if options[:presence].is_a?(Hash)
19
+ raise ValidationError, message || I18n.t(
20
+ "cmdx.validators.presence",
21
+ default: "cannot be empty"
22
+ )
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+
5
+ VERSION = "0.1.0"
6
+
7
+ end
data/lib/cmdx.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "date"
5
+ require "i18n"
6
+ require "json"
7
+ require "logger"
8
+ require "securerandom"
9
+ require "time"
10
+ require "timeout"
11
+
12
+ require_relative "cmdx/version"
13
+ require_relative "cmdx/core_ext/object"
14
+ require_relative "cmdx/core_ext/hash"
15
+ require_relative "cmdx/core_ext/module"
16
+ require_relative "cmdx/log_formatters/json"
17
+ require_relative "cmdx/log_formatters/key_value"
18
+ require_relative "cmdx/log_formatters/line"
19
+ require_relative "cmdx/log_formatters/logstash"
20
+ require_relative "cmdx/log_formatters/raw"
21
+ require_relative "cmdx/coercions/array"
22
+ require_relative "cmdx/coercions/big_decimal"
23
+ require_relative "cmdx/coercions/boolean"
24
+ require_relative "cmdx/coercions/complex"
25
+ require_relative "cmdx/coercions/date"
26
+ require_relative "cmdx/coercions/date_time"
27
+ require_relative "cmdx/coercions/float"
28
+ require_relative "cmdx/coercions/hash"
29
+ require_relative "cmdx/coercions/integer"
30
+ require_relative "cmdx/coercions/rational"
31
+ require_relative "cmdx/coercions/string"
32
+ require_relative "cmdx/coercions/time"
33
+ require_relative "cmdx/coercions/virtual"
34
+ require_relative "cmdx/validators/custom"
35
+ require_relative "cmdx/validators/exclusion"
36
+ require_relative "cmdx/validators/format"
37
+ require_relative "cmdx/validators/inclusion"
38
+ require_relative "cmdx/validators/length"
39
+ require_relative "cmdx/validators/numeric"
40
+ require_relative "cmdx/validators/presence"
41
+ require_relative "cmdx/utils/datetime_formatter"
42
+ require_relative "cmdx/utils/method_name"
43
+ require_relative "cmdx/utils/runtime"
44
+ require_relative "cmdx/error"
45
+ require_relative "cmdx/errors"
46
+ require_relative "cmdx/fault"
47
+ require_relative "cmdx/faults"
48
+ require_relative "cmdx/logger"
49
+ require_relative "cmdx/lazy_struct"
50
+ require_relative "cmdx/configuration"
51
+ require_relative "cmdx/context"
52
+ require_relative "cmdx/run"
53
+ require_relative "cmdx/run_serializer"
54
+ require_relative "cmdx/run_inspector"
55
+ require_relative "cmdx/parameter"
56
+ require_relative "cmdx/parameter_value"
57
+ require_relative "cmdx/parameter_validator"
58
+ require_relative "cmdx/parameter_serializer"
59
+ require_relative "cmdx/parameter_inspector"
60
+ require_relative "cmdx/parameters"
61
+ require_relative "cmdx/parameters_serializer"
62
+ require_relative "cmdx/parameters_inspector"
63
+ require_relative "cmdx/result"
64
+ require_relative "cmdx/result_serializer"
65
+ require_relative "cmdx/result_inspector"
66
+ require_relative "cmdx/result_logger"
67
+ require_relative "cmdx/task"
68
+ require_relative "cmdx/task_hook"
69
+ require_relative "cmdx/batch"
70
+ require_relative "cmdx/immutator"
71
+
72
+ if defined?(Rails::Generators)
73
+ require_relative "generators/cmdx/install_generator"
74
+ require_relative "generators/cmdx/task_generator"
75
+ require_relative "generators/cmdx/batch_generator"
76
+ end
77
+
78
+ # Load the Railtie last after everything else is required so we don't
79
+ # need to load any CMDx components when we use this Railtie.
80
+ require_relative "cmdx/railtie" if defined?(Rails::Railtie)
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cmdx
4
+ class BatchGenerator < Rails::Generators::NamedBase
5
+
6
+ source_root File.expand_path("templates", __dir__)
7
+ check_class_collision prefix: "Batch"
8
+
9
+ desc "Generates a batch task with the given NAME (if one does not exist)."
10
+
11
+ def copy_files
12
+ name = file_name.sub(/^batch_?/i, "")
13
+ path = File.join("app/cmds", class_path, "batch_#{name}.rb")
14
+ template("batch.rb.tt", path)
15
+ end
16
+
17
+ private
18
+
19
+ def class_name
20
+ @class_name ||= super.delete_prefix("Batch")
21
+ end
22
+
23
+ def parent_class_name
24
+ ApplicationBatch
25
+ rescue StandardError
26
+ CMDx::Batch
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cmdx
4
+ class InstallGenerator < Rails::Generators::Base
5
+
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Generates a CMDx configurations files for global settings."
9
+
10
+ def copy_initializer_file
11
+ copy_file("install.rb", "config/initializers/cmdx.rb")
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cmdx
4
+ class TaskGenerator < Rails::Generators::NamedBase
5
+
6
+ source_root File.expand_path("templates", __dir__)
7
+ check_class_collision suffix: "Task"
8
+
9
+ desc "Generates a task with the given NAME (if one does not exist)."
10
+
11
+ def copy_files
12
+ name = file_name.sub(/_?task$/i, "")
13
+ path = File.join("app/cmds", class_path, "#{name}_task.rb")
14
+ template("task.rb.tt", path)
15
+ end
16
+
17
+ private
18
+
19
+ def class_name
20
+ @class_name ||= super.end_with?("Task") ? super : "#{super}Task"
21
+ end
22
+
23
+ def parent_class_name
24
+ ApplicationTask
25
+ rescue StandardError
26
+ CMDx::Task
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < <%= parent_class_name %>
3
+
4
+ process # TODO
5
+
6
+ end
7
+ <% end -%>
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ CMDx.configure do |config|
4
+ # Define which statuses a bang `call!` will halt and raise a fault.
5
+ # This option can accept an array of statuses.
6
+ config.task_halt = CMDx::Result::FAILED
7
+
8
+ # Enable task timeouts to prevent call execution beyond a defined threshold.
9
+ config.task_timeout = nil
10
+
11
+ # Define which statuses a batch task will halt execution from proceeding to the next step.
12
+ # By default skipped tasks are treated as a NOOP so processing is continued.
13
+ # This option can accept an array of statuses.
14
+ config.batch_halt = CMDx::Result::FAILED
15
+
16
+ # Enable batch timeouts to prevent call execution beyond a defined threshold.
17
+ # TIP: remember to account for all defined tasks when setting this value
18
+ config.batch_timeout = nil
19
+
20
+ # A list of available log formatter can be found at:
21
+ # https://github.com/drexed/cmdx/tree/main/lib/cmdx/log_formatters
22
+ config.logger = Logger.new($stdout, formatter: CMDx::LogFormatters::Line.new)
23
+ end
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < <%= parent_class_name %>
3
+
4
+ def call
5
+ # TODO
6
+ end
7
+
8
+ end
9
+ <% end -%>
@@ -0,0 +1,36 @@
1
+ en:
2
+ cmdx:
3
+ coercions:
4
+ into_a: "could not coerce into a %{type}"
5
+ into_an: "could not coerce into an %{type}"
6
+ into_any: "could not coerce into one of: %{values}"
7
+ unknown: "unknown %{type} coercion type"
8
+ faults:
9
+ unspecified: no reason given
10
+ parameters:
11
+ required: is a required parameter
12
+ undefined: delegates to undefined method %{source}
13
+ validators:
14
+ custom: is not valid
15
+ exclusion:
16
+ of: "must not be one of: %{values}"
17
+ within: must not be within %{min} and %{max}
18
+ format: is an invalid format
19
+ inclusion:
20
+ of: "must be one of: %{values}"
21
+ within: must be within %{min} and %{max}
22
+ length:
23
+ is: length must be %{is}
24
+ is_not: length must not be %{is_not}
25
+ min: length must be at least %{min}
26
+ max: length must be at most %{max}
27
+ not_within: length must not be within %{min} and %{max}
28
+ within: length must be within %{min} and %{max}
29
+ numeric:
30
+ is: must be %{is}
31
+ is_not: must not be %{is_not}
32
+ min: must be at least %{min}
33
+ max: must be at most %{max}
34
+ not_within: must not be within %{min} and %{max}
35
+ within: must be within %{min} and %{max}
36
+ presence: cannot be empty
@@ -0,0 +1,36 @@
1
+ es:
2
+ cmdx:
3
+ coercions:
4
+ into_a: "no podía coacciona el valor a un %{type}"
5
+ into_an: "no podía coacciona el valor a un %{type}"
6
+ into_any: "no podía coacciona el valor a un: %{values}"
7
+ unknown: "%{type} tipo de coacciona desconocido"
8
+ faults:
9
+ unspecified: ninguna razón dada
10
+ parameters:
11
+ required: es un parámetro requerido
12
+ undefined: delegado al método indefinido %{source}
13
+ validators:
14
+ custom: no es válida
15
+ exclusion:
16
+ of: "no debe ser uno de: %{values}"
17
+ within: no debe estar dentro %{min} y %{max}
18
+ format: es un formato inválido
19
+ inclusion:
20
+ of: "debe ser uno de: %{values}"
21
+ within: debe estar dentro %{min} y %{max}
22
+ length:
23
+ is: tiene una longitud que debe ser %{is}
24
+ is_not: tiene una longitud no debe ser %{is}
25
+ min: tiene una longitud que debe ser menos de %{min}
26
+ max: tiene una longitud que debe ser mas de %{max}
27
+ not_within: tiene una longitud que no debe estar dentro %{min} y %{max}
28
+ within: tiene una longitud que debe estar dentro %{min} y %{max}
29
+ numeric:
30
+ is: debe ser %{is}
31
+ is_not: no debe ser %{is}
32
+ min: debe ser %{min} como minimo
33
+ max: debe ser %{max} como máximo
34
+ not_within: no debe estar dentro %{min} y %{max}
35
+ within: debe estar dentro %{min} y %{max}
36
+ presence: no puede estar vacío