Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Move into ::Closure namespace.

  • Loading branch information...
commit 0cdcb6b6e09658a771fb6bca2a8acee7814142fa 1 parent 930e940
@AE9RB authored
Showing with 500 additions and 492 deletions.
  1. +11 −4 README.md
  2. +1 −1  beanshell/LICENSE
  3. +5 −5 closure.gemspec
  4. +15 −13 config.ru
  5. +5 −5 java_src/{Googly.java → ClosureScript.java}
  6. +5 −5 java_src/make.rb
  7. BIN  lib/closure.jar
  8. +31 −32 lib/{googly.rb → closure.rb}
  9. +5 −5 lib/{googly → closure}/beanshell.rb
  10. +181 −0 lib/closure/compiler.rb
  11. +2 −2 lib/{googly → closure}/file_response.rb
  12. +29 −31 lib/{googly → closure}/goog.rb
  13. +9 −9 lib/{googly → closure}/middleware.rb
  14. +6 −6 lib/{googly → closure}/sass.rb
  15. +27 −27 lib/{googly/template.rb → closure/script.rb}
  16. +12 −11 lib/{googly → closure}/server.rb
  17. +42 −32 lib/{googly → closure}/sources.rb
  18. +25 −14 lib/{googly/soy.rb → closure/templates.rb}
  19. +3 −3 lib/{googly → closure}/version.rb
  20. BIN  lib/googly.jar
  21. +0 −161 lib/googly/compilation.rb
  22. +0 −3  lib/googlyscript.rb
  23. +8 −24 scripts/demos/compile.js.erb
  24. +4 −0 scripts/demos/compiler.js
  25. +0 −1  scripts/demos/helloworld.haml
  26. +2 −2 scripts/demos/index.haml
  27. +3 −6 scripts/demos/rails_ujs.haml
  28. +0 −17 scripts/demos/rails_ujs.js.erb
  29. +0 −45 scripts/dist/rails_ujs.js
  30. +47 −7 scripts/{dist → examples}/rails/ujs.js
  31. +5 −5 scripts/index.haml
  32. +1 −1  test/beanshell_test.rb
  33. +8 −9 test/server_test.rb
  34. +5 −5 test/sources_test.rb
  35. +3 −1 test/test_helper.rb
