Module: Anthropic::Internal::Util Private

Extended by:
SorbetRuntimeSupport
Defined in:
lib/anthropic/internal/util.rb

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Defined Under Namespace

Modules: SorbetRuntimeSupport Classes: ReadIOAdapter

Constant Summary collapse

RFC_3986_NOT_PCHARS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

www.rfc-editor.org/rfc/rfc3986.html#section-3.3

/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/
JSON_CONTENT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%r{^application/(?:[a-zA-Z0-9.-]+\+)?json(?!l)}
JSONL_CONTENT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)}

Class Method Summary collapse

Methods included from SorbetRuntimeSupport

const_missing, define_sorbet_constant!, sorbet_constant_defined?, to_sorbet_type, to_sorbet_type

Class Method Details

.archString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (String)


65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/anthropic/internal/util.rb', line 65

def arch
  case (arch = RbConfig::CONFIG["arch"])&.downcase
  in nil
    "unknown"
  in /aarch64|arm64/
    "arm64"
  in /x86_64/
    "x64"
  in /arm/
    "arm"
  else
    "other:#{arch}"
  end
end

.chain_fused(enum, &blk) {|| ... } ⇒ Enumerable<Object>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • enum (Enumerable<Object>, nil)
  • blk (Proc)

Yield Parameters:

  • (Enumerator::Yielder)

Returns:

  • (Enumerable<Object>)


825
826
827
828
# File 'lib/anthropic/internal/util.rb', line 825

def chain_fused(enum, &blk)
  iter = Enumerator.new { blk.call(_1) }
  fused_enum(iter) { close_fused!(enum) }
end

.close_fused!(enum) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • enum (Enumerable<Object>, nil)


810
811
812
813
814
815
816
# File 'lib/anthropic/internal/util.rb', line 810

def close_fused!(enum)
  return unless enum.is_a?(Enumerator)

  # rubocop:disable Lint/UnreachableLoop
  enum.rewind.each { break }
  # rubocop:enable Lint/UnreachableLoop
end

.coerce_boolean(input) ⇒ Boolean, Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

Returns:



123
124
125
126
127
128
129
130
131
132
# File 'lib/anthropic/internal/util.rb', line 123

def coerce_boolean(input)
  case input.is_a?(String) ? input.downcase : input
  in "true"
    true
  in "false"
    false
  else
    input
  end
end

.coerce_boolean!(input) ⇒ Boolean?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

Returns:

Raises:

  • (ArgumentError)


140
141
142
143
144
145
146
147
# File 'lib/anthropic/internal/util.rb', line 140

def coerce_boolean!(input)
  case coerce_boolean(input)
  in true | false | nil => coerced
    coerced
  else
    raise ArgumentError.new("Unable to coerce #{input.inspect} into boolean value")
  end
end

.coerce_float(input) ⇒ Float, Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • input (String, Integer, Float)

Returns:

  • (Float, Object)


163
164
165
# File 'lib/anthropic/internal/util.rb', line 163

def coerce_float(input)
  Float(input, exception: false) || input
end

.coerce_hash(input) ⇒ Hash{Object=>Object}, Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • input (Object)

Returns:

  • (Hash{Object=>Object}, Object)


172
173
174
175
176
177
178
179
# File 'lib/anthropic/internal/util.rb', line 172

def coerce_hash(input)
  case input
  in NilClass | Array | Set | Enumerator | StringIO | IO
    input
  else
    input.respond_to?(:to_h) ? input.to_h : input
  end
end

.coerce_hash!(input) ⇒ Hash{Object=>Object}?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • input (Object)

Returns:

  • (Hash{Object=>Object}, nil)

Raises:

  • (ArgumentError)


187
188
189
190
191
192
193
194
195
# File 'lib/anthropic/internal/util.rb', line 187

def coerce_hash!(input)
  case coerce_hash(input)
  in Hash | nil => coerced
    coerced
  else
    message = "Expected a #{Hash} or #{Anthropic::Internal::Type::BaseModel}, got #{input.inspect}"
    raise ArgumentError.new(message)
  end
end

.coerce_integer(input) ⇒ Integer, Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • input (String, Integer)

Returns:

  • (Integer, Object)


