ninjs 0.16.3 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/sprockets/.gitignore +4 -0
- data/lib/sprockets/CHANGELOG +22 -0
- data/lib/sprockets/LICENSE +20 -0
- data/lib/sprockets/README.markdown +230 -0
- data/lib/sprockets/bin/sprocketize +54 -0
- data/lib/sprockets/ext/nph-sprockets.cgi +127 -0
- data/lib/sprockets/lib/sprockets.rb +42 -0
- data/lib/sprockets/lib/sprockets/concatenation.rb +36 -0
- data/lib/sprockets/lib/sprockets/environment.rb +52 -0
- data/lib/sprockets/lib/sprockets/error.rb +5 -0
- data/lib/sprockets/lib/sprockets/pathname.rb +37 -0
- data/lib/sprockets/lib/sprockets/preprocessor.rb +96 -0
- data/lib/sprockets/lib/sprockets/secretary.rb +110 -0
- data/lib/sprockets/lib/sprockets/source_file.rb +56 -0
- data/lib/sprockets/lib/sprockets/source_line.rb +85 -0
- data/lib/sprockets/lib/sprockets/version.rb +9 -0
- data/lib/sprockets/sprockets.gemspec +15 -0
- data/lib/sprockets/test/fixtures/assets/images/script_with_assets/one.png +1 -0
- data/lib/sprockets/test/fixtures/assets/images/script_with_assets/two.png +1 -0
- data/lib/sprockets/test/fixtures/assets/stylesheets/script_with_assets.css +1 -0
- data/lib/sprockets/test/fixtures/constants.yml +1 -0
- data/lib/sprockets/test/fixtures/double_slash_comments_that_are_not_requires_should_be_ignored_when_strip_comments_is_false.js +8 -0
- data/lib/sprockets/test/fixtures/double_slash_comments_that_are_not_requires_should_be_removed_by_default.js +2 -0
- data/lib/sprockets/test/fixtures/multiline_comments_should_be_removed_by_default.js +4 -0
- data/lib/sprockets/test/fixtures/requiring_a_file_after_it_has_already_been_required_should_do_nothing.js +5 -0
- data/lib/sprockets/test/fixtures/requiring_a_file_that_does_not_exist_should_raise_an_error.js +1 -0
- data/lib/sprockets/test/fixtures/requiring_a_single_file_should_replace_the_require_comment_with_the_file_contents.js +3 -0
- data/lib/sprockets/test/fixtures/requiring_the_current_file_should_do_nothing.js +1 -0
- data/lib/sprockets/test/fixtures/src/constants.yml +3 -0
- data/lib/sprockets/test/fixtures/src/foo.js +1 -0
- data/lib/sprockets/test/fixtures/src/foo/bar.js +4 -0
- data/lib/sprockets/test/fixtures/src/foo/foo.js +1 -0
- data/lib/sprockets/test/fixtures/src/script_with_assets.js +3 -0
- data/lib/sprockets/test/fixtures/src/script_with_comments.js +13 -0
- data/lib/sprockets/test/test_concatenation.rb +28 -0
- data/lib/sprockets/test/test_environment.rb +64 -0
- data/lib/sprockets/test/test_helper.rb +55 -0
- data/lib/sprockets/test/test_pathname.rb +43 -0
- data/lib/sprockets/test/test_preprocessor.rb +107 -0
- data/lib/sprockets/test/test_secretary.rb +89 -0
- data/lib/sprockets/test/test_source_file.rb +34 -0
- data/lib/sprockets/test/test_source_line.rb +89 -0
- data/ninjs.gemspec +55 -13
- metadata +46 -4
@@ -0,0 +1,42 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module Sprockets
|
7
|
+
class << self
|
8
|
+
def running_on_windows?
|
9
|
+
RUBY_PLATFORM =~ /(win|w)32$/
|
10
|
+
end
|
11
|
+
|
12
|
+
def absolute?(location)
|
13
|
+
same_when_expanded?(location) || platform_absolute_path?(location)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def same_when_expanded?(location)
|
18
|
+
location[0, 1] == File.expand_path(location)[0, 1]
|
19
|
+
end
|
20
|
+
|
21
|
+
def platform_absolute_path?(location)
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
if Sprockets.running_on_windows?
|
26
|
+
def platform_absolute_path?(location)
|
27
|
+
location[0, 1] == File::SEPARATOR && File.expand_path(location) =~ /[A-Za-z]:[\/\\]/
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require "sprockets/version"
|
34
|
+
require "sprockets/error"
|
35
|
+
require "sprockets/environment"
|
36
|
+
require "sprockets/pathname"
|
37
|
+
require "sprockets/source_line"
|
38
|
+
require "sprockets/source_file"
|
39
|
+
require "sprockets/concatenation"
|
40
|
+
require "sprockets/preprocessor"
|
41
|
+
require "sprockets/secretary"
|
42
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class Concatenation
|
3
|
+
attr_reader :source_lines
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@source_lines = []
|
7
|
+
@source_file_mtimes = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def record(source_line)
|
11
|
+
source_lines << source_line
|
12
|
+
record_mtime_for(source_line.source_file)
|
13
|
+
source_line
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
source_lines.join
|
18
|
+
end
|
19
|
+
|
20
|
+
def mtime
|
21
|
+
@source_file_mtimes.values.max
|
22
|
+
end
|
23
|
+
|
24
|
+
def save_to(filename)
|
25
|
+
timestamp = mtime
|
26
|
+
File.open(filename, "w") { |file| file.write(to_s) }
|
27
|
+
File.utime(timestamp, timestamp, filename)
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
def record_mtime_for(source_file)
|
33
|
+
@source_file_mtimes[source_file] ||= source_file.mtime
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class Environment
|
3
|
+
attr_reader :root, :load_path
|
4
|
+
|
5
|
+
def initialize(root, load_path = [])
|
6
|
+
@load_path = [@root = Pathname.new(self, root)]
|
7
|
+
|
8
|
+
load_path.reverse_each do |location|
|
9
|
+
register_load_location(location)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def pathname_from(location)
|
14
|
+
Pathname.new(self, absolute_location_from(location))
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_load_location(location)
|
18
|
+
pathname = pathname_from(location)
|
19
|
+
load_path.delete(pathname)
|
20
|
+
load_path.unshift(pathname)
|
21
|
+
location
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(location)
|
25
|
+
if Sprockets.absolute?(location) && File.exists?(location)
|
26
|
+
pathname_from(location)
|
27
|
+
else
|
28
|
+
find_all(location).first
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def constants(reload = false)
|
33
|
+
@constants = nil if reload
|
34
|
+
@constants ||= find_all("constants.yml").inject({}) do |constants, pathname|
|
35
|
+
contents = YAML.load(pathname.contents) rescue nil
|
36
|
+
contents = {} unless contents.is_a?(Hash)
|
37
|
+
constants.merge(contents)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def absolute_location_from(location)
|
43
|
+
location = location.to_s
|
44
|
+
location = File.join(root.absolute_location, location) unless Sprockets.absolute?(location)
|
45
|
+
File.expand_path(location)
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_all(location)
|
49
|
+
load_path.map { |pathname| pathname.find(location) }.compact
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class Pathname
|
3
|
+
attr_reader :environment, :absolute_location
|
4
|
+
|
5
|
+
def initialize(environment, absolute_location)
|
6
|
+
@environment = environment
|
7
|
+
@absolute_location = File.expand_path(absolute_location)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a Pathname for the location relative to this pathname's absolute location.
|
11
|
+
def find(location, kind = :file)
|
12
|
+
location = File.join(absolute_location, location)
|
13
|
+
File.send("#{kind}?", location) ? Pathname.new(environment, location) : nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def parent_pathname
|
17
|
+
Pathname.new(environment, File.dirname(absolute_location))
|
18
|
+
end
|
19
|
+
|
20
|
+
def source_file
|
21
|
+
SourceFile.new(environment, self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def contents
|
25
|
+
IO.read(absolute_location)
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(pathname)
|
29
|
+
environment == pathname.environment &&
|
30
|
+
absolute_location == pathname.absolute_location
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
absolute_location
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class Preprocessor
|
3
|
+
attr_reader :environment, :concatenation, :source_files, :asset_paths
|
4
|
+
|
5
|
+
def initialize(environment, options = {})
|
6
|
+
@environment = environment
|
7
|
+
@concatenation = Concatenation.new
|
8
|
+
@source_files = []
|
9
|
+
@asset_paths = []
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def require(source_file)
|
14
|
+
return if source_files.include?(source_file)
|
15
|
+
source_files << source_file
|
16
|
+
source_file.interpolate_constants = interpolate_constants?
|
17
|
+
|
18
|
+
source_file.each_source_line do |source_line|
|
19
|
+
if source_line.require?
|
20
|
+
require_from_source_line(source_line)
|
21
|
+
elsif source_line.provide?
|
22
|
+
provide_from_source_line(source_line)
|
23
|
+
else
|
24
|
+
record_source_line(source_line)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def provide(asset_path)
|
30
|
+
return if !asset_path || asset_paths.include?(asset_path)
|
31
|
+
asset_paths << asset_path
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
attr_reader :options
|
36
|
+
|
37
|
+
def require_from_source_line(source_line)
|
38
|
+
require pathname_from(source_line).source_file
|
39
|
+
end
|
40
|
+
|
41
|
+
def provide_from_source_line(source_line)
|
42
|
+
provide asset_path_from(source_line)
|
43
|
+
end
|
44
|
+
|
45
|
+
def record_source_line(source_line)
|
46
|
+
unless source_line.comment? && strip_comments?
|
47
|
+
concatenation.record(source_line)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def strip_comments?
|
52
|
+
options[:strip_comments] != false
|
53
|
+
end
|
54
|
+
|
55
|
+
def interpolate_constants?
|
56
|
+
options[:interpolate_constants] != false
|
57
|
+
end
|
58
|
+
|
59
|
+
def pathname_from(source_line)
|
60
|
+
pathname = send(pathname_finder_from(source_line), source_line)
|
61
|
+
raise_load_error_for(source_line) unless pathname
|
62
|
+
pathname
|
63
|
+
end
|
64
|
+
|
65
|
+
def pathname_for_require_from(source_line)
|
66
|
+
environment.find(location_from(source_line))
|
67
|
+
end
|
68
|
+
|
69
|
+
def pathname_for_relative_require_from(source_line)
|
70
|
+
source_line.source_file.find(location_from(source_line))
|
71
|
+
end
|
72
|
+
|
73
|
+
def pathname_finder_from(source_line)
|
74
|
+
"pathname_for_#{kind_of_require_from(source_line)}_from"
|
75
|
+
end
|
76
|
+
|
77
|
+
def kind_of_require_from(source_line)
|
78
|
+
source_line.require[/^(.)/, 1] == '"' ? :relative_require : :require
|
79
|
+
end
|
80
|
+
|
81
|
+
def location_from(source_line)
|
82
|
+
location = source_line.require[/^.(.*).$/, 1]
|
83
|
+
File.join(File.dirname(location), File.basename(location, ".js") + ".js")
|
84
|
+
end
|
85
|
+
|
86
|
+
def asset_path_from(source_line)
|
87
|
+
source_line.source_file.find(source_line.provide, :directory)
|
88
|
+
end
|
89
|
+
|
90
|
+
def raise_load_error_for(source_line)
|
91
|
+
kind = kind_of_require_from(source_line).to_s.tr("_", " ")
|
92
|
+
file = File.split(location_from(source_line)).last
|
93
|
+
raise LoadError, "can't find file for #{kind} `#{file}' (#{source_line.inspect})"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class Secretary
|
3
|
+
DEFAULT_OPTIONS = {
|
4
|
+
:root => ".",
|
5
|
+
:load_path => [],
|
6
|
+
:source_files => [],
|
7
|
+
:expand_paths => true,
|
8
|
+
:strip_comments => true,
|
9
|
+
:interpolate_constants => true
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :environment, :preprocessor
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
reset!(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset!(options = @options)
|
19
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
20
|
+
@environment = Sprockets::Environment.new(@options[:root])
|
21
|
+
@preprocessor = Sprockets::Preprocessor.new(@environment,
|
22
|
+
:strip_comments => @options[:strip_comments],
|
23
|
+
:interpolate_constants => @options[:interpolate_constants])
|
24
|
+
|
25
|
+
add_load_locations(@options[:load_path])
|
26
|
+
add_source_files(@options[:source_files])
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_load_location(load_location, options = {})
|
30
|
+
add_load_locations([load_location], options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_load_locations(load_locations, options = {})
|
34
|
+
expand_paths(load_locations, options).each do |load_location|
|
35
|
+
environment.register_load_location(load_location)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_source_file(source_file, options = {})
|
40
|
+
add_source_files([source_file], options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_source_files(source_files, options = {})
|
44
|
+
expand_paths(source_files, options).each do |source_file|
|
45
|
+
if pathname = environment.find(source_file)
|
46
|
+
preprocessor.require(pathname.source_file)
|
47
|
+
else
|
48
|
+
raise Sprockets::LoadError, "no such file `#{source_file}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def concatenation
|
54
|
+
preprocessor.concatenation
|
55
|
+
end
|
56
|
+
|
57
|
+
def install_assets
|
58
|
+
if @options[:asset_root]
|
59
|
+
preprocessor.asset_paths.each do |asset_path|
|
60
|
+
copy_assets_from(asset_path.absolute_location)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def source_last_modified
|
66
|
+
preprocessor.source_files.map { |s| s.mtime }.max
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
def expand_paths(paths, options = {})
|
71
|
+
if options.has_key?(:expand_paths) ? options[:expand_paths] : @options[:expand_paths]
|
72
|
+
paths.map { |path| Dir[from_root(path)].sort }.flatten.compact
|
73
|
+
else
|
74
|
+
paths.map { |path| from_root(path) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def from_root(path)
|
79
|
+
if Sprockets.absolute?(path)
|
80
|
+
path
|
81
|
+
else
|
82
|
+
File.join(@options[:root], path)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def copy_assets_from(asset_path)
|
87
|
+
relative_file_paths_beneath(asset_path).each do |filename|
|
88
|
+
source, destination = File.join(asset_path, filename), File.join(asset_root, File.dirname(filename))
|
89
|
+
if !File.directory?(source)
|
90
|
+
FileUtils.mkdir_p(destination)
|
91
|
+
FileUtils.cp(source, destination)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def relative_file_paths_beneath(path)
|
97
|
+
Dir[File.join(path, "**", "*")].map do |filename|
|
98
|
+
File.join(*path_pieces(filename)[path_pieces(path).length..-1])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def asset_root
|
103
|
+
from_root(@options[:asset_root])
|
104
|
+
end
|
105
|
+
|
106
|
+
def path_pieces(path)
|
107
|
+
path.split(File::SEPARATOR)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class SourceFile
|
3
|
+
attr_reader :environment, :pathname
|
4
|
+
attr_accessor :interpolate_constants
|
5
|
+
|
6
|
+
def initialize(environment, pathname)
|
7
|
+
@environment = environment
|
8
|
+
@pathname = pathname
|
9
|
+
@interpolate_constants = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def source_lines
|
13
|
+
@lines ||= begin
|
14
|
+
lines = []
|
15
|
+
|
16
|
+
comments = []
|
17
|
+
File.open(pathname.absolute_location) do |file|
|
18
|
+
file.each do |line|
|
19
|
+
lines << line = SourceLine.new(self, line, file.lineno)
|
20
|
+
|
21
|
+
if line.begins_pdoc_comment? || comments.any?
|
22
|
+
comments << line
|
23
|
+
end
|
24
|
+
|
25
|
+
if line.ends_multiline_comment?
|
26
|
+
if line.ends_pdoc_comment?
|
27
|
+
comments.each { |l| l.comment! }
|
28
|
+
end
|
29
|
+
comments.clear
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
lines
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_source_line(&block)
|
39
|
+
source_lines.each(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def find(location, kind = :file)
|
43
|
+
pathname.parent_pathname.find(location, kind)
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(source_file)
|
47
|
+
pathname == source_file.pathname
|
48
|
+
end
|
49
|
+
|
50
|
+
def mtime
|
51
|
+
File.mtime(pathname.absolute_location)
|
52
|
+
rescue Errno::ENOENT
|
53
|
+
Time.now
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Sprockets
|
2
|
+
class SourceLine
|
3
|
+
attr_reader :source_file, :line, :number
|
4
|
+
|
5
|
+
def initialize(source_file, line, number)
|
6
|
+
@source_file = source_file
|
7
|
+
@line = line
|
8
|
+
@number = number
|
9
|
+
end
|
10
|
+
|
11
|
+
def comment
|
12
|
+
@comment ||= line[/^\s*\/\/(.*)/, 1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def comment?
|
16
|
+
!!comment
|
17
|
+
end
|
18
|
+
|
19
|
+
def comment!
|
20
|
+
@comment = line
|
21
|
+
end
|
22
|
+
|
23
|
+
def begins_multiline_comment?
|
24
|
+
line =~ /^\s*\/\*(.*)/
|
25
|
+
end
|
26
|
+
|
27
|
+
def begins_pdoc_comment?
|
28
|
+
line =~ /^\s*\/\*\*(.*)/
|
29
|
+
end
|
30
|
+
|
31
|
+
def ends_multiline_comment?
|
32
|
+
line =~ /^(.*)\*\/\s*/
|
33
|
+
end
|
34
|
+
|
35
|
+
def ends_pdoc_comment?
|
36
|
+
line =~ /^(.*)\*\*\/\s*/
|
37
|
+
end
|
38
|
+
|
39
|
+
def require
|
40
|
+
@require ||= (comment || "")[/^=\s+require\s+(\"(.*?)\"|<(.*?)>)\s*$/, 1]
|
41
|
+
end
|
42
|
+
|
43
|
+
def require?
|
44
|
+
!!require
|
45
|
+
end
|
46
|
+
|
47
|
+
def provide
|
48
|
+
@provide ||= (comment || "")[/^=\s+provide\s+\"(.*?)\"\s*$/, 1]
|
49
|
+
end
|
50
|
+
|
51
|
+
def provide?
|
52
|
+
!!provide
|
53
|
+
end
|
54
|
+
|
55
|
+
def inspect
|
56
|
+
"line #@number of #{@source_file.pathname}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s(constants = source_file.environment.constants)
|
60
|
+
result = line.chomp
|
61
|
+
interpolate_constants!(result, constants) if interpolate_constants?
|
62
|
+
strip_trailing_whitespace!(result)
|
63
|
+
result + $/
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def interpolate_constants?
|
68
|
+
source_file.interpolate_constants != false
|
69
|
+
end
|
70
|
+
def interpolate_constants!(result, constants)
|
71
|
+
result.gsub!(/<%=(.*?)%>/) do
|
72
|
+
constant = $1.strip
|
73
|
+
if value = constants[constant]
|
74
|
+
value
|
75
|
+
else
|
76
|
+
raise UndefinedConstantError, "couldn't find constant `#{constant}' in #{inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def strip_trailing_whitespace!(result)
|
82
|
+
result.gsub!(/\s+$/, "")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|