module RTM
# Topology information about a Topic Map.
# This class provides some statistical and structural information about a topic map.
# All methods take an optional modifier OR block which specifies how a Topic Maps construct shall be transformed before it is returned.
# Some modifiers are defined in the sub module Modifier.
class Topology
# @return [RTM::TopicMap] The topic map this topology provides information about.
attr_reader :topic_map
def initialize(topic_map)
@topic_map = topic_map
end
# A list of constructs defined in TMDM which have a (single) type
SINGLE_TYPED_CONSTRUCTS = %w[name occurrence association role]
# A list of constructs defined in TMDM which may have multiple types
TYPED_CONSTRUCTS = ["topic"] + SINGLE_TYPED_CONSTRUCTS
# A list of constructs defined in TMDM which are scopeable
SCOPEABLE_CONSTRUCTS = %w[name variant occurrence association]
SINGLE_TYPED_CONSTRUCTS.each do |item|
# define_method "#{item}_types" do |modifier=nil, &block|
eval(<<-EOS)
def #{item}_types(modifier=nil, &block)
modifier ||= block || Modifier.default
@#{item}_types ||= Hash[@topic_map.#{item}_types.map{|i| [modifier.call(i), i.typed_#{item}s.size]}]
end
def #{item}_types_count(modifier=nil, &block)
@#{item}_types_count ||= @topic_map.#{item}_types.size
end
EOS
end
SCOPEABLE_CONSTRUCTS.each do |item|
eval(<<-EOS)
def #{item}_themes(modifier=nil, &block)
modifier ||= block || Modifier.default
@#{item}_themes ||= Hash[@topic_map.#{item}_themes.map{|i| [modifier.call(i), i.scoped_#{item}s.size]}]
end
def #{item}_themes_count(modifier=nil, &block)
@#{item}_themes_count ||= @topic_map.#{item}_themes.size
end
EOS
end
# The number of topics in this topic map
# @return [Number]
def topics_count(modifier=nil, &block)
@topic_map.topics.size
end
# The number of associations in this topic map
# @return [Number]
def associations_count(modifier=nil, &block)
@topic_map.associations.size
end
# The following are not available in RTM yet
# def names_count
# @topic_map.names.size
# end
# def occurrences_count
# @topic_map.occurrences.size
# end
# def variants_count
# @topic_map.variants.size
# end
# All topology information in one step
# @return [Hash] with all topology information. Keys correspond to method names, values to their returned results.
def all(modifier=nil, &block)
modifier ||= block || Modifier.default
puts "modifier: #{modifier.inspect}"
ms = self.methods - Object.new.methods - %w[topic_map all]
Hash[ms.map {|m| [m, self.send(m, modifier)]}]
end
# String representation of all topology information
# @return [String] with all topology information
def to_s(modifier=nil, &block)
modifier ||= block || Modifier.best_name
all(modifier).sort_by{|k,v| k}.map {|k,v| "#{k}: #{v.inspect}"}.join("\n")
end
# Manages Modifiers which may be applied to Constructs (or only to Topics?!)
module Modifier
# The nop Modifier just returns the construct given as is: {|x| x}
#
# @return [#call] The nop Modifier which is a callable object which takes one argument and returns this argument.
def nop
Proc.new {|x| x}
end
# The best_name Modifier returns the best name for a Construct: {|x| x.best_name}
#
# @return [#call] The best_name Modifier returns a name suitable for human consumption
def best_name
Proc.new {|x| x.best_name}
end
# The reference Modifier returns a reference for a Construct: {|x| x.reference}
#
# @return [#call] The reference Modifier returns a name suitable for human consumption
def reference
Proc.new {|x| x.reference}
end
# Make all instance methods available as class methods, too.
extend self
# The default modifier is {#nop}
# @return [#call] the default modifier
attr_reader :default
# Set the default modifier
@default = nop
end
# The TopologyExtension for RTM::TopicMap adds an #topology method to a topic map which provides an overview over a topic map.
module TopologyExtension
# Topology information about this TopicMap.
# @return [Topology] an object which provides some topology information
def topology
RTM::Topology.new(self)
end
RTM::TopicMap.register_extension(self)
end
end
end