cmdx 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aed549d510aee08ccdb114f75b51b7aefe1a9776905f53e75ec5c39477932350
4
- data.tar.gz: b57596b1393185082d94616f8c08494d030a2d78bb85610674363a365efa15f5
3
+ metadata.gz: 198e34bfa10cf9b640e3a768e335e3901063e2cde3817be7c63fb710b322acc6
4
+ data.tar.gz: 59f99b87b1c2cc5fff64e2092f3f5ef5230a43d11de6f27c6609802627509164
5
5
  SHA512:
6
- metadata.gz: 7d123c5a08fc89494b759eddea90e614858e55db733a3690e899de46b5e6e93e574a9bf2d9899f4f9c9c118686d5ff2f84cfd75b110ce242b79d7627ae3dfbd8
7
- data.tar.gz: 17e336e03307f3dddaf7dba53d4a201f031f54348bc0e43059a17ace90cf7f4a762ad6e97ec731b32d1064616c978948867e8aa746ff96f52e93996376828a7c
6
+ metadata.gz: e60556e4f9af0a9af56d748a1084d95e5fecbe5316268d1d2f1414e5d4c323be81a7c56066bf19edf121eab3fb48080d6b5b3470086ee96241008eb28df9a152
7
+ data.tar.gz: cc37a5a0029f708f624e449b0526060e203b649d282f33f69551c641ae06f34a3d53886b346b8e48b68f6dbaff23654171d34e58e7d854429c58f0c3d90c62af
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2025-03-07
3
+ ## [0.2.0] - 2025-03-12
4
+ ### Added
5
+ - Add `PrettyJson` log formatter
6
+ - Add `PrettyKeyValue` log formatter
7
+ - Add `PrettyLine` log formatter
8
+ ### Changed
9
+ - Make `PrettyLine` the default log formatter
10
+ - Rename `MethodName` util to `NameAffix`
11
+ - Rename `DatetimeFormatter` util to `LogTimestamp`
12
+ - Rename `Runtime` util to `MonotonicRuntime`
13
+ - Fix logging non hash values from raising an error
14
+ - Fix bubbling of faults with nested halted calls
15
+ - Wrap result logger in a `Logger#with_logger` block
4
16
 
17
+ ## [0.1.0] - 2025-03-07
18
+ ### Added
5
19
  - Initial release
