Module: Clyops
- Defined in:
- lib/clyops.rb,
lib/clyops/completions.rb
Overview
Generated by tools/sync-completions.py from spec/completions/. Do not edit.
Defined Under Namespace
Classes: Cli, DefinitionError, ParseResult, ValidationError, Values
Constant Summary collapse
- VERSION =
Release version of this library.
"0.3.0"- BASH_COMPLETION =
<<'CLYOPS_BASH_TEMPLATE' # bash completion for __CLYOPS_PROG__ (generated by clyops) # Enable with: eval "$(__CLYOPS_PROG__ --completion bash)" _clyops___CLYOPS_FUNC__() { local cur="${COMP_WORDS[COMP_CWORD]}" prev="" data rec name short type kind values rest i skip=0 local -A otype=() okind=() ovalues=() local -a names=() cmds=() akind=() avalues=() aarity=() (( COMP_CWORD > 0 )) && prev="${COMP_WORDS[COMP_CWORD-1]}" # The words before the cursor let a dispatcher answer for the subcommand being typed. data=$("${COMP_WORDS[0]}" --bash-completion -- "${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null) || return 0 [[ "$data" == "#clyops-completion 1"* ]] || return 0 while IFS=$'\t' read -r rec name short type kind values rest; do [[ "$values" == - ]] && values="" case "$rec" in skip) skip="$name" ;; cmd) cmds+=("$name") ;; opt) for i in "$name" "$short"; do [[ -z "$i" || "$i" == - ]] && continue names+=("$i"); otype[$i]="$type"; okind[$i]="$kind"; ovalues[$i]="$values" done ;; arg) # arg records: name, arity, kind, values, description [[ "$kind" == - ]] && kind="" aarity+=("$short"); akind+=("$type"); avalues+=("$kind") ;; esac done <<< "$data" # Words up to and including a dispatched subcommand belong to the dispatcher. local first=$(( 1 + skip )) (( COMP_CWORD <= first )) && prev="" # Option value: --opt=VALUE (bash splits on "=") or --opt VALUE. local opt="" if [[ "$cur" == --*=* ]]; then opt="${cur%%=*}"; cur="${cur#*=}" elif [[ "$cur" == = && "${otype[$prev]}" == value ]]; then opt="$prev"; cur="" elif [[ "$prev" == = ]] && (( COMP_CWORD > first + 1 )); then opt="${COMP_WORDS[COMP_CWORD-2]}" elif [[ "$prev" == -* && "${otype[$prev]}" == value ]]; then opt="$prev" fi if [[ -n "$opt" ]]; then _clyops_value___CLYOPS_FUNC__ "${okind[$opt]}" "${ovalues[$opt]}" "$cur" return 0 fi if [[ "$cur" == -* ]]; then COMPREPLY=($(compgen -W "${names[*]}" -- "$cur")) return 0 fi # A dispatcher group: complete its subcommands. if (( ${#cmds[@]} )); then COMPREPLY=($(compgen -W "${cmds[*]}" -- "$cur")) return 0 fi # A dispatched program without completion data: fall back to file names. if (( skip > 0 && ${#names[@]} == 0 && ${#akind[@]} == 0 )); then compopt -o default 2>/dev/null COMPREPLY=() return 0 fi # Positional: count earlier positionals, skipping options and their values. local pos=0 endopts="" w for (( i = first; i < COMP_CWORD; i++ )); do w="${COMP_WORDS[i]}" if [[ -z "$endopts" && "$w" == -- ]]; then endopts=1 elif [[ -z "$endopts" && "$w" == -?* ]]; then [[ "$w" != *=* && "${otype[$w]}" == value ]] && (( i++ )) elif [[ "$w" != = ]]; then (( pos++ )) fi done local n=${#akind[@]} (( n == 0 )) && return 0 if (( pos >= n )); then [[ "${aarity[n-1]}" == variadic ]] || return 0 pos=$(( n - 1 )) fi _clyops_value___CLYOPS_FUNC__ "${akind[pos]}" "${avalues[pos]}" "$cur" } _clyops_value___CLYOPS_FUNC__() { local kind="$1" values="$2" cur="$3" dir IFS=$'\n' case "$kind" in choice) COMPREPLY=($(IFS=$' \t\n'; compgen -W "${values//,/ }" -- "$cur")) ;; file|dir) local flag=-f [[ "$kind" == dir ]] && flag=-d compopt -o filenames 2>/dev/null COMPREPLY=($(compgen $flag -- "$cur")) # Bare names also match entries in the option's search dirs. if [[ -n "$values" && "$cur" != /* && "$cur" != ./* && "$cur" != ../* ]]; then local -a dirs IFS=: read -ra dirs <<< "$values" for dir in "${dirs[@]}"; do [[ -d "$dir" ]] && COMPREPLY+=($(cd "$dir" && compgen $flag -- "$cur")) done fi ;; host) COMPREPLY=($(compgen -A hostname -- "$cur")) ;; none) COMPREPLY=() ;; *) compopt -o default 2>/dev/null; COMPREPLY=() ;; esac } complete -F _clyops___CLYOPS_FUNC__ __CLYOPS_PROG__ CLYOPS_BASH_TEMPLATE
- ZSH_COMPLETION =
<<'CLYOPS_ZSH_TEMPLATE' #compdef __CLYOPS_PROG__ # zsh completion for __CLYOPS_PROG__ (generated by clyops) # Enable with: eval "$(__CLYOPS_PROG__ --completion zsh)" # or install: __CLYOPS_PROG__ --completion zsh > "${fpath[1]}/___CLYOPS_PROG__" _clyops___CLYOPS_FUNC__() { local data line esc action skip=0 local -a f specs cmds # The words before the cursor let a dispatcher answer for the subcommand being typed. data=$("${words[1]}" --bash-completion -- "${(@)words[2,CURRENT-1]}" 2>/dev/null) || return 1 [[ "$data" == "#clyops-completion 1"* ]] || return 1 for line in "${(@f)data}"; do [[ "$line" == \#* ]] && continue f=("${(@ps:\t:)line}") if [[ "$f[1]" == skip ]]; then skip=$f[2] elif [[ "$f[1]" == cmd ]]; then cmds+=("${f[2]//:/\\:}:$f[3]") elif [[ "$f[1]" == opt ]]; then esc="${${${${f[7]//\\/\\\\}//\[/\\[}//\]/\\]}//:/\\:}" if [[ "$f[4]" == flag ]]; then specs+=("$f[2][$esc]") [[ "$f[3]" != - ]] && specs+=("$f[3][$esc]") continue fi action="$(_clyops_action___CLYOPS_FUNC__ "$f[5]" "$f[6]")" specs+=("$f[2]=[$esc]:value:$action") [[ "$f[3]" != - ]] && specs+=("$f[3]+[$esc]:value:$action") elif [[ "$f[1]" == arg ]]; then esc="${${f[6]//\\/\\\\}//:/\\:}" action="$(_clyops_action___CLYOPS_FUNC__ "$f[4]" "$f[5]")" if [[ "$f[3]" == variadic ]]; then specs+=("*:$esc:$action"); else specs+=(":$esc:$action"); fi fi done # Past a dispatched subcommand, complete its words as if they were the whole line. if (( skip )); then words=("${words[1]}" "${(@)words[2+skip,-1]}") (( CURRENT -= skip )) fi # A dispatcher group: complete its subcommands. if (( ${#cmds} )) && [[ "${words[CURRENT]}" != -* ]]; then _describe -t commands command cmds return fi # A dispatched program without completion data: fall back to file names. if (( skip && ${#specs} == 0 )); then _files return fi _arguments -s -S : "${specs[@]}" } _clyops_action___CLYOPS_FUNC__() { local kind="$1" values="$2" [[ "$values" == - ]] && values="" case "$kind" in choice) print -r -- "(${values//,/ })" ;; file) if [[ -n "$values" ]]; then print -r -- "{_files; _files -W \"(${values//:/ })\"}"; else print -r -- _files; fi ;; dir) if [[ -n "$values" ]]; then print -r -- "{_files -/; _files -/ -W \"(${values//:/ })\"}"; else print -r -- "_files -/"; fi ;; host) print -r -- _hosts ;; none) print -r -- " " ;; *) print -r -- _files ;; esac } if [[ "${zsh_eval_context[-1]}" == loadautofunc ]]; then _clyops___CLYOPS_FUNC__ "$@" else compdef _clyops___CLYOPS_FUNC__ __CLYOPS_PROG__ fi CLYOPS_ZSH_TEMPLATE
- FISH_COMPLETION =
<<'CLYOPS_FISH_TEMPLATE' # fish completion for __CLYOPS_PROG__ (generated by clyops) # Enable with: __CLYOPS_PROG__ --completion fish | source # or install: __CLYOPS_PROG__ --completion fish > ~/.config/fish/completions/__CLYOPS_PROG__.fish function __clyops___CLYOPS_FUNC___value --argument-names kind values cur switch $kind case choice string split , -- $values case file __fish_complete_path $cur # Bare names also match entries in the option's search dirs. if test -n "$values"; and not string match -qr -- '^(/|\./|\.\./)' $cur for dir in (string split : -- $values) for f in $dir/$cur* string replace -- "$dir/" '' $f end end end case dir __fish_complete_directories $cur case host __fish_print_hostnames case none case '*' __fish_complete_path $cur end end function __clyops___CLYOPS_FUNC___complete set -l tokens (commandline -opc) set -l cur (commandline -ct) # The words before the cursor let a dispatcher answer for the subcommand being typed. set -l data (command $tokens[1] --bash-completion -- $tokens[2..-1] 2>/dev/null) string match -q '#clyops-completion 1' -- $data[1]; or return set -l skip 0 set -l cmds set -l onames; set -l otypes; set -l okinds; set -l ovalues; set -l odescs set -l akinds; set -l avalues; set -l aarity for line in $data[2..-1] set -l f (string split \t -- $line) switch $f[1] case skip set skip $f[2] case cmd set -a cmds "$f[2]"\t"$f[3]" case opt # "-" marks an empty field. set -l values $f[6] test "$values" = -; and set values '' for n in $f[2] $f[3] test "$n" = -; and continue set -a onames $n; set -a otypes $f[4]; set -a okinds $f[5]; set -a ovalues "$values"; set -a odescs "$f[7]" end case arg set -l values $f[5] test "$values" = -; and set values '' set -a aarity $f[3]; set -a akinds $f[4]; set -a avalues "$values" end end # Words up to and including a dispatched subcommand belong to the dispatcher. set -l words $tokens[(math $skip + 2)..-1] # --opt=VALUE if string match -qr -- '^--[^=]+=' $cur set -l opt (string replace -r '=.*' '' -- $cur) set -l i (contains -i -- $opt $onames) if test -n "$i"; and test "$otypes[$i]" = value for v in (__clyops___CLYOPS_FUNC___value $okinds[$i] "$ovalues[$i]" (string replace -r '^[^=]*=' '' -- $cur)) echo "$opt=$v" end end return end # --opt VALUE if test (count $words) -gt 0 set -l i (contains -i -- $words[-1] $onames) if test -n "$i"; and test "$otypes[$i]" = value __clyops___CLYOPS_FUNC___value $okinds[$i] "$ovalues[$i]" $cur return end end if string match -q -- '-*' $cur for i in (seq (count $onames)) echo $onames[$i]\t$odescs[$i] end return end # A dispatcher group: complete its subcommands. if test (count $cmds) -gt 0 printf '%s\n' $cmds return end # A dispatched program without completion data: fall back to file names. if test $skip -gt 0; and test (count $onames) -eq 0; and test (count $akinds) -eq 0 __fish_complete_path $cur return end # Positional: count earlier positionals, skipping options and their values. set -l pos 0 set -l skipnext 0 set -l endopts 0 for w in $words if test $skipnext -eq 1 set skipnext 0 else if test $endopts -eq 0; and test "$w" = -- set endopts 1 else if test $endopts -eq 0; and string match -q -- '-?*' $w set -l i (contains -i -- $w $onames) test -n "$i"; and test "$otypes[$i]" = value; and set skipnext 1 else set pos (math $pos + 1) end end set -l n (count $akinds) test $n -eq 0; and return if test $pos -ge $n test "$aarity[$n]" = variadic; or return set pos (math $n - 1) end set -l k (math $pos + 1) __clyops___CLYOPS_FUNC___value $akinds[$k] "$avalues[$k]" $cur end complete -c __CLYOPS_PROG__ -f -a '(__clyops___CLYOPS_FUNC___complete)' CLYOPS_FISH_TEMPLATE
- COMPLETION_SCRIPTS =
{ "bash" => BASH_COMPLETION, "zsh" => ZSH_COMPLETION, "fish" => FISH_COMPLETION }.freeze
Class Attribute Summary collapse
-
.silent ⇒ Object
writeonly
Suppress info/warn/error/success output (die and parse errors still print).
Class Method Summary collapse
-
.bool_word(value) ⇒ Boolean?
Convert a supported boolean word, or return nil when unknown.
-
.bounds(rule) ⇒ Array<String>
Split a parameterized range rule into lower and upper text bounds.
-
.completion_kind(rule, search_dirs) ⇒ Array<String>
Return completion kind and values for the validation rule.
-
.describe_rule(rule) ⇒ String
Help text for a validation rule (spec section 5).
-
.die(code, msg) ⇒ void
Print an error and exit with ‘code`.
-
.emit(level, msg, force: false) ⇒ Integer?
Write a timestamped log message; force bypasses the silent setting.
-
.error(msg) ⇒ Integer?
Write an error to stderr.
-
.info(msg) ⇒ Integer?
Write an informational message to stderr.
-
.known_rule?(rule) ⇒ Boolean
Whether the validation rule is supported.
-
.normpath(base, value) ⇒ String
Join and normalize like Python’s os.path.normpath(os.path.join(…)): an absolute ‘value` replaces `base`.
-
.path_rule?(rule) ⇒ Boolean
Whether the rule denotes a path, file, or directory.
-
.pretty_json(value) ⇒ String
JSON with two-space indents and empty arrays and objects written as [] and {}, whatever the json gem version.
-
.resolve_path(value, base, search_dirs = []) ⇒ String
Resolve a path value against ‘base` (spec section 6).
-
.success(msg) ⇒ Integer?
Write a success message to stderr.
-
.validate(value, rule, name) ⇒ String, ...
Validate ‘value` against `rule` and return its typed form; raises ValidationError with the spec’s error text.
-
.warn(msg) ⇒ Integer?
Write a warning to stderr.
-
.wrap_text(text, width) ⇒ Array<String>
Greedy word wrap that keeps existing line breaks (spec section 7).
Class Attribute Details
.silent=(value) ⇒ Object (writeonly)
Suppress info/warn/error/success output (die and parse errors still print).
35 36 37 |
# File 'lib/clyops.rb', line 35 def silent=(value) @silent = value end |
Class Method Details
.bool_word(value) ⇒ Boolean?
Convert a supported boolean word, or return nil when unknown.
104 105 106 107 108 109 |
# File 'lib/clyops.rb', line 104 def bool_word(value) case value.downcase when "true", "yes", "1", "on" then true when "false", "no", "0", "off" then false end end |
.bounds(rule) ⇒ Array<String>
Split a parameterized range rule into lower and upper text bounds.
133 134 135 136 |
# File 'lib/clyops.rb', line 133 def bounds(rule) lo, _, hi = rule.split(":", 2)[1].partition("-") [lo, hi] end |
.completion_kind(rule, search_dirs) ⇒ Array<String>
Return completion kind and values for the validation rule.
323 324 325 326 327 328 329 330 331 |
# File 'lib/clyops.rb', line 323 def completion_kind(rule, search_dirs) return ["file", search_dirs.join(":")] if rule == "path" || rule.start_with?("file:") return ["dir", search_dirs.join(":")] if rule.start_with?("dir:") return ["choice", rule[7..]] if rule.start_with?("choice:") return ["choice", "true,false"] if rule == "bool" return ["host", ""] if %w[hostname ip].include?(rule) rule.empty? ? ["default", ""] : ["none", ""] end |
.describe_rule(rule) ⇒ String
Help text for a validation rule (spec section 5).
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/clyops.rb', line 148 def describe_rule(rule) return FIXED_RULES[rule] if FIXED_RULES.key?(rule) [["int:", "integer", ""], ["float:", "number", ""], ["string:", "text", " chars"]].each do |prefix, noun, suffix| next unless rule.start_with?(prefix) return "#{noun}: #{rule[prefix.length..]}#{suffix}" unless rule.include?("-") lo, hi = bounds(rule) return "#{noun}: #{lo}-#{hi}#{suffix}" if !lo.empty? && !hi.empty? return lo.empty? ? "#{noun}: <=#{hi}#{suffix}" : "#{noun}: >=#{lo}#{suffix}" end return "choices: #{rule[7..].split(',', -1).join(', ')}" if rule.start_with?("choice:") return "pattern: #{rule[6..]}" if rule.start_with?("regex:") rule end |
.die(code, msg) ⇒ void
This method returns an undefined value.
Print an error and exit with ‘code`. Never suppressed.
70 71 72 73 |
# File 'lib/clyops.rb', line 70 def die(code, msg) emit("error", msg, force: true) exit(code) end |
.emit(level, msg, force: false) ⇒ Integer?
Write a timestamped log message; force bypasses the silent setting.
42 43 44 45 46 47 |
# File 'lib/clyops.rb', line 42 def emit(level, msg, force: false) return if @silent && !force tag = $stderr.tty? && !ENV["NO_COLOR"] ? "#{COLORS[level]}#{level}\e[0m" : level $stderr.write("#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} [#{tag}] #{msg}\n") end |
.error(msg) ⇒ Integer?
Write an error to stderr.
60 61 62 63 |
# File 'lib/clyops.rb', line 60 def error(msg) = emit("error", msg) # Write a success message to stderr. # @param msg [String] The msg value. # @return [Integer, nil] bytes written, or nil when suppressed. |
.info(msg) ⇒ Integer?
Write an informational message to stderr.
52 53 54 55 |
# File 'lib/clyops.rb', line 52 def info(msg) = emit("info", msg) # Write a warning to stderr. # @param msg [String] The msg value. # @return [Integer, nil] bytes written, or nil when suppressed. |
.known_rule?(rule) ⇒ Boolean
Whether the validation rule is supported.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/clyops.rb', line 114 def known_rule?(rule) return true if rule.empty? || FIXED_RULES.key?(rule) return true if rule.match?(/\Aint:(\d+-\d*|-\d+)\z/) || rule.match?(/\Afloat:(\d*\.?\d+-(\d*\.?\d+)?|-\d*\.?\d+)\z/) return true if rule.match?(/\Astring:(\d+|\d+-\d*|-\d+)\z/) || rule.match?(/\Achoice:.+\z/m) if rule.start_with?("regex:") && rule.length > 6 begin Regexp.new(rule[6..]) return true rescue RegexpError return false end end false end |
.normpath(base, value) ⇒ String
Join and normalize like Python’s os.path.normpath(os.path.join(…)): an absolute ‘value` replaces `base`.
262 263 264 |
# File 'lib/clyops.rb', line 262 def normpath(base, value) Pathname.new(base).join(value).cleanpath.to_s end |
.path_rule?(rule) ⇒ Boolean
Whether the rule denotes a path, file, or directory.
141 142 143 |
# File 'lib/clyops.rb', line 141 def path_rule?(rule) rule == "path" || rule.start_with?("file:", "dir:") end |
.pretty_json(value) ⇒ String
JSON with two-space indents and empty arrays and objects written as
-
and {}, whatever the json gem version. A raw newline only appears
between JSON tokens (in strings it is escaped), so this can’t touch values.
315 316 317 |
# File 'lib/clyops.rb', line 315 def pretty_json(value) JSON.pretty_generate(value).gsub(/\[\n\s*\]/, "[]").gsub(/\{\n\s*\}/, "{}") end |
.resolve_path(value, base, search_dirs = []) ⇒ String
Resolve a path value against ‘base` (spec section 6).
271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/clyops.rb', line 271 def resolve_path(value, base, search_dirs = []) return value if value.empty? || %w[- disabled optional].include?(value) return value if value.start_with?("/") || value.match?(/\A[A-Za-z][A-Za-z0-9+.-]+:/) from_base = normpath(base, value) if !value.match?(%r{\A\.\.?(/|\z)}) && !search_dirs.empty? && !File.exist?(from_base) search_dirs.each do |dir| candidate = normpath(dir, value) return candidate if File.exist?(candidate) end end from_base end |
.success(msg) ⇒ Integer?
Write a success message to stderr.
64 |
# File 'lib/clyops.rb', line 64 def success(msg) = emit("success", msg) |
.validate(value, rule, name) ⇒ String, ...
Validate ‘value` against `rule` and return its typed form; raises ValidationError with the spec’s error text.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/clyops.rb', line 171 def validate(value, rule, name) fail_with = ->(msg) { raise ValidationError, "#{name} #{msg}" } check_bounds = lambda do |num| lo, hi = bounds(rule) fail_with.("must be >= #{lo}, got #{value}") if !lo.empty? && num < lo.to_f fail_with.("must be <= #{hi}, got #{value}") if !hi.empty? && num > hi.to_f end if rule == "int" || rule.start_with?("int:") fail_with.("must be an integer, got '#{value}'") unless value.match?(/\A-?[0-9]+\z/) num = Integer(value, 10) check_bounds.(num) unless rule == "int" return num end if rule == "float" || rule.start_with?("float:") fail_with.("must be a number, got '#{value}'") unless value.match?(/\A-?[0-9]*\.?[0-9]+\z/) num = Float(value.sub(/\A(-?)\./, '\10.')) check_bounds.(num) unless rule == "float" return num end if rule.start_with?("string:") length = value.length if rule.include?("-") lo, hi = bounds(rule) fail_with.("must be at least #{lo} characters, got #{length}") if !lo.empty? && length < lo.to_i fail_with.("must be at most #{hi} characters, got #{length}") if !hi.empty? && length > hi.to_i elsif length != rule[7..].to_i fail_with.("must be exactly #{rule[7..]} characters, got #{length}") end return value end if rule.start_with?("choice:") choices = rule[7..].split(",", -1) fail_with.("must be one of: #{choices.join(', ')}, got '#{value}'") unless choices.include?(value) return value end if rule.start_with?("regex:") fail_with.("does not match required pattern, got '#{value}'") unless value.match?(Regexp.new(rule[6..])) return value end case rule when "bool" b = bool_word(value) fail_with.("must be a boolean (true/false, yes/no, 1/0, on/off), got '#{value}'") if b.nil? return b when "port" unless value.match?(/\A[0-9]+\z/) && (1..65_535).cover?(value.to_i) fail_with.("must be a valid port (1-65535), got '#{value}'") end return value.to_i when "ip" unless value.match?(/\A([0-9]{1,3}\.){3}[0-9]{1,3}\z/) || value.match?(/\A([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}\z/) fail_with.("must be a valid IP address, got '#{value}'") end when "hostname" fail_with.("must be a valid hostname, got '#{value}'") unless value.match?(HOSTNAME) when "url" fail_with.("must be a valid URL, got '#{value}'") unless value.match?(%r{\Ahttps?://[a-zA-Z0-9.-]+(:[0-9]+)?(/.*)?\z}m) when "email" fail_with.("must be a valid email address, got '#{value}'") unless value.match?(/\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/) when "uuid" unless value.match?(/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/) fail_with.("must be a valid UUID, got '#{value}'") end when "date:YYYY-MM-DD" fail_with.("must be in YYYY-MM-DD format, got '#{value}'") unless value.match?(/\A[0-9]{4}-[0-9]{2}-[0-9]{2}\z/) when "file:exists" fail_with.("file does not exist: #{value}") unless File.file?(value) when "file:readable" fail_with.("file is not readable: #{value}") unless File.readable?(value) when "file:writable" if File.exist?(value) || File.symlink?(value) fail_with.("file is not writable: #{value}") unless File.writable?(value) else dir = File.dirname(value) fail_with.("directory is not writable: #{dir}") unless File.directory?(dir) && File.writable?(dir) end when "dir:exists" fail_with.("directory does not exist: #{value}") unless File.directory?(value) when "dir:writable" fail_with.("directory does not exist or is not writable: #{value}") unless File.directory?(value) && File.writable?(value) end value end |
.warn(msg) ⇒ Integer?
Write a warning to stderr.
56 57 58 59 |
# File 'lib/clyops.rb', line 56 def warn(msg) = emit("warning", msg) # Write an error to stderr. # @param msg [String] The msg value. # @return [Integer, nil] bytes written, or nil when suppressed. |
.wrap_text(text, width) ⇒ Array<String>
Greedy word wrap that keeps existing line breaks (spec section 7).
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/clyops.rb', line 289 def wrap_text(text, width) text.split(/\r?\n/, -1).flat_map do |original| words = original.split next [""] if words.empty? out = [] line = +"" words.each do |word| if line.empty? line = +word elsif line.length + 1 + word.length <= width line << " " << word else out << line line = +word end end out << line end end |