This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Initial commit

  • Loading branch information...
Sam Stephenson
Sam Stephenson committed May 29, 2008
0 parents commit 0b427dc790bdc4a9170d42b4f434facc51168483
@@ -0,0 +1,3 @@
*.txt
tmp
@@ -0,0 +1,9 @@
require "rake/testtask"
task :default => :test
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList["test/*_test.rb"]
t.verbose = true
end
@@ -0,0 +1,12 @@
#!/usr/bin/env ruby
require File.join(File.dirname(__FILE__), *%w".. lib sprockets")
environment = Sprockets::Environment.new(".")
preprocessor = Sprockets::Preprocessor.new(environment)
ARGV.each do |filename|
preprocessor.require(environment.find(filename).source_file)
end
print preprocessor.output_file
@@ -0,0 +1,9 @@
$:.unshift File.dirname(__FILE__)
require "sprockets/error"
require "sprockets/environment"
require "sprockets/pathname"
require "sprockets/source_line"
require "sprockets/source_file"
require "sprockets/output_file"
require "sprockets/preprocessor"
@@ -0,0 +1,35 @@
module Sprockets
class Environment
attr_reader :root, :load_path
def initialize(root, load_path = [])
@root = pathname_from(File.expand_path(root))
@load_path = [@root]
load_path.each do |location|
register_load_location(location)
end
end
def absolute_location_from(location)
location = location.to_s
location = File.join(root.absolute_location, location) unless location[/^\//]
File.expand_path(location)
end
def pathname_from(location)
Pathname.new(self, absolute_location_from(location))
end
def register_load_location(location)
pathname = pathname_from(location)
load_path.delete(pathname)
load_path.unshift(pathname)
location
end
def find(location)
load_path.map { |pathname| pathname.find(location) }.compact.first
end
end
end
@@ -0,0 +1,4 @@
module Sprockets
class Error < ::StandardError; end
class LoadError < Error; end
end
@@ -0,0 +1,20 @@
module Sprockets
class OutputFile
attr_reader :source_lines
def initialize
@source_lines = []
end
def record(source_line)
@source_lines << source_line
source_line
end
def to_s
@source_lines.map do |source_line|
source_line.line
end.join
end
end
end
@@ -0,0 +1,33 @@
module Sprockets
class Pathname
attr_reader :environment, :absolute_location
def initialize(environment, absolute_location)
@environment = environment
@absolute_location = File.expand_path(absolute_location)
end
# Returns a Pathname for the location relative to this pathname's absolute location.
def find(location)
location = File.join(absolute_location, location)
File.file?(location) ? Pathname.new(environment, location) : nil
end
def parent_pathname
Pathname.new(environment, File.dirname(absolute_location))
end
def source_file
SourceFile.new(environment, self)
end
def ==(pathname)
environment == pathname.environment &&
absolute_location == pathname.absolute_location
end
def to_s
absolute_location
end
end
end
@@ -0,0 +1,75 @@
module Sprockets
class Preprocessor
attr_reader :environment, :output_file, :source_files
def initialize(environment, options = {})
@environment = environment
@output_file = OutputFile.new
@source_files = []
@options = options
end
def require(source_file)
return if source_files.include?(source_file)
source_files << source_file
source_file.each_source_line do |source_line|
if source_line.require?
require_from_source_line(source_line)
else
record_source_line(source_line)
end
end
end
protected
attr_reader :options
def require_from_source_line(source_line)
require pathname_from(source_line).source_file
end
def record_source_line(source_line)
unless source_line.comment? && strip_comments?
output_file.record(source_line)
end
end
def strip_comments?
options[:strip_comments] != false
end
def pathname_from(source_line)
pathname = send(pathname_finder_from(source_line), source_line)
raise_load_error_for(source_line) unless pathname
pathname
end
def pathname_for_require_from(source_line)
environment.find(location_from(source_line))
end
def pathname_for_relative_require_from(source_line)
source_line.source_file.find(location_from(source_line))
end
def pathname_finder_from(source_line)
"pathname_for_#{kind_of_require_from(source_line)}_from"
end
def kind_of_require_from(source_line)
source_line.require[/^(.)/, 1] == '"' ? :relative_require : :require
end
def location_from(source_line)
location = source_line.require[/^.(.*).$/, 1]
File.join(File.dirname(location), File.basename(location, ".js") + ".js")
end
def raise_load_error_for(source_line)
kind = kind_of_require_from(source_line).to_s.tr("_", " ")
file = File.split(location_from(source_line)).last
raise LoadError, "can't find file for #{kind} `#{file}' (#{source_line.inspect})"
end
end
end
@@ -0,0 +1,26 @@
module Sprockets
class SourceFile
attr_reader :environment, :pathname
def initialize(environment, pathname)
@environment = environment
@pathname = pathname
end
def each_source_line
File.open(pathname.absolute_location) do |file|
file.each do |line|
yield SourceLine.new(self, line, file.lineno)
end
end
end
def find(location)
pathname.parent_pathname.find(location)
end
def ==(source_file)
pathname == source_file.pathname
end
end
end
@@ -0,0 +1,31 @@
module Sprockets
class SourceLine
attr_reader :source_file, :line, :number
def initialize(source_file, line, number)
@source_file = source_file
@line = line
@number = number
end
def comment
@comment ||= line[/^\s*\/\/(.*)/, 1]
end
def comment?
!!comment
end
def require
@require ||= (comment || "")[/^=\s+require\s+(\"(.*?)\"|<(.*?)>)/, 1]
end
def require?
!!require
end
def inspect
"line #@number of #{@source_file.pathname}"
end
end
end
@@ -0,0 +1 @@
// This is a double-slash comment that should appear in the resulting output file.
@@ -0,0 +1,2 @@
// This is a double-slash comment that should not appear in the resulting output file.
/* This is a slash-star comment that should appear in the resulting output file. */
@@ -0,0 +1,5 @@
var before_first_require;
//= require <foo>
var after_first_require_and_before_second_require;
//= require <foo>
var after_second_require;
@@ -0,0 +1 @@
//= require <nonexistent>
@@ -0,0 +1,3 @@
var before_require;
//= require <foo>
var after_require;
@@ -0,0 +1 @@
//= require "requiring_the_current_file_should_do_nothing"
@@ -0,0 +1 @@
var Foo = { };
@@ -0,0 +1,96 @@
require "test_helper"
class PreprocessorTest < Test::Unit::TestCase
def setup
@environment = Sprockets::Environment.new(FIXTURES_PATH, source_directories_in_fixtures_path)
@preprocessor = Sprockets::Preprocessor.new(@environment)
end
def test_double_slash_comments_that_are_not_requires_should_be_removed_by_default
require_file_for_this_test
assert_output_file_does_not_contain_line "// This is a double-slash comment that should not appear in the resulting output file."
assert_output_file_contains_line "/* This is a slash-star comment that should appear in the resulting output file. */"
end
def test_double_slash_comments_that_are_not_requires_should_be_ignored_when_strip_comments_is_false
@preprocessor = Sprockets::Preprocessor.new(@environment, :strip_comments => false)
require_file_for_this_test
assert_output_file_contains_line "// This is a double-slash comment that should appear in the resulting output file."
end
def test_requiring_a_single_file_should_replace_the_require_comment_with_the_file_contents
require_file_for_this_test
assert_output_file_contains <<-LINES
var before_require;
var Foo = { };
var after_require;
LINES
end
def test_requiring_a_file_that_does_not_exist_should_raise_an_error
assert_raises(Sprockets::LoadError) do
require_file_for_this_test
end
end
def test_requiring_the_current_file_should_do_nothing
require_file_for_this_test
assert_equal "", output_text
end
def test_requiring_a_file_after_it_has_already_been_required_should_do_nothing
require_file_for_this_test
assert_output_file_contains <<-LINES
var before_first_require;
var Foo = { };
var after_first_require_and_before_second_require;
var after_second_require;
LINES
end
protected
attr_reader :environment, :preprocessor
def output_file
preprocessor.output_file
end
def output_text
preprocessor.output_file.to_s
end
def source_lines_matching(line)
output_file.source_lines.select { |source_line| source_line.line.strip == line }
end
def require_file(location)
preprocessor.require(environment.find(location).source_file)
end
def require_file_for_this_test
require_file(file_for_this_test)
end
def file_for_this_test
caller.map { |c| c[/`(.*?)'$/, 1] }.grep(/^test_/).first[5..-1] + ".js"
end
def assert_output_file_does_not_contain_line(line)
assert source_lines_matching(line).empty?
end
def assert_output_file_contains_line(line)
assert source_lines_matching(line).any?
end
def assert_output_file_contains(indented_text)
lines = indented_text.split($/)
initial_indent = lines.first[/^\s*/].length
unindented_text = lines.map { |line| line[initial_indent..-1] }.join($/)
assert output_text[unindented_text]
end
def source_directories_in_fixtures_path
Dir[File.join(FIXTURES_PATH, "**", "src")]
end
end
@@ -0,0 +1,6 @@
require File.join(File.dirname(__FILE__), *%w".. lib sprockets")
require "test/unit"
class Test::Unit::TestCase
FIXTURES_PATH = File.expand_path(File.join(File.dirname(__FILE__), "fixtures"))
end

3 comments on commit 0b427dc

@ELLIOTTCABLE

This comment has been minimized.

Show comment
Hide comment
@ELLIOTTCABLE

ELLIOTTCABLE Oct 29, 2008

I can’t quite figure out exactly what this does. You should add a brief README, describing basic usage d-:

I can’t quite figure out exactly what this does. You should add a brief README, describing basic usage d-:

@haraldmartin

This comment has been minimized.

Show comment
Hide comment
@haraldmartin

haraldmartin Oct 29, 2008

@elliottcable You can find an example which usesSprockets over at wysihat

@elliottcable You can find an example which usesSprockets over at wysihat

@ELLIOTTCABLE

This comment has been minimized.

Show comment
Hide comment
@ELLIOTTCABLE

ELLIOTTCABLE Oct 29, 2008

This is exactly what I’ve been looking for! An example of how to manage a JavaScript project! Thank you (-:

This is exactly what I’ve been looking for! An example of how to manage a JavaScript project! Thank you (-:

Please sign in to comment.