data/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  [![forthebadge](http://forthebadge.com/images/badges/made-with-ruby.svg)](http://forthebadge.com)
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/cmdx.svg)](https://badge.fury.io/rb/cmdx)
6
- [![CI](https://github.com/drexed/cmdx/actions/workflows/ruby.yml/badge.svg)](https://github.com/drexed/cmdx/actions/workflows/ruby.yml)
5
+ [![Gem Version](https://badge.fury.io/rb/cmdx.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/cmdx)
6
+ [![CI](https://github.com/drexed/cmdx/actions/workflows/ci.yml/badge.svg)](https://github.com/drexed/cmdx/actions/workflows/ci.yml)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=shields)](http://makeapullrequest.com)
8
8
 
9
9
  `CMDx` is a framework for expressive processing of business logic. Design
data/docs/logging.md CHANGED
@@ -5,7 +5,9 @@ tasks executing concurrently so `CMDx` uses a custom logger to make debugging ea
5
5
 
6
6
  ## Output
7
7
 
8
- Built-in log formatters are: `Line` (default), `Json`, `KeyValue`, `Logstash`, `Raw`
8
+ Built-in log formatters are:
9
+ - Standard: `Line`, `Json`, `KeyValue`, `Logstash`, `Raw`
10
+ - Stylized: `PrettyLine` (default), `PrettyJson`, `PrettyKeyValue`
9
11
 
10
12
  #### Success:
11
13
  ```txt
@@ -14,7 +14,7 @@ module CMDx
14
14
 
15
15
  def reset_configuration!
16
16
  @configuration = LazyStruct.new(
17
- logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::Line.new),
17
+ logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::PrettyLine.new),
18
18
  task_halt: CMDx::Result::FAILED,
19
19
  task_timeout: nil,
20
20
  batch_halt: CMDx::Result::FAILED,
@@ -6,7 +6,7 @@ module CMDx
6
6
 
7
7
  def __cmdx_attr_delegator(*methods, **options)
8
8
  methods.each do |method|
9
- method_name = Utils::MethodName.call(method, options.fetch(:to), options)
9
+ method_name = Utils::NameAffix.call(method, options.fetch(:to), options)
10
10
 
11
11
  define_method(method_name) do |*args, **kwargs, &block|
12
12
  object = (options[:to] == :class ? self.class : send(options[:to]))
@@ -5,7 +5,8 @@ module CMDx
5
5
  class Json
6
6
 
7
7
  def call(_severity, _time, _progname, message)
8
- JSON.dump(message)
8
+ message = message.to_h if message.is_a?(Result)
9
+ JSON.dump(message) << "\n"
9
10
  end
10
11
 
11
12
  end
@@ -5,7 +5,13 @@ module CMDx
5
5
  class KeyValue
6
6
 
7
7
  def call(_severity, _time, _progname, message)
8
- message.map { |k, v| "#{k}=#{v}" }.join(" ")
8
+ if message.is_a?(Result)
9
+ message = message.to_h.map do |k, v|
10
+ "#{k}=#{v}"
11
+ end.join(" ")
12
+ end
13
+
14
+ message << "\n"
9
15
  end
10
16
 
11
17
  end
@@ -5,8 +5,10 @@ module CMDx
5
5
  class Line
6
6
 
7
7
  def call(severity, time, progname, message)
8
- message = message.map { |k, v| "#{k}=#{v}" }.join(" ")
9
- "#{severity[0]}, [#{Utils::DatetimeFormatter.call(time.utc)} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}"
8
+ timestamp = Utils::LogTimestamp.call(time.utc)
9
+ message = KeyValue.new.call(severity, time, progname, message).chomp
10
+
11
+ "#{severity[0]}, [#{timestamp} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}\n"
10
12
  end
11
13
 
12
14
  end
@@ -5,12 +5,14 @@ module CMDx
5
5
  class Logstash
6
6
 
7
7
  def call(_severity, time, _progname, message)
8
+ message = message.to_h if message.is_a?(Result)
9
+
8
10
  if message.is_a?(Hash)
9
11
  message["@version"] ||= "1"
10
- message["@timestamp"] ||= Utils::DatetimeFormatter.call(time.utc)
12
+ message["@timestamp"] ||= Utils::LogTimestamp.call(time.utc)
11
13
  end
12
14
 
13
- JSON.dump(message)
15
+ JSON.dump(message) << "\n"
14
16
  end
15
17
 
16
18
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyJson
6
+
7
+ def call(_severity, _time, _progname, message)
8
+ message = message.to_h if message.is_a?(Result)
9
+ JSON.pretty_generate(message) << "\n"
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyKeyValue
6
+
7
+ COLORED_KEYS = %i[
8
+ state status outcome
9
+ ].freeze
10
+
11
+ def call(_severity, _time, _progname, message)
12
+ if message.is_a?(Result)
13
+ message = message.to_h.map do |k, v|
14
+ v = ResultAnsi.call(v) if COLORED_KEYS.include?(k)
15
+ "#{k}=#{v}"
16
+ end.join(" ")
17
+ end
18
+
19
+ message << "\n"
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyLine
6
+
7
+ def call(severity, time, progname, message)
8
+ indicator = LoggerAnsi.call(severity[0])
9
+ severity = LoggerAnsi.call(severity)
10
+ timestamp = Utils::LogTimestamp.call(time.utc)
11
+ message = PrettyKeyValue.new.call(severity, time, progname, message).chomp
12
+
13
+ "#{indicator}, [#{timestamp} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}\n"
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -5,7 +5,7 @@ module CMDx
5
5
  class Raw
6
6
 
7
7
  def call(_severity, _time, _progname, message)
8
- message
8
+ message.inspect << "\n"
9
9
  end
10
10
 
11
11
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LoggerAnsi
5
+
6
+ SEVERITY_COLOR_CODES = {
7
+ "D" => 34, # DEBUG - Blue
8
+ "I" => 32, # INFO - Green
9
+ "W" => 33, # WARN - Yellow
10
+ "E" => 31, # ERROR - Red
11
+ "F" => 35 # FATAL - Magenta
12
+ }.freeze
13
+
14
+ module_function
15
+
16
+ def call(s)
17
+ c = SEVERITY_COLOR_CODES[s[0]] || 39 # Default
18
+ "\e[1;#{c}m#{s}\e[0m"
19
+ end
20
+
21
+ end
22
+ end
@@ -60,7 +60,7 @@ module CMDx
60
60
  end
61
61
 
62
62
  def method_name
63
- @method_name ||= Utils::MethodName.call(name, method_source, options)
63
+ @method_name ||= Utils::NameAffix.call(name, method_source, options)
64
64
  end
65
65
 
66
66
  def method_source
data/lib/cmdx/result.rb CHANGED
@@ -103,11 +103,13 @@ module CMDx
103
103
  raise Fault.build(self)
104
104
  end
105
105
 
106
- def throw!(result)
106
+ def throw!(result, local_metadata = {})
107
107
  raise ArgumentError, "must be a Result" unless result.is_a?(Result)
108
108
 
109
- skip!(**result.metadata) if result.skipped?
110
- fail!(**result.metadata) if result.failed?
109
+ md = result.metadata.merge(local_metadata)
110
+
111
+ skip!(**md) if result.skipped?
112
+ fail!(**md) if result.failed?
111
113
  end
112
114
 
113
115
  def caused_failure
@@ -154,7 +156,7 @@ module CMDx
154
156
  timeout_secs = task.task_setting(timeout_type)
155
157
 
156
158
  Timeout.timeout(timeout_secs, TimeoutError, "execution exceeded #{timeout_secs} seconds") do
157
- @runtime = Utils::Runtime.call(&block)
159
+ @runtime = Utils::MonotonicRuntime.call(&block)
158
160
  end
159
161
  end
160
162
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module ResultAnsi
5
+
6
+ STATE_COLOR_CODES = {
7
+ Result::INITIALIZED => 34, # Blue
8
+ Result::EXECUTING => 33, # Yellow
9
+ Result::COMPLETE => 32, # Green
10
+ Result::INTERRUPTED => 31 # Red
11
+ }.freeze
12
+ STATUS_COLOR_CODES = {
13
+ Result::SUCCESS => 32, # Green
14
+ Result::SKIPPED => 33, # Yellow
15
+ Result::FAILED => 31 # Red
16
+ }.freeze
17
+
18
+ module_function
19
+
20
+ def call(s)
21
+ c = STATE_COLOR_CODES[s] || STATUS_COLOR_CODES[s] || 39 # Default
22
+ "\e[1;#{c}m#{s}\e[0m"
23
+ end
24
+
25
+ end
26
+ end
@@ -3,7 +3,7 @@
3
3
  module CMDx
4
4
  module ResultLogger
5
5
 
6
- STATUS_TO_LEVEL = {
6
+ STATUS_TO_SEVERITY = {
7
7
  Result::SUCCESS => :info,
8
8
  Result::SKIPPED => :warn,
9
9
  Result::FAILED => :error
@@ -12,10 +12,12 @@ module CMDx
12
12
  module_function
13
13
 
14
14
  def call(result)
15
- logger = result.task.send(:logger)
16
- status = STATUS_TO_LEVEL[result.status]
15
+ logger = result.task.send(:logger)
16
+ severity = STATUS_TO_SEVERITY[result.status]
17
17
 
18
- logger.send(status) { result.to_h }
18
+ logger.with_level(severity) do
19
+ logger.send(severity) { result }
20
+ end
19
21
  end
20
22
 
21
23
  end
data/lib/cmdx/task.rb CHANGED
@@ -121,8 +121,10 @@ module CMDx
121
121
  call
122
122
  rescue UndefinedCallError => e
123
123
  raise(e)
124
+ rescue Fault => e
125
+ throw!(e.result, original_exception: e) if Array(task_setting(:task_halt)).include?(e.result.status)
124
126
  rescue StandardError => e
125
- result.fail!(reason: "[#{e.class}] #{e.message}", original_exception: e) unless e.is_a?(Fault)
127
+ fail!(reason: "[#{e.class}] #{e.message}", original_exception: e)
126
128
  ensure
127
129
  after_call
128
130
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module DatetimeFormatter
5
+ module LogTimestamp
6
6
 
7
7
  DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N"
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module Runtime
5
+ module MonotonicRuntime
6
6
 
7
7
  module_function
8
8
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module MethodName
5
+ module NameAffix
6
6
 
7
- ROOTFIX = proc do |o, &block|
7
+ AFFIX = proc do |o, &block|
8
8
  o == true ? block.call : o
9
9
  end.freeze
10
10
 
@@ -12,8 +12,8 @@ module CMDx
12
12
 
13
13
  def call(method_name, source, options = {})
14
14
  options[:as] || begin
15
- prefix = ROOTFIX.call(options[:prefix]) { "#{source}_" }
16
- suffix = ROOTFIX.call(options[:suffix]) { "_#{source}" }
15
+ prefix = AFFIX.call(options[:prefix]) { "#{source}_" }
16
+ suffix = AFFIX.call(options[:suffix]) { "_#{source}" }
17
17
 
18
18
  "#{prefix}#{method_name}#{suffix}".strip.to_sym
19
19
  end
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
 
7
7
  end
data/lib/cmdx.rb CHANGED
@@ -18,6 +18,9 @@ require_relative "cmdx/log_formatters/key_value"
18
18
  require_relative "cmdx/log_formatters/line"
19
19
  require_relative "cmdx/log_formatters/logstash"
20
20
  require_relative "cmdx/log_formatters/raw"
21
+ require_relative "cmdx/log_formatters/pretty_json"
22
+ require_relative "cmdx/log_formatters/pretty_key_value"
23
+ require_relative "cmdx/log_formatters/pretty_line"
21
24
  require_relative "cmdx/coercions/array"
22
25
  require_relative "cmdx/coercions/big_decimal"
23
26
  require_relative "cmdx/coercions/boolean"
@@ -38,13 +41,14 @@ require_relative "cmdx/validators/inclusion"
38
41
  require_relative "cmdx/validators/length"
39
42
  require_relative "cmdx/validators/numeric"
40
43
  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/utils/log_timestamp"
45
+ require_relative "cmdx/utils/name_affix"
46
+ require_relative "cmdx/utils/monotonic_runtime"
44
47
  require_relative "cmdx/error"
45
48
  require_relative "cmdx/errors"
46
49
  require_relative "cmdx/fault"
47
50
  require_relative "cmdx/faults"
51
+ require_relative "cmdx/logger_ansi"
48
52
  require_relative "cmdx/logger"
49
53
  require_relative "cmdx/lazy_struct"
50
54
  require_relative "cmdx/configuration"
@@ -63,6 +67,7 @@ require_relative "cmdx/parameters_inspector"
63
67
  require_relative "cmdx/result"
64
68
  require_relative "cmdx/result_serializer"
65
69
  require_relative "cmdx/result_inspector"
70
+ require_relative "cmdx/result_ansi"
66
71
  require_relative "cmdx/result_logger"
67
72
  require_relative "cmdx/task"
68
73
  require_relative "cmdx/task_hook"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-08 00:00:00.000000000 Z
10
+ date: 2025-03-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -219,8 +219,12 @@ files:
219
219
  - lib/cmdx/log_formatters/key_value.rb
220
220
  - lib/cmdx/log_formatters/line.rb
221
221
  - lib/cmdx/log_formatters/logstash.rb
222
+ - lib/cmdx/log_formatters/pretty_json.rb
223
+ - lib/cmdx/log_formatters/pretty_key_value.rb
224
+ - lib/cmdx/log_formatters/pretty_line.rb
222
225
  - lib/cmdx/log_formatters/raw.rb
223
226
  - lib/cmdx/logger.rb
227
+ - lib/cmdx/logger_ansi.rb
224
228
  - lib/cmdx/parameter.rb
225
229
  - lib/cmdx/parameter_inspector.rb
226
230
  - lib/cmdx/parameter_serializer.rb
@@ -231,6 +235,7 @@ files:
231
235
  - lib/cmdx/parameters_serializer.rb
232
236
  - lib/cmdx/railtie.rb
233
237
  - lib/cmdx/result.rb
238
+ - lib/cmdx/result_ansi.rb
234
239
  - lib/cmdx/result_inspector.rb
235
240
  - lib/cmdx/result_logger.rb
236
241
  - lib/cmdx/result_serializer.rb
@@ -239,9 +244,9 @@ files:
239
244
  - lib/cmdx/run_serializer.rb
240
245
  - lib/cmdx/task.rb
241
246
  - lib/cmdx/task_hook.rb
242
- - lib/cmdx/utils/datetime_formatter.rb
243
- - lib/cmdx/utils/method_name.rb
244
- - lib/cmdx/utils/runtime.rb
247
+ - lib/cmdx/utils/log_timestamp.rb
248
+ - lib/cmdx/utils/monotonic_runtime.rb
249
+ - lib/cmdx/utils/name_affix.rb
245
250
  - lib/cmdx/validators/custom.rb
246
251
  - lib/cmdx/validators/exclusion.rb
247
252
  - lib/cmdx/validators/format.rb