Skip to content
Rakefile 18.5 KiB
Newer Older
require 'rubygems'
require 'rake'
require 'json'
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)

require 'rspec'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
  spec.rspec_opts = ["--color"]
  spec.pattern = "spec/**/*_spec.rb"
def load_sdk_vars
  if File.exists?("sdk-vars.rb")
Rene Saarsoo's avatar
Rene Saarsoo committed
    require "./sdk-vars.rb"
  else
    puts "Error: sdk-vars.rb not found."
    puts
    puts "Please create file sdk-vars.rb and define in it:"
    puts "    # path to Ext JS 4 build"
    puts "    EXT_BUILD='/path/to/ext-4.0.7'"
    puts "    # path to Touch 2 build"
    puts "    TOUCH_BUILD='/path/to/touch-2.0.0'"
    puts "    # where to output the docs"
    puts "    OUT_DIR='/path/to/ouput/dir'"
    puts "    # path to SDK (for developers at Sencha)"
    puts "    SDK_DIR='/path/to/SDK'"
    puts "    # paths to other projects (for developers at Sencha)"
    puts "    ANIMATOR_DIR='/path/to/Animator'"
    puts "    ARCHITECT_DIR='/path/to/Architect'"
    puts "    SENCHAIO_DIR='/path/to/IO'"
    puts "    EXT3_DIR='/path/to/ext3'"
    puts "    EXT2_DIR='/path/to/ext2'"
# Compress JS/CSS file in-place
# Using a hackish way to access yui-compressor
def yui_compress(fname)
  system "java -jar $(dirname $(which sencha))/bin/yuicompressor.jar -o #{fname} #{fname}"

# Reads in all CSS files referenced between BEGIN CSS and END CSS markers.
# Deletes those input CSS files and writes out concatenated CSS to
# resources/css/app.css
# Finally replaces the CSS section with <link> to that one CSS file.
def combine_css(html, dir, opts = :write)
  css_section_re = /<!-- BEGIN CSS -->.*<!-- END CSS -->/m
  css = []
  css_section_re.match(html)[0].each_line do |line|
    if line =~ /<link rel="stylesheet" href="(.*?)"/
      file = $1
      css << IO.read(dir + "/" + file)
      system("rm", dir + "/" + file) if opts == :write
  if opts == :write
    fname = "#{dir}/resources/css/app.css"
    File.open(fname, 'w') {|f| f.write(css.join("\n")) }
    yui_compress(fname)
  end
  html.sub(css_section_re, '<link rel="stylesheet" href="resources/css/app.css" type="text/css" />')
end

# Same thing for JavaScript, result is written to: app.js
def combine_js(html, dir)
  js_section_re = /<!-- BEGIN JS -->.*<!-- END JS -->/m
  js = []
  js_section_re.match(html)[0].each_line do |line|
    if line =~ /<script .* src="(.*)">/
      file = $1
      js << IO.read(dir + "/" + file)
        system("rm", dir + "/" + file)
    elsif line =~ /<script .*>(.*)<\/script>/
      js << $1
    end
  end

  fname = "#{dir}/app.js"
  File.open(fname, 'w') {|f| f.write(js.join("\n")) }
  yui_compress(fname)
  html.sub(js_section_re, '<script type="text/javascript" src="app.js"></script>')
# Compress JavaScript and CSS files of JSDuck
def compress

  # Clean up template-min/ left over from previous compress task
  system("rm", "-rf", "template-min")
  # Copy template/ files to template-min/
  system("cp", "-r", "template", "template-min")
  # Now do everything that follows in template-min/ dir
  dir = "template-min"

