lib/closure/goog.rb in closure-1.2.701 vs lib/closure/goog.rb in closure-1.3.0
- old
+ new
@@ -16,11 +16,11 @@
class Closure
# Scripts render with an instance named goog in the context.
class Goog
-
+
def initialize(env, sources, render_stack)
@sources = sources
@env = env
@render_stack = render_stack
@dependencies = []
@@ -29,93 +29,140 @@
# You can add additional files to have their mtimes scanned.
# Perhaps you want to use a .yml file to define build options.
# Closure::Script calls this for every render so you don't need
# to define compiler arguments in the same script that calls compile.
def add_dependency(dependency)
- dependency = File.expand_path dependency, @render_stack.last
+ dependency = File.expand_path dependency, File.dirname(@render_stack.last)
@dependencies << dependency unless @dependencies.include? dependency
end
+
+ # If you change any javascript sources then you need to tell Script.
+ # This is a lazy refresh, you may call it repeatedly.
+ def refresh
+ @sources.invalidate @env
+ end
+
+ # Convert soy templates to javascript. Accepts all arguments that
+ # SoyToJsSrcCompiler.jar support plus it expands filename globs.
+ # All source filenames are relative to the script calling #soy_to_js.
+ # @param [Array<String>] args
+ def soy_to_js(args)
+ Templates::compile(args, File.dirname(@render_stack.last))
+ refresh
+ end
- # Run a compiler job. Accepts every argument that compiler.jar supports.
- # Accepts new `--ns namespace` option which literally expands into
- # `--js filename` arguments in place to satisfy the namespace.
- # If you specify a --js_output_file then the compiler will check File.mtime
- # on every source file plus all the closure-scripts and skip the compilation
- # if the js_output_file is newest.
- # Paths are relative to the script calling #compile.
+ # Compile javascript. Accepts every argument that compiler.jar supports.
+ # This method supports all compiler augmentations added by Closure Script.
+ # Path options are expanded relative to the script calling #compile.
+ # - `--ns namespace` expands in place to `--js filename` arguments which satisfy the namespace.
+ # - `--module name:*:dep` File count will be filled in automatically. The * is replaced with the
+ # count of files up to next --module or the end.
+ # - `--js_output_file file` is compared against sources modification times to determine
+ # if compilation is to be performed.
+ # - `--compilation_level` when not supplied, the scripts are loaded raw.
# @example myapp.js.erb
# <% @response = goog.compile(%w{
# --js_output_file ../public/myapp.js
# --ns myapp.HelloWorld
# --compilation_level ADVANCED_OPTIMIZATIONS
- # }).to_response_with_console %>
+ # }).to_response %>
# @param [Array<String>] args
# @return [Compilation]
def compile(args)
- args = Array.new args
- files = []
- files_index = 0
- args_index = 0
- temp_deps_js = nil
- compilation_level = nil
+ args = Array.new args # work on a copy
+ pre_js_tempfile = nil
begin
- while args_index < args.length
- option, value = args[args_index, 2]
- compilation_level = value if option == '--compilation_level'
- if option == '--ns'
- files_for(value, files)
- replacement = []
- while files_index < files.length
- if files[files_index] =~ /\.externs$/
- require 'tempfile'
- temp_deps_js ||= Tempfile.new 'closure_deps_js'
- replacement.push '--externs'
- else
- replacement.push '--js'
- end
- replacement.push files[files_index]
- files_index = files_index + 1
+ Compiler::Util.expand_paths args, File.dirname(@render_stack.last)
+ orig_externs = Compiler::Util.arg_values args, '--externs'
+ Compiler::Util.namespace_augment args, @sources, @env
+ mods = Compiler::Util.module_augment args
+ if Compiler::Util.arg_values(args, '--compilation_level').empty?
+ # Raw mode
+ comp = Compiler::Compilation.new @env
+ unless mods.empty?
+ comp << Compiler::Util.module_info(mods)
+ comp << Compiler::Util.module_uris_raw(mods, @sources)
+ end
+ js_counter = 0
+ args_index = 0
+ while args_index < args.length
+ option, value = args[args_index, 2]
+ if option == '--js'
+ value = File.expand_path value, File.dirname(@render_stack.last)
+ script_tag = "<script src=#{src_for(value).dump}></script>"
+ comp << "document.write(#{script_tag.dump});\n"
+ js_counter += 1
+ # For modules, just the files for the first module
+ break if !mods.empty? and js_counter >= mods[0][:files].length
end
- args[args_index, 2] = replacement
- else
args_index = args_index + 2
end
- end
- if compilation_level
- if temp_deps_js
- # EXPERIMENTAL: support for goog.provide and require in externs.
- # This is ugly but I hope it will no longer be necessary
- # once compiler.jar is made aware of goog.provide in externs.
- temp_deps_js.open
+ else
+ # Compiled mode
+ module_output_path_prefix = Compiler::Util.arg_values(args, '--module_output_path_prefix').last
+ if !mods.empty? and !module_output_path_prefix
+ # raise this before compilation so we don't write to a weird place
+ raise "--module_output_path_prefix is required when using --module"
+ end
+ # If the externs were changed by namespace_augment then we need to include
+ # a temp file containing the goog.provide statements that satisfy compiler.jar.
+ if orig_externs != Compiler::Util.arg_values(args, '--externs')
+ pre_js_tempfile = Tempfile.new 'closure_pre_js'
+ # Insert before the first --js (in case of modules)
+ args_index = 0
+ while args_index < args.length
+ if args[args_index] == '--js'
+ args.insert args_index, '--js', pre_js_tempfile.path
+ break
+ end
+ args_index = args_index + 2
+ end
+ pre_js_tempfile.open
@sources.deps_response(File.dirname(base_js), @env).each do |s|
- temp_deps_js.write s
+ next unless s =~ /^goog\.provide/
+ pre_js_tempfile.write s
end
- temp_deps_js.close
+ pre_js_tempfile.close
# File mtime is rolled back to not trigger compilation.
- File.utime(Time.now, Time.at(0), temp_deps_js.path)
- args.unshift temp_deps_js.path
- args.unshift '--js'
+ File.utime(Time.now, Time.at(0), pre_js_tempfile.path)
end
- Compiler.new args, @dependencies, File.dirname(@render_stack.last), @env
- else
- comp = Compiler.new []
- comp.stdout = ''
- args_index = 0
- while args_index < args.length
- option, value = args[args_index, 2]
- if option == '--js'
- script_tag = "<script src=#{path_for(value).dump}></script>"
- comp.stdout += "document.write(#{script_tag.dump});\n"
+ comp = Compiler.compile args, @dependencies, @env
+ unless mods.empty?
+ refresh # compilation may add new files, module_uris_compiled uses src_for
+ prefix = File.expand_path module_output_path_prefix, File.dirname(@render_stack.last)
+ if comp.js_output_file
+ File.open comp.js_output_file, 'w' do |f|
+ f.write Compiler::Util.module_info mods
+ f.write Compiler::Util.module_uris_compiled mods, @sources, prefix
+ end
+ else
+ comp << Compiler::Util.module_info(mods)
+ comp << Compiler::Util.module_uris_compiled(mods, @sources, prefix)
end
- args_index = args_index + 2
+ # Load the first module
+ first_module_file = module_output_path_prefix + mods[0][:name] + '.js'
+ first_module_file = File.expand_path first_module_file, File.dirname(@render_stack.last)
+ script_tag = "<script src=#{src_for(first_module_file).dump}></script>"
+ comp << "document.write(#{script_tag.dump});\n"
end
- comp
end
+ comp
ensure
- temp_deps_js.unlink if temp_deps_js
+ if pre_js_tempfile
+ pre_js_tempfile.close
+ pre_js_tempfile.unlink
+ end
end
end
+
+ # Calculate the deps src for a filename.
+ # @param (String) filename
+ # @return (String) http path info with forward caching query.
+ def src_for(filename)
+ filename = File.expand_path filename
+ @sources.src_for(filename, @env)
+ end
# Calculate files needed to satisfy a namespace.
# This will be especially useful for module generation.
# If you pass the filenames returned from last run,
# additional files (if any) will be appended to satisfy
@@ -125,30 +172,26 @@
# @return (Array)
def files_for(namespace, filenames=nil)
@sources.files_for(namespace, filenames, @env)
end
- # Calculate the file server path for a filename.
- # @param (String) filename
- # @return (String)
- def path_for(filename)
- @sources.path_for(filename, @env)
- end
-
# The Google Closure base.js script.
# If you use this instead of a static link, you are free to relocate relative
# to the Google Closure library without updating every html fixture page.
- # Unfortunately, the better caching can't be used because of the way
- # base.js explores the DOM looking for where to load deps.js.
# @example view_test.erb
# <script src="<%= goog.base_js %>"></script>
+ # @return [String]
def base_js
@sources.base_js(@env)
end
# This is where base.js looks to find deps.js by default. You will always
# be served a Closure Script generated deps.js from this location.
+ # Very old Library versions may get confused by the forward caching query
+ # string; either update your base.js, install a deps_response Script where
+ # it's looking, or manually set CLOSURE_BASE_PATH.
+ # @return [String]
def deps_js
@sources.deps_js(@env)
end
# You can serve a deps.js from anywhere you want to drop a script.
@@ -156,9 +199,20 @@
# <% @response = goog.deps_response %>
# @return (Rack::Response)
def deps_response
@sources.deps_response(File.dirname(Rack::Utils.unescape(@env["PATH_INFO"])), @env)
end
+
+ # Advanced Scripts may need to know where all the sources are.
+ # This has potential for a source browser, editor, and more.
+ # @example
+ # goog.each {|directory, path| ... }
+ def each
+ @sources.each do |directory, path|
+ yield directory, path
+ end
+ end
+ include Enumerable
end
end