module GlobalID::Locator

def find_allowed?(model_class, only = nil)

def find_allowed?(model_class, only = nil)
  only ? Array(only).any? { |c| model_class <= c } : true
end

def locate(gid, options = {})

modules match, +nil+ is returned.
instances of returned classes to those including that module. If no classes or
classes to those classes or their subclasses. Passing one or more modules in limits
allowed to be located. Passing one or more classes limits instances of returned
* :only - A class, module or Array of classes and/or modules that are
Options:

Takes either a GlobalID or a string that can be turned into a GlobalID
def locate(gid, options = {})
  if gid = GlobalID.parse(gid)
    locator_for(gid).locate gid if find_allowed?(gid.model_class, options[:only])
  end
end

def locate_many(gids, options = {})

we will use #where(id: ids) instead, which does not raise on missing records.
#find will raise an exception if a named ID can't be found. When you set this option to true,
ids extracted from the GIDs. In Active Record (and other data stores following the same pattern),
* :ignore_missing - By default, locate_many will call #find on the model to locate the
modules match, +nil+ is returned.
instances of returned classes to those including that module. If no classes or
classes to those classes or their subclasses. Passing one or more modules in limits
allowed to be located. Passing one or more classes limits instances of returned
* :only - A class, module or Array of classes and/or modules that are
Options:

per model class, but still interpolate the results to match the order in which the gids were passed.
This approach will efficiently call only one #find (or #where(id: id), when using ignore_missing)

models must respond to that finder signature.
By default the GlobalIDs will be located using Model.find(array_of_ids), so the

the same locator using its locate_many method.
All GlobalIDs must belong to the same app, as they will be located using
Takes an array of GlobalIDs or strings that can be turned into a GlobalIDs.
def locate_many(gids, options = {})
  if (allowed_gids = parse_allowed(gids, options[:only])).any?
    locator = locator_for(allowed_gids.first)
    locator.locate_many(allowed_gids, options)
  else
    []
  end
end

def locate_many_signed(sgids, options = {})

modules match, +nil+ is returned.
instances of returned classes to those including that module. If no classes or
classes to those classes or their subclasses. Passing one or more modules in limits
allowed to be located. Passing one or more classes limits instances of returned
* :only - A class, module or Array of classes and/or modules that are
Options:

the results to match the order in which the gids were passed.
This approach will efficiently call only one #find per model class, but still interpolate

that finder signature.
The SignedGlobalIDs are located using Model.find(array_of_ids), so the models must respond to
Takes an array of SignedGlobalIDs or strings that can be turned into a SignedGlobalIDs.
def locate_many_signed(sgids, options = {})
  locate_many sgids.collect { |sgid| SignedGlobalID.parse(sgid, options.slice(:for)) }.compact, options
end

def locate_signed(sgid, options = {})

modules match, +nil+ is returned.
instances of returned classes to those including that module. If no classes or
classes to those classes or their subclasses. Passing one or more modules in limits
allowed to be located. Passing one or more classes limits instances of returned
* :only - A class, module or Array of classes and/or modules that are
Options:

Takes either a SignedGlobalID or a string that can be turned into a SignedGlobalID
def locate_signed(sgid, options = {})
  SignedGlobalID.find sgid, options
end

def locator_for(gid)

def locator_for(gid)
  @locators.fetch(normalize_app(gid.app)) { DEFAULT_LOCATOR }
end

def normalize_app(app)

def normalize_app(app)
  app.to_s.downcase
end

def parse_allowed(gids, only = nil)

def parse_allowed(gids, only = nil)
  gids.collect { |gid| GlobalID.parse(gid) }.compact.select { |gid| find_allowed?(gid.model_class, only) }
end

def use(app, locator = nil, &locator_block)

end
end
@search_client.search name: gid.model_name, id: gid.model_id
def locate(gid)
class BarLocator

GlobalID::Locator.use :bar, BarLocator.new

Using a class:

end
FooRemote.const_get(gid.model_name).find(gid.model_id)
GlobalID::Locator.use :foo do |gid|

Using a block:

The locator can be either a block or a class.

Useful when different apps collaborate and reference each others' Global IDs.
Tie a locator to an app.
def use(app, locator = nil, &locator_block)
  raise ArgumentError, 'No locator provided. Pass a block or an object that responds to #locate.' unless locator || block_given?
  URI::GID.validate_app(app)
  @locators[normalize_app(app)] = locator || BlockLocator.new(locator_block)
end