Module: Hammer::Input
- Defined in:
- lib/hammer/input.rb
Overview
Stdin + JSON helpers for opts. Hammer always attaches piped stdin as
opts[:stdin]; recipes opt into JSON body handling via
Hammer::Input.prepare_json! (typically from a before hook) and/or
opt :json, type: :json / global_opt :json, type: :json.
Class Method Summary collapse
-
.attach_stdin!(opts) ⇒ Object
Idempotent: sets opts if not already present.
-
.parse_json(raw, source: 'json') ⇒ Object
Parse a JSON source string into a Hash/Array with symbol keys.
-
.prepare_json!(opts, key: :json) ⇒ Object
Prepare opts as a Hash/Array when possible.
-
.read_stdin ⇒ Object
Read piped stdin once.
-
.resolve_json_value(value, opts = {}, source: 'json') ⇒ Object
Resolve a value that may be: - Hash / Array -> returned as-is (symbolized if Hash has string keys) - "-" -> use opts - "@path" -> File.read(path) - JSON string -> parse.
- .symbolize(obj) ⇒ Object
Class Method Details
.attach_stdin!(opts) ⇒ Object
Idempotent: sets opts if not already present.
29 30 31 32 33 |
# File 'lib/hammer/input.rb', line 29 def attach_stdin!(opts) return opts[:stdin] if opts.key?(:stdin) opts[:stdin] = read_stdin end |
.parse_json(raw, source: 'json') ⇒ Object
Parse a JSON source string into a Hash/Array with symbol keys. source is only used in error messages ('stdin', '--json', path, ...).
37 38 39 40 41 42 |
# File 'lib/hammer/input.rb', line 37 def parse_json(raw, source: 'json') data = JSON.parse(raw) symbolize(data) rescue JSON::ParserError => e raise Hammer::Parser::Error, "invalid JSON (#{source}): #{e.}" end |
.prepare_json!(opts, key: :json) ⇒ Object
Prepare opts as a Hash/Array when possible.
1. If opts[key] is already Hash/Array -> symbolize, done
2. If opts[key] is a String ("...", @file, -) -> parse
3. If opts[key] is nil/absent and opts[:stdin] looks like JSON
object/array -> fill from stdin
4. Boolean true/false left alone (legacy `opt :json, type: :boolean`)
Returns the resolved value (or nil). Mutates opts.
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 |
# File 'lib/hammer/input.rb', line 80 def prepare_json!(opts, key: :json) attach_stdin!(opts) key = key.to_sym val = opts[key] if val.is_a?(Hash) || val.is_a?(Array) opts[key] = symbolize(val) return opts[key] end if val.is_a?(String) && !val.empty? opts[key] = resolve_json_value(val, opts, source: "--#{key.to_s.tr('_', '-')}") return opts[key] end # Skip booleans (output-mode flags) and other non-nil junk. return val unless val.nil? raw = opts[:stdin] return nil if raw.nil? || raw.empty? stripped = raw.lstrip return nil unless stripped.start_with?('{', '[') opts[key] = parse_json(raw, source: 'stdin') opts[key] end |
.read_stdin ⇒ Object
Read piped stdin once. Returns nil when stdin is a TTY or empty. Does not consume an interactive TTY.
15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/hammer/input.rb', line 15 def read_stdin return nil if $stdin.closed? return nil if $stdin.tty? data = $stdin.read return nil if data.nil? data = data.dup.force_encoding(Encoding::UTF_8) if data.respond_to?(:force_encoding) data.empty? ? nil : data rescue StandardError nil end |
.resolve_json_value(value, opts = {}, source: 'json') ⇒ Object
Resolve a value that may be:
- Hash / Array -> returned as-is (symbolized if Hash has string keys)
- "-" -> use opts[:stdin]
- "@path" -> File.read(path)
- JSON string -> parse
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/hammer/input.rb', line 49 def resolve_json_value(value, opts = {}, source: 'json') return symbolize(value) if value.is_a?(Hash) || value.is_a?(Array) s = value.to_s if s == '-' attach_stdin!(opts) raw = opts[:stdin] raise Hammer::Parser::Error, "no JSON on stdin for #{source}" if raw.nil? || raw.empty? return parse_json(raw, source: 'stdin') end if s.start_with?('@') path = s[1..] raise Hammer::Parser::Error, "JSON file not found: #{path}" unless File.file?(path) return parse_json(File.read(path), source: path) end parse_json(s, source: source) end |
.symbolize(obj) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/hammer/input.rb', line 108 def symbolize(obj) case obj when Hash obj.each_with_object({}) do |(k, v), h| h[k.respond_to?(:to_sym) ? k.to_sym : k] = symbolize(v) end when Array obj.map { |v| symbolize(v) } else obj end end |