class Proc::Client

public

Connection to proc, configured with an authorization.

Constants

DEFAULT_HEADERS

Attributes

authorization[R]
public

The configured authorization.

host[R]
public

The configured host.

request_count[R]
public

The number of requests this client has performed.

response[R]
scheme[R]
public

The configured scheme.

Public Class Methods

new(authorization, scheme: "https", host: "proc.dev") click to toggle source
# File lib/proc/client.rb, line 85
def initialize(authorization, scheme: "https", host: "proc.dev")
  @authorization = authorization
  @scheme = scheme
  @host = host
  @request_count = 0

  @__base_url = "#{@scheme}://#{host}"
  @__headers = {
    "authorization" => "bearer #{@authorization}"
  }.merge(DEFAULT_HEADERS)
end

Public Instance Methods

[](proc) { || ... } click to toggle source
public

Returns a callable context for `proc`.

# File lib/proc/client.rb, line 99
def [](proc)
  if ::Kernel.block_given?
    ::Proc::Callable.new(proc, client: self, arguments: {proc: yield})
  else
    ::Proc::Callable.new(proc, client: self)
  end
end
arg(name, **options)
Alias for: argument
argument(name, **options) click to toggle source
public

Builds a named argument with options.

# File lib/proc/client.rb, line 212
def argument(name, **options)
  ::Proc::Argument.new(name, **options)
end
Also aliased as: arg
call(proc = nil, input = ::Proc.undefined, **arguments, &block) click to toggle source
public

Calls a proc with the given input and arguments.

If a block is passed and the proc returns an enumerable, the block will be called with each value.

# File lib/proc/client.rb, line 138
def call(proc = nil, input = ::Proc.undefined, **arguments, &block)
  body = []

  unless ::Proc.undefined?(input)
    body << [">>", serialize_value(input)]
  end

  arguments.each_pair do |key, value|
    body << ["$$", key.to_s, serialize_value(value)]
  end

  status, headers, payload = get_payload(proc: proc, body: body)

  case status
  when 200
    result = extract_output(payload)

    if (cursor = headers["x-cursor"])
      enumerator = if cursor.empty?
        ::Proc::Enumerator.new(result)
      else
        ::Proc::Enumerator.new(result) {
          arguments[:cursor] = cursor.to_s
          call(proc, input, **arguments)
        }
      end

      if block
        enumerator.each(&block)
      else
        enumerator
      end
    else
      result
    end
  when 400
    ::Kernel.raise ::Proc::Invalid, extract_error_message(payload)
  when 401
    ::Kernel.raise ::Proc::Unauthorized, extract_error_message(payload)
  when 403
    ::Kernel.raise ::Proc::Forbidden, extract_error_message(payload)
  when 404
    ::Kernel.raise ::Proc::Undefined, extract_error_message(payload)
  when 408
    ::Kernel.raise ::Proc::Timeout, extract_error_message(payload)
  when 413
    ::Kernel.raise ::Proc::Invalid, extract_error_message(payload)
  when 429
    ::Kernel.raise ::Proc::Limited, extract_error_message(payload)
  when 500
    ::Kernel.raise ::Proc::Error, extract_error_message(payload)
  when 508
    ::Kernel.raise ::Proc::Error, extract_error_message(payload)
  else
    ::Kernel.raise ::Proc::Error, "unhandled"
  end
end
method_missing(name, input = input_omitted = true, *, **arguments) click to toggle source
public

Allows callable contexts to be built through method lookups.

# File lib/proc/client.rb, line 198
def method_missing(name, input = input_omitted = true, *, **arguments)
  if input_omitted
    ::Proc::Callable.new(name, client: self, arguments: arguments)
  else
    ::Proc::Callable.new(name, client: self, input: input, arguments: arguments)
  end
end
rate_limit() click to toggle source
public

Returns the current rate limit.

# File lib/proc/client.rb, line 109
def rate_limit
  refresh_rate_limit
  @rate_limit
end
rate_limit_reset() click to toggle source
public

Returns the time at which the current rate limit will reset.

# File lib/proc/client.rb, line 123
def rate_limit_reset
  refresh_rate_limit
  @rate_limit_reset
end
rate_limit_window() click to toggle source
public

Returns the current rate limit window.

# File lib/proc/client.rb, line 116
def rate_limit_window
  refresh_rate_limit
  @rate_limit_window
end
respond_to_missing?(name, *) click to toggle source
# File lib/proc/client.rb, line 206
def respond_to_missing?(name, *)
  true
end

Private Instance Methods

build_uri(proc) click to toggle source
# File lib/proc/client.rb, line 217
        def build_uri(proc)
  ::File.join(@__base_url, proc.to_s.split(".").join("/"))
end
extract_error(payload) click to toggle source
# File lib/proc/client.rb, line 275
        def extract_error(payload)
  payload.each do |tuple|
    case tuple[0]
    when "!!"
      return tuple[1]
    end
  end

  nil
end
extract_error_message(payload) click to toggle source
# File lib/proc/client.rb, line 286
        def extract_error_message(payload)
  extract_error(payload)&.dig("message")
end
extract_output(payload) click to toggle source
# File lib/proc/client.rb, line 264
        def extract_output(payload)
  payload.each do |tuple|
    case tuple[0]
    when "<<"
      return tuple[1]
    end
  end

  nil
end
get_payload(proc:, body:) click to toggle source
# File lib/proc/client.rb, line 232
        def get_payload(proc:, body:)
  await {
    @request_count += 1

    response = ::HTTP.headers(@__headers).post(build_uri(proc), body: ::MessagePack.pack(body))

    update_rate_limit(response)
    @response = response

    [response.status, response.headers, ::MessagePack.unpack(response.to_s)]
  }
rescue
  ::Kernel.raise ::Proc::Unavailable
end
refresh_rate_limit() click to toggle source
# File lib/proc/client.rb, line 128
        def refresh_rate_limit
  unless defined?(@rate_limit)
    self["core.ping"].call
  end
end
serialize_value(value) click to toggle source
# File lib/proc/client.rb, line 221
        def serialize_value(value)
  case value
  when ::Symbol
    ["@@", value.to_s, {}]
  when ::Proc::Argument, ::Proc::Callable, ::Proc::Composition
    value.serialize
  else
    ["%%", value]
  end
end
update_rate_limit(response) click to toggle source
# File lib/proc/client.rb, line 247
        def update_rate_limit(response)
  split_limit = response.headers["x-rate-limit"].to_s.split(";window=")

  @rate_limit = split_limit[0].to_i

  @rate_limit_window = case split_limit[1]
  when "60"
    :minute
  when "1"
    :second
  end

  @rate_limit_reset = if (reset = response.headers["x-rate-limit-reset"])
    ::Time.at(reset.to_s.to_i)
  end
end