class Ractor::Server::Client

Constants

CONFIG
NON_SETTERS
NOT_IMPLICITLY_DEFINED

Attributes

server[R]

Public Class Methods

call_server_alias(*args, **options, &block) click to toggle source
# File lib/ractor/server/client.rb, line 100
        def call_server_alias(*args, **options, &block)
  call_server(__callee__, *args, **options, &block)
end
config(key) { |cur_value| ... } click to toggle source
# File lib/ractor/server/client.rb, line 69
def config(key)
  cur = self::CONFIG
  cur_value = cur.fetch(key)
  if block_given?
    cur_value = yield cur_value
    remove_const(:CONFIG) if const_defined?(:CONFIG, false)
    const_set(:CONFIG, Ractor.make_shareable(cur.merge(key => cur_value)))
  end
  cur_value
end
interface_with_server(*methods) click to toggle source
# File lib/ractor/server/client.rb, line 51
def interface_with_server(*methods)
  methods.flatten!(1)
  self::ServerCallLayer.class_eval do
    methods.each do |method|
      public alias_method(method, :call_server_alias)
    end
  end
  debug(:interface) { "Defined methods #{methods.join(', ')}" }

  methods
end
new(server) click to toggle source
# File lib/ractor/server/client.rb, line 12
def initialize(server)
  raise ArgumentError, "Expected a Ractor, got #{server.inspect}" unless server.is_a?(::Ractor)

  @nest_request_key = :"Ractor::Server::Client#{object_id}"
  @server = server
  freeze
end
refresh_server_call_layer() click to toggle source
# File lib/ractor/server/client.rb, line 42
def refresh_server_call_layer
  layer = self::ServerCallLayer
  server_klass = self::Server
  are_defined = layer.instance_methods
  should_be_defined = server_klass.instance_methods - NOT_IMPLICITLY_DEFINED
  (are_defined - should_be_defined).each { layer.remove_method _1 }
  interface_with_server(*config(:tell_methods) | should_be_defined - are_defined)
end
share_args(*methods) click to toggle source
# File lib/ractor/server/client.rb, line 91
def share_args(*methods)
  methods.flatten!(1)
  config(:share_args) { |val| val + methods }

  methods
end
start(*args, **options) click to toggle source
# File lib/ractor/server/client.rb, line 37
def start(*args, **options)
  ractor = self.class::Server.start_ractor(*args, **options)
  new(ractor)
end
sync_kind(method, block_given) click to toggle source
# File lib/ractor/server/client.rb, line 80
def sync_kind(method, block_given)
  case
  when setter?(method) || config(:tell_methods).include?(method)
    :tell
  when block_given
    :converse
  else
    :ask
  end
end
tells(*methods) click to toggle source
# File lib/ractor/server/client.rb, line 63
def tells(*methods)
  methods.flatten!(1)
  config(:tell_methods) { |set| set + methods }
  interface_with_server(*methods)
end

Private Class Methods

inherited(base) click to toggle source
Calls superclass method
# File lib/ractor/server/client.rb, line 98
        def inherited(base)
  mod = Module.new do
    private def call_server_alias(*args, **options, &block)
      call_server(__callee__, *args, **options, &block)
    end
  end

  base.const_set(:ServerCallLayer, mod)
  base.include mod

  super
end
setter?(method) click to toggle source
# File lib/ractor/server/client.rb, line 114
        def setter?(method)
  method.end_with?('=') && !NON_SETTERS.include?(method)
end

Public Instance Methods

inspect() click to toggle source
# File lib/ractor/server/client.rb, line 25
def inspect
  "<##{self.class} server: #{call_server(:inspect)}>"
end
Also aliased as: to_s
to_s()
Alias for: inspect

Private Instance Methods

await_response(rq, method) { |result| ... } click to toggle source
# File lib/ractor/server/client.rb, line 162
        def await_response(rq, method)
  debug(:await) { "Awaiting response to #{rq}" }

  loop do
    response, result = rq.receive
    case response.sync
    in :converse then handle_yield(method, response) { yield result }
    in :conclude then return result
    end
  end
ensure
  debug(:await) { "Finished waiting for #{rq}" }
end
call_server(method, *args, **options, &block) click to toggle source

@returns [Request] if method should be called as `:tell`, otherwise returns the result of the concluded method call.

# File lib/ractor/server/client.rb, line 147
        def call_server(method, *args, **options, &block)
  Ractor.make_shareable([args, options]) if share_inputs?(method)

  info = format_call(method, *args, **options, &block) if $DEBUG
  rq = Request.send(
    @server, method, args, options,
    response_to: Thread.current[@nest_request_key],
    sync: self.class.sync_kind(method, !!block),
    info: info,
  )
  return rq if rq.tell?

  await_response(rq, method, &block)
end
format_call(method, *args, **options, &block) click to toggle source
# File lib/ractor/server/client.rb, line 207
        def format_call(method, *args, **options, &block)
  args = args.map(&:inspect) + options.map { _1.map(&:inspect).join(': ') }
  arg_list = "(#{args.join(', ')})" unless args.empty?
  block_sig = ' {...}' if block
  "#{method}#{arg_list}#{block_sig}"
end
handle_yield(method, response) { |]| ... } click to toggle source
# File lib/ractor/server/client.rb, line 176
        def handle_yield(method, response)
  begin
    status, result = with_requests_nested(response) do
      [:ok, yield]
    rescue Exception => e
      [:exception, e]
    end
  ensure
    response.interrupt unless status # throw/return/...
  end
  if status == :exception
    response.send_exception(result)
  else
    Ractor.make_shareable(result) if share_inputs?(method)
    response.conclude result
  end
end
implemented_by_server?(method) click to toggle source
# File lib/ractor/server/client.rb, line 137
        def implemented_by_server?(method)
  self.class::Server.method_defined?(method)
end
method_missing(method, *args, **options, &block) click to toggle source
Calls superclass method
# File lib/ractor/server/client.rb, line 123
        def method_missing(method, *args, **options, &block)
  if implemented_by_server?(method)
    refresh_server_call_layer
    # sanity check
    unless self.class::ServerCallLayer.method_defined?(method)
      raise "`refresh_server_call_layer` failed for #{method}"
    end

    return __send__(method, *args, **options, &block)
  end

  super
end
refresh_server_call_layer() click to toggle source
# File lib/ractor/server/client.rb, line 141
        def refresh_server_call_layer
  self.class.refresh_server_call_layer
end
respond_to_missing?(method, priv = false) click to toggle source
Calls superclass method
# File lib/ractor/server/client.rb, line 119
        def respond_to_missing?(method, priv = false)
  !priv && implemented_by_server?(method) || super
end
share_inputs?(method_name) click to toggle source
# File lib/ractor/server/client.rb, line 203
        def share_inputs?(method_name)
  self.class.config(:share_args).include?(method_name)
end
with_requests_nested(context) { || ... } click to toggle source
# File lib/ractor/server/client.rb, line 194
        def with_requests_nested(context)
  store = Thread.current
  prev = store[@nest_request_key]
  store[@nest_request_key] = context
  yield
ensure
  store[@nest_request_key] = prev
end