1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# frozen_string_literal: true
require_relative 'option_definition'
require_relative 'run_options'
module ProcessExecuter
module Options
# Define options for {ProcessExecuter.run_with_capture}
#
# @api public
#
class RunWithCaptureOptions < RunOptions
# The default encoding used for stdout and stderr
# if no other encoding is specified.
#
# @return [Encoding]
#
DEFAULT_ENCODING = Encoding::UTF_8
# Determines the character encoding to use for stdout
#
# It prioritizes `stdout_encoding` if set, otherwise falls back to
# `encoding`, and finally defaults to `DEFAULT_ENCODING` if neither
# is available.
#
# @return [Encoding]
#
# @api private
#
def effective_stdout_encoding
stdout_encoding || encoding || DEFAULT_ENCODING
end
# Determines the character encoding to use for stderr
#
# It prioritizes `stderr_encoding` if set, otherwise falls back to
# `encoding`, and finally defaults to `DEFAULT_ENCODING` if neither
# is available.
#
# @return [Encoding]
#
# @api private
#
def effective_stderr_encoding
stderr_encoding || encoding || DEFAULT_ENCODING
end
private
# The options allowed for objects of this class
# @return [Array<OptionDefinition>]
# @api private
def define_options
[
*super,
OptionDefinition.new(:merge_output, default: false, validator: method(:validate_merge_output)),
OptionDefinition.new(:encoding, default: DEFAULT_ENCODING, validator: method(:validate_encoding_option)),
OptionDefinition.new(:stdout_encoding, default: nil, validator: method(:validate_encoding_option)),
OptionDefinition.new(:stderr_encoding, default: nil, validator: method(:validate_encoding_option))
].freeze
end
# Note any errors in the merge_output option
#
# Possible errors include:
# - if the merge_output value is not a Boolean
# - if merge_output: true and a stderr redirection is given
# - if merge_output: true and stdout and stderr encodings are different
#
# @param _key [Symbol] the option key (not used)
# @param _value [Object] the option value (not used)
# @return [Void]
# @api private
def validate_merge_output(_key, _value)
unless [true, false].include?(merge_output)
errors << "merge_output must be true or false but was #{merge_output.inspect}"
end
return unless merge_output == true
errors << 'Cannot give merge_output: true AND a stderr redirection' if stderr_redirection_source
return if effective_stdout_encoding == effective_stderr_encoding
errors << 'Cannot give merge_output: true AND give different encodings for stdout and stderr'
end
# Note an error if the encoding option is not valid
# @param key [Symbol] the option key
# @param value [Object] the option value
# @return [Void]
# @api private
def validate_encoding_option(key, value)
return unless valid_encoding_type?(key, value)
return if value.nil? || value.is_a?(Encoding)
validate_encoding_symbol(key, value) if value.is_a?(Symbol)
validate_encoding_string(key, value) if value.is_a?(String)
end
# False if the value is not a valid encoding type, true otherwise
#
# @param key [Symbol] the option key
#
# @param value [Object] the option value
#
# @return [Boolean]
#
# @api private
#
def valid_encoding_type?(key, value)
return true if value.nil? || value.is_a?(Encoding) || value.is_a?(Symbol) || value.is_a?(String)
errors << "#{key} must be an Encoding object, String, Symbol (:binary, :default_external), " \
"or nil, but was #{value.inspect}"
false
end
# Note an error if the encoding symbol is not valid
#
# @param key [Symbol] the option key
#
# @param value [Symbol] the option value
#
# @return [Void]
#
# @api private
#
def validate_encoding_symbol(key, value)
return if %i[binary default_external].include?(value)
errors << "#{key} when given as a symbol must be :binary or :default_external, " \
"but was #{value.inspect}"
end
# Note an error if the encoding string is not valid
#
# @param key [Symbol] the option key
#
# @param value [String] the option value
#
# @return [void]
#
# @api private
#
def validate_encoding_string(key, value)
Encoding.find(value)
rescue ::ArgumentError
errors << "#{key} specifies an unknown encoding name: #{value.inspect}"
end
end
end
end
|