154
155
156
# File 'lib/anthropic/internal/util.rb', line 154

def coerce_integer(input)
  Integer(input, exception: false) || input
end

.decode_content(headers, stream:, suppress_error: false) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Assumes each chunk in stream has ‘Encoding::BINARY`.

Parameters:

  • headers (Hash{String=>String})
  • stream (Enumerable<String>)
  • suppress_error (Boolean) (defaults to: false)

Returns:

  • (Object)

Raises:

  • (JSON::ParserError)


743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
# File 'lib/anthropic/internal/util.rb', line 743

def decode_content(headers, stream:, suppress_error: false)
  case (content_type = headers["content-type"])
  in Anthropic::Internal::Util::JSON_CONTENT
    return nil if (json = stream.to_a.join).empty?

    begin
      JSON.parse(json, symbolize_names: true)
    rescue JSON::ParserError => e
      raise e unless suppress_error
      json
    end
  in Anthropic::Internal::Util::JSONL_CONTENT
    lines = decode_lines(stream)
    chain_fused(lines) do |y|
      lines.each do
        next if _1.empty?

        y << JSON.parse(_1, symbolize_names: true)
      end
    end
  in %r{^text/event-stream}
    lines = decode_lines(stream)
    decode_sse(lines)
  else
    text = stream.to_a.join
    force_charset!(content_type, text: text)
    StringIO.new(text)
  end
end

.decode_lines(enum) ⇒ Enumerable<String>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Assumes Strings have been forced into having ‘Encoding::BINARY`.

This decoder is responsible for reassembling lines split across multiple fragments.

Parameters:

  • enum (Enumerable<String>)

Returns:

  • (Enumerable<String>)


842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# File 'lib/anthropic/internal/util.rb', line 842

def decode_lines(enum)
  re = /(\r\n|\r|\n)/
  buffer = String.new
  cr_seen = nil

  chain_fused(enum) do |y|
    enum.each do |row|
      offset = buffer.bytesize
      buffer << row
      while (match = re.match(buffer, cr_seen&.to_i || offset))
        case [match.captures.first, cr_seen]
        in ["\r", nil]
          cr_seen = match.end(1)
          next
        in ["\r" | "\r\n", Integer]
          y << buffer.slice!(..(cr_seen.pred))
        else
          y << buffer.slice!(..(match.end(1).pred))
        end
        offset = 0
        cr_seen = nil
      end
    end

    y << buffer.slice!(..(cr_seen.pred)) unless cr_seen.nil?
    y << buffer unless buffer.empty?
  end
end

.decode_query(query) ⇒ Hash{String=>Array<String>}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • query (String, nil)

Returns:

  • (Hash{String=>Array<String>})


320
321
322
# File 'lib/anthropic/internal/util.rb', line 320

def decode_query(query)
  CGI.parse(query.to_s)
end

.decode_sse(lines) ⇒ Enumerable<Hash{Symbol=>Object}>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream

Assumes that ‘lines` has been decoded with `#decode_lines`.

Parameters:

  • lines (Enumerable<String>)

Returns:

  • (Enumerable<Hash{Symbol=>Object}>)


880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
# File 'lib/anthropic/internal/util.rb', line 880

def decode_sse(lines)
  # rubocop:disable Metrics/BlockLength
  chain_fused(lines) do |y|
    blank = {event: nil, data: nil, id: nil, retry: nil}
    current = {}

    lines.each do |line|
      case line.sub(/\R$/, "")
      in ""
        next if current.empty?
        y << {**blank, **current}
        current = {}
      in /^:/
        next
      in /^([^:]+):\s?(.*)$/
        field, value = Regexp.last_match.captures
        case field
        in "event"
          current.merge!(event: value)
        in "data"
          (current[:data] ||= String.new) << (value << "\n")
        in "id" unless value.include?("\0")
          current.merge!(id: value)
        in "retry" if /^\d+$/ =~ value
          current.merge!(retry: Integer(value))
        else
        end
      else
      end
    end
    # rubocop:enable Metrics/BlockLength

    y << {**blank, **current} unless current.empty?
  end
end

