class Glyph::Analyzer

@since 0.4.0 This class is used to collect statistics about a Glyph document.

Attributes

stats[R]

Public Class Methods

new(doc=Glyph.document) click to toggle source

Initializes a new Analyzer @param [Glyph::Document] doc the document to analyze

# File lib/glyph/analyzer.rb, line 15
def initialize(doc=Glyph.document)
        @doc = doc
        @stats = {}
        @macros = []
        @macros_by_def = {}
end

Public Instance Methods

macro_array_for(name) click to toggle source

Helper method used to return an array of specific macro instances @param [String, Symbol] name the name of the macro definition

# File lib/glyph/analyzer.rb, line 24
def macro_array_for(name)
        return @macros_by_def[name.to_sym] if @macros_by_def[name.to_sym]
        key = @macros_by_def.keys.select{|k| macro_eq?(k, name.to_sym) }[0] || name.to_sym
        @macros_by_def[key] = [] unless @macros_by_def[key]
        @macros_by_def[key]
end
stats_for(stats_type, *args) click to toggle source

Retrieves statistics of a given type @param [String, Symbol] stats_type the type of stats to retrieve (:macros, :bookmarks, :links, :snippets, :files, :global, :macro, :bookmark, :snippet, :link) @param [String, Symbol] *args Stats parameter(s) (e.g. a macro name, bookmark ID, etc.)

# File lib/glyph/analyzer.rb, line 70
def stats_for(stats_type, *args)
        begin
                send :"stats_#{stats_type}", *args 
        rescue NoMethodError => e
                raise RuntimeError, "Unable to calculate #{stats_type} stats"
        end
end
with_macros(name=nil, &block) click to toggle source

Iterator over specific macro instances @param [String, Symbol] name the name of the macro definition (if left blank, iterates over all macro instances) @yieldparam [Glyph::MacroNode] n the macro node

# File lib/glyph/analyzer.rb, line 34
def with_macros(name=nil, &block)
        raise ArgumentError, "No block given" unless block_given?
        name = name.to_sym if name
        if !name then
                unless @macros.blank? then
                        @macros.each(&block)
                else
                        @doc.structure.descend do |n, level|
                                if n.is_a?(Glyph::MacroNode) && n.source
                                        @macros << n
                                        macro_array_for(n[:name]) << n
                                        block.call n
                                end
                        end
                end
        else
                existing = @macros_by_def[name]
                if existing then
                        existing.each(&block)
                else
                        macros = []
                        @doc.structure.descend do |n, level|
                                if n.is_a?(Glyph::MacroNode) && macro_eq?(name, n[:name]) && n.source
                                        macros << n
                                        block.call n
                                end
                        end
                        @macros_by_def[name] = macros
                end
        end
end

Protected Instance Methods

