Class: Dommy::Request

Inherits:
Object
  • Object
show all
Includes:
Bridge::Methods
Defined in:
lib/dommy/fetch.rb

Overview

Request polyfill — minimal Fetch API Request object so callers constructing new Request(url, init) get a value with .url, .method, .headers, .body. The stub-based fetch doesn't consume it directly (it still takes (url, init)), but having Request available means JS code that constructs one before passing to fetch keeps working.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Bridge::Methods

included

Constructor Details

#initialize(url, init = nil, window = nil) ⇒ Request

Returns a new instance of Request.



569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
# File 'lib/dommy/fetch.rb', line 569

def initialize(url, init = nil, window = nil)
  opts = init.is_a?(Hash) ? init : {}
  @window = window
  @url = url.to_s
  @method = (opts["method"] || opts[:method] || "GET").to_s.upcase
  @body = opts["body"] || opts[:body]
  raw_headers = opts["headers"] || opts[:headers] || {}
  @headers = Headers.new(raw_headers)
  # WHATWG "extract a body": normalize the body source to a byte string once
  # (shared with Response), so the Body consume methods (text/arrayBuffer/…)
  # read from it. A default Content-Type from the extraction is applied only
  # when the caller supplied none.
  unless @body.nil?
    @body_bytes, default_ct = Response.extract_body(@body)
    if default_ct && !@headers.__js_call__("has", ["content-type"])
      @headers.__js_call__("set", ["content-type", default_ct])
    end
  end
  @body_bytes ||= ""
  @credentials = (opts["credentials"] || opts[:credentials] || "same-origin").to_s
  @mode = (opts["mode"] || opts[:mode] || "cors").to_s
  @cache = (opts["cache"] || opts[:cache] || "default").to_s
  @redirect = (opts["redirect"] || opts[:redirect] || "follow").to_s
  # WHATWG: a Request ALWAYS has an associated signal (an AbortSignal). Use a
  # provided signal when present (so `request.signal` is the caller's own
  # controller signal — react-router add/removeEventListener's it directly),
  # else a fresh, never-aborted one. Never undefined, or consumers that read
  # `request.signal.removeEventListener` crash.
  sig = opts["signal"] || opts[:signal]
  @signal = sig.respond_to?(:__js_call__) ? sig : AbortSignal.new
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



567
568
569
# File 'lib/dommy/fetch.rb', line 567

def body
  @body
end

#cacheObject (readonly)

Returns the value of attribute cache.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def cache
  @cache
end

#credentialsObject (readonly)

Returns the value of attribute credentials.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def credentials
  @credentials
end

#headersObject (readonly)

Returns the value of attribute headers.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def headers
  @headers
end

#methodObject (readonly)

Returns the value of attribute method.



567
568
569
# File 'lib/dommy/fetch.rb', line 567

def method
  @method
end

#modeObject (readonly)

Returns the value of attribute mode.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def mode
  @mode
end

#redirectObject (readonly)

Returns the value of attribute redirect.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def redirect
  @redirect
end

#signalObject (readonly)

Returns the value of attribute signal.



601
602
603
# File 'lib/dommy/fetch.rb', line 601

def signal
  @signal
end

#urlObject (readonly)

Returns the value of attribute url.



567
568
569
# File 'lib/dommy/fetch.rb', line 567

def url
  @url
end

Instance Method Details

#__js_call__(method, _args) ⇒ Object



630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'lib/dommy/fetch.rb', line 630

def __js_call__(method, _args)
  case method
  when "clone"
    Request.new(
      @url,
      {
        "method" => @method,
        "body" => @body,
        "headers" => @headers.to_h,
        "credentials" => @credentials,
        "mode" => @mode,
        "cache" => @cache,
        "redirect" => @redirect,
        "signal" => @signal
      },
      @window
    )
  when "text"
    consume_body { immediate(Response.utf8_decode(@body_bytes)) }
  when "json"
    consume_body do
      immediate(JSON.parse(Response.utf8_decode(@body_bytes)))
    rescue JSON::ParserError => e
      rejected(ErrorValue.new("JSON parse: #{e.message}"))
    end
  when "arrayBuffer"
    consume_body { immediate(Bridge::ArrayBuffer.new(@body_bytes.bytes)) }
  when "bytes"
    consume_body { immediate(Bridge::Bytes.new(@body_bytes.bytes)) }
  when "blob"
    ct = @headers.__js_call__("get", ["content-type"]) || ""
    consume_body { immediate(Blob.new([@body_bytes], {"type" => ct}, @window)) }
  end
end

#__js_get__(key) ⇒ Object



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/dommy/fetch.rb', line 603

def __js_get__(key)
  case key
  when "url"
    @url
  when "method"
    @method
  when "headers"
    @headers
  when "body"
    @body
  when "credentials"
    @credentials
  when "mode"
    @mode
  when "cache"
    @cache
  when "redirect"
    @redirect
  when "signal"
    @signal
  else
    Bridge::ABSENT
  end
end