class Yoda::Store::Query::FindConstant

Public Instance Methods

find(path) click to toggle source

@param path [String, Model::Path, Model::ScopedPath] @return [Objects::Base, nil]

# File lib/yoda/store/query/find_constant.rb, line 7
def find(path)
  lexical_scope_paths = lexical_scopes_of(path)
  base_name, *constant_names = path_of(path).split
  base_namespace = select_base_namespace(base_name, lexical_scope_paths).first

  find_constant(constant_names.join('::'), base_namespace)
end
select_with_prefix(path) click to toggle source

@param path [String, Model::Path, Model::ScopedPath] @return [Array<Objects::Base>]

# File lib/yoda/store/query/find_constant.rb, line 17
def select_with_prefix(path)
  lexical_scope_paths = lexical_scopes_of(path)
  base_name, *constant_names, bottom_name = path_of(path).split

  if constant_names.empty? && !bottom_name
    # When the path does not contain separator (`::`)
    select_base_namespace(/\A#{Regexp.escape(base_name || '')}/, lexical_scope_paths).to_a.uniq
  else
    base_namespace = select_base_namespace(base_name, lexical_scope_paths).first
    scope = find_constant(constant_names.join('::'), base_namespace)
    return [] unless scope
    select_constants_from_ancestors(scope, /\A#{bottom_name}/).to_a
  end
end

Private Instance Methods

find_constant(name, namespace = nil) click to toggle source

@param name [String, Model::Path] @param namespace [Objects::Base, nil] @return [Objects::Base, nil]

# File lib/yoda/store/query/find_constant.rb, line 61
def find_constant(name, namespace = nil)
  constant_names = path_of(name).split
  namespace = registry.find('Object') unless namespace
  constant_names.reduce(namespace) do |namespace, name|
    # @todo resolve its value if namespace is ValueObject
    if namespace && namespace.is_a?(Objects::NamespaceObject)
      select_constants_from_ancestors(namespace, name).first
    else
      return nil
    end
  end
end
lexical_scopes_of(path) click to toggle source

@param path [String, Model::Path, Model::ScopedPath] @return [Array<String>]

# File lib/yoda/store/query/find_constant.rb, line 107
def lexical_scopes_of(path)
  case path
  when Model::Path
    ['Object']
  when Model::ScopedPath
    if path.path.absolute?
      ['Object']
    else
      path.scopes.map { |scope| scope.to_s.gsub(/\A::/, '') }
    end
  else
    ['Object']
  end
end
match_name?(name, expected_name_or_pattern) click to toggle source

@param name [String] @param expected_name_or_pattern [String, Regexp] @return [true, false]

# File lib/yoda/store/query/find_constant.rb, line 140
def match_name?(name, expected_name_or_pattern)
  if expected_name_or_pattern.is_a?(String)
    name == expected_name_or_pattern
  else
    name.match?(expected_name_or_pattern)
  end
end
path_of(path) click to toggle source

@param path [String, Model::Path, Model::ScopedPath] @return [Model::Path]

# File lib/yoda/store/query/find_constant.rb, line 124
def path_of(path)
  case path
  when Model::Path
    path
  when Model::ScopedPath
    path.path
  when String
    Model::Path.new(path == '::' ? '::' : path.gsub(/\A::/, ''))
  else
    fail ArgumentError, path
  end
end
select_base_namespace(base_name, lexical_scope_paths) click to toggle source

Find namespaces which matches with the lexical scopes and the unnested constant name.

@param base_name [String, Regexp] is an unnested constant name or a pattern of unnested constant name. @param lexical_scope_paths [Array<String>] @return [Enumerator<Objects::Base>]

# File lib/yoda/store/query/find_constant.rb, line 39
def select_base_namespace(base_name, lexical_scope_paths)
  Enumerator.new do |yielder|
    lexical_scope_paths.each do |path|
      scope = find_constant(path.to_s)
      next if !scope || !scope.is_a?(Objects::NamespaceObject)
      select_child_constants(scope, base_name).each do |obj|
        yielder << obj
      end
    end

    nearest_scope_path = lexical_scope_paths.first
    if nearest_scope_path && nearest_scope = find_constant(nearest_scope_path) && nearest_scope.is_a?(Objects::NamespaceObject)
      select_constants_from_ancestors(nearest_scope, base_name).each do |obj|
        yielder << obj
      end
    end
  end
end
select_child_constants(scope, name) click to toggle source

@param scope [Objects::Base] @param name [String, Regexp] @return [Enumerator<Objects::Base>]

# File lib/yoda/store/query/find_constant.rb, line 94
def select_child_constants(scope, name)
  Enumerator.new do |yielder|
    if scope.is_a?(Objects::NamespaceObject)
      scope.constant_addresses.select { |address| match_name?(Model::Path.new(address).basename, name) }.each do |address|
        obj = registry.find(address)
        yielder << obj if obj
      end
    end
  end
end
select_constants_from_ancestors(scope, name) click to toggle source

@param scope [Objects::NamespaceObject] @param name [String, Regexp] @return [Enumerator<Objects::Base>]

# File lib/yoda/store/query/find_constant.rb, line 77
def select_constants_from_ancestors(scope, name)
  Enumerator.new do |yielder|
    met = Set.new

    Associators::AssociateAncestors.new(registry).associate(scope).each do |ancestor|
      select_child_constants(ancestor, name).each do |obj|
        next if met.include?(obj.name)
        met.add(obj.name)
        yielder << obj
      end
    end
  end
end