Nick Poulden's avatar
Nick Poulden committed
  # Create JSB3 file for Docs app
  system("sencha", "create", "jsb", "-a", "#{dir}/build-js.html", "-p", "#{dir}/app.jsb3")
  # Concatenate files listed in JSB3 file
  system("sencha", "build", "-p", "#{dir}/app.jsb3", "-d", dir)
  # Remove intermediate build files
  system("rm", "#{dir}/app.jsb3")
  system("rm", "#{dir}/all-classes.js")
  # Replace app.js with app-all.js
  system("mv", "#{dir}/app-all.js", "#{dir}/app.js")
  # Remove the entire app/ dir
  system("rm", "-r", "#{dir}/app")

  # Concatenate CSS in print-template.html file
  print_template = "#{dir}/print-template.html";
  html = IO.read(print_template);
  # Just modify HTML to link app.css, don't write files.
  html = combine_css(html, dir, :replace_html_only)
  File.open(print_template, 'w') {|f| f.write(html) }

  # Concatenate CSS and JS files referenced in template.html file
  template_html = "#{dir}/template.html"
  html = IO.read(template_html)
  html = combine_css(html, dir)
  html = combine_js(html, dir)
  File.open(template_html, 'w') {|f| f.write(html) }

  # Clean up SASS files
  # (But keep prettify lib, which is needed for source files)
  system "rm -rf #{dir}/resources/sass"
  system "rm -rf #{dir}/resources/codemirror"
  system "rm -rf #{dir}/resources/.sass-cache"
  # Empty the extjs dir, leave only the main JS file and images
  system "rm -rf #{dir}/extjs"
  system "mkdir #{dir}/extjs"
  system "cp template/extjs/ext-all.js #{dir}/extjs"
  system "mkdir -p #{dir}/extjs/resources/themes/images"
  system "cp -r template/extjs/resources/themes/images/default #{dir}/extjs/resources/themes/images"
class JsDuckRunner
  def initialize
    @options = []
    load_sdk_vars
  end

  def add_options(options)
    @options += options
  end

  # Enables comments when CORS is supported by browser.
  # This excludes Opera and IE < 8.
  # We check explicitly for IE version to make sure the code works the
  # same way in both real IE7 and IE7-mode of IE8/9.
Nick Poulden's avatar
Nick Poulden committed
  def add_comments(db_name, version)
    comments_base_url = "http://projects.sencha.com/auth"
    @options += ["--head-html", <<-EOHTML]
      <script type="text/javascript">
        Docs.enableComments = ("withCredentials" in new XMLHttpRequest()) || (Ext.ieVersion >= 8);
        Docs.baseUrl = "#{comments_base_url}";
        Docs.commentsDb = "#{db_name}";
