Module: Exa::Internal::Util
- Defined in:
- lib/exa/internal/util.rb
Constant Summary collapse
- JSON_CONTENT =
%r{application/(json|problem\+json)}i.freeze
- JSONL_CONTENT =
%r{application/x-ndjson}i.freeze
Class Method Summary collapse
- .build_query(query) ⇒ Object
- .close_fused!(enum) ⇒ Object
- .decode_content(headers, stream:) ⇒ Object
- .decode_lines(enum) ⇒ Object
- .decode_sse(enum) ⇒ Object
- .deep_merge_hash(base, extra) ⇒ Object
- .force_charset!(content_type, text:) ⇒ Object
- .fused_enum(enum, &on_close) ⇒ Object
- .normalized_headers(headers) ⇒ Object
Class Method Details
.build_query(query) ⇒ Object
33 34 35 36 |
# File 'lib/exa/internal/util.rb', line 33 def build_query(query) return nil if query.nil? || query.empty? URI.encode_www_form(query) end |
.close_fused!(enum) ⇒ Object
126 127 128 129 130 |
# File 'lib/exa/internal/util.rb', line 126 def close_fused!(enum) if enum.respond_to?(:close) enum.close end end |
.decode_content(headers, stream:) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/exa/internal/util.rb', line 38 def decode_content(headers, stream:) case headers["content-type"] when JSON_CONTENT json = stream.to_a.join JSON.parse(json, symbolize_names: true) when JSONL_CONTENT stream.map { JSON.parse(_1, symbolize_names: true) } when /^text\/event-stream/ decode_sse(stream) else StringIO.new(stream.to_a.join) end end |
.decode_lines(enum) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/exa/internal/util.rb', line 64 def decode_lines(enum) Enumerator.new do |y| buffer = String.new enum.each do |chunk| buffer << chunk while (idx = buffer.index(/\r?\n/)) y << buffer.slice!(0..idx) end end y << buffer unless buffer.empty? end end |
.decode_sse(enum) ⇒ Object
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 |
# File 'lib/exa/internal/util.rb', line 77 def decode_sse(enum) lines = decode_lines(enum) Enumerator.new do |y| event = {event: nil, data: String.new, id: nil, retry: nil} lines.each do |line| stripped = line.strip if stripped.empty? y << event.dup if event[:data]&.length&.positive? event = {event: nil, data: String.new, id: nil, retry: nil} next end case stripped when /^event:(.*)$/ event[:event] = Regexp.last_match(1).strip when /^data:(.*)$/ event[:data] << Regexp.last_match(1).lstrip << "\n" when /^id:(.*)$/ event[:id] = Regexp.last_match(1).strip when /^retry:(\d+)$/ event[:retry] = Regexp.last_match(1).to_i end end end end |
.deep_merge_hash(base, extra) ⇒ Object
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/exa/internal/util.rb', line 22 def deep_merge_hash(base, extra) return base unless extra base.merge(extra) do |_k, old_val, new_val| if old_val.is_a?(Hash) && new_val.is_a?(Hash) deep_merge_hash(old_val, new_val) else new_val end end end |
.force_charset!(content_type, text:) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/exa/internal/util.rb', line 52 def force_charset!(content_type, text:) return text unless content_type return text if text.encoding == Encoding::UTF_8 if (match = /charset=([^;]+)/i.match(content_type)) encoding = Encoding.find(match[1]) text.force_encoding(encoding) end text rescue ArgumentError text end |
.fused_enum(enum, &on_close) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/exa/internal/util.rb', line 103 def fused_enum(enum, &on_close) closed = false wrapper = Enumerator.new do |y| begin enum.each { y << _1 } ensure unless closed closed = true on_close&.call end end end wrapper.define_singleton_method(:close) do unless closed closed = true on_close&.call end end wrapper end |
.normalized_headers(headers) ⇒ Object
15 16 17 18 19 20 |
# File 'lib/exa/internal/util.rb', line 15 def normalized_headers(headers) headers.each_with_object({}) do |(key, value), acc| next if value.nil? acc[key.to_s.downcase] = value.to_s end end |