console 1.21.0 → 1.23.1

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: 36a5fff3c1cafc8686f77440fc2dcb09d3a94d1399b15b9bf6967e4b21e6a511
4
- data.tar.gz: 3c7e6218667002f2a0f745bcfddbeec1dc8b126fdd1b81cec71fa03c53c3eba5
3
+ metadata.gz: f053978f1ebc28b2973844d0ef018eeb200651ffb9bf00702a09ca3b04614fce
4
+ data.tar.gz: 4f8177c79c3e0d4f9b43e0e4b2c3f02e72837ca7d31e76a6eff308b41848e064
5
5
  SHA512:
6
- metadata.gz: b4d6ebc41b6ea36a711f5f054a30a81ff4a29d06e0f4a2ef6a6554f6c94fd874439428df40e7a098f4bec25a8605452c2380987d1e275e38e6cf522254fdc3b8
7
- data.tar.gz: 693ed3f6a7d6786a87aef0ff42d238a3cbd1fc267c0cafb1683b8236e0f878bb7a8dc316822f00ab84cdba7e6f58212e8474d0e85109d67ff59a65b3003548f3
6
+ metadata.gz: 01bed9d6648e51ca76c7af4944f640eff416510bd7160ce9e9fd54c6c6397a213b45cfe8b4628d0e2071716b2651362e187f119d82053b85a7c4e5bb06d66fed
7
+ data.tar.gz: 80de59979995f867f791052666b20d5d1f50ed01a74af4529797b604934b3f18e064f113963b55014c5f90497b40be82ba124443036f8cb34414b48e6c6bc50b
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Samuel Williams.
5
+
6
+ require 'json'
7
+
8
+ module Console
9
+ module Format
10
+ # This class is used to safely dump objects.
11
+ # It will attempt to dump the object using the given format, but if it fails, it will generate a safe version of the object.
12
+ class Safe
13
+ def initialize(format: ::JSON, limit: 8, encoding: ::Encoding::UTF_8)
14
+ @format = format
15
+ @limit = limit
16
+ @encoding = encoding
17
+ end
18
+
19
+ def dump(object)
20
+ @format.dump(object, @limit)
21
+ rescue SystemStackError, StandardError => error
22
+ @format.dump(safe_dump(object, error))
23
+ end
24
+
25
+ private
26
+
27
+ def default_objects
28
+ Hash.new.compare_by_identity
29
+ end
30
+
31
+ # The first N frames, noting that the last frame is a placeholder for all the skipped frames:
32
+ FIRST_N_FRAMES = 10 + 1
33
+ LAST_N_FRAMES = 20
34
+ MAXIMUM_FRAMES = FIRST_N_FRAMES + LAST_N_FRAMES
35
+
36
+ def filter_backtrace(error)
37
+ frames = error.backtrace
38
+
39
+ # Select only the first and last few frames:
40
+ if frames.size > MAXIMUM_FRAMES
41
+ frames[FIRST_N_FRAMES-1] = "[... #{frames.size - (MAXIMUM_FRAMES-1)} frames ...]"
42
+ frames.slice!(FIRST_N_FRAMES...-LAST_N_FRAMES)
43
+ end
44
+
45
+ return frames
46
+ end
47
+
48
+ def safe_dump(object, error)
49
+ object = safe_dump_recurse(object)
50
+
51
+ object[:truncated] = true
52
+ object[:error] = {
53
+ class: safe_dump_recurse(error.class.name),
54
+ message: safe_dump_recurse(error.message),
55
+ backtrace: safe_dump_recurse(filter_backtrace(error)),
56
+ }
57
+
58
+ return object
59
+ end
60
+
61
+ def replacement_for(object)
62
+ case object
63
+ when Array
64
+ "[...]"
65
+ when Hash
66
+ "{...}"
67
+ else
68
+ "..."
69
+ end
70
+ end
71
+
72
+ # This will recursively generate a safe version of the object.
73
+ # Nested hashes and arrays will be transformed recursively.
74
+ # Strings will be encoded with the given encoding.
75
+ # Primitive values will be returned as-is.
76
+ # Other values will be converted using `as_json` if available, otherwise `to_s`.
77
+ def safe_dump_recurse(object, limit = @limit, objects = default_objects)
78
+ if limit <= 0 || objects[object]
79
+ return replacement_for(object)
80
+ end
81
+
82
+ case object
83
+ when Hash
84
+ objects[object] = true
85
+
86
+ object.to_h do |key, value|
87
+ [
88
+ String(key).encode(@encoding, invalid: :replace, undef: :replace),
89
+ safe_dump_recurse(value, limit - 1, objects)
90
+ ]
91
+ end
92
+ when Array
93
+ objects[object] = true
94
+
95
+ object.map do |value|
96
+ safe_dump_recurse(value, limit - 1, objects)
97
+ end
98
+ when String
99
+ object.encode(@encoding, invalid: :replace, undef: :replace)
100
+ when Numeric, TrueClass, FalseClass, NilClass
101
+ object
102
+ else
103
+ objects[object] = true
104
+
105
+ # We could do something like this but the chance `as_json` will blow up.
106
+ # We'd need to be extremely careful about it.
107
+ # if object.respond_to?(:as_json)
108
+ # safe_dump_recurse(object.as_json, limit - 1, objects)
109
+ # else
110
+
111
+ safe_dump_recurse(object.to_s, limit - 1, objects)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Samuel Williams.
5
+
6
+ require_relative 'format/safe'
7
+
8
+ module Console
9
+ module Format
10
+ def self.default
11
+ Safe.new(format: ::JSON)
12
+ end
13
+
14
+ def self.default_json
15
+ self.default
16
+ end
17
+ end
18
+ end
@@ -4,16 +4,12 @@
4
4
  # Copyright, 2021-2022, by Samuel Williams.