stats_bookmark(name) click to toggle source
# File lib/glyph/analyzer.rb, line 142
def stats_bookmark(name)
        code = name.to_s.gsub(/^#/, '').to_sym
        raise ArgumentError, "Bookmark '#{code}' does not exist" unless @doc.bookmark? code
        c = @stats[:bookmark] = {}
        bmk = @doc.bookmark? code
        c[:param] = name
        c[:definition] = bmk.definition.to_s
        c[:file] = bmk.file.to_s
        c[:type] = bmk.is_a?(Glyph::Header) ? :header : :anchor
        references = {}
        with_macros(:link) do |n|
                target = n.parameters[0].to_s.gsub(/^#/, '').to_sym
                count_occurrences_for references, target, n if target == code
        end
        c[:references]= references[code][:files] rescue []
end
stats_bookmarks() click to toggle source
# File lib/glyph/analyzer.rb, line 119
def stats_bookmarks
        c = @stats[:bookmarks] = {}
        c[:codes] = []
        files = {}
        @doc.bookmarks.each_pair do |k, v|
                c[:codes] << k
                files[v.file] ||= 0
                files[v.file] +=1
        end
        c[:codes].sort!
        referenced = {}
        with_macros(:link) do |n|
                target =n.parameters[0][:value].to_s
                if target.match(/^#/) then
                        code = target.gsub(/^#/, '').to_sym 
                        referenced[code] ||= 0
                        referenced[code] += 1      
                end
        end
        c[:referenced] = referenced.to_a.sort
        c[:unreferenced] = c[:codes] - c[:referenced].map{|e| e[0]}
end
stats_files() click to toggle source
# File lib/glyph/analyzer.rb, line 223
def stats_files
        @stats[:files] = {}
        count_files_in = lambda do |dir|
                files = []
                (Glyph::PROJECT/"#{dir}").find{|f| files << f if f.file? } rescue nil
                files.length
        end
        @stats[:files][:text] = count_files_in.call 'text'
        @stats[:files][:lib] = count_files_in.call 'lib'
        @stats[:files][:styles] = count_files_in.call 'styles'
        @stats[:files][:layouts] = count_files_in.call 'layouts'
        @stats[:files][:images] = count_files_in.call 'images'
end
stats_global() click to toggle source
# File lib/glyph/analyzer.rb, line 80
def stats_global
        stats_macros
        stats_bookmarks
        stats_links
        stats_snippets
        stats_files
end
stats_macro(name) click to toggle source
# File lib/glyph/analyzer.rb, line 97
def stats_macro(name)
        name = name.to_sym
        raise ArgumentError, "Unknown macro '#{name}'" unless Glyph::MACROS.include? name
        c = @stats[:macro] = {}
        c[:param] = name
        c[:instances] = []
        c[:alias_for] = macro_definition_for name 
        files = {}
        with_macros(name) do |n|
                unless n.source.blank? then 
                        c[:instances] << n[:name]
                        files[n.source] ||= 0
                        files[n.source]    += 1
                end
        end
        raise ArgumentError, "Macro '#{name}' is not used in this document" if c[:instances].blank?
        if c[:alias_for] && !name.in?(c[:instances]) then
                raise ArgumentError, "Macro '#{name}' is not used in this document, did you mean '#{c[:alias_for]}'?" 
        end
        c[:files] = files.to_a.sort
end
stats_macros() click to toggle source
# File lib/glyph/analyzer.rb, line 88
def stats_macros
        c = @stats[:macros] = {}
        c[:aliases] = Glyph::ALIASES[:by_alias].keys.sort
        c[:definitions] = (Glyph::MACROS.keys - c[:aliases]).uniq.sort
        c[:instances] = []
        with_macros {|n|  c[:instances] << n[:name]}
        c[:used_definitions] = c[:instances].map{|m| macro_definition_for(m) || m}.uniq.sort
end
stats_snippet(name) click to toggle source
# File lib/glyph/analyzer.rb, line 207
def stats_snippet(name)
        name = name.to_sym
        snippets = {}
        raise ArgumentError, "Snippet '#{name}' does not exist" unless @doc.snippet? name
        with_macros(:snippet) do |n|
                code = n.parameters[0].to_s.to_sym
                if code == name then
                        count_occurrences_for snippets, code, n
                end
        end
        raise ArgumentError, "Snippet '#{name}' is not used in this document" if snippets.blank?
        @stats[:snippet] = {}
        @stats[:snippet][:stats] = snippets[name]
        @stats[:snippet][:param] = name
end
stats_snippets() click to toggle source
# File lib/glyph/analyzer.rb, line 188
def stats_snippets
        c = @stats[:snippets] = {}
        snippets = {}
        c[:definitions] = @doc.snippets.keys.sort
        c[:values] = @doc.snippets
        c[:used] = []
        c[:unused] = []
        c[:total] = 0
        with_macros(:snippet) do |n|
                code = n.parameters[0].to_s.to_sym
                c[:used] << code unless c[:used].include? code
                c[:total] += 1
                #count_occurrences_for snippets, code, n
        end
        #c[:used_details] = snippets.to_a.sort
        c[:used].sort!
        c[:unused] = (c[:definitions] - c[:used]).sort
end

Private Instance Methods

count_occurrences_for(collection, code, n) click to toggle source
# File lib/glyph/analyzer.rb, line 239
def count_occurrences_for(collection, code, n)
        collection[code] ||= {:total => 0, :files =>[]} unless collection[code]
        collection[code][:total] += 1
        coll = collection[code][:files]
        added = false
        coll.each do |file|
                if file[0] == n.source then
                        file[1] += 1
                        added = true
                        break
                end
        end
        coll << [n.source, 1] unless added
        coll.sort!
end