class NScript::CommandLine

The CommandLine handles all of the functionality of the `nscript` utility.

Constants

ROOT

Path to the root of the NScript install.

RUNNERS

Commands to execute NScripts.

WATCH_INTERVAL

Seconds to pause between checks for changed source files.

Public Class Methods

new() click to toggle source

Run the CommandLine off the contents of ARGV.

# File lib/nscript/command_line.rb, line 38
def initialize
  @mtimes = {}
  parse_options
  return launch_repl if @options[:interactive]
  return eval_scriptlet if @options[:eval]
  check_sources
  return run_scripts if @options[:run]
  @sources.each {|source| compile_javascript(source) }
  watch_nscript_scripts if @options[:watch]
end

Public Instance Methods

usage() click to toggle source

The “–help” usage message.

# File lib/nscript/command_line.rb, line 50
def usage
  puts "\n#{@option_parser}\n"
  exit
end

Private Instance Methods

check_sources() click to toggle source

Ensure that all of the source files exist.

# File lib/nscript/command_line.rb, line 91
def check_sources
  usage if @sources.empty?
  missing = @sources.detect {|s| !File.exists?(s) }
  if missing
    STDERR.puts("File not found: '#{missing}'")
    exit(1)
  end
end
compile(script, source='error') click to toggle source

Compile a single source file to JavaScript.

# File lib/nscript/command_line.rb, line 143
def compile(script, source='error')
  begin
    options = {}
    options[:no_wrap] = true if @options[:no_wrap]
    options[:globals] = true if @options[:globals]
    NScript.compile(script, options)
  rescue NScript::ParseError => e
    STDERR.puts "#{source}: #{e.message}"
    exit(1) unless @options[:watch]
    nil
  end
end
compile_javascript(source) click to toggle source

Compiles (or partially compiles) the source NScript file, returning the desired JS, tokens, or lint results.

# File lib/nscript/command_line.rb, line 60
def compile_javascript(source)
  script = File.read(source)
  return tokens(script) if @options[:tokens]
  js = compile(script, source)
  return unless js
  return puts(js) if @options[:print]
  return lint(js) if @options[:lint]
  File.open(path_for(source), 'w+') {|f| f.write(js) }
end
eval_scriptlet() click to toggle source

Eval a little piece of NScript directly from the command line.

# File lib/nscript/command_line.rb, line 112
def eval_scriptlet
  script = STDIN.tty? ? @sources.join(' ') : STDIN.read
  return tokens(script) if @options[:tokens]
  js = compile(script)
  return lint(js) if @options[:lint]
  puts js
end
install_bundle() click to toggle source

Install the NScript TextMate bundle to ~/Library.

# File lib/nscript/command_line.rb, line 165
def install_bundle
  bundle_dir = File.expand_path('~/Library/Application Support/TextMate/Bundles/')
  FileUtils.cp_r("#{ROOT}/extras/NScript.tmbundle", bundle_dir)
end
launch_repl() click to toggle source

Use Node.js or Narwhal to run an interactive NScript session.

# File lib/nscript/command_line.rb, line 121
def launch_repl
  exec "#{RUNNERS[@options[:runner]]}"
rescue Errno::ENOENT
  puts "Error: #{@options[:runner]} must be installed to use the interactive REPL."
  exit(1)
end
lint(js) click to toggle source

Pipe compiled JS through JSLint (requires a working 'jsl' command).

# File lib/nscript/command_line.rb, line 101
def lint(js)
  stdin, stdout, stderr = Open3.popen3('jsl -nologo -stdin')
  stdin.write(js)
  stdin.close
  puts stdout.read.tr("\n", '')
  errs = stderr.read.chomp
  puts errs unless errs.empty?
  stdout.close and stderr.close
end
parse_options() click to toggle source

Use OptionParser for all the options.

# File lib/nscript/command_line.rb, line 171
def parse_options
  @options = {:runner => :node}
  @option_parser = OptionParser.new do |opts|
    opts.on('-i', '--interactive', 'run an interactive NScript REPL') do |i|
      @options[:interactive] = true
    end
    opts.on('-r', '--run', 'compile and run a NScript') do |r|
      @options[:run] = true
    end
    opts.on('-o', '--output [DIR]', 'set the directory for compiled JavaScript') do |d|
      @options[:output] = d
      FileUtils.mkdir_p(d) unless File.exists?(d)
    end
    opts.on('-w', '--watch', 'watch scripts for changes, and recompile') do |w|
      @options[:watch] = true
    end
    opts.on('-p', '--print', 'print the compiled JavaScript to stdout') do |d|
      @options[:print] = true
    end
    opts.on('-l', '--lint', 'pipe the compiled JavaScript through JSLint') do |l|
      @options[:lint] = true
    end
    opts.on('-e', '--eval', 'compile a cli scriptlet or read from stdin') do |e|
      @options[:eval] = true
    end
    opts.on('-t', '--tokens', 'print the tokens that the lexer produces') do |t|
      @options[:tokens] = true
    end
    opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
      ENV['VERBOSE'] = 'true'
    end
    opts.on('-n', '--no-wrap', 'raw output, no function safety wrapper') do |n|
      @options[:no_wrap] = true
    end
    opts.on('-g', '--globals', 'attach all top-level variable as globals') do |n|
      @options[:globals] = true
    end
    opts.on_tail('--narwhal', 'use Narwhal instead of Node.js') do |n|
      @options[:runner] = :narwhal
    end
    opts.on_tail('--install-bundle', 'install the NScript TextMate bundle') do |i|
      install_bundle
      exit
    end
    opts.on_tail('--version', 'display NScript version') do
      puts "NScript version #{NScript::VERSION}"
      exit
    end
    opts.on_tail('-h', '--help', 'display this help message') do
      usage
    end
  end
  @option_parser.banner = BANNER
  begin
    @option_parser.parse!(ARGV)
  rescue OptionParser::InvalidOption => e
    puts e.message
    exit(1)
  end
  @sources = ARGV
end
path_for(source) click to toggle source

Write out JavaScript alongside NScript unless an output directory is specified.

# File lib/nscript/command_line.rb, line 158
def path_for(source)
  filename = File.basename(source, File.extname(source)) + '.js'
  dir      = @options[:output] || File.dirname(source)
  File.join(dir, filename)
end
run_scripts() click to toggle source

Use Node.js or Narwhal to compile and execute NScripts.

# File lib/nscript/command_line.rb, line 129
def run_scripts
  sources = @sources.join(' ')
  exec "#{RUNNERS[@options[:runner]]} #{sources}"
rescue Errno::ENOENT
  puts "Error: #{@options[:runner]} must be installed in order to execute scripts."
  exit(1)
end
tokens(script) click to toggle source

Print the tokens that the lexer generates from a source script.

# File lib/nscript/command_line.rb, line 138
def tokens(script)
  puts Lexer.new.tokenize(script).inspect
end
watch_nscript_scripts() click to toggle source

Spins up a watcher thread to keep track of the modification times of the source files, recompiling them whenever they're saved.

# File lib/nscript/command_line.rb, line 72
def watch_nscript_scripts
  watch_thread = Thread.start do
    loop do
      @sources.each do |source|
        mtime = File.stat(source).mtime
        @mtimes[source] ||= mtime
        if mtime > @mtimes[source]
          @mtimes[source] = mtime
          compile_javascript(source)
        end
      end
      sleep WATCH_INTERVAL
    end
  end
  Signal.trap("INT") { watch_thread.kill }
  watch_thread.join
end