5
5
 
6
6
  require_relative '../serialized/logger'
7
- require_relative 'encoder'
8
7
 
9
8
  module Console
10
9
  module Output
11
10
  module JSON
12
11
  def self.new(output, **options)
13
- # The output encoder can prevent encoding issues (e.g. invalid UTF-8):
14
- Output::Encoder.new(
15
- Serialized::Logger.new(output, format: ::JSON, **options)
16
- )
12
+ Serialized::Logger.new(output, format: Format.default_json, **options)
17
13
  end
18
14
  end
19
15
  end
@@ -5,16 +5,16 @@
5
5
 
6
6
  require_relative '../buffer'
7
7
  require_relative '../filter'
8
+ require_relative '../format'
8
9
 
9
10
  require 'time'
10
- require 'json'
11
11
 
12
12
  require 'fiber/annotation'
13
13
 
14
14
  module Console
15
15
  module Serialized
16
16
  class Logger
17
- def initialize(io = $stderr, format: JSON, verbose: false, **options)
17
+ def initialize(io = $stderr, format: Format.default, verbose: false, **options)
18
18
  @io = io
19
19
  @start = Time.now
20
20
  @format = format
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2019-2023, by Samuel Williams.
5
5
 
6
6
  module Console
7
- VERSION = "1.21.0"
7
+ VERSION = "1.23.1"
8
8
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: console
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.21.0
4
+ version: 1.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -46,7 +46,7 @@ cert_chain:
46
46
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
47
47
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
48
48
  -----END CERTIFICATE-----
49
- date: 2023-08-07 00:00:00.000000000 Z
49
+ date: 2023-08-11 00:00:00.000000000 Z
50
50
  dependencies:
51
51
  - !ruby/object:Gem::Dependency
52
52
  name: fiber-annotation
@@ -95,10 +95,11 @@ files:
95
95
  - lib/console/event/progress.rb
96
96
  - lib/console/event/spawn.rb
97
97
  - lib/console/filter.rb
98
+ - lib/console/format.rb
99
+ - lib/console/format/safe.rb
98
100
  - lib/console/logger.rb
99
101
  - lib/console/output.rb
100
102
  - lib/console/output/default.rb
101
- - lib/console/output/encoder.rb
102
103
  - lib/console/output/json.rb
103
104
  - lib/console/output/null.rb
104
105
  - lib/console/output/sensitive.rb
metadata.gz.sig CHANGED
Binary file
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2023, by Samuel Williams.
5
-
6
- module Console
7
- module Output
8
- class Encoder
9
- def initialize(output, encoding = ::Encoding::UTF_8)
10
- @output = output
11
- @encoding = encoding
12
- end
13
-
14
- attr :output
15
-
16
- attr :encoding
17
-
18
- def call(subject = nil, *arguments, **options, &block)
19
- subject = encode(subject)
20
- arguments = encode(arguments)
21
- options = encode(options)
22
-
23
- @output.call(subject, *arguments, **options, &block)
24
- end
25
-
26
- def encode(value)
27
- case value
28
- when String
29
- value.encode(@encoding, invalid: :replace, undef: :replace)
30
- when Array
31
- value.map{|item| encode(item)}
32
- when Hash
33
- value.transform_values{|item| encode(item)}
34
- else
35
- value
36
- end
37
- end
38
- end
39
- end
40
- end