Nick Poulden's avatar
Nick Poulden committed
        Docs.commentsVersion = "#{version}";
      </script>
    EOHTML
  end

  # For export of ExtJS, reference extjs from the parent dir
  def make_extjs_path_relative
    ["#{OUT_DIR}/index.html"].each do |file|
      out = []
      IO.read(file).each_line do |line|
        out << line.sub(/(src|href)="extjs\//, '\1="../')
      end
      File.open(file, 'w') {|f| f.write(out) }
    end
    system "rm -rf #{OUT_DIR}/extjs"
  def add_ext4
    @options += [
      "--title", "Sencha Docs - Ext JS 4.0",
      "--footer", "Ext JS 4.0 Docs - Generated with <a href='https://github.com/senchalabs/jsduck'>JSDuck</a> {VERSION}." +
                  " <a href='http://www.sencha.com/legal/terms-of-use/'>Terms of Use</a>",
      "--ignore-global",
      "--no-warnings",
      "--images", "#{EXT_BUILD}/docs/doc-resources",
      "--local-storage-db", "ext-4",
      "--output", "#{OUT_DIR}",
      "#{EXT_BUILD}/src",
Rene Saarsoo's avatar
Rene Saarsoo committed
  def add_phone_redirect
    @options += ["--body-html", <<-EOHTML]
Nick Poulden's avatar
Nick Poulden committed
      <script type="text/javascript">
Rene Saarsoo's avatar
Rene Saarsoo committed
        if (Ext.is.Phone) { window.location = "../examples/"; }
Nick Poulden's avatar
Nick Poulden committed
      </script>
    EOHTML
  def add_debug
    @options += [
      "--extjs-path", "extjs/ext-all-debug.js",
      "--template-links",
      "--template", "template",
    ]
  end

  def add_seo
    @options += [
      "--seo",
    ]
  end

  def add_export_notice path
    @options += [
      "--body-html", <<-EOHTML
      <div id="notice-text" style="display: none">
        Use <a href="http://docs.sencha.com/#{path}">http://docs.sencha.com/#{path}</a> for up to date documentation and features
  def add_google_analytics
    @options += [
      "--body-html", <<-EOHTML
      <script type="text/javascript">
        var _gaq = _gaq || [];
        _gaq.push(['_setAccount', 'UA-1396058-10']);
        _gaq.push(['_trackPageview']);
        (function() {
          var ga = document.createElement('script');
          ga.type = 'text/javascript';
          ga.async = true;
          ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
          var s = document.getElementsByTagName('script')[0];
          s.parentNode.insertBefore(ga, s);
        })();

        Docs.initEventTracking = function() {
            Docs.App.getController('Classes').addListener({
                showClass: function(cls) {
                    _gaq.push(['_trackEvent', 'Classes', 'Show', cls]);
                },
                showMember: function(cls, anchor) {
                    _gaq.push(['_trackEvent', 'Classes', 'Member', cls + ' - ' + anchor]);
                }
            });
            Docs.App.getController('Guides').addListener({
                showGuide: function(guide) {
                    _gaq.push(['_trackEvent', 'Guides', 'Show', guide]);
                }
            });
            Docs.App.getController('Videos').addListener({
                showVideo: function(video) {
                    _gaq.push(['_trackEvent', 'Video', 'Show', video]);
                }
            });
            Docs.App.getController('Examples').addListener({
                showExample: function(example) {
                    _gaq.push(['_trackEvent', 'Example', 'Show', example]);
                }
            });
        }
Nick Poulden's avatar
Nick Poulden committed

        Docs.otherProducts = [
          {
              text: 'Ext JS 4.1',
              href: 'http://docs.sencha.com/ext-js/4-1'
          },
          {
              text: 'Ext JS 4.0',
Nick Poulden's avatar
Nick Poulden committed
              href: 'http://docs.sencha.com/ext-js/4-0'
          },
          {
              text: 'Ext JS 3',
              href: 'http://docs.sencha.com/ext-js/3-4'
          },
          {
              text: 'Ext JS 2',
              href: 'http://docs.sencha.com/ext-js/2-3'
          },
Nick Poulden's avatar
Nick Poulden committed
          {
              text: 'Sencha Touch 2',
              href: 'http://docs.sencha.com/touch/2-0'
          },
          {
              text: 'Sencha Touch 1',
              href: 'http://docs.sencha.com/touch/1-1'
          },
Nick Poulden's avatar
Nick Poulden committed
          {
              text: 'Touch Charts',
              href: 'http://docs.sencha.com/touch-charts/1-0'
          },
Nick Poulden's avatar
Nick Poulden committed
          {
              text: 'Sencha Animator',
              href: 'http://docs.sencha.com/animator/1-0'
          {
              text: 'Sencha Architect',
              href: 'http://docs.sencha.com/arhitect/2-0'
          },
          {
              text: 'Sencha.io',
              href: 'http://docs.sencha.com/io/1-0'
      </script>
    EOHTML
    ]
    system "cp -r #{EXT_BUILD} #{OUT_DIR}/extjs-build"
  # Copy over Sencha Touch
  def copy_touch2_build
    system "cp -r #{TOUCH_BUILD} #{OUT_DIR}/touch"
  def run
    # Pass multiple arguments to system, so we'll take advantage of the built-in escaping
    system(*["ruby", "bin/jsduck"].concat(@options))
  end
# Run compass to generate CSS files
task :sass do
  system "compass compile --quiet template/resources/sass"
end
desc "Run JSDuck on Ext JS SDK (for internal use at Sencha)\n" +
     "sdk         - creates debug/development version\n" +
     "sdk[export] - creates export version\n" +
     "sdk[live]   - create live version for deployment\n"
task :sdk, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
  compress if mode == "export" || mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{SDK_DIR}/extjs/docs/config.json"]
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
  runner.add_export_notice("ext-js/4-0") if mode == "export"
  runner.add_google_analytics if mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_comments('ext-js', '4') if mode == "debug" || mode == "live"
  if mode == "export"
    runner.add_options ["--eg-iframe", "#{SDK_DIR}/extjs/docs/eg-iframe-build.html"]
    runner.add_options ["--examples-base-url", "../examples/"]
  else
    runner.add_options ["--examples-base-url", "extjs-build/examples/"]
  end
  runner.run

  if mode == "export"
    runner.make_extjs_path_relative
  else
    runner.copy_extjs_build
  end
desc "Run JSDuck on Docs app itself"
task :docs do
  runner = JsDuckRunner.new
  runner.add_ext4
  runner.add_options([
    "--builtin-classes",
    "template/app"
  ])
  runner.add_debug
  runner.add_seo
  runner.run
end

desc "Run JSDuck on official Ext JS 4.0.2a build\n" +
     "ext4             - creates debug/development version\n" +
     "ext4[export]     - creates export/deployable version\n"
task :ext4, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "export"].include?(mode)
  compress if mode == "export"

  runner = JsDuckRunner.new
  runner.add_ext4
  runner.add_debug if mode == "debug"
  runner.add_seo
  runner.run
end

Nick Poulden's avatar
Nick Poulden committed
desc "Run JSDuck on official Ext JS 3.4 build\n" +
     "ext3             - creates debug/development version\n" +
     "ext3[export]     - creates export/deployable version\n"
     "ext3[live]       - creates live version for deployment\n"
task :ext3, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
Nick Poulden's avatar
Nick Poulden committed
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
Nick Poulden's avatar
Nick Poulden committed
  compress if mode == "export"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{EXT3_DIR}/src/doc-config.json"]
Nick Poulden's avatar
Nick Poulden committed
  runner.add_debug if mode == "debug"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_seo if mode == "live"
  runner.add_google_analytics if mode == "live"
  runner.run
end

desc "Run JSDuck on official Ext JS 2.3 build\n" +
     "ext2             - creates debug/development version\n" +
     "ext2[export]     - creates export/deployable version\n"
     "ext2[live]       - creates live version for deployment\n"
task :ext2, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
  compress if mode == "export"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{EXT2_DIR}/doc-config.json"]
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_google_analytics if mode == "live"
  runner.run
end

desc "Run JSDuck on Sencha Touch (for internal use at Sencha)\n" +
     "touch       - creates debug/development version\n" +
     "touch[live] - create live version for deployment\n"
task :touch, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "live"].include?(mode)
  compress if mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{SDK_DIR}/touch/doc-resources/config.json"]
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_google_analytics if mode == "live"
  runner.run
end
Nick Poulden's avatar
Nick Poulden committed
desc "Run JSDuck on Sencha Touch 2 (for internal use at Sencha)\n" +
Rene Saarsoo's avatar
Rene Saarsoo committed
     "touch2         - creates debug/development version\n" +
     "touch2[export] - creates export version\n" +
     "touch2[live]   - create live version for deployment\n"
Nick Poulden's avatar
Nick Poulden committed
task :touch2, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
Rene Saarsoo's avatar
Rene Saarsoo committed
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
  compress if mode == "live" || mode == "export"
Nick Poulden's avatar
Nick Poulden committed

  runner = JsDuckRunner.new
Rene Saarsoo's avatar
Rene Saarsoo committed
  runner.add_options [
    "--output", OUT_DIR,
    "--config", "#{SDK_DIR}/touch/docs/config.json"
  ]

  if mode == "export"
Rene Saarsoo's avatar
Rene Saarsoo committed
    runner.add_export_notice("touch/2-0")
    runner.add_phone_redirect
    # override settings in config.json
Rene Saarsoo's avatar
Rene Saarsoo committed
    runner.add_options [
      "--welcome", "#{SDK_DIR}/touch/docs/build-welcome.html",
      "--eg-iframe", "#{SDK_DIR}/touch/docs/build-eg-iframe.html",
      "--examples-base-url", "../examples/",
    ]
  else
    runner.add_options ["--examples-base-url", "touch/examples/production/"]
Rene Saarsoo's avatar
Rene Saarsoo committed

  runner.add_debug if mode == "debug"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_seo if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_google_analytics if mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_comments('touch', '2') if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.run

  runner.copy_touch2_build if mode != "export"
Nick Poulden's avatar
Nick Poulden committed
desc "Run JSDuck on Sencha Touch Charts (for internal use at Sencha)\n" +
     "charts         - creates debug/development version\n" +
     "charts[export] - create live version for deployment\n"
     "charts[live]   - create live version for deployment\n"
task :charts, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
  compress if mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{SDK_DIR}/charts/docs/config.json"]
Nick Poulden's avatar
Nick Poulden committed
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
  runner.add_google_analytics if mode == "live"
  runner.run
end

Nick Poulden's avatar
Nick Poulden committed
desc "Run JSDuck on Sencha.IO Sync (for internal use at Sencha)\n" +
     "senchaio         - creates debug/development version\n" +
     "senchaio[export] - create live version for deployment\n"
     "senchaio[live]   - create live version for deployment\n"
task :senchaio, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "export", "live"].include?(mode)
  compress if mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{SENCHAIO_DIR}/docs/config.json"]
Nick Poulden's avatar
Nick Poulden committed
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
  runner.add_google_analytics if mode == "live"
  runner.run
end

Nick Poulden's avatar
Nick Poulden committed
desc "Run JSDuck on Sencha Animator (for internal use at Sencha)\n" +
Nick Poulden's avatar
Nick Poulden committed
     "animator         - creates debug/development version\n" +
     "animator[export] - create live version for deployment\n"
     "animator[live]   - create live version for deployment\n"
Nick Poulden's avatar
Nick Poulden committed
task :animator, [:mode] => :sass do |t, args|
  mode = args[:mode] || "debug"
Nick Poulden's avatar
Nick Poulden committed
  throw "Unknown mode #{mode}" unless ["debug", "live", "export"].include?(mode)
Nick Poulden's avatar
Nick Poulden committed
  compress if mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{ANIMATOR_DIR}/docs/config.json"]
Nick Poulden's avatar
Nick Poulden committed
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.add_google_analytics if mode == "live"
  runner.add_comments('animator', '1') if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.run
Nick Poulden's avatar
Nick Poulden committed

desc "Run JSDuck on Sencha Architect (for internal use at Sencha)\n" +
     "architect         - creates debug/development version\n" +
     "architect[export] - create live version for deployment\n"
     "architect[live]   - create live version for deployment\n"
task :architect, [:mode] => :sass do |t, args|
Nick Poulden's avatar
Nick Poulden committed
  mode = args[:mode] || "debug"
  throw "Unknown mode #{mode}" unless ["debug", "live", "export"].include?(mode)
  compress if mode == "live"

  runner = JsDuckRunner.new
  runner.add_options ["--output", OUT_DIR, "--config", "#{ARCHITECT_DIR}/docs/config.json"]
Nick Poulden's avatar
Nick Poulden committed
  runner.add_debug if mode == "debug"
  runner.add_seo if mode == "debug" || mode == "live"
  runner.add_google_analytics if mode == "live"
  runner.add_comments('architect', '2') if mode == "debug" || mode == "live"
Nick Poulden's avatar
Nick Poulden committed
  runner.run
end

desc "Build JSDuck gem"
task :gem => :sass do
  compress
  system "gem build jsduck.gemspec"
end
task :default => :spec