.deep_frozen_copy(obj) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Structurally copy and freeze ‘obj` (Hash/Array recursively; mutable `String` leaves dup-frozen; `URI::Generic` re-parsed with each component string frozen) so the result is fully de-aliased from the input and any in-place mutation raises `FrozenError`. Other leaves (Integer/Symbol — already frozen; typed models; IO) pass through, IO because it must stay live for streamed uploads.

Parameters:

  • obj (Object)

Returns:

  • (Object)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/anthropic/internal/util.rb', line 41

def deep_frozen_copy(obj)
  case obj
  when Hash
    obj.transform_values { deep_frozen_copy(_1) }.freeze
  when Array
    obj.map { deep_frozen_copy(_1) }.freeze
  when String
    obj.frozen? ? obj : obj.dup.freeze
  when URI::Generic
    # Re-parse de-aliases every component string; freezing each via its
    # public reader (then the URI) makes `url.path << "x"` raise without
    # reaching below `URI::Generic`'s public surface. Callers `dup` then
    # reassign components, so a frozen URI is fine to derive from.
    URI.parse(obj.to_s).tap do |u|
      [u.scheme, u.userinfo, u.host, u.path, u.query, u.opaque, u.fragment].each { _1&.freeze }
    end.freeze
  else
    obj
  end
end

.deep_merge(*values, sentinel: nil, concat: false) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively merge one hash with another. If the values at a given key are not both hashes, just take the new value.

Parameters:

  • values (Array<Object>)
  • sentinel (Object, nil) (defaults to: nil)

    the value to return if no values are provided.

  • concat (Boolean) (defaults to: false)

    whether to merge sequences by concatenation.

Returns:

  • (Object)


229
230
231
232
233
234
235
236
237
238
# File 'lib/anthropic/internal/util.rb', line 229

def deep_merge(*values, sentinel: nil, concat: false)
  case values
  in [value, *values]
    values.reduce(value) do |acc, val|
      deep_merge_lr(acc, val, concat: concat)
    end
  else
    sentinel
  end
end

.dig(data, pick, &blk) ⇒ Object?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • data (Hash{Symbol=>Object}, Array<Object>, Object)
  • pick (Symbol, Integer, Array<Symbol, Integer>, Proc, nil)
  • blk (Proc, nil)

Returns:

  • (Object, nil)


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/anthropic/internal/util.rb', line 247

def dig(data, pick, &blk)
  case [data, pick]
  in [_, nil]
    data
  in [Hash, Symbol] | [Array, Integer]
    data.fetch(pick) { blk&.call }
  in [Hash | Array, Array]
    pick.reduce(data) do |acc, key|
      case acc
      in Hash if acc.key?(key)
        acc.fetch(key)
      in Array if key.is_a?(Integer) && key < acc.length
        acc[key]
      else
        return blk&.call
      end
    end
  in [_, Proc]
    pick.call(data)
  else
    blk&.call
  end
end

.encode_content(headers, body) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • headers (Hash{String=>String})
  • body (Object)

Returns:

  • (Object)


684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
# File 'lib/anthropic/internal/util.rb', line 684

def encode_content(headers, body)
  # rubocop:disable Style/CaseEquality
  # rubocop:disable Layout/LineLength
  content_type = headers["content-type"]
  case [content_type, body]
  in [Anthropic::Internal::Util::JSON_CONTENT, Hash | Array | -> { primitive?(_1) }]
    [headers, JSON.generate(body)]
  in [Anthropic::Internal::Util::JSONL_CONTENT, Enumerable] unless Anthropic::Internal::Type::FileInput === body
    [headers, body.lazy.map { JSON.generate(_1) }]
  # A `boundary=` already in the content-type means the body was
  # encoded upstream (e.g. SigV4 signing encodes-then-signs and the
  # terminal calls this again) — fall through to the pass-through arms
  # instead of re-wrapping the signed bytes with a second boundary.
  in [%r{^multipart/form-data}, Hash | Anthropic::Internal::Type::FileInput] unless content_type.include?("boundary=")
    boundary, strio = encode_multipart_streaming(body)
    headers = {**headers, "content-type" => "#{content_type}; boundary=#{boundary}"}
    [headers, strio]
  in [_, Symbol | Numeric]
    [headers, body.to_s]
  in [_, StringIO]
    [headers, body.string]
  in [_, Anthropic::FilePart]
    [headers, body.content]
  else
    [headers, body]
  end
  # rubocop:enable Layout/LineLength
  # rubocop:enable Style/CaseEquality
end

.encode_path(path) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • path (String, Integer)

Returns:

  • (String)


292
293
294
# File 'lib/anthropic/internal/util.rb', line 292

def encode_path(path)
  path.to_s.gsub(Anthropic::Internal::Util::RFC_3986_NOT_PCHARS) { ERB::Util.url_encode(_1) }
end

.encode_query(query) ⇒ String?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • query (Hash{String=>Array<String>, String, nil}, nil)

Returns:

  • (String, nil)


329
330
331
# File 'lib/anthropic/internal/util.rb', line 329

def encode_query(query)
  query.to_h.empty? ? nil : URI.encode_www_form(query)
end

.encode_query_params(query) ⇒ Hash{Symbol=>Object}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • query (Hash{Symbol=>Object})

Returns:

  • (Hash{Symbol=>Object})


544
545
546
547
548
# File 'lib/anthropic/internal/util.rb', line 544

def encode_query_params(query)
  out = {}
  query.each { write_query_param_element!(out, _1, _2) }
  out
end

.force_charset!(content_type, text:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

www.iana.org/assignments/character-sets/character-sets.xhtml

Parameters:

  • content_type (String)
  • text (String)


720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/anthropic/internal/util.rb', line 720

def force_charset!(content_type, text:)
  charset = /charset=([^;\s]+)/.match(content_type)&.captures&.first

  return unless charset

  begin
    encoding = Encoding.find(charset)
    text.force_encoding(encoding)
  rescue ArgumentError
    nil
  end
end

.fused_enum(enum, external: false, &close) ⇒ Enumerable<Object>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

doc.rust-lang.org/std/iter/trait.FusedIterator.html

Parameters:

  • enum (Enumerable<Object>)
  • external (Boolean) (defaults to: false)
  • close (Proc)

Returns:

  • (Enumerable<Object>)


784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
# File 'lib/anthropic/internal/util.rb', line 784

def fused_enum(enum, external: false, &close)
  fused = false
  iter = Enumerator.new do |y|
    next if fused

    fused = true
    if external
      loop { y << enum.next }
    else
      enum.each(&y)
    end
  ensure
    close&.call
    close = nil
  end

  iter.define_singleton_method(:rewind) do
    fused = true
    self
  end
  iter
end

.interpolate_path(path) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • path (String, Array<String>)

Returns:

  • (String)


301
302
303
304
305
306
307
308
309
310
311
# File 'lib/anthropic/internal/util.rb', line 301

def interpolate_path(path)
  case path
  in String
    path
  in []
    ""
  in [String => p, *interpolations]
    encoded = interpolations.map { encode_path(_1) }
    format(p, *encoded)
  end
end

.join_parsed_uri(lhs, rhs) ⇒ URI::Generic

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • lhs (Hash{Symbol=>String, Integer, nil})

    .

    @option lhs [String, nil] :scheme

    @option lhs [String, nil] :host

    @option lhs [Integer, nil] :port

    @option lhs [String, nil] :path

    @option lhs [HashString=>Array<String>] :query

  • rhs (Hash{Symbol=>String, Integer, nil})

    .

    @option rhs [String, nil] :scheme

    @option rhs [String, nil] :host

    @option rhs [Integer, nil] :port

    @option rhs [String, nil] :path

    @option rhs [HashString=>Array<String>] :query

Returns:

  • (URI::Generic)


391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/anthropic/internal/util.rb', line 391

def join_parsed_uri(lhs, rhs)
  base_path, base_query = lhs.fetch_values(:path, :query)
  slashed = base_path.end_with?("/") ? base_path : "#{base_path}/"

  merged = {**parse_uri(rhs.fetch(:path)), **rhs.except(:path, :query)}
  parsed_path, parsed_query = merged.fetch_values(:path, :query)
  override = URI::Generic.build(**merged.slice(:scheme, :host, :port), path: parsed_path)

  joined = URI.join(URI::Generic.build(lhs.except(:path, :query)), slashed, override)
  query = deep_merge(
    joined.path == base_path ? base_query : {},
    parsed_query,
    rhs[:query].to_h,
    concat: true
  )

  joined.query = encode_query(query)
  joined
end

.monotonic_secsFloat

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Float)


10
# File 'lib/anthropic/internal/util.rb', line 10

def self.monotonic_secs = Process.clock_gettime(Process::CLOCK_MONOTONIC)

.normalized_headers(*headers) ⇒ Hash{String=>String}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • headers (Hash{String=>String, Integer, Array<String, Integer, nil>, nil})

Returns:

  • (Hash{String=>String})


418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/anthropic/internal/util.rb', line 418

def normalized_headers(*headers)
  {}.merge(*headers.compact).to_h do |key, val|
    value =
      case val
      in Array
        val.filter_map { _1&.to_s&.strip }.join(", ")
      else
        val&.to_s&.strip
      end
    [key.downcase, value]
  end
end

.osString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (String)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/anthropic/internal/util.rb', line 83

def os
  case (host = RbConfig::CONFIG["host_os"])&.downcase
  in nil
    "Unknown"
  in /linux/
    "Linux"
  in /darwin/
    "MacOS"
  in /freebsd/
    "FreeBSD"
  in /openbsd/
    "OpenBSD"
  in /mswin|mingw|cygwin|ucrt/
    "Windows"
  else
    "Other:#{host}"
  end
end

.parse_uri(url) ⇒ Hash{Symbol=>String, Integer, nil}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • url (URI::Generic, String)

Returns:

  • (Hash{Symbol=>String, Integer, nil})


340
341
342
343
# File 'lib/anthropic/internal/util.rb', line 340

def parse_uri(url)
  parsed = URI::Generic.component.zip(URI.split(url)).to_h
  {**parsed, query: decode_query(parsed.fetch(:query))}
end

.primitive?(input) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • input (Object)

Returns:



109
110
111
112
113
114
115
116
# File 'lib/anthropic/internal/util.rb', line 109

def primitive?(input)
  case input
  in true | false | Numeric | Symbol | String
    true
  else
    false
  end
end

.unparse_uri(parsed) ⇒ URI::Generic

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • parsed (Hash{Symbol=>String, Integer, nil})

    .

    @option parsed [String, nil] :scheme

    @option parsed [String, nil] :host

    @option parsed [Integer, nil] :port

    @option parsed [String, nil] :path

    @option parsed [HashString=>Array<String>] :query

Returns:

  • (URI::Generic)


360
361
362
# File 'lib/anthropic/internal/util.rb', line 360

def unparse_uri(parsed)
  URI::Generic.build(**parsed, query: encode_query(parsed.fetch(:query)))
end

.uri_origin(uri) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • uri (URI::Generic)

Returns:

  • (String)


283
284
285
# File 'lib/anthropic/internal/util.rb', line 283

def uri_origin(uri)
  "#{uri.scheme}://#{uri.host}#{":#{uri.port}" unless uri.port == uri.default_port}"
end

.walk_namespaces(ns) ⇒ Enumerable<Module, Class>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • ns (Module, Class)

Returns:

  • (Enumerable<Module, Class>)


17
18
19
20
21
22
23
24
25
26
27
# File 'lib/anthropic/internal/util.rb', line 17

def self.walk_namespaces(ns)
  ns.constants(false).lazy.flat_map do
    case (c = ns.const_get(_1, false))
    in Module | Class
      walk_namespaces(c)
    else
      []
    end
  end
    .chain([ns])
end

.writable_enum(&blk) {|| ... } ⇒ Enumerable<String>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • blk (Proc)

Yield Parameters:

  • (Enumerator::Yielder)

Returns:

  • (Enumerable<String>)


521
522
523
524
525
526
527
528
529
530
# File 'lib/anthropic/internal/util.rb', line 521

def writable_enum(&blk)
  Enumerator.new do |y|
    y.define_singleton_method(:write) do
      self << _1.dup
      _1.bytesize
    end

    blk.call(y)
  end
end