class MetaRuby::GUI::RubyConstantsItemModel

A Qt item model that enumerates models stored in the Ruby constant hierarchy

The model exposes all registered constants for which {#predicate} returns true in a hierarchy, allowing the user to interact with it.

Discovery starts at Object

Constants

ModuleInfo

Stored per-module information test

TypeInfo

Information about different model types

Attributes

excludes[R]

Explicitely excluded objects

Set of objects that should be excluded from discovery, regardless of what {#predicate} would return from them.

Note that such objects are not discovered at all, meaning that if they contain objects that should have been discovered, they won't be.

@return [Set]

filtered_out_modules[R]

Set of objects that have been filtered out by {#predicate}

id_to_module[R]

Mapping from module ID to a module object

@return [{Integer=>ModuleInfo}]

object_paths[R]

List of paths for each of the discovered objects

@return [{Object=>String}]

predicate[R]

Predicate that filters objects in addition to {#excludes}

Only objects for which call returns true and the constants that contain them are exposed by this model

@return [#call]

title[RW]

Name of the root item

@return [String]

type_info[R]

A list of expected object types

This is used to decide where a given object should be “attached” in the hierarchy. Matching types are stored in {ModuleInfo#types}.

@return [{Class=>TypeInfo}]

Public Class Methods

new(type_info = Hash.new, &predicate) click to toggle source

Initialize this model for objects of the given type

@param [Hash] type_info value for {#type_info} @param [#call] predicate the filter {#predicate}

Calls superclass method
# File lib/metaruby/gui/ruby_constants_item_model.rb, line 67
def initialize(type_info = Hash.new, &predicate)
    super()
    @predicate = predicate || proc { true }
    @type_info = type_info
    @title = "Model Browser"
    @excludes = [Qt].to_set

    @id_to_module = []
    @filtered_out_modules = Set.new
    @object_paths = Hash.new
end

Public Instance Methods

columnCount(parent) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 369
def columnCount(parent)
    return 1
end
compute_full_name(info) click to toggle source

@api private

Lazily computes the full name of a discovered object. It updates {ModuleInfo#full_name}

@param [ModuleInfo] info @return [String]

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 224
def compute_full_name(info)
    if name = info.full_name
        return name
    else
        full_name = []
        current = info
        while current.parent
            full_name << current.name
            current = current.parent
        end
        info.full_name = full_name.reverse
    end
end
compute_keyword_string(info) click to toggle source

@api private

Lazily compute a comma-separated string that can be used to search for the given node. The result is stored in {ModuleInfo#keyword_string}

The returned string is of the form

type0[,type1...]:name0[,name1...]

@param [ModuleInfo] info @return [String]

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 305
def compute_keyword_string(info)
    if keywords = info.keyword_string
        return keywords
    else
        types = info.types.map do |type|
            type_info[type].name
        end.sort.join(",")
        paths = [compute_path(info)]
        paths.concat info.children.map { |child| compute_keyword_string(child) }
        info.keyword_string = "#{types};#{paths.join(",")}"
    end
end
compute_path(info) click to toggle source

@api private

Lazily compute the path of a discovered object. The result is stored in {ModuleInfo#path}

@param [ModuleInfo] info @return [String]

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 245
def compute_path(info)
    if path = info.path
        return path
    else
        full_name = compute_full_name(info)
        info.path = ("/" + full_name.map(&:downcase).join("/"))
    end
end
data(index, role) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 327
def data(index, role)
    if info = info_from_index(index)
        if role == Qt::DisplayRole
            return Qt::Variant.new(info.name)
        elsif role == Qt::EditRole
            return Qt::Variant.new(compute_full_name(info).join("/"))
        elsif role == Qt::UserRole
            return Qt::Variant.new(compute_keyword_string(info))
        end
    end
    return Qt::Variant.new
end
discover_module(mod, stack = Array.new) click to toggle source

@api private

Discovers an object and its children

@param [Object] mod an object that should be discovered @param [Array] stack the current stack (to avoid infinite recursions) @return [ModuleInfo]

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 142
def discover_module(mod, stack = Array.new)
    return if excludes.include?(mod)
    stack.push mod

    children = []
    mod_info = ModuleInfo.new(nil, nil, mod, nil, children, nil, Set.new)

    is_needed = (mod.kind_of?(Class) && mod == Object) || predicate.call(mod)

    if mod.respond_to?(:constants)
        children_modules = begin mod.constants
                           rescue TypeError
                               puts "cannot discover module #{mod}"
                               []
                           end

        children_modules = children_modules.map do |child_name|
            next if !mod.const_defined?(child_name, false)
            # Ruby issues a warning when one tries to access Config
            # (it has been deprecated in favor of RbConfig). Ignore
            # it explicitly
            next if mod == Object && child_name == :Config
            next if mod.autoload?(child_name)
            child_mod = begin mod.const_get(child_name)
                        rescue LoadError
                            # Handle autoload errors
                        end
            next if !child_mod
            next if filtered_out_modules.include?(child_mod)
            next if stack.include?(child_mod)
            [child_name.to_s, child_mod]
        end.compact.sort_by(&:first)

        children_modules.each do |child_name, child_mod|
            if info = discover_module(child_mod, stack)
                info.id = id_to_module.size
                info.name = child_name.to_s
                info.parent = mod_info
                info.row = children.size
                children << info
                id_to_module << info
            else
                filtered_out_modules << child_mod
            end
        end
    end

    if is_needed
        klass = if mod.respond_to?(:ancestors) then mod
                else mod.class
                end

        current_priority = nil
        klass.ancestors.each do |ancestor|
            if info = type_info[ancestor]
                current_priority ||= info.priority
                if current_priority < info.priority
                    mod_info.types.clear
                    mod_info.types << ancestor
                    current_priority = info.priority
                elsif current_priority == info.priority
                    mod_info.types << ancestor
                end
            end
        end
    end

    update_module_type_info(mod_info)

    if !children.empty? || is_needed
        mod_info
    end
ensure stack.pop
end
find_index_by_model(model) click to toggle source

Return the Qt::ModelIndex that represents a given object

@return [Qt::ModelIndex,nil] the index, or nil if the object is

not included in this model
# File lib/metaruby/gui/ruby_constants_item_model.rb, line 268
def find_index_by_model(model)
    if info = id_to_module.find { |info| info.this == model }
        return create_index(info.row, 0, info.id)
    end
end
find_index_by_path(*path) click to toggle source

Returns the Qt::ModelIndex that matches a given path

@param [Array<String>] path path to the desired object @return [Qt::ModelIndex,nil] the index, or nil if the path does

not resolve to an object included in this model
# File lib/metaruby/gui/ruby_constants_item_model.rb, line 279
def find_index_by_path(*path)
    current = id_to_module.last
    if path.first == current.name
        path.shift
    end

    path.each do |name|
        current = id_to_module.find do |info|
            info.name == name && info.parent == current
        end
        return if !current
    end
    create_index(current.row, 0, current.id)
end
generate_paths(paths, info, current) click to toggle source

@api private

Generate the path information, i.e. per-object path string

@param [Hash] paths the generated paths (matches {#object_paths}) @param [ModuleInfo] info the object information for the object to

be discovered

@param [String] current the path of 'info'

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 111
def generate_paths(paths, info, current)
    info.children.each do |child|
        child_uri = current + '/' + child.name
        paths[child.this] = child_uri
        generate_paths(paths, child, child_uri)
    end
end
headerData(section, orientation, role) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 319
def headerData(section, orientation, role)
    if role == Qt::DisplayRole && section == 0
        Qt::Variant.new(title)
    else Qt::Variant.new
    end
end
index(row, column, parent) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 341
def index(row, column, parent)
    if info = info_from_index(parent)
        if child_info = info.children[row]
            return create_index(row, column, child_info.id)
        end
    end
    Qt::ModelIndex.new
end
info_from_index(index) click to toggle source

Resolves a {ModuleInfo} from a Qt::ModelIndex

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 256
def info_from_index(index)
    if !index.valid?
        return id_to_module.last
    else
        id_to_module[index.internal_id >> 1]
    end
end
parent(child) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 351
def parent(child)
    if info = info_from_index(child)
        if info.parent && info.parent != root_info
            return create_index(info.parent.row, 0, info.parent.id)
        end
    end
    Qt::ModelIndex.new
end
reload() click to toggle source

Discovers or rediscovers the objects

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 80
def reload
    begin_reset_model
    @id_to_module = []
    @filtered_out_modules = Set.new
    
    info = discover_module(Object)
    info.id = id_to_module.size
    info.name = title
    update_module_type_info(info)
    info.row = 0
    id_to_module << info

    @object_paths = Hash.new
    generate_paths(object_paths, info, "")
ensure
    end_reset_model
end
root_info() click to toggle source

{ModuleInfo} for the root

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 99
def root_info
    id_to_module.last
end
rowCount(parent) click to toggle source

Reimplemented for Qt model interface

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 361
def rowCount(parent)
    if info = info_from_index(parent)
        info.children.size
    else 0
    end
end
update_module_type_info(info) click to toggle source

@api private

Updates {ModuleInfo#types} so that it includes the type of its

children

@param [ModuleInfo] info the object info that should be updated

# File lib/metaruby/gui/ruby_constants_item_model.rb, line 125
def update_module_type_info(info)
    types = info.types.to_set
    info.children.each do |child_info|
        types |= child_info.types.to_set
    end
    info.types = types.to_a.sort_by do |type|
        type_info[type].priority
    end.reverse
end