Commit 482b6a12 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Extracted App class.

This takes care of the main application logic.
The jsduck.rb main file now only does command line options parsing
and passing them on to App.
parent 452e1586
Loading
Loading
Loading
Loading
+12 −100
Original line number Diff line number Diff line
@@ -15,111 +15,26 @@

$:.unshift File.dirname(__FILE__) # For running the actual JsDuck app

require 'rubygems'
require 'jsduck/aggregator'
require 'jsduck/class'
require 'jsduck/tree'
require 'jsduck/tree_icons'
require 'jsduck/page'
require 'json'

require 'jsduck/app'
require 'optparse'
require 'fileutils'
require 'pp'

module JsDuck
  def self.parse(input)
    agr = Aggregator.new
    agr.parse(input)
    agr.result
  end

  # Given array of filenames, parses all files and returns array of
  # documented items in all of those files.
  def self.parse_files(filenames, verbose)
    agr = Aggregator.new
    filenames.each do |name|
      puts "Parsing #{name} ..." if verbose
      agr.parse(IO.read(name))
    end
    agr.result
  end

  # Filters out class-documentations, converting them to Class objects.
  # For each other type, prints a warning message and discards it
  def self.filter_classes(docs)
    classes = {}
    docs.each do |d|
      if d[:tagname] == :class
        classes[d[:name]] = Class.new(d, classes)
      else
        puts "Warning: Ignoring " + d[:tagname].to_s + ": " + (d[:name] || "")
      end
    end
    classes.values
  end

  def self.print_debug(docs)
    docs.each do |doc|
      puts (doc[:name] || "?") + ":"
      if doc[:tagname] == :class
        [:cfg, :property, :method, :event].each do |key|
          puts "  " + key.to_s + "s:"
          doc[key].each {|item| puts "    " + (item[:name] || "?")}
        end
      end
      puts
    end
  end

  # Given array of doc-objects, generates namespace tree and writes in
  # in JSON form into a file.
  def self.write_tree(filename, docs)
    tree = Tree.new.create(docs)
    icons = TreeIcons.new.extract_icons(tree)
    js = "Docs.classData = " + JSON.generate( tree ) + ";"
    js += "Docs.icons = " + JSON.generate( icons ) + ";"
    File.open(filename, 'w') {|f| f.write(js) }
  end

  # Writes documentation page for each class
  def self.write_pages(path, docs, verbose)
    docs.each do |cls|
      filename = path + "/" + cls[:name] + ".html"
      puts "Writing to #{filename} ..." if verbose
      File.open(filename, 'w') {|f| f.write( Page.new(cls).to_html ) }
    end
  end

  def self.copy_template(template_dir, dir, verbose)
    puts "Copying template files to #{dir}..." if verbose
    if File.exists?(dir)
      FileUtils.rm_r(dir)
    end
    FileUtils.cp_r(template_dir, dir)
    FileUtils.mkdir(dir + "/output")
  end
end


if __FILE__ == $0 then
  output_dir = nil
  template_dir = File.dirname(File.dirname(__FILE__)) + "/template"
  verbose = false
  app = JsDuck::App.new
  app.template_dir = File.dirname(File.dirname(__FILE__)) + "/template"

  opts = OptionParser.new do | opts |
    opts.banner = "Usage: ruby jsduck.rb [options] files..."

    opts.on('-o', '--output=PATH', "Directory to output all this amazing documentation.") do |path|
      output_dir = path
      app.output_dir = path
    end

    opts.on('-t', '--template=PATH', "Directory containing doc-browser UI template.") do |path|
      template_dir = path
      app.template_dir = path
    end

    opts.on('-v', '--verbose', "This will fill up your console.") do
      verbose = true
      app.verbose = true
    end

    opts.on('-h', '--help', "Prints this help message") do
@@ -128,25 +43,22 @@ if __FILE__ == $0 then
    end
  end

  input_files = opts.parse!(ARGV)
  app.input_files = opts.parse!(ARGV)

  if input_files.length == 0
  if app.input_files.length == 0
    puts "You should specify some input files, otherwise there's nothing I can do :("
    exit(1)
  elsif !output_dir
  elsif !app.output_dir
    puts "You should also specify an output directory, where I could write all this amazing documentation."
    exit(1)
  elsif File.exists?(output_dir) && !File.directory?(output_dir)
  elsif File.exists?(app.output_dir) && !File.directory?(app.output_dir)
    puts "Oh noes!  The output directory is not really a directory at all :("
    exit(1)
  elsif !File.exists?(File.dirname(output_dir))
  elsif !File.exists?(File.dirname(app.output_dir))
    puts "Oh noes!  The parent directory for #{output_dir} doesn't exist."
    exit(1)
  end

  classes = JsDuck.filter_classes(JsDuck.parse_files(input_files, verbose))
  JsDuck.copy_template(template_dir, output_dir, verbose)
  JsDuck.write_tree(output_dir+"/output/tree.js", classes)
  JsDuck.write_pages(output_dir+"/output", classes, verbose)
  app.run()
end

lib/jsduck/app.rb

0 → 100644
+89 −0
Original line number Diff line number Diff line
require 'rubygems'
require 'jsduck/aggregator'
require 'jsduck/class'
require 'jsduck/tree'
require 'jsduck/tree_icons'
require 'jsduck/page'
require 'json'
require 'fileutils'

module JsDuck

  # The main application logic of jsduck
  class App
    # These are basically input parameters for app
    attr_accessor :output_dir
    attr_accessor :template_dir
    attr_accessor :input_files
    attr_accessor :verbose

    def initialize
      @output_dir = nil
      @template_dir = nil
      @input_files = []
      @verbose = false
    end

    # Call this after input parameters set
    def run
      classes = filter_classes(parse_files(@input_files))
      copy_template(@template_dir, @output_dir)
      write_tree(@output_dir+"/output/tree.js", classes)
      write_pages(@output_dir+"/output", classes)
    end

    # Given array of filenames, parses all files and returns array of
    # documented items in all of those files.
    def parse_files(filenames)
      agr = Aggregator.new
      filenames.each do |name|
        puts "Parsing #{name} ..." if @verbose
        agr.parse(IO.read(name))
      end
      agr.result
    end

    # Filters out class-documentations, converting them to Class objects.
    # For each other type, prints a warning message and discards it
    def filter_classes(docs)
      classes = {}
      docs.each do |d|
        if d[:tagname] == :class
          classes[d[:name]] = Class.new(d, classes)
        else
          puts "Warning: Ignoring " + d[:tagname].to_s + ": " + (d[:name] || "")
        end
      end
      classes.values
    end

    # Given array of doc-objects, generates namespace tree and writes in
    # in JSON form into a file.
    def write_tree(filename, docs)
      tree = Tree.new.create(docs)
      icons = TreeIcons.new.extract_icons(tree)
      js = "Docs.classData = " + JSON.generate( tree ) + ";"
      js += "Docs.icons = " + JSON.generate( icons ) + ";"
      File.open(filename, 'w') {|f| f.write(js) }
    end

    # Writes documentation page for each class
    def write_pages(path, docs)
      docs.each do |cls|
        filename = path + "/" + cls[:name] + ".html"
        puts "Writing to #{filename} ..." if @verbose
        File.open(filename, 'w') {|f| f.write( Page.new(cls).to_html ) }
      end
    end

    def copy_template(template_dir, dir)
      puts "Copying template files to #{dir}..." if @verbose
      if File.exists?(dir)
        FileUtils.rm_r(dir)
      end
      FileUtils.cp_r(template_dir, dir)
      FileUtils.mkdir(dir + "/output")
    end
  end

end