View
15 README.md
@@ -1,13 +1,20 @@
-Googlyscript - A build tool for Google Closure.
+Closure Script for Google Closure Compiler, Library, and Templates.
Licensed under the Apache License, Version 2.0 (the "License");
<http://www.apache.org/licenses/LICENSE-2.0>
Project blog;
-<http://www.googlyscript.com/>
+<http://www.closure-script.com/>
Getting Started documentation is on the wiki;
-<https://github.com/dturnbull/googlyscript/wiki>
+<https://github.com/dturnbull/closure-script/wiki>
Advanced documentation is in YARD format;
-<http://rubydoc.info/gems/googlyscript/frames>
+<http://rubydoc.info/gems/closure/frames>
+
+
+ * New gem name: gem install closure
+ * New project name: Closure Script
+ * ::Closure namespace is used with sub-namespaces Closure::Compiler Closure::Templates and Closure::Script.
+ * Experimental support for provide/require in externs. Scripts with a .externs suffix are scanned for goog.provide and goog.require statements. Due to compiler.jar not supporting this yet, place start and end comment markers on the lines before and after the goog statements.
+ * Closure Templates error reporting has been integrated. If you were checking Soy errors you no longer need to if you are loading goog.deps_js or using goog.compile(args).to_response_with_console.
View
2  beanshell/LICENSE
@@ -1,4 +1,4 @@
-Googlyscript uses an unmodified version of BeanShell.
+Closure Script uses an unmodified version of BeanShell.
The BeanShell jar isn't distributed with a license.
The source code didn't have a license in it either.
View
10 closure.gemspec
@@ -1,15 +1,15 @@
# -*- encoding: utf-8 -*-
-require File.expand_path("../lib/googly/version", __FILE__)
+require File.expand_path("../lib/closure/version", __FILE__)
Gem::Specification.new do |s|
- s.name = "Closure Script"
- s.version = Googly::VERSION
+ s.name = "closure"
+ s.version = Closure::VERSION
s.platform = Gem::Platform::RUBY
s.homepage = "https://github.com/dturnbull/closure-script"
- s.summary = "Google Closure build tools"
+ s.summary = "Closure Script for Google Closure Compiler, Library, and Templates."
s.required_rubygems_version = ">= 1.3"
- s.rubyforge_project = "closure"
+ # s.rubyforge_project = "closure-script"
s.add_dependency 'rack', '>= 1.0.0'
View
28 config.ru
@@ -1,38 +1,40 @@
#\ -p 9009 -E none
-# This is the rackup for developers working on (not with) Googlyscript.
+# This is the rackup for developers working on (not with) Closure Script.
-require File.join(File.dirname(__FILE__), 'lib', 'googlyscript.rb')
+closure_lib_path = File.expand_path(File.dirname(__FILE__), 'lib')
+$LOAD_PATH.unshift(closure_lib_path) if !$LOAD_PATH.include?(closure_lib_path)
+require 'closure'
-Googly.script '/goog', :goog
-Googly.script '/goog_vendor', :goog_vendor
-Googly.script '/soy_js', :soy_js
-Googly.script '/', File.join(Googly.base_path, 'scripts')
-Googly.config.haml[:format] = :html5
+Closure.add_source :goog, '/goog'
+Closure.add_source :goog_vendor, '/goog_vendor'
+Closure.add_source :templates, '/soy_js'
+Closure.add_source File.join(Closure.base_path, 'scripts'), '/'
+Closure.config.haml[:format] = :html5
use Rack::CommonLogger # slow
use Rack::Reloader, 1
use Rack::Lint # slow
use Rack::ShowExceptions
-use Googly::Soy, %w{
+use Closure::Templates, %w{
--shouldProvideRequireSoyNamespaces
--cssHandlingScheme goog
--shouldGenerateJsdoc
--outputPathFormat {INPUT_DIRECTORY}{INPUT_FILE_NAME_NO_EXT}.js
scripts/**/*.soy
}
-use Googly::Middleware, File.join(Googly.base_path, 'scripts', 'index.html')
+use Closure::Middleware, File.join(Closure.base_path, 'scripts', 'index.html')
# Yard will have a better Middleware in a future release.
# This maps /(root), /docs and /list (maybe others).
-# Googly::Middleware serves the home page because it's run first.
+# Closure::Middleware serves the home page because it's run first.
require 'yard'
`rm -r .yardoc 2>/dev/null` # Because Yard doesn't mark and sweep for deletes.
YARD::CLI::Yardoc.new.run('-c', '-n', '--no-stats') # Must be run once before starting.
use YARD::Server::RackMiddleware, {
- :libraries => {'googly' => [YARD::Server::LibraryVersion.new('googly', nil, '.yardoc')]},
+ :libraries => {'closure' => [YARD::Server::LibraryVersion.new('closure', nil, '.yardoc')]},
:options => {:incremental => true}
}
-run Rack::File.new File.join(Googly.base_path, 'scripts')
+run Rack::File.new File.join(Closure.base_path, 'scripts')
-print "Scripting engaged. Caution: Googlies bond instantly to skin.\n"
+print "Closure Script development server started.\n"
View
10 java_src/Googly.java → java_src/ClosureScript.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Googlyscript Authors
+// Copyright 2011 The Closure Script Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
// limitations under the License.
-// The Google Closure javascript compiler calls System.exit() internally.
+// The Google Closure Compiler calls System.exit() internally.
// I tried subclassing as they suggest, but the main System.exit() was at
// the end of the critical compiler run function. Rather than take control
// of this important code which would need to be kept in sync with Google's
@@ -23,13 +23,13 @@
// specified, so we have to hack around that too.
// Once loaded up in a BeanShell or other REPL:
-// java -classpath bsh-core-2.0b4.jar:Googly.jar:../closure-compiler/compiler.jar bsh.Interpreter
+// java -classpath bsh-core-2.0b4.jar:closure.jar:../closure-compiler/compiler.jar bsh.Interpreter
// You may repeatedly request javascript compilations:
-// Googly.compile_js(new String[]{"--js", "../app/javascripts/test.js", "--js_output_file", "out.js", "--compilation_level", "ADVANCED_OPTIMIZATIONS"});
+// ClosureScript.compile_js(new String[]{"--js", "../app/javascripts/test.js", "--js_output_file", "out.js", "--compilation_level", "ADVANCED_OPTIMIZATIONS"});
import java.io.PrintStream;
-public class Googly {
+public class ClosureScript {
// This PrintStream can not be closed
private static class UnclosablePrintStream extends PrintStream {
View
10 java_src/make.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# I'm not a Java programmer.
+# I'm not a Java programmer. I didn't want to learn ant.
raise "Remove old .class files before running make" unless Dir.glob("*.class").empty?
-`javac -classpath ../closure-compiler/compiler.jar:../closure-templates/SoyToJsSrcCompiler.jar:../beanshell/bsh-core-2.0b4.jar Googly.java`
-`jar cf ../lib/googly.jar *.class`
-%w{Googly.class Googly$1.class Googly$SystemExitException.class Googly$UnclosablePrintStream.class}.each {|f| File.unlink f rescue nil}
+`javac -classpath ../closure-compiler/compiler.jar:../closure-templates/SoyToJsSrcCompiler.jar:../beanshell/bsh-core-2.0b4.jar ClosureScript.java`
+`jar cf ../lib/closure.jar *.class`
+%w{ClosureScript.class ClosureScript$1.class ClosureScript$SystemExitException.class ClosureScript$UnclosablePrintStream.class}.each {|f| File.unlink f rescue nil}
View
BIN  lib/closure.jar
Binary file not shown
View
63 lib/googly.rb → lib/closure.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,34 +15,34 @@
require 'ostruct'
-# Googlyscript can be run with rackup using a config.ru, installed as
-# middleware into a framework, or adapted to anything with a rack environment.
+# Closure tools may be called directly, run as a stand-alone server, installed as
+# middleware into a framework like Rails, or adapted to anything with a rack environment.
# @example config.ru
# #\ -p 9009 -E none
# require 'rubygems'
-# require 'googlyscript'
-# Googly.script '/goog', :goog
-# Googly.script '/myapp', './src/myapp'
+# require 'closure'
+# Closure.add_source :goog, '/goog'
+# Closure.add_source './src/myapp', '/myapp'
# use Rack::ShowExceptions
-# use Googly::Middleware
+# use Closure::Middleware
# run Rack::File.new './public'
-class Googly
+class Closure
- autoload(:VERSION, 'googly/version')
- autoload(:BeanShell, 'googly/beanshell')
- autoload(:Sass, 'googly/sass')
- autoload(:Template, 'googly/template')
- autoload(:Sources, 'googly/sources')
- autoload(:FileResponse, 'googly/file_response')
- autoload(:Middleware, 'googly/middleware')
- autoload(:Compilation, 'googly/compilation')
- autoload(:Server, 'googly/server')
- autoload(:Goog, 'googly/goog')
- autoload(:Soy, 'googly/soy')
+ autoload(:VERSION, 'closure/version')
+ autoload(:BeanShell, 'closure/beanshell')
+ autoload(:Sass, 'closure/sass')
+ autoload(:Script, 'closure/script')
+ autoload(:Sources, 'closure/sources')
+ autoload(:FileResponse, 'closure/file_response')
+ autoload(:Middleware, 'closure/middleware')
+ autoload(:Compiler, 'closure/compiler')
+ autoload(:Server, 'closure/server')
+ autoload(:Goog, 'closure/goog')
+ autoload(:Templates, 'closure/templates')
- # Filesystem location of the Googlyscript install.
+ # Filesystem location of the Closure Script install.
# Typically, where the gem was installed. This is mainly used
# internally but may be useful for experimental configurations.
# @return [String]
@@ -52,35 +52,35 @@ def self.base_path
# Scripts that are distributed with the gem. These will help get you started quickly.
- # Googlyscript isn't tied to any Google Closure release, so feel free to use whatever
+ # Closure Script isn't tied to any Google Closure release, so feel free to use whatever
# version you want and check it in to your repository.
BUILT_INS = {
:goog => File.join(base_path, 'closure-library', 'closure', 'goog'),
:goog_vendor => File.join(base_path, 'closure-library', 'third_party', 'closure', 'goog'),
- :soy_js => File.join(base_path, 'closure-templates'),
- :googly => File.join(base_path, 'scripts', 'dist')
+ :templates => File.join(base_path, 'closure-templates'),
+ :examples => File.join(base_path, 'scripts', 'examples')
}
# Easy config. This adds to the global instance of sources and
# supports using the {BUILT_INS}.
# @example
- # Googly.script('/goog', :goog)
- # Googly.script('/myapp', './myapp')
+ # Closure.add_source :goog, '/goog'
+ # Closure.add_source './myapp', '/myapp'
# @overload script(path, directory)
# @overload script(path, built_in)
# @param (String) path http server mount point.
# @param (String) directory Where the scripts are in the filesystem.
# @param (Symbol) built_in
- def self.script(path, directory)
+ def self.add_source(directory, path=nil)
directory = BUILT_INS[directory] if directory.kind_of? Symbol
- sources.add path, directory
+ sources.add directory, path
end
- # This is a global instance of sources, configured with Googly.script()
- # and used for {Googlyscript::Middleware} by default.
- # Path and directory pairs configured with Googly.script().
+ # This is a global instance of sources, configured with Closure.add_source()
+ # and used for {Closure Script::Middleware} by default.
+ # Path and directory pairs configured with Closure.add_source().
# @return [Array]
def self.sources
@@sources ||= Sources.new
@@ -89,14 +89,13 @@ def self.sources
# Run Java command in a REPL (read-execute-print-loop).
# This keeps Java running so you only pay the startup cost on the first job.
- # It will have compiler.jar and googly.jar loaded.
# @param (String) command BeanShell Java command.
# @return (Array)[stdout, stderr]
def self.java(command)
@@beanshell ||= BeanShell.new [
config.compiler_jar,
config.soy_js_jar,
- File.join(base_path, 'lib', 'googly.jar')
+ File.join(base_path, 'lib', 'closure.jar')
]
@@beanshell.run(command)
end
View
10 lib/googly/beanshell.rb → lib/closure/beanshell.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
require 'open3'
-class Googly
+class Closure
- # Googlyscript will manage a single BeanShell to run the Java tools.
+ # Closure Script will manage a single BeanShell to run the Java tools.
# This way we don't pay the Java startup costs on every compile job.
class BeanShell
PROMPT = /^bsh % $\Z/
- JAR = File.join(Googly.base_path, 'beanshell', 'bsh-core-2.0b4.jar')
+ JAR = File.join(Closure.base_path, 'beanshell', 'bsh-core-2.0b4.jar')
# @param classpath (Array)<string>
def initialize(classpath=[])
@@ -56,7 +56,7 @@ def execute(command)
@semaphore.synchronize do
unless $cmdin
classpath = [@classpath, JAR].flatten
- java_repl = "#{Googly.config.java} -classpath #{classpath.join(':').dump} bsh.Interpreter"
+ java_repl = "#{Closure.config.java} -classpath #{classpath.join(':').dump} bsh.Interpreter"
$cmdin, $cmdout, $cmderr = Open3::popen3(java_repl)
eat_startup = ''
eat_startup << $cmdout.readpartial(8192) until eat_startup =~ PROMPT
View
181 lib/closure/compiler.rb
@@ -0,0 +1,181 @@
+# Copyright 2011 The Closure Script Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class Closure
+
+ class Compiler
+
+ # Java won't let you change working directories and the Closure Compiler
+ # doesn't allow setting a base path. No problem, we can do it.
+
+ # These are filename options and will be expanded to a new base.
+ # If supplied as arguments, output options are available as instance
+ # variables and attributes that have been expanded to the new base.
+ OUTPUT_OPTIONS = %w{
+ --create_source_map
+ --js_output_file
+ --output_manifest
+ --property_map_output_file
+ --variable_map_output_file
+ }
+
+ # These are filename options and will be expanded to a new base.
+ # These will have their modifification times checked against js_output_file.
+ INPUT_OPTIONS = %w{
+ --js
+ --externs
+ --property_map_input_file
+ --variable_map_input_file
+ }
+
+ # @param (Array) args Arguments for the compiler.
+ # @param (Array) dependencies Any other files to check mtime on, like makefiles.
+ # @param (String) base All filenames will be expanded to this location.
+ # @param (Hash) env Rack environment. If you want the response to be cachable.
+ # @param (Exception) exception Ruby {Exception} that prevents compilation.
+ def initialize(args, dependencies = [], base = nil, env = {}, exception = nil)
+ @env = env
+ @exception = exception
+ unless exception
+ args = Array.new args
+ files = []
+ # Scan to expand paths and extend self with output options
+ args_index = 0
+ while args_index < args.length
+ option, value = args[args_index, 2]
+ value = File.expand_path(value, base) if base
+ if INPUT_OPTIONS.include?(option)
+ files << args[args_index+1] = value
+ end
+ if OUTPUT_OPTIONS.include?(option)
+ var_name = option.sub(/^--/, '')
+ instance_variable_set "@#{var_name}", args[args_index+1] = value
+ eval "def self.#{var_name}; @#{var_name}; end"
+ end
+ args_index = args_index + 2
+ end
+ # We don't bother compiling if we can detect that no sources were modified
+ if @js_output_file
+ js_mtime = File.mtime @js_output_file rescue Errno::ENOENT
+ compiled = !!File.size?(@js_output_file) # catches empty files too
+ (files + dependencies).each do |filename|
+ break unless compiled
+ mtime = File.mtime filename
+ compiled = false if !mtime or mtime > js_mtime
+ end
+ return if compiled
+ File.unlink @js_output_file rescue Errno::ENOENT
+ end
+ # Do it; defensive .to_s.dump allows for bools and nums
+ java_opts = args.collect{|a|a.to_s.dump}.join(', ')
+ @stdout, @stderr = Closure.java("ClosureScript.compile_js(new String[]{#{java_opts}});")
+ end
+ end
+
+ # Allows http caching of the js_output_file for scripts that want to do
+ # their own error checking.
+ # @example
+ # <% @response = goog.compile(args).to_response %>
+ # @return (#finish)
+ def to_response
+ if @js_output_file
+ FileResponse.new @env, @js_output_file, 'application/javascript'
+ else
+ response = Rack::Response.new
+ response.headers['Content-Type'] = 'application/javascript'
+ response.headers["Cache-Control"] = 'max-age=0, private, must-revalidate'
+ response.write @stdout
+ response
+ end
+ end
+
+ # Checks the compilation status and will log to the javascript console.
+ # This is the best technique for compiling unless you have different
+ # needs for reporting errors.
+ # @example
+ # <% @response = goog.compile(args).to_response_with_console %>
+ def to_response_with_console
+ response = Rack::Response.new
+ # Ruby exceptions
+ if @exception
+ response.write 'try{console.error('
+ response.write '"Closure Script: Ruby Exception\n\n", '
+ response.write @exception.to_s.dump
+ response.write ")}catch(err){};\n"
+ end
+ # Closure Template Errors
+ templates_errors_js = Templates.errors_js @env
+ response.write templates_errors_js if templates_errors_js
+ # Closure Compiler Errors
+ if stderr and !stderr.empty?
+ split_log = stderr.split("\n")
+ if split_log.last =~ /^\d+ err/i
+ error_message = split_log.pop
+ else
+ error_message = split_log.shift
+ end
+ error_log = "'Closure Compiler: %s', "
+ if split_log.empty?
+ error_log += error_message.dump
+ else
+ error_log += (error_message + "\n\n" + split_log.join("\n")).dump
+ end
+ if error_message =~ /^0 err/i
+ response.write "try{console.log(#{error_log})}catch(err){};\n"
+ else
+ response.write "try{console.error(#{error_log})}catch(err){};\n"
+ end
+ end
+ # Finally, the javascript
+ return to_response if response.empty?
+ response.write javascript
+ response.headers['Content-Type'] = 'application/javascript'
+ response.headers["Cache-Control"] = 'max-age=0, private, must-revalidate'
+ response
+ end
+
+ # Always returns the compiled javascript (possibly an empty string).
+ # @example
+ # <%= goog.compile(args) %>
+ def javascript
+ if @js_output_file
+ File.read(@js_output_file) rescue ''
+ else
+ @stdout
+ end
+ end
+ alias :to_s :javascript
+
+ # Results from compiler.jar. If you didn't specify a --js_output_file
+ # then this will be the compiled script. Otherwise, it's usually empty
+ # but may contain output depending on the arguments.
+ # If nil, compilation was skipped because js_output_file was up to date
+ # or an exception was passed on initialization.
+ attr_reader :stdout
+
+ # Results from compiler.jar. The log, when there is one, is found here.
+ # Use `--summary_detail_level 3` to see log when no errors or warnings.
+ # If nil, compilation was skipped because js_output_file was up to date
+ # or an exception was passed on initialization.
+ attr_reader :stderr
+
+ # Ruby exception; typically from {Sources}. The compiler will not
+ # generate these exceptions. This is only a mechanism to get Ruby
+ # exceptions about dependencies on to the Javascript console.log.
+ attr_reader :exception
+
+ end
+
+end
View
4 lib/googly/file_response.rb → lib/closure/file_response.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
# limitations under the License.
-class Googly
+class Closure
# Can be used as a Rack::Response. Provides advanced cache control.
View
60 lib/googly/goog.rb → lib/closure/goog.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,11 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'tempfile'
-class Googly
+class Closure
- # Templates render with an instance named goog in the context.
+ # Scripts render with an instance named goog in the context.
class Goog
@@ -29,8 +28,8 @@ def initialize(env, sources, render_stack)
# You can add additional files to have their mtimes scanned.
# Perhaps you want to use a .yml file to define build options.
- # Googly::Template calls this for every render so you don't need
- # to define compiler arguments in the same template that calls compile.
+ # 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
@dependencies << dependency unless @dependencies.include? dependency
@@ -40,9 +39,9 @@ def add_dependency(dependency)
# 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 templates and skip the compilation
+ # 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 template calling #compile.
+ # Paths are relative to the script calling #compile.
# @example myapp.js.erb
# <% @response = goog.compile(%w{
# --js_output_file ../public/myapp.js
@@ -56,9 +55,8 @@ def compile(args)
files = []
files_index = 0
args_index = 0
- comp = Compilation.new @env
- deps_js = Tempfile.new 'googlyscript_deps_js'
- has_externs = false
+ temp_deps_js = nil
+ exception = nil
begin
while args_index < args.length
option, value = args[args_index, 2]
@@ -67,7 +65,8 @@ def compile(args)
replacement = []
while files_index < files.length
if files[files_index] =~ /\.externs$/
- has_externs = true
+ require 'tempfile'
+ temp_deps_js ||= Tempfile.new 'closure_deps_js'
replacement.push '--externs'
else
replacement.push '--js'
@@ -80,27 +79,26 @@ def compile(args)
args_index = args_index + 2
end
end
- if has_externs
- # We need to compile with a copy of deps.js
- # to pick up the goog.provides for externs.
- # File mtime is rolled back to not trigger compilation.
- deps_js.open
- @sources.deps_response(@env).each do |s|
- deps_js.write s
+ 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
+ @sources.deps_response(File.dirname(base_js), @env).each do |s|
+ temp_deps_js.write s
end
- deps_js.close
- File.utime(Time.now, Time.at(0), deps_js.path)
- args.unshift deps_js.path
+ temp_deps_js.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'
end
- comp.compile_js args, File.dirname(@render_stack.last), @dependencies
rescue Exception => e
- # Namespace problems are Ruby exceptions
- comp.stderr = "#{e.inspect}\n\n1 error(s)"
+ exception = e
ensure
- deps_js.unlink
+ temp_deps_js.unlink if temp_deps_js
end
- comp
+ Compiler.new args, @dependencies, File.dirname(@render_stack.last), @env, exception
end
# Calculate files needed to satisfy a namespace.
@@ -112,7 +110,7 @@ def compile(args)
# <%= goog.files_for %w{myapp.Calendar} %>
# @return (Array)
def files_for(namespace, filenames=nil)
- @sources.files_for(@env, namespace, filenames)
+ @sources.files_for(namespace, filenames, @env)
end
# The Google Closure base.js script.
@@ -127,17 +125,17 @@ def base_js
end
# This is where base.js looks to find deps.js by default. You will always
- # be served a Googlyscript generated deps.js from this location.
+ # be served a Closure Script generated deps.js from this location.
def deps_js
@sources.deps_js(@env)
end
- # You can serve a deps.js from anywhere you want to drop a template.
+ # You can serve a deps.js from anywhere you want to drop a script.
# @example deps.jazz.erb
# <% @response = goog.deps_response %>
# @return (Rack::Response)
def deps_response
- @sources.deps_response(@env, File.dirname(Rack::Utils.unescape(@env["PATH_INFO"])))
+ @sources.deps_response(File.dirname(Rack::Utils.unescape(@env["PATH_INFO"])), @env)
end
end
View
18 lib/googly/middleware.rb → lib/closure/middleware.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,23 +13,23 @@
# limitations under the License.
-class Googly
+class Closure
- # Although Googlyscript can run as an app or in a cascade, most installations
- # will use this {Middleware} configured with Googly.script().
+ # Although Closure Script can run as an app or in a cascade, most installations
+ # will use this {Middleware} configured with Closure.add_source().
# @example config.ru
- # require 'googlyscript'
- # Googly.script '/myapp', '../src'
- # use Googly::Middleware, '../public/index.html'
+ # require 'closure'
+ # Closure.add_source '../src/myapp', '/myapp'
+ # use Closure::Middleware
class Middleware
# @param (String) home_page File to serve at the root. Handy for stand-alone projects.
- # You can use a template, even in non-source folders, by using the url extension
+ # You can use a closure-script, even in non-source folders, by using the url extension
# e.g. 'index.html' instead of the actual filename 'index.haml'.
def initialize(app, home_page=nil)
@app = app
- @server = Server.new(Googly.sources, home_page)
+ @server = Server.new(Closure.sources, home_page)
end
def call(env)
View
12 lib/googly/sass.rb → lib/closure/sass.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,18 +13,18 @@
# limitations under the License.
-class Googly
+class Closure
- # Googlyscript can easily respond to hundreds of requests
+ # Closure Script can easily respond to hundreds of requests
# per second, but not with Sass::Plugin::Rack in the stack.
# This change has been submitted to and accepted by the Sass team.
# Don't use Sass::Plugin::Rack until you are on a version that
- # has the dwell option. Use Googly::Sass in the meantime.
+ # has the dwell option. Use Closure::Sass in the meantime.
# @example config.ru
- # require 'googlyscript'
+ # require 'closure'
# require 'sass/plugin'
# Sass::Plugin.options[:template_location] = {in_dir => out_dir}
- # use Googly::Sass, 10
+ # use Closure::Sass, 10
class Sass
View
54 lib/googly/template.rb → lib/closure/script.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,33 +13,33 @@
# limitations under the License.
-class Googly
+class Closure
# @private
- class TemplateNotFoundError < StandardError
+ class ScriptNotFoundError < StandardError
end
# @private
- class TemplateCallStackTooDeepError < StandardError
+ class ScriptCallStackTooDeepError < StandardError
end
- # A Googly::Template instance is the context in which Ruby templates are rendered.
+ # A Closure::Script instance is the context in which scripts are rendered.
# It inherits everything from Rack::Request and supplies a response instance
# you can use for redirects, cookies, and other controller actions.
- class Template < Rack::Request
+ class Script < Rack::Request
def initialize(env, sources, filename)
super(env)
- @googly_template_render_stack = []
- @goog = Goog.new(env, sources, @googly_template_render_stack)
+ @closure_script_render_stack = []
+ @goog = Goog.new(env, sources, @closure_script_render_stack)
@response = original_response = Rack::Response.new
rendering = render(filename)
if @response == original_response and @response.empty?
@response.write rendering
end
- rescue TemplateCallStackTooDeepError, TemplateNotFoundError => e
+ rescue ScriptCallStackTooDeepError, ScriptNotFoundError => e
e.set_backtrace e.backtrace[1..-1]
- raise e if @googly_template_render_stack.size > 1
+ raise e if @closure_script_render_stack.size > 1
@response.status = 404
@response.write "404 Not Found\n"
@response.header["X-Cascade"] = "pass"
@@ -48,7 +48,7 @@ def initialize(env, sources, filename)
# After rendering, #finish will be sent to the client.
# If you replace the response or add to the response#body,
- # the template rendering will not be added.
+ # the script engine rendering will not be added.
# @return [Rack::Response]
attr_accessor :response
@@ -56,51 +56,51 @@ def initialize(env, sources, filename)
# @return [Goog]
attr_accessor :goog
- # Render another template. The same Googly::Template instance is
- # used for all internally rendered templates so you can pass
+ # Render another script. The same Closure::Script instance is
+ # used for all internally rendered scripts so you can pass
# information with instance variables.
# @example view_test.erb
# <%= render 'util/logger_popup' %>
- # @param (String) filename Relative to current template.
+ # @param (String) filename Relative to current script.
def render(filename)
- if @googly_template_render_stack.size > 100
+ if @closure_script_render_stack.size > 100
# Since nobody sane would recurse through here, this mainly
# finds a render self that you might get after a copy and paste
- raise TemplateCallStackTooDeepError
- elsif @googly_template_render_stack.size > 0
+ raise ScriptCallStackTooDeepError
+ elsif @closure_script_render_stack.size > 0
# Hooray for relative paths and easily movable files
- filename = File.expand_path(filename, File.dirname(@googly_template_render_stack.last))
+ filename = File.expand_path(filename, File.dirname(@closure_script_render_stack.last))
else
- # Underbar templates are partials by convention; keep them from rendering at root
+ # Underbar scripts are partials by convention; keep them from rendering at root
filename = File.expand_path(filename)
- raise TemplateNotFoundError if File.basename(filename) =~ /^_/
+ raise ScriptNotFoundError if File.basename(filename) =~ /^_/
end
ext = File.extname(filename)
files1 = [filename]
files1 << filename + '.html' if ext == ''
files1 << filename.sub(/.html$/,'') if ext == '.html'
files1.each do |filename1|
- Googly.config.engines.each do |ext, engine|
+ Closure.config.engines.each do |ext, engine|
files2 = [filename1+ext]
files2 << filename1.gsub(/.html$/, ext) if File.extname(filename1) == '.html'
- unless filename1 =~ /^_/ or @googly_template_render_stack.empty?
+ unless filename1 =~ /^_/ or @closure_script_render_stack.empty?
files2 = files2 + files2.collect {|f| "#{File.dirname(f)}/_#{File.basename(f)}"}
end
files2.each do |filename2|
if File.file?(filename2) and File.readable?(filename2)
- if @googly_template_render_stack.empty?
+ if @closure_script_render_stack.empty?
response.header["Content-Type"] = Rack::Mime.mime_type(File.extname(filename1), 'text/html')
end
@goog.add_dependency filename2
- @googly_template_render_stack.push filename2
+ @closure_script_render_stack.push filename2
result = engine.call self, filename2
- @googly_template_render_stack.pop
+ @closure_script_render_stack.pop
return result
end
end
end
end
- raise TemplateNotFoundError
+ raise ScriptNotFoundError
end
# Helper for URL escaping.
@@ -122,7 +122,7 @@ def escape_html(s)
# @param [String]
# @return [String]
def expand_path(s)
- File.expand_path(s, File.dirname(@googly_template_render_stack.last))
+ File.expand_path(s, File.dirname(@closure_script_render_stack.last))
end
# Helper to add file mtime as query for future-expiry caching.
View
23 lib/googly/server.rb → lib/closure/server.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,19 +13,19 @@
# limitations under the License.
-class Googly
+class Closure
- # The Googlyscript rack server. There is {Googly::Middleware} available too.
+ # The Closure Script rack server. There is {Closure::Middleware} available too.
# @example config.ru
- # require 'googlyscript'
- # sources = Googly::Sources.new
+ # require 'closure'
+ # sources = Closure::Sources.new
# sources.add '/myapp', '../src'
- # run Googly::Server.new sources
+ # run Closure::Server.new sources
class Server
# @param (Sources) sources An instance configured with your scripts.
- # @param (home_page) home_page Optional file or template to serve as root.
+ # @param (home_page) home_page Optional file or closure-script to serve as root.
def initialize(sources, home_page = nil)
@sources = sources
@home_page = home_page
@@ -40,25 +40,26 @@ def call(env)
# Stand-alone projects will find this useful
if @home_page and path_info == '/'
response = FileResponse.new(env, @home_page)
- response = Template.new(env, @sources, @home_page).response unless response.found?
+ response = Script.new(env, @sources, @home_page).response unless response.found?
return response.finish
end
# Usurp the deps.js in detected Closure Library
begin
if path_info == @sources.deps_js(env)
- return @sources.deps_response(env).finish
+ return @sources.deps_response(File.dirname(path_info), env).finish
end
rescue ClosureBaseNotFoundError
end
# Then check all the sources
- @sources.each do |path, dir|
+ @sources.each do |dir, path|
+ next unless path
if path_info =~ %r{^#{Regexp.escape(path)}(/.*|)$}
filename = File.join(dir, $1)
response = FileResponse.new(env, filename)
if !response.found? and File.extname(path_info) == ''
response = FileResponse.new(env, filename + '.html')
end
- response = Template.new(env, @sources, filename).response unless response.found?
+ response = Script.new(env, @sources, filename).response unless response.found?
return response.finish
end
end
View
74 lib/googly/sources.rb → lib/closure/sources.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
require 'pathname'
-class Googly
+class Closure
# @private
class MultipleClosureBaseError < StandardError
@@ -42,7 +42,7 @@ class Sources
BASE_JS_REGEX = /^var goog = goog \|\| \{\};/
# Flag env so that refresh is never run more than once per request
- ENV_FLAG = 'googly.sources_fresh'
+ ENV_FLAG = 'closure.sources_fresh'
# @param (Float) dwell in seconds.
def initialize(dwell = 1.0)
@@ -68,14 +68,16 @@ def initialize(dwell = 1.0)
# @param (String) path Where to mount on the http server.
# @param (String) directory Filesystem location of your sources.
# @return (Sources) self
- def add(path, directory)
- raise "path must start with /" unless path =~ %r{^/}
- path = '' if path == '/'
- raise "path must not end with /" if path =~ %r{/$}
- raise "path already exists" if @sources.find{|s|s[0]==path}
+ def add(directory, path=nil)
+ if path
+ raise "path must start with /" unless path =~ %r{^/}
+ path = '' if path == '/'
+ raise "path must not end with /" if path =~ %r{/$}
+ raise "path already exists" if @sources.find{|s|s[0]==path}
+ end
raise "directory already exists" if @sources.find{|s|s[1]==directory}
- @sources << [path, File.expand_path(directory)]
- @sources.sort! {|a,b| b[0] <=> a[0]}
+ @sources << [File.expand_path(directory), path]
+ @sources.sort! {|a,b| (b[1]||'') <=> (a[1]||'')}
self
end
@@ -83,13 +85,13 @@ def add(path, directory)
# Yields path and directory for each of the added sources.
# @yield (path, directory)
def each
- @sources.each { |path, directory| yield path, directory }
+ @sources.each { |directory, path| yield directory, path }
end
# Determine the path_info for where base_js is located.
# @return [String]
- def base_js(env)
+ def base_js(env={})
if (goog = @goog) and @last_been_run
return goog[:base_js]
end
@@ -103,10 +105,10 @@ def base_js(env)
# Determine the path_info for where deps_js is located.
# @return [String]
- def deps_js(env)
+ def deps_js(env={})
# Because Server uses this on every call, it's best to never lock.
# We grab a local goog so we don't need the lock if everything looks good.
- # This works because #refresh won't unset @goog while it's running anymore.
+ # This works because #refresh creates new @goog hashes instead of modifying.
if (goog = @goog) and @last_been_run
return goog[:deps_js]
end
@@ -120,18 +122,14 @@ def deps_js(env)
# Builds a Rack::Response to serve a dynamic deps.js
# @return (Rack::Response)
- def deps_response(env, base=nil)
+ def deps_response(base, env={})
@semaphore.synchronize do
refresh(env)
- unless base
- raise ClosureBaseNotFoundError unless @goog
- base = File.dirname(@goog[:base_js])
- end
base = Pathname.new(base)
unless @deps[base]
response = @deps[base] ||= Rack::Response.new
- response.write "// Deps by Googlyscript\n"
- @files.sort{|a,b|a[1][:path]<=>b[1][:path]}.each do |filename, dep|
+ response.write "// Dynamic Deps by Closure Script\n"
+ @files.reject{|a,b|!b[:path]}.sort{|a,b|a[1][:path]<=>b[1][:path]}.each do |filename, dep|
path = Pathname.new(dep[:path]).relative_path_from(base)
if path.to_s =~ /\.externs$/
dep[:provide].each do |dep_provide|
@@ -146,8 +144,16 @@ def deps_response(env, base=nil)
response.headers['Cache-Control'] = "max-age=#{[1,@dwell.floor].max}, private, must-revalidate"
response.headers['Last-Modified'] = Time.now.httpdate
end
+ templates_errors_js = Templates.errors_js env
mod_since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']) rescue nil
- if mod_since == Time.httpdate(@deps[base].headers['Last-Modified'])
+ if templates_errors_js
+ response = Rack::Response.new
+ response.headers['Content-Type'] = 'application/javascript'
+ response.headers['Cache-Control'] = "max-age=0, private, must-revalidate"
+ response.write @deps[base].body
+ response.write templates_errors_js
+ response
+ elsif mod_since == Time.httpdate(@deps[base].headers['Last-Modified'])
Rack::Response.new [], 304 # Not Modified
else
@deps[base]
@@ -159,7 +165,7 @@ def deps_response(env, base=nil)
# Calculate all required files for a namespace.
# @param (String) namespace
# @return (Array<String>) New Array of filenames.
- def files_for(env, namespace, filenames=nil)
+ def files_for(namespace, filenames=nil, env={})
ns = nil
@semaphore.synchronize do
refresh(env)
@@ -223,7 +229,7 @@ def refresh(env)
# Mark everything for deletion.
@files.each {|f, dep| dep[:not_found] = true}
# Scan filesystem for changes.
- @sources.each do |path, dir|
+ @sources.each do |dir, path|
dir_range = (dir.length..-1)
Dir.glob(File.join(dir,'**','*.{js,externs}')).each do |filename|
dep = (@files[filename] ||= {})
@@ -243,9 +249,13 @@ def refresh(env)
dep[:provide] = file.scan(PROVIDE_REGEX).flatten.uniq
old_dep_require = dep[:require]
dep[:require] = file.scan(REQUIRE_REGEX).flatten.uniq
- if !dep[:path]
+ if !dep.has_key? :path
raise unless filename.index(dir) == 0 # glob sanity
- dep[:path] = "#{path}#{filename.slice(dir_range)}"
+ if path
+ dep[:path] = "#{path}#{filename.slice(dir_range)}"
+ else
+ dep[:path] = nil
+ end
added_files << filename
elsif old_dep_provide != dep[:provide] or old_dep_require != dep[:require]
# We're changed only if the provides or requires changes.
@@ -258,16 +268,16 @@ def refresh(env)
if File.basename(filename) == 'base.js'
if file =~ BASE_JS_REGEX
multiple_base_js_failure if goog
- goog = {:base_filename => filename,
- :base_js => dep[:path],
- :deps_js => dep[:path].gsub(/base.js$/, 'deps.js')}
+ goog = {:base_filename => filename}
+ if dep[:path]
+ goog[:base_js] = dep[:path]
+ goog[:deps_js] = dep[:path].gsub(/base.js$/, 'deps.js')
+ end
end
end
end
end
end
-
-
end
# Sweep to delete not-found files.
@files.select{|f, dep| dep[:not_found]}.each do |filename, o|
@@ -277,7 +287,7 @@ def refresh(env)
# Decide if deps has changed.
if 0 < added_files.length + changed_files.length + deleted_files.length
@ns = nil
- STDERR.write "Googlyscript deps cache: #{added_files.length} added, #{changed_files.length} changed, #{deleted_files.length} deleted.\n"
+ STDERR.write "Closure Script deps cache: #{added_files.length} added, #{changed_files.length} changed, #{deleted_files.length} deleted.\n"
end
# Finish
@goog = goog
View
39 lib/googly/soy.rb → lib/closure/templates.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,20 +13,20 @@
# limitations under the License.
-class Googly
+class Closure
# The arguments to this middleware are the arguments you would use for
# SoyToJsSrcCompiler.jar (get them using: `java -jar SoyToJsSrcCompiler.jar`).
- # Googlyscript will expand filenames that appear to be globs,
+ # Closure Script will expand filenames that appear to be globs,
# as shown in the examples. You may still use static filenames.
# File modification times are remembered and compilation is run only
# when source changes are detected.
# @example config.ru
- # require 'googlyscript'
- # Googly.script '/soy', :soy_js
- # Googly.script '/app', 'app/javascripts'
- # Googly.script '/vendor', 'vendor/javascripts'
- # use Googly::Soy, %w{
+ # require 'closure'
+ # Closure.add_source :templates, '/soy'
+ # Closure.add_source 'app/javascripts', '/app'
+ # Closure.add_source 'vendor/javascripts', '/vendor'
+ # use Closure::Templates, %w{
# --shouldProvideRequireSoyNamespaces
# --cssHandlingScheme goog
# --shouldGenerateJsdoc
@@ -35,12 +35,23 @@ class Googly
# vendor/javascripts/**/*.soy
# }
- class Soy
+ class Templates
- # Logs in env['googly.soy.errors'] will persist until the errors are fixed.
+ # Logs in env[ENV_ERRORS] will persist until the errors are fixed.
# It will be nil when no errors or a string with the Java exception.
# It will be an array if you have multiple Soy middlewares running.
- ENV_ERRORS = 'googly.soy.errors'
+ ENV_ERRORS = 'closure.template.errors'
+
+ def self.errors_js(env)
+ errors = [env[ENV_ERRORS]].flatten.compact
+ return nil if errors.empty?
+ out = 'try{console.error('
+ out += "'Closure Templates: #{errors.size} error(s)', "
+ out += '"\n\n", '
+ out += errors.join("\n").dump
+ out += ')}catch(err){}'
+ out
+ end
# @param app [#call] The Rack application
# @param args [Array] Arguments for SoyToJsSrcCompiler.jar. Supports globbing.
@@ -63,7 +74,7 @@ def initialize(app, args, dwell = 1.0)
# @return (Array)[status, headers, body]
def call(env)
# This lock will block all other threads until soy is compiled
- # (it is not to synchronize globals like in Googly::Sources)
+ # (it is not to synchronize globals like in Closure::Sources)
@semaphore.synchronize do
if Time.now.to_f > @check_after
args = @args.dup
@@ -110,11 +121,11 @@ def call(env)
if !compiled or @errors
java_opts = args.collect{|a|a.to_s.dump}.join(', ')
puts "compiling soy: #{java_opts}"
- out, err = Googly.java("Googly.compile_soy_to_js_src(new String[]{#{java_opts}});")
+ out, err = Closure.java("ClosureScript.compile_soy_to_js_src(new String[]{#{java_opts}});")
if err.empty?
@errors = nil
else
- # Remove confusing "Googly.compile_soy_to_js_src" message
+ # Remove confusing "ClosureScript.compile_soy_to_js_src" message
err.sub! /\A^.*$\n^.*$\n/, ''
puts err
@errors = err
View
6 lib/googly/version.rb → lib/closure/version.rb
@@ -1,4 +1,4 @@
-# Copyright 2010 The Googlyscript Authors
+# Copyright 2011 The Closure Script Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
# limitations under the License.
-class Googly
- # The first two numerics are the Googlyscript major and minor version.
+class Closure
+ # The first two numerics are the Closure Script major and minor version.
# The third numeric is the Closure Library version.
VERSION = "1.1.620.pre"
end
View
BIN  lib/googly.jar
Binary file not shown
View
161 lib/googly/compilation.rb
@@ -1,161 +0,0 @@
-# Copyright 2010 The Googlyscript Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class Googly
-
- class Compilation
-
- # Java won't let you change working directories and the Closure Compiler
- # doesn't allow setting a base path. No problem, we can do it.
-
- # These are filename options and will be expanded to a new base.
- # If supplied as arguments, output options are available as instance
- # variables and attributes that have been expanded to the new base.
- OUTPUT_OPTIONS = %w{
- --create_source_map
- --js_output_file
- --output_manifest
- --property_map_output_file
- --variable_map_output_file
- }
-
- # These are filename options and will be expanded to a new base.
- # These will have their modifification times checked against js_output_file.
- INPUT_OPTIONS = %w{
- --js
- --externs
- --property_map_input_file
- --variable_map_input_file
- }
-
- # @param (Hash) env Rack environment. If you want the response to be cachable.
- def initialize(env={})
- @env = env
- end
-
-
- # @param (Array) args Arguments for the compiler.
- # @param (String) base All filenames will be expanded to this location.
- # @param (Array) dependencies Any other files to check mtime on, like makefiles.
- def compile_js(args, base, dependencies = [])
- args = Array.new args
- files = []
- # Scan to expand paths and extend self with output options
- args_index = 0
- while args_index < args.length
- option, value = args[args_index, 2]
- if INPUT_OPTIONS.include?(option)
- files << args[args_index+1] = File.expand_path(value, base)
- end
- if OUTPUT_OPTIONS.include?(option)
- var_name = option.sub(/^--/, '')
- instance_variable_set "@#{var_name}", args[args_index+1] = File.expand_path(value, base)
- eval "def self.#{var_name}; @#{var_name}; end"
- end
- args_index = args_index + 2
- end
- # We don't bother compiling if we can detect that no sources were modified
- if @js_output_file
- js_mtime = File.mtime @js_output_file rescue Errno::ENOENT
- compiled = !!File.size?(@js_output_file) # catches empty files too
- (files + dependencies).each do |filename|
- break unless compiled
- mtime = File.mtime filename
- compiled = false if !mtime or mtime > js_mtime
- end
- return if compiled
- File.unlink @js_output_file rescue Errno::ENOENT
- end
- # Do it; defensive .to_s.dump allows for bools and nums
- java_opts = args.collect{|a|a.to_s.dump}.join(', ')
- @stdout, @stderr = Googly.java("Googly.compile_js(new String[]{#{java_opts}});")
- end
-
- # Compilation state is an error
- def stderr=(e)
- @stdout = ''
- @stderr = e.to_s
- end
-
- # Allows http caching of the js_output_file for templates that want to do
- # their own error checking.
- # @example
- # <% @response = goog.compile(args).to_response %>
- # @return (#finish)
- def to_response
- if @js_output_file
- FileResponse.new @env, @js_output_file, 'application/javascript'
- else
- response = Rack::Response.new
- response.headers['Content-Type'] = 'application/javascript'
- response.headers["Cache-Control"] = "no-cache"
- response.write @stdout
- response
- end
- end
-
- # Checks the compilation status and will log to the javascript console.
- # This is the best technique for compiling unless you have different
- # needs for reporting errors.
- # @example
- # <% @response = goog.compile(args).to_response_with_console %>
- def to_response_with_console
- return to_response if !stderr or stderr.empty?
- response = Rack::Response.new
- response.headers['Content-Type'] = 'application/javascript'
- response.headers["Cache-Control"] = "no-cache"
- split_log = stderr.split("\n")
- if split_log.last =~ /^\d+ err/i
- error_message = split_log.pop
- else
- error_message = split_log.shift
- end
- error_log = "Closure Compiler: #{error_message}".dump
- error_log += ',"\n\n",' + split_log.join("\n").dump unless split_log.empty?
- if error_message =~ /^0 err/i
- response.write "try{console.log(#{error_log})}catch(err){};\n"
- else
- response.write "try{console.error(#{error_log})}catch(err){};\n"
- end
- response.write javascript
- response
- end
-
- # Always returns the compiled javascript, or possibly an empty string.
- # @example
- # <%= goog.compile(args) %>
- def javascript
- if @js_output_file
- File.read(@js_output_file) rescue ''
- else
- @stdout
- end
- end
- alias :to_s :javascript
-
- # Results from compiler.jar. If you didn't specify a --js_output_file
- # then this will be the compiled script. Otherwise, it's usually empty
- # but may contain output depending on the arguments.
- # If nil, compilation was skipped because js_output_file was up to date.
- attr_reader :stdout
-
- # Results from compiler.jar. The log, when there is one, is found here.
- # Use `--summary_detail_level 3` to see log when no errors or warnings.
- # If nil, compilation was skipped because js_output_file was up to date.
- attr_reader :stderr
-
- end
-
-end
View
3  lib/googlyscript.rb
@@ -1,3 +0,0 @@
-googly_lib_path = File.expand_path(File.dirname(__FILE__))
-$LOAD_PATH.unshift(googly_lib_path) if !$LOAD_PATH.include?(googly_lib_path)
-require 'googly'
View
32 scripts/demos/compile.js.erb
@@ -1,24 +1,8 @@
-<%
-# This template demonstrates how to get at the compiler logs.
-# You will see the log on the browser console any time the
-# compiler is run and there is an error or warning.
-# Use `--summary_detail_level 3` if you want to see a log
-# on all successful compilations (no errors or warnings).
-# If there's no log to display, a cachable file response is used.
-# This is just an example to get you started. There are certainly
-# more elegant ways to display a log and you could easily save
-# it to the filesystem if you wanted to show it every time.
-
-soy_errors = [env[Soy::ENV_ERRORS]].flatten.compact
-if !soy_errors.empty? -%>
-try{console.error('Soy Compiler: <%= soy_errors.size %> error(s)', "\n\n", <%= soy_errors.join("\n").dump %>)}catch(err){}
-<% else
- @response = goog.compile(%w{
- --compilation_level ADVANCED_OPTIMIZATIONS
- --js_output_file compile.out
- --summary_detail_level 3
- --define goog.DEBUG=false
- --warning_level VERBOSE
- --ns googly.demos.compiler
- }).to_response_with_console
-end -%>
+<% @response = goog.compile(%w{
+ --compilation_level ADVANCED_OPTIMIZATIONS
+ --js_output_file compile.out
+ --summary_detail_level 3
+ --define goog.DEBUG=false
+ --warning_level VERBOSE
+ --ns googly.demos.compiler
+}).to_response_with_console -%>
View
4 scripts/demos/compiler.js
@@ -6,3 +6,7 @@ googly.demos.compiler = function() {
}
goog.exportProperty(window, 'run_test', googly.demos.compiler);
+
+var f= function(){
+ this.f = 1;
+}
View
1  scripts/demos/helloworld.haml
@@ -1,7 +1,6 @@
!!!
%html
%head
- %title The Hello World of Closure Templates
%script{:src => goog.base_js}
:javascript
goog.require('googly.demos.soy.helloworld');
View
4 scripts/demos/index.haml
@@ -1,9 +1,9 @@
!!!
%html
%head
- %title Googlyscript Demos
+ %title Closure Script Demos
%body
- %h1 Googlyscript
+ %h1 Closure Script Demos
%ul
%li
%a(href='compiler') Require Test
View
9 scripts/demos/rails_ujs.haml
@@ -3,12 +3,9 @@
%head
%meta(name="csrf-param" content="authenticity_token")
%meta(name="csrf-token" content="cf50faa3fe97702ca1ae&lt;=?")
- - if params.has_key? 'build'
- %script{:src => 'rails_ujs.js'}
- - else
- %script{:src => goog.base_js}
- :javascript
- goog.require('googly.rails.ujs');
+ %script{:src => goog.base_js}
+ :javascript
+ goog.require('rails.ujs');
%body
%ul
%li
View
17 scripts/demos/rails_ujs.js.erb
@@ -1,17 +0,0 @@
-<%
-comp = goog.compile(%w{
- --compilation_level ADVANCED_OPTIMIZATIONS
- --js_output_file ../dist/rails_ujs.js
- --summary_detail_level 3
- --define goog.DEBUG=false
- --ns googly.rails.ujs
-})
-if !comp.stderr or comp.stderr.empty?
- @response = comp.to_response
-else -%>
-<% err_str = comp.stderr.split("\n").last; if err_str.to_i > 0 -%>
-try{console.error(<%= ('Closure Compiler: '+err_str).dump %>)}catch(err){}
-<% end -%>
-try{console.log(<%= comp.stderr.dump %>)}catch(err){}
-<%= comp %>
-<% end -%>
View
45 scripts/dist/rails_ujs.js
@@ -1,45 +0,0 @@
-var h=true,i=null,j=false,l,aa=aa||{},q=this;function ba(a,b){for(var c=a.split("."),d=b||q,f;f=c.shift();)if(d[f])d=d[f];else return i;return d}function r(){}
-function s(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array||!(a instanceof Object)&&Object.prototype.toString.call(a)=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(!(a instanceof Object)&&(Object.prototype.toString.call(a)=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call")))return"function"}else return"null";
-else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function ca(a){var b=s(a);return b=="array"||b=="object"&&typeof a.length=="number"}function t(a){return typeof a=="string"}function da(a){return s(a)=="function"}function ea(a){a=s(a);return a=="object"||a=="array"||a=="function"}function v(a){return a[fa]||(a[fa]=++ga)}var fa="closure_uid_"+Math.floor(Math.random()*2147483648).toString(36),ga=0;
-function ha(a,b){var c=b||q;if(arguments.length>2){var d=Array.prototype.slice.call(arguments,2);return function(){var f=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(f,d);return a.apply(c,f)}}else return function(){return a.apply(c,arguments)}}var ia=Date.now||function(){return+new Date};function x(a,b){function c(){}c.prototype=b.prototype;a.i=b.prototype;a.prototype=new c};function y(a,b){if(b)return a.replace(ja,"&amp;").replace(ka,"&lt;").replace(la,"&gt;").replace(ma,"&quot;");else{if(!na.test(a))return a;if(a.indexOf("&")!=-1)a=a.replace(ja,"&amp;");if(a.indexOf("<")!=-1)a=a.replace(ka,"&lt;");if(a.indexOf(">")!=-1)a=a.replace(la,"&gt;");if(a.indexOf('"')!=-1)a=a.replace(ma,"&quot;");return a}}var ja=/&/g,ka=/</g,la=/>/g,ma=/\"/g,na=/[&<>\"]/;
-function oa(a,b){for(var c=0,d=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),f=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),e=Math.max(d.length,f.length),g=0;c==0&&g<e;g++){var k=d[g]||"",m=f[g]||"",n=RegExp("(\\d*)(\\D*)","g"),w=RegExp("(\\d*)(\\D*)","g");do{var p=n.exec(k)||["","",""],o=w.exec(m)||["","",""];if(p[0].length==0&&o[0].length==0)break;c=pa(p[1].length==0?0:parseInt(p[1],10),o[1].length==0?0:parseInt(o[1],10))||pa(p[2].length==0,o[2].length==0)||pa(p[2],o[2])}while(c==
-0)}return c}function pa(a,b){if(a<b)return-1;else if(a>b)return 1;return 0};var z=Array.prototype,A=z.indexOf?function(a,b,c){return z.indexOf.call(a,b,c)}:function(a,b,c){c=c==i?0:c<0?Math.max(0,a.length+c):c;if(t(a)){if(!t(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},B=z.forEach?function(a,b,c){z.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,f=t(a)?a.split(""):a,e=0;e<d;e++)e in f&&b.call(c,f[e],e,a)};function qa(a,b){var c=A(a,b),d;if(d=c>=0)z.splice.call(a,c,1);return d}
-function ra(){return z.concat.apply(z,arguments)}function sa(a){if(s(a)=="array")return ra(a);else{for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b}}function ta(a,b,c){return arguments.length<=2?z.slice.call(a,b):z.slice.call(a,b,c)};var C,ua,va,wa;function xa(){return q.navigator?q.navigator.userAgent:i}wa=va=ua=C=j;var ya;if(ya=xa()){var za=q.navigator;C=ya.indexOf("Opera")==0;ua=!C&&ya.indexOf("MSIE")!=-1;va=!C&&ya.indexOf("WebKit")!=-1;wa=!C&&!va&&za.product=="Gecko"}var D=ua,Aa=wa,Ba=va,Ca=q.navigator,Da=(Ca&&Ca.platform||"").indexOf("Mac")!=-1,Ea;
-a:{var Fa="",E;if(C&&q.opera){var Ga=q.opera.version;Fa=typeof Ga=="function"?Ga():Ga}else{if(Aa)E=/rv\:([^\);]+)(\)|;)/;else if(D)E=/MSIE\s+([^\);]+)(\)|;)/;else if(Ba)E=/WebKit\/(\S+)/;if(E){var Ha=E.exec(xa());Fa=Ha?Ha[1]:""}}if(D){var Ia,Ja=q.document;Ia=Ja?Ja.documentMode:undefined;if(Ia>parseFloat(Fa)){Ea=String(Ia);break a}}Ea=Fa}var Ka={};function F(a){return Ka[a]||(Ka[a]=oa(Ea,a)>=0)};var La;!D||F("9");var Ma=D&&!F("8");function G(){}G.prototype.W=j;G.prototype.A=function(){if(!this.W){this.W=h;this.f()}};G.prototype.f=function(){};function H(a,b){this.type=a;this.currentTarget=this.target=b}x(H,G);l=H.prototype;l.f=function(){delete this.type;delete this.target;delete this.currentTarget};l.m=j;l.w=h;l.stopPropagation=function(){this.m=h};l.preventDefault=function(){this.w=j};function I(a,b){a&&this.F(a,b)}x(I,H);l=I.prototype;l.target=i;l.relatedTarget=i;l.offsetX=0;l.offsetY=0;l.clientX=0;l.clientY=0;l.screenX=0;l.screenY=0;l.button=0;l.keyCode=0;l.charCode=0;l.ctrlKey=j;l.altKey=j;l.shiftKey=j;l.metaKey=j;l.ka=j;l.o=i;
-l.F=function(a,b){var c=this.type=a.type;this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(Aa)try{d=d.nodeName&&d}catch(f){d=i}}else if(c=="mouseover")d=a.fromElement;else if(c=="mouseout")d=a.toElement;this.relatedTarget=d;this.offsetX=a.offsetX!==undefined?a.offsetX:a.layerX;this.offsetY=a.offsetY!==undefined?a.offsetY:a.layerY;this.clientX=a.clientX!==undefined?a.clientX:a.pageX;this.clientY=a.clientY!==undefined?a.clientY:a.pageY;this.screenX=a.screenX||0;
-this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||(c=="keypress"?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.ka=Da?a.metaKey:a.ctrlKey;this.o=a;delete this.w;delete this.m};l.stopPropagation=function(){I.i.stopPropagation.call(this);if(this.o.stopPropagation)this.o.stopPropagation();else this.o.cancelBubble=h};
-l.preventDefault=function(){I.i.preventDefault.call(this);var a=this.o;if(a.preventDefault)a.preventDefault();else{a.returnValue=j;if(Ma)try{if(a.ctrlKey||a.keyCode>=112&&a.keyCode<=123)a.keyCode=-1}catch(b){}}};l.f=function(){I.i.f.call(this);this.relatedTarget=this.currentTarget=this.target=this.o=i};function Na(){}var Oa=0;l=Na.prototype;l.key=0;l.p=j;l.T=j;l.F=function(a,b,c,d,f,e){if(da(a))this.$=h;else if(a&&a.handleEvent&&da(a.handleEvent))this.$=j;else throw Error("Invalid listener argument");this.u=a;this.fa=b;this.src=c;this.type=d;this.capture=!!f;this.P=e;this.T=j;this.key=++Oa;this.p=j};l.handleEvent=function(a){if(this.$)return this.u.call(this.P||this.src,a);return this.u.handleEvent.call(this.u,a)};function J(a,b){this.ca=b;this.k=[];if(a>this.ca)throw Error("[goog.structs.SimplePool] Initial cannot be greater than max");for(var c=0;c<a;c++)this.k.push(this.g?this.g():{})}x(J,G);J.prototype.g=i;J.prototype.V=i;function K(a){if(a.k.length)return a.k.pop();return a.g?a.g():{}}function L(a,b){a.k.length<a.ca?a.k.push(b):Pa(a,b)}function Pa(a,b){if(a.V)a.V(b);else if(ea(b))if(da(b.A))b.A();else for(var c in b)delete b[c]}
-J.prototype.f=function(){J.i.f.call(this);for(var a=this.k;a.length;)Pa(this,a.pop());delete this.k};var Qa;var Ra=(Qa="ScriptEngine"in q&&q.ScriptEngine()=="JScript")?q.ScriptEngineMajorVersion()+"."+q.ScriptEngineMinorVersion()+"."+q.ScriptEngineBuildVersion():"0";var Sa,Ta,M,Ua,Va,Wa,Xa,Ya,Za,$a,ab;
-(function(){function a(){return{c:0,e:0}}function b(){return[]}function c(){function o(u){return g.call(o.src,o.key,u)}return o}function d(){return new Na}function f(){return new I}var e=Qa&&!(oa(Ra,"5.7")>=0),g;Wa=function(o){g=o};if(e){Sa=function(){return K(k)};Ta=function(o){L(k,o)};M=function(){return K(m)};Ua=function(o){L(m,o)};Va=function(){return K(n)};Xa=function(){L(n,c())};Ya=function(){return K(w)};Za=function(o){L(w,o)};$a=function(){return K(p)};ab=function(o){L(p,o)};var k=new J(0,
-600);k.g=a;var m=new J(0,600);m.g=b;var n=new J(0,600);n.g=c;var w=new J(0,600);w.g=d;var p=new J(0,600);p.g=f}else{Sa=a;Ta=r;M=b;Ua=r;Va=c;Xa=r;Ya=d;Za=r;$a=f;ab=r}})();function bb(a,b,c){for(var d in a)b.call(c,a[d],d,a)}function cb(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function db(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}var eb=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"];function fb(a){for(var b,c,d=1;d<arguments.length;d++){c=arguments[d];for(b in c)a[b]=c[b];for(var f=0;f<eb.length;f++){b=eb[f];if(Object.prototype.hasOwnProperty.call(c,b))a[b]=c[b]}}};var N={},O={},P={},gb={};
-function Q(a,b,c,d,f){if(b)if(s(b)=="array"){for(var e=0;e<b.length;e++)Q(a,b[e],c,d,f);return i}else{d=!!d;var g=O;b in g||(g[b]=Sa());g=g[b];if(!(d in g)){g[d]=Sa();g.c++}g=g[d];var k=v(a),m;g.e++;if(g[k]){m=g[k];for(e=0;e<m.length;e++){g=m[e];if(g.u==c&&g.P==f){if(g.p)break;return m[e].key}}}else{m=g[k]=M();g.c++}e=Va();e.src=a;g=Ya();g.F(c,e,a,b,d,f);c=g.key;e.key=c;m.push(g);N[c]=g;P[k]||(P[k]=M());P[k].push(g);if(a.addEventListener){if(a==q||!a.U)a.addEventListener(b,e,d)}else a.attachEvent(hb(b),
-e);return c}else throw Error("Invalid event type");}function ib(a,b,c,d,f){if(s(b)=="array"){for(var e=0;e<b.length;e++)ib(a,b[e],c,d,f);return i}d=!!d;a:{e=O;if(b in e){e=e[b];if(d in e){e=e[d];a=v(a);if(e[a]){a=e[a];break a}}}a=i}if(!a)return j;for(e=0;e<a.length;e++)if(a[e].u==c&&a[e].capture==d&&a[e].P==f)return jb(a[e].key);return j}
-function jb(a){if(!N[a])return j;var b=N[a];if(b.p)return j;var c=b.src,d=b.type,f=b.fa,e=b.capture;if(c.removeEventListener){if(c==q||!c.U)c.removeEventListener(d,f,e)}else c.detachEvent&&c.detachEvent(hb(d),f);c=v(c);f=O[d][e][c];if(P[c]){var g=P[c];qa(g,b);g.length==0&&delete P[c]}b.p=h;f.da=h;kb(d,e,c,f);delete N[a];return h}
-function kb(a,b,c,d){if(!d.G)if(d.da){for(var f=0,e=0;f<d.length;f++)if(d[f].p){var g=d[f].fa;g.src=i;Xa(g);Za(d[f])}else{if(f!=e)d[e]=d[f];e++}d.length=e;d.da=j;if(e==0){Ua(d);delete O[a][b][c];O[a][b].c--;if(O[a][b].c==0){Ta(O[a][b]);delete O[a][b];O[a].c--}if(O[a].c==0){Ta(O[a]);delete O[a]}}}}
-function lb(a,b,c){var d=0,f=a==i,e=b==i,g=c==i;c=!!c;if(f)bb(P,function(m){for(var n=m.length-1;n>=0;n--){var w=m[n];if((e||b==w.type)&&(g||c==w.capture)){jb(w.key);d++}}});else{a=v(a);if(P[a]){a=P[a];for(f=a.length-1;f>=0;f--){var k=a[f];if((e||b==k.type)&&(g||c==k.capture)){jb(k.key);d++}}}}return d}function hb(a){if(a in gb)return gb[a];return gb[a]="on"+a}
-function R(a,b,c,d,f){var e=1;b=v(b);if(a[b]){a.e--;a=a[b];if(a.G)a.G++;else a.G=1;try{for(var g=a.length,k=0;k<g;k++){var m=a[k];if(m&&!m.p)e&=mb(m,f)!==j}}finally{a.G--;kb(c,d,b,a)}}return Boolean(e)}function mb(a,b){var c=a.handleEvent(b);a.T&&jb(a.key);return c}
-function nb(a,b){if(t(b))b=new H(b,a);else if(b instanceof H)b.target=b.target||a;else{var c=b;b=new H(b.type,a);fb(b,c)}c=1;var d,f=b.type,e=O;if(!(f in e))return h;e=e[f];f=h in e;var g;if(f){d=[];for(g=a;g;g=g.S)d.push(g);g=e[h];g.e=g.c;for(var k=d.length-1;!b.m&&k>=0&&g.e;k--){b.currentTarget=d[k];c&=R(g,d[k],b.type,h,b)&&b.w!=j}}if(j in e){g=e[j];g.e=g.c;if(f)for(k=0;!b.m&&k<d.length&&g.e;k++){b.currentTarget=d[k];c&=R(g,d[k],b.type,j,b)&&b.w!=j}else for(d=a;!b.m&&d&&g.e;d=d.S){b.currentTarget=
-d;c&=R(g,d,b.type,j,b)&&b.w!=j}}return Boolean(c)}
-Wa(function(a,b){if(!N[a])return h;var c=N[a],d=c.type,f=O;if(!(d in f))return h;f=f[d];var e,g;if(La===undefined)La=D&&!q.addEventListener;if(La){e=b||ba("window.event");var k=h in f,m=j in f;if(k){if(e.keyCode<0||e.returnValue!=undefined)return h;a:{var n=j;if(e.keyCode==0)try{e.keyCode=-1;break a}catch(w){n=h}if(n||e.returnValue==undefined)e.returnValue=h}}n=$a();n.F(e,this);e=h;try{if(k){for(var p=M(),o=n.currentTarget;o;o=o.parentNode)p.push(o);g=f[h];g.e=g.c;for(var u=p.length-1;!n.m&&u>=0&&
-g.e;u--){n.currentTarget=p[u];e&=R(g,p[u],d,h,n)}if(m){g=f[j];g.e=g.c;for(u=0;!n.m&&u<p.length&&g.e;u++){n.currentTarget=p[u];e&=R(g,p[u],d,j,n)}}}else e=mb(c,n)}finally{if(p){p.length=0;Ua(p)}n.A();ab(n)}return e}d=new I(b,this);try{e=mb(c,d)}finally{d.A()}return e});var ob=!D||F("9");D&&F("9");function pb(a){var b;b=(b=a.className)&&typeof b.split=="function"?b.split(/\s+/):[];var c;c=ta(arguments,1);for(var d=0,f=0;f<c.length;f++)if(!(A(b,c[f])>=0)){b.push(c[f]);d++}c=d==c.length;a.className=b.join(" ");return c};function qb(a,b,c,d){a=d||a;b=b&&b!="*"?b.toUpperCase():"";if(a.querySelectorAll&&a.querySelector&&(!Ba||document.compatMode=="CSS1Compat"||F("528"))&&(b||c))return a.querySelectorAll(b+(c?"."+c:""));if(c&&a.getElementsByClassName){a=a.getElementsByClassName(c);if(b){d={};for(var f=0,e=0,g;g=a[e];e++)if(b==g.nodeName)d[f++]=g;d.length=f;return d}else return a}a=a.getElementsByTagName(b||"*");if(c){d={};for(e=f=0;g=a[e];e++){b=g.className;if(typeof b.split=="function"&&A(b.split(/\s+/),c)>=0)d[f++]=
-g}d.length=f;return d}else return a}function rb(a,b){bb(b,function(c,d){if(d=="style")a.style.cssText=c;else if(d=="class")a.className=c;else if(d=="for")a.htmlFor=c;else if(d in sb)a.setAttribute(sb[d],c);else a[d]=c})}var sb={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",type:"type"};
-function tb(){var a=arguments,b=a[0],c=a[1];if(!ob&&c&&(c.name||c.type)){b=["<",b];c.name&&b.push(' name="',y(c.name),'"');if(c.type){b.push(' type="',y(c.type),'"');var d={};fb(d,c);c=d;delete c.type}b.push(">");b=b.join("")}b=document.createElement(b);if(c)if(t(c))b.className=c;else s(c)=="array"?pb.apply(i,[b].concat(c)):rb(b,c);a.length>2&&ub(document,b,a,2);return b}
-function ub(a,b,c,d){function f(g){if(g)b.appendChild(t(g)?a.createTextNode(g):g)}for(d=d;d<c.length;d++){var e=c[d];ca(e)&&!(ea(e)&&e.nodeType>0)?B(vb(e)?sa(e):e,f):f(e)}}function wb(a,b){a.appendChild(b)}function vb(a){if(a&&typeof a.length=="number")if(ea(a))return typeof a.item=="function"||typeof a.item=="string";else if(da(a))return typeof a.item=="function";return j};function xb(a){if(typeof a.C=="function")return a.C();if(t(a))return a.split("");if(ca(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return cb(a)}function yb(a,b,c){if(typeof a.forEach=="function")a.forEach(b,c);else if(ca(a)||t(a))B(a,b,c);else{var d;if(typeof a.O=="function")d=a.O();else if(typeof a.C!="function")if(ca(a)||t(a)){d=[];for(var f=a.length,e=0;e<f;e++)d.push(e);d=d}else d=db(a);else d=void 0;f=xb(a);e=f.length;for(var g=0;g<e;g++)b.call(c,f[g],d&&d[g],a)}};function S(a){this.v={};this.d=[];var b=arguments.length;if(b>1){if(b%2)throw Error("Uneven number of arguments");for(var c=0;c<b;c+=2)zb(this,arguments[c],arguments[c+1])}else if(a){if(a instanceof S){b=a.O();c=a.C()}else{b=db(a);c=cb(a)}for(var d=0;d<b.length;d++)zb(this,b[d],c[d])}}S.prototype.c=0;S.prototype.na=0;S.prototype.C=function(){Ab(this);for(var a=[],b=0;b<this.d.length;b++)a.push(this.v[this.d[b]]);return a};S.prototype.O=function(){Ab(this);return this.d.concat()};
-function Ab(a){if(a.c!=a.d.length){for(var b=0,c=0;b<a.d.length;){var d=a.d[b];if(Object.prototype.hasOwnProperty.call(a.v,d))a.d[c++]=d;b++}a.d.length=c}if(a.c!=a.d.length){var f={};for(c=b=0;b<a.d.length;){d=a.d[b];if(!Object.prototype.hasOwnProperty.call(f,d)){a.d[c++]=d;f[d]=1}b++}a.d.length=c}}function zb(a,b,c){if(!Object.prototype.hasOwnProperty.call(a.v,b)){a.c++;a.d.push(b);a.na++}a.v[b]=c};function Bb(a){for(var b=[],c=Cb,d=a.elements,f,e=0;f=d[e];e++)if(!(f.disabled||f.tagName.toLowerCase()=="fieldset")){var g=f.name;switch(f.type.toLowerCase()){case "file":case "submit":case "reset":case "button":break;case "select-multiple":f=Db(f);if(f!=i)for(var k,m=0;k=f[m];m++)c(b,g,k);break;default:k=Db(f);k!=i&&c(b,g,k)}}d=a.getElementsByTagName("input");for(e=0;f=d[e];e++)if(f.form==a&&f.type.toLowerCase()=="image"){g=f.name;c(b,g,f.value);c(b,g+".x","0");c(b,g+".y","0")}return b.join("&")}
-function Cb(a,b,c){a.push(encodeURIComponent(b)+"="+encodeURIComponent(c))}function Db(a){var b=a.type;if(b===undefined)return i;switch(b.toLowerCase()){case "checkbox":case "radio":return a.checked?a.value:i;case "select-one":b=a.selectedIndex;return b>=0?a.options[b].value:i;case "select-multiple":b=[];for(var c,d=0;c=a.options[d];d++)c.selected&&b.push(c.value);return b.length?b:i;default:return a.value!==undefined?a.value:i}};function Eb(){}x(Eb,G);l=Eb.prototype;l.U=h;l.S=i;l.addEventListener=function(a,b,c,d){Q(this,a,b,c,d)};l.removeEventListener=function(a,b,c,d){ib(this,a,b,c,d)};l.dispatchEvent=function(a){return nb(this,a)};l.f=function(){Eb.i.f.call(this);lb(this);this.S=i};var Fb=q.window;function Gb(a){return Hb(a||arguments.callee.caller,[])}
-function Hb(a,b){var c=[];if(A(b,a)>=0)c.push("[...circular reference...]");else if(a&&b.length<50){c.push(Ib(a)+"(");for(var d=a.arguments,f=0;f<d.length;f++){f>0&&c.push(", ");var e;e=d[f];switch(typeof e){case "object":e=e?"object":"null";break;case "string":e=e;break;case "number":e=String(e);break;case "boolean":e=e?"true":"false";break;case "function":e=(e=Ib(e))?e:"[fn]";break;default:e=typeof e}if(e.length>40)e=e.substr(0,40)+"...";c.push(e)}b.push(a);c.push(")\n");try{c.push(Hb(a.caller,
-b))}catch(g){c.push("[exception trying to get caller]\n")}}else a?c.push("[...long stack...]"):c.push("[end]");return c.join("")}function Ib(a){a=String(a);if(!Jb[a]){var b=/function ([^\(]+)/.exec(a);Jb[a]=b?b[1]:"[Anonymous]"}return Jb[a]}var Jb={};function T(a,b,c,d,f){this.reset(a,b,c,d,f)}T.prototype.la=0;T.prototype.Y=i;T.prototype.X=i;var Kb=0;T.prototype.reset=function(a,b,c,d,f){this.la=typeof f=="number"?f:Kb++;this.ra=d||ia();this.t=a;this.qa=b;this.pa=c;delete this.Y;delete this.X};T.prototype.ga=function(a){this.t=a};function U(a){this.ia=a}U.prototype.H=i;U.prototype.t=i;U.prototype.M=i;U.prototype.Z=i;function V(a,b){this.name=a;this.value=b}V.prototype.toString=function(){return this.name};var Lb=new V("SEVERE",1E3),Mb=new V("WARNING",900),Nb=new V("CONFIG",700),Ob=new V("FINE",500),Pb=new V("FINEST",300);U.prototype.ga=function(a){this.t=a};function Qb(a){if(a.t)return a.t;if(a.H)return Qb(a.H);return i}
-U.prototype.log=function(a,b,c){if(a.value>=Qb(this).value){a=this.ha(a,b,c);for(b=this;b;){c=b;var d=a;if(c.Z)for(var f=0,e=void 0;e=c.Z[f];f++)e(d);b=b.H}}};
-U.prototype.ha=function(a,b,c){var d=new T(a,String(b),this.ia);if(c){d.Y=c;var f;var e=arguments.callee.caller;try{var g,k=ba("window.location.href");g=typeof c=="string"?{message:c,name:"Unknown error",lineNumber:"Not available",fileName:k,stack:"Not available"}:!c.lineNumber||!c.fileName||!c.stack?{message:c.message,name:c.name,lineNumber:c.lineNumber||c.oa||"Not available",fileName:c.fileName||c.filename||c.sourceURL||k,stack:c.stack||"Not available"}:c;f="Message: "+y(g.message)+'\nUrl: <a href="view-source:'+
-g.fileName+'" target="_new">'+g.fileName+"</a>\nLine: "+g.lineNumber+"\n\nBrowser stack:\n"+y(g.stack+"-> ")+"[end]\n\nJS stack traversal:\n"+y(Gb(e)+"-> ")}catch(m){f="Exception trying to expose exception! You win, we lose. "+m}d.X=f}return d};function W(a,b,c){a.log(Ob,b,c)}var Rb={},Sb=i;function Tb(a){if(!Sb){Sb=new U("");Rb[""]=Sb;Sb.ga(Nb)}var b;if(!(b=Rb[a])){b=new U(a);var c=a.lastIndexOf("."),d=a.substr(c+1);c=Tb(a.substr(0,c));if(!c.M)c.M={};c.M[d]=b;b.H=c;b=Rb[a]=b}return b};function Ub(){}Ub.prototype.z=i;function Vb(){return Wb(X)}var X;function Xb(){}x(Xb,Ub);function Wb(a){return(a=Yb(a))?new ActiveXObject(a):new XMLHttpRequest}function Zb(a){var b={};if(Yb(a)){b[0]=h;b[1]=h}return b}Xb.prototype.Q=i;
-function Yb(a){if(!a.Q&&typeof XMLHttpRequest=="undefined"&&typeof ActiveXObject!="undefined"){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{new ActiveXObject(d);return a.Q=d}catch(f){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.Q}X=new Xb;function $b(){if(Aa){this.j={};this.L={};this.I=[]}}$b.prototype.b=Tb("goog.net.xhrMonitor");$b.prototype.B=Aa;function ac(a,b){if(a.B){var c=t(b)?b:ea(b)?v(b):"";a.b.log(Pb,"Pushing context: "+b+" ("+c+")",void 0);a.I.push(c)}}function bc(a){if(a.B){var b=a.I.pop();a.b.log(Pb,"Popping context: "+b,void 0);cc(a,b)}}function dc(a,b){if(a.B){var c=v(b);W(a.b,"Opening XHR : "+c);for(var d=0;d<a.I.length;d++){var f=a.I[d];ec(a,a.j,f,c);ec(a,a.L,c,f)}}}
-function cc(a,b){var c=a.L[b],d=a.j[b];if(c&&d){a.b.log(Pb,"Updating dependent contexts",void 0);B(c,function(f){B(d,function(e){ec(this,this.j,f,e);ec(this,this.L,e,f)},this)},a)}}function ec(a,b,c,d){b[c]||(b[c]=[]);A(b[c],d)>=0||b[c].push(d)}var Y=new $b;function Z(a){this.headers=new S;this.q=a||i}x(Z,Eb);l=Z.prototype;l.b=Tb("goog.net.XhrIo");l.h=j;l.a=i;l.K=i;l.ba="";l.aa="";l.r=0;l.s="";l.N=j;l.D=j;l.R=j;l.l=j;l.J=0;l.n=i;
-l.send=function(a,b,c,d){if(this.a)throw Error("[goog.net.XhrIo] Object is active with another request");b=b||"GET";this.ba=a;this.s="";this.r=0;this.aa=b;this.N=j;this.h=h;this.a=this.q?Wb(this.q):new Vb;this.K=this.q?this.q.z||(this.q.z=Zb(this.q)):X.z||(X.z=Zb(X));dc(Y,this.a);this.a.onreadystatechange=ha(this.ea,this);try{W(this.b,$(this,"Opening Xhr"));this.R=h;this.a.open(b,a,h);this.R=j}catch(f){W(this.b,$(this,"Error opening Xhr: "+f.message));fc(this,5,f);return}a=c||"";var e=new S(this.headers);
-d&&yb(d,function(k,m){zb(e,m,k)});b=="POST"&&!Object.prototype.hasOwnProperty.call(e.v,"Content-Type")&&zb(e,"Content-Type","application/x-www-form-urlencoded;charset=utf-8");yb(e,function(k,m){this.a.setRequestHeader(m,k)},this);try{if(this.n){Fb.clearTimeout(this.n);this.n=i}if(this.J>0){W(this.b,$(this,"Will abort after "+this.J+"ms if incomplete"));this.n=Fb.setTimeout(ha(this.ma,this),this.J)}W(this.b,$(this,"Sending request"));this.D=h;this.a.send(a);this.D=j}catch(g){W(this.b,$(this,"Send error: "+
-g.message));fc(this,5,g)}};l.dispatchEvent=function(a){if(this.a){ac(Y,this.a);try{return Z.i.dispatchEvent.call(this,a)}finally{bc(Y)}}else return Z.i.dispatchEvent.call(this,a)};l.ma=function(){if(typeof aa!="undefined")if(this.a){this.s="Timed out after "+this.J+"ms, aborting";this.r=8;W(this.b,$(this,this.s));this.dispatchEvent("timeout");this.abort(8)}};function fc(a,b,c){a.h=j;if(a.a){a.l=h;a.a.abort();a.l=j}a.s=c;a.r=b;gc(a);hc(a)}
-function gc(a){if(!a.N){a.N=h;a.dispatchEvent("complete");a.dispatchEvent("error")}}l.abort=function(a){if(this.a&&this.h){W(this.b,$(this,"Aborting"));this.h=j;this.l=h;this.a.abort();this.l=j;this.r=a||7;this.dispatchEvent("complete");this.dispatchEvent("abort");hc(this)}};l.f=function(){if(this.a){if(this.h){this.h=j;this.l=h;this.a.abort();this.l=j}hc(this,h)}Z.i.f.call(this)};l.ea=function(){!this.R&&!this.D&&!this.l?this.ja():ic(this)};l.ja=function(){ic(this)};
-function ic(a){if(a.h)if(typeof aa!="undefined")if(a.K[1]&&jc(a)==4&&kc(a)==2)W(a.b,$(a,"Local request error detected and ignored"));else if(a.D&&jc(a)==4)Fb.setTimeout(ha(a.ea,a),0);else{a.dispatchEvent("readystatechange");if(jc(a)==4){W(a.b,$(a,"Request complete"));a.h=j;if(lc(a)){a.dispatchEvent("complete");a.dispatchEvent("success")}else{a.r=6;var b;try{b=jc(a)>2?a.a.statusText:""}catch(c){W(a.b,"Can not get status: "+c.message);b=""}a.s=b+" ["+kc(a)+"]";gc(a)}hc(a)}}}
-function hc(a,b){if(a.a){var c=a.a,d=a.K[0]?r:i;a.a=i;a.K=i;if(a.n){Fb.clearTimeout(a.n);a.n=i}if(!b){ac(Y,c);a.dispatchEvent("ready");bc(Y)}if(Y.B){var f=v(c);W(Y.b,"Closing XHR : "+f);delete Y.L[f];for(var e in Y.j){qa(Y.j[e],f);Y.j[e].length==0&&delete Y.j[e]}}try{c.onreadystatechange=d}catch(g){a.b.log(Lb,"Problem encountered resetting onreadystatechange: "+g.message,void 0)}}}function lc(a){switch(kc(a)){case 0:case 200:case 204:case 304:return h;default:return j}}
-function jc(a){return a.a?a.a.readyState:0}function kc(a){try{return jc(a)>2?a.a.status:-1}catch(b){a.b.log(Mb,"Can not get status: "+b.message,void 0);return-1}}function $(a,b){return b+" ["+a.aa+" "+a.ba+" "+kc(a)+"]"};Q(document,"click",function(a){if(a.target.hasAttribute("data-confirm"))if(!confirm(a.target.getAttribute("data-confirm"))){a.preventDefault();a.stopPropagation()}},h);Q(document,"click",function(a){if(a.target.hasAttribute("data-remote")){a.preventDefault();mc(a.target)}else if(a.target.hasAttribute("data-method")){a.preventDefault();nc(a.target)}},j);Q(document,"submit",function(a){if(a.target.hasAttribute("data-remote")){a.preventDefault();mc(a.target)}},h);
-function mc(a){var b,c,d;if(a.nodeName=="FORM"){b=Bb(a);c=a.getAttribute("method")||"POST";d=a.getAttribute("action")}else{c=a.getAttribute("data-method")||"GET";d=a.getAttribute("href")}var f=new Z;f.onreadystatechange=function(){f.readyState==4&&nb(a,new H("ajax:complete"))};f.send(d,c.toUpperCase(),b);lc(f)?nb(a,new H("ajax:success")):nb(a,new H("ajax:failure"))}
-function nc(a){var b=a.getAttribute("data-method").toLowerCase(),c=a.getAttribute("href");c=tb("form",{method:"POST",action:c,style:"display: none;"});a.appendChild(c);b!=="post"&&wb(c,tb("input",{type:"hidden",name:"_method",value:b}));var d,f;B(qb(document,"meta",void 0,void 0),function(e){var g=e.getAttribute("name");if(g=="csrf-param")d=e.getAttribute("content");else if(g=="csrf-token")f=e.getAttribute("content")});d&&wb(c,tb("input",{type:"hidden",name:d,value:f}));c.submit()};
View
54 scripts/dist/rails/ujs.js → scripts/examples/rails/ujs.js
@@ -1,4 +1,44 @@
-goog.provide('googly.rails.ujs');
+// Copyright 2011 The Closure Script Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// AND/OR -- You may also choose to use the MIT license instead. The dual-licensing
+// intent is so that you may drop one if it doesn't fit your legal requirements.
+
+// The MIT License
+//
+// Copyright (c) 2011 The Closure Script Authors
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+goog.provide('rails.ujs');
goog.require('goog.events');
goog.require('goog.dom');
@@ -18,29 +58,29 @@ goog.events.listen(document, 'click', function(e) {
goog.events.listen(document, 'click', function(e) {
if (e.target.hasAttribute('data-remote')) {
e.preventDefault();
- googly.rails.ujs.handleRemote(e.target);
+ rails.ujs.handleRemote(e.target);
} else if (e.target.hasAttribute('data-method')) {
e.preventDefault();
- googly.rails.ujs.handleMethod(e.target);
+ rails.ujs.handleMethod(e.target);
}
}, false);
goog.events.listen(document, 'submit', function(e) {
if (e.target.hasAttribute('data-remote')) {
e.preventDefault();
- googly.rails.ujs.handleRemote(e.target);
+ rails.ujs.handleRemote(e.target);
}
}, true);
-googly.rails.ujs.dispatchEvent = function(el, type) {
+rails.ujs.dispatchEvent = function(el, type) {
var evObj = document.createEvent('Event');
evObj.initEvent(type, true, true);
el.dispatchEvent(evObj);
}
-googly.rails.ujs.handleRemote = function(el) {
+rails.ujs.handleRemote = function(el) {
var data, method, url;
if (el.nodeName == goog.dom.TagName.FORM) {
data = goog.dom.forms.getFormDataString(el)
@@ -65,7 +105,7 @@ googly.rails.ujs.handleRemote = function(el) {
}
-googly.rails.ujs.handleMethod = function(element) {
+rails.ujs.handleMethod = function(element) {
var method = element.getAttribute('data-method').toLowerCase();
var url = element.getAttribute('href');
var form = goog.dom.createDom('form', { method: "POST", action: url, style: "display: none;" })
View
10 scripts/index.haml
@@ -1,14 +1,14 @@
!!!
%html
%head
- %title Googlyscript Development Home
+ %title Closure Script Development Home
%link(rel="shortcut icon" href="/favicon.ico")
%body
- %h1 Googlyscript
+ %h1 Closure Script
%ul
%li
- %a(href='/docs/googly') Googlyscript Docs (YARD)
+ %a(href='/demos/index') Closure Script Demos
%li
- %a(href='/goog/demos/index') Closure Library Demos
+ %a(href='/docs/closure') Closure Script Docs (YARD)
%li
- %a(href='/demos/index') Googly Demos
+ %a(href='/goog/demos/index') Closure Library Demos
View
2  test/beanshell_test.rb
@@ -2,7 +2,7 @@
class BeanShellTest < Test::Unit::TestCase
- BEANSHELL = Googly::BeanShell.new
+ BEANSHELL = Closure::BeanShell.new
def test_basic_stdout
5.times do
View
17 test/server_test.rb
@@ -3,9 +3,9 @@
class ServerTest < Test::Unit::TestCase
def setup
- sources = Googly::Sources.new
- sources.add '/', File.join(Googly.base_path, 'scripts', 'fixtures')
- @request = Rack::MockRequest.new(Googly::Server.new(sources))
+ sources = Closure::Sources.new
+ sources.add File.join(Closure.base_path, 'scripts', 'fixtures'), '/'
+ @request = Rack::MockRequest.new(Closure::Server.new(sources))
end
def test_basics
@@ -17,7 +17,7 @@ def test_basics
assert_equal 'text/html', response.content_type, msg
# The string PASS is generated by Ruby from a partial
# (except route_html which simply has is hardcoded)
- # This will test integration with Googly::Template
+ # This will test integration with Closure::Script
assert response =~ /PASS/, msg
end
end
@@ -31,11 +31,11 @@ def test_static_of_template
# It should not have run as a template
assert !(response =~ /PASS/)
end
-
+
def test_file_not_found
assert @request.get("/nOT/Real.fILE").not_found?
end
-
+
def test_partials_not_found
# We can always get the raw source
assert @request.get("/_partial.haml").ok?
@@ -45,7 +45,7 @@ def test_partials_not_found
assert @request.get("/partial.html").not_found?
assert @request.get("/_partial.html").not_found?
end
-
+
def test_static_html_extension_magic
# The .html is always optional
assert @request.get("/html").ok?
@@ -62,7 +62,6 @@ def test_non_html_template_extension
response = @request.get("/route_js.js")
assert response.ok?
assert_equal 'application/javascript', response.content_type
- end
-
+ end
end
View
10 test/sources_test.rb
@@ -4,7 +4,7 @@
class SourcesTest < Test::Unit::TestCase
- CLOSURE_LIBRARY = File.join(Googly.base_path, 'closure-library')
+ CLOSURE_LIBRARY = File.join(Closure.base_path, 'closure-library')
NAMESPACES = ["goog.editor.Field", "goog.ds.JsonDataSource"]
FIELD_JS = File.join(CLOSURE_LIBRARY, 'closure', 'goog', 'editor', 'field.js')
@@ -14,10 +14,10 @@ class SourcesTest < Test::Unit::TestCase
CALCDEPS = File.join(CLOSURE_LIBRARY, 'closure', 'bin', 'calcdeps.py')
FILES = []
- sources = Googly::Sources.new