Skip to content

Commit b73e905

Browse files
committedOct 11, 2014
Merge pull request #617 from opal/require-tree
Require tree
2 parents 95a483f + 0a722ac commit b73e905

27 files changed

+207
-84
lines changed
 

‎bin/opal-mspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env ruby
22

33
specs = ARGV.map do |s|
4-
s.end_with?('.rb') ? s : "#{s}/**/**/*_spec.rb"
4+
s.end_with?('.rb') ? s : "#{s}/**/*_spec.rb"
55
end
66
pattern = %Q{MSPEC_PATTERN="{#{specs.join(',')}}"} if specs.any?
77
command = [pattern, 'rake mspec'].compact.join(' ')

‎lib/mspec/opal/rake_task.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ def files_to_run(pattern=nil)
205205

206206
if pattern
207207
# add custom opal specs from spec/
208-
add_files paths_from_glob(pattern) & rubyspec_white_list, :custom_pattern
208+
add_files paths_from_glob(pattern) & rubyspec_white_list, :rubyspec_custom_pattern
209+
add_files paths_from_glob(pattern).grep(/(?!spec\/(corelib|stdlib)\/)/), :other_custom_pattern
209210

210211
else
211212
# add opal specific specs

‎lib/mspec/opal/runner.rb

+9
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ def red(str)
133133
def log(str)
134134
`console.log(str)`
135135
end
136+
137+
def after(state)
138+
super
139+
unless exception?
140+
print '.'
141+
else
142+
print failure? ? 'F' : 'E'
143+
end
144+
end
136145
end
137146

138147
class PhantomDebugFormatter < PhantomFormatter

‎lib/mspec/opal/sprockets.js

+17
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ page.onInitialized = function() {
1414
});
1515
};
1616

17+
var system = require('system');
18+
page.onCallback = function(data) {
19+
switch (data[0]) {
20+
case 'exit':
21+
var status = data[1] || 0;
22+
phantom.exit(status);
23+
case 'stdout':
24+
system.stdout.write(data[1] || '');
25+
break;
26+
case 'stderr':
27+
system.stderr.write(data[1] || '');
28+
break;
29+
default:
30+
console.error('Unknown callback data: ', data);
31+
}
32+
};
33+
1734
page.open(args[0], function(status) {
1835
if (status !== 'success') {
1936
console.error("Cannot load: " + args[0]);

‎lib/opal/builder.rb

+34-11
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def self.build(*args, &block)
2727
end
2828

2929
def build(path, options = {})
30-
source = path_reader.read(path)
30+
source = read(path)
3131
build_str(source, path, options)
3232
end
3333

@@ -63,11 +63,25 @@ def source_map
6363
private
6464

6565
def tree_requires(asset, path)
66+
if path.nil? or path.empty?
67+
dirname = Dir.pwd
68+
else
69+
dirname = File.dirname(File.expand_path(path))
70+
end
71+
72+
paths = path_reader.paths.map{|p| File.expand_path(p)}
73+
6674
asset.required_trees.flat_map do |tree|
67-
base = File.expand_path(File.dirname(path))
68-
expanded = File.expand_path File.join(base, tree, '*.rb')
69-
Dir[expanded].map do |file|
70-
file.gsub(/(\.js)?(\.(?:rb|opal))/, '')[(base.size+1)..-1]
75+
expanded = File.expand_path(tree, dirname)
76+
base = paths.find { |p| expanded.start_with?(p) }
77+
next [] if base.nil?
78+
79+
globs = []
80+
globs << File.join(base, tree, '*.rb')
81+
globs << File.join(base, tree, '*.opal')
82+
globs << File.join(base, tree, '*.js')
83+
Dir[*globs].map do |file|
84+
Pathname(file).relative_path_from(Pathname(base)).to_s.gsub(/(\.js)?(\.(?:rb|opal))/, '')
7185
end
7286
end
7387
end
@@ -78,25 +92,34 @@ def processor_for(source, filename, path, options)
7892
return processor.new(source, filename, compiler_options.merge(options))
7993
end
8094

95+
def read(path)
96+
path_reader.read(path) or
97+
raise ArgumentError, "can't find file: #{path.inspect} in #{path_reader.paths.inspect}"
98+
end
99+
81100
def process_require(filename, options)
82101
return if prerequired.include?(filename)
83102
return if already_processed.include?(filename)
84103
already_processed << filename
85104

86-
source = stub?(filename) ? '' : path_reader.read(filename)
105+
source = stub?(filename) ? '' : read(filename)
87106

88-
if source.nil? && @compiler_options[:dynamic_require_severity] != :error
89-
raise LoadError, "can't find file: #{filename.inspect}"
107+
if source.nil?
108+
message = "can't find file: #{filename.inspect}"
109+
case @compiler_options[:dynamic_require_severity]
110+
when :error then raise LoadError, message
111+
when :warning then warn "can't find file: #{filename.inspect}"
112+
end
90113
end
91114

92115
path = path_reader.expand(filename).to_s unless stub?(filename)
93116
asset = processor_for(source, filename, path, options.merge(requirable: true))
94-
process_requires(asset, options)
117+
process_requires(asset.requires+tree_requires(asset, path), options)
95118
processed << asset
96119
end
97120

98-
def process_requires(asset, options)
99-
asset.requires.map { |r| process_require(r, options) }
121+
def process_requires(requires, options)
122+
requires.map { |r| process_require(r, options) }
100123
end
101124

102125
def already_processed

‎lib/opal/cli_runners/phantom.js

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ page.onCallback = function(data) {
1313
case 'exit':
1414
var status = data[1] || 0;
1515
phantom.exit(status);
16+
case 'stdout':
17+
system.stdout.write(data[1] || '');
18+
break;
19+
case 'stderr':
20+
system.stderr.write(data[1] || '');
1621
break;
1722
default:
1823
console.error('Unknown callback data: ', data);

‎lib/opal/nodes/call.rb

+5-2
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,15 @@ def compile_default?
187187
end
188188

189189
add_special :require_tree do
190-
compile_default!
191190
arg = arglist[1]
192191
if arg[0] == :str
193192
dir = File.dirname(compiler.file)
194-
compiler.required_trees << arg[1]
193+
relative_path = arg[1]
194+
full_path = Pathname(dir).join(relative_path).cleanpath.to_s
195+
compiler.required_trees << full_path
196+
arg[1] = full_path
195197
end
198+
compile_default!
196199
push fragment('')
197200
end
198201

‎lib/opal/path_reader.rb

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def expand(path)
1616
file_finder.find(path)
1717
end
1818

19+
def paths
20+
file_finder.paths
21+
end
22+
1923

2024
private
2125

‎lib/opal/sprockets/path_reader.rb

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def expand path
2323
env.resolve(path)
2424
end
2525

26+
def paths
27+
env.paths
28+
end
29+
2630
attr_reader :env, :context
2731
end
2832

‎opal/corelib/file.rb

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class File < IO
2+
Separator = SEPARATOR = '/'
3+
4+
class << self
5+
def expand_path(path, basedir = nil)
6+
path = [basedir, path].compact.join(SEPARATOR)
7+
parts = path.split(SEPARATOR)
8+
new_parts = []
9+
parts[0] = Dir.home if parts.first == '~'
10+
11+
parts.each do |part|
12+
if part == '..'
13+
new_parts.pop
14+
else
15+
new_parts << part
16+
end
17+
end
18+
new_parts.join(SEPARATOR)
19+
end
20+
21+
def dirname(path)
22+
split(path)[0..-2]
23+
end
24+
25+
def basename(path)
26+
split(path)[-1]
27+
end
28+
29+
def exist? path
30+
`Opal.modules[#{path}] != null`
31+
end
32+
alias exists? exist?
33+
34+
def directory?(path)
35+
files = []
36+
%x{
37+
for (var key in Opal.modules) {
38+
#{files}.push(key)
39+
}
40+
}
41+
path = path.gsub(%r{(^.#{SEPARATOR}+|#{SEPARATOR}+$)})
42+
file = files.find do |file|
43+
file =~ /^#{path}/
44+
end
45+
file
46+
end
47+
48+
def join(*paths)
49+
paths.join(SEPARATOR).gsub(%r{#{SEPARATOR}+}, SEPARATOR)
50+
end
51+
52+
def split(path)
53+
path.split(SEPARATOR)
54+
end
55+
end
56+
end

‎opal/corelib/kernel.rb

+16
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,22 @@ def require_relative file
553553
`$opal.require( $opal.normalize_loadable_path(#{file}) )`
554554
end
555555

556+
# `path` should be the ful path to be found in registered modules (`Opal.modules`)
557+
def require_tree path
558+
path = File.expand_path(path)
559+
%x{
560+
var file_name, file_names = Object.keys($opal.modules);
561+
path = path.replace(/\/?$/, '/');
562+
for (var i = 0; i < file_names.length; i++) {
563+
file_name = file_names[i];
564+
if (file_name['$start_with?'](path)) {
565+
$opal.require(file_name);
566+
}
567+
}
568+
}
569+
nil
570+
end
571+
556572
def load file
557573
`$opal.load( $opal.normalize_loadable_path(#{file}) )`
558574
end

‎opal/opal.rb

+1
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@
2929
require 'corelib/main'
3030
require 'corelib/variables'
3131
require 'corelib/dir'
32+
require 'corelib/file'

‎spec/lib/builder_processors_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
it 'fills required_trees' do
2323
processor = described_class.new('require_tree "./pippo"', '-e')
24-
expect(processor.required_trees).to eq(['./pippo'])
24+
expect(processor.required_trees).to eq(['pippo'])
2525
end
2626
end
2727

‎spec/lib/builder_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
it 'respect #require_tree calls' do
1414
begin
15-
Opal.append_path(File.expand_path('../fixtures/', __FILE__))
16-
expect(builder.build('require_tree_test').to_s).to match('required_file1')
15+
Opal.append_path(File.expand_path('..', __FILE__))
16+
expect(builder.build('fixtures/require_tree_test').to_s).to include('Opal.modules["fixtures/required_tree_test/required_file1"]')
1717
ensure
1818
Opal.instance_variable_set('@paths', nil)
1919
end

‎spec/lib/compiler_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182

183183
it 'parses and resolve #require argument' do
184184
compiler = compiler_for(file.read)
185-
expect(compiler.required_trees).to eq(['./required_tree_test'])
185+
expect(compiler.required_trees).to eq(['../fixtures/required_tree_test'])
186186
end
187187
end
188188
end
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
require_tree './required_tree_test'
1+
require_tree '../fixtures/required_tree_test'
22

33
puts 5

‎spec/lib/path_reader_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
before do
1515
path_finder.stub(:find) {|path| nil}
1616
path_finder.stub(:find).with(path).and_return(full_path)
17+
path_finder.stub(:paths).and_return(Opal.paths)
1718
end
1819

1920
include_examples :path_finder

‎spec/lib/shared/path_reader_shared.rb

+24-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
require 'lib/spec_helper'
22

3+
# Below the helpers expected from a spec that
4+
# includes these shared examples:
5+
#
6+
# @object [PathReader] path_reader the object under test
7+
# @method [String] path the path we want to read
8+
# @method [String] contents the contents we expect to be read
9+
#
310
shared_examples :path_reader do
4-
# @param path
5-
# the path we want to read
6-
#
7-
# @param contents
8-
# the contents we expect to be read
9-
#
10-
it 'responds to #path' do
11-
expect(path_reader.read(path)).to eq(contents)
11+
describe '#paths' do
12+
it 'is an Enumberable' do
13+
expect(path_reader.paths).to be_an(Enumerable)
14+
end
15+
16+
it 'includes Opal.paths' do
17+
paths = path_reader.paths.to_a
18+
Opal.paths.each { |path| expect(paths).to include(path) }
19+
end
1220
end
1321

14-
it 'returns nil if the file is missing' do
15-
expect(path_reader.read('unexpected-path!')).to be_nil
22+
describe '#read' do
23+
it 'responds to #path' do
24+
expect(path_reader.read(path)).to eq(contents)
25+
end
26+
27+
it 'returns nil if the file is missing' do
28+
expect(path_reader.read('unexpected-path!')).to be_nil
29+
end
1630
end
1731
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ScratchPad << File.basename(__FILE__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ScratchPad << File.basename(__FILE__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ScratchPad << File.basename(__FILE__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ScratchPad << File.basename(__FILE__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$ScratchPad << File.basename(__FILE__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
describe 'Kernel.require_tree' do
2+
it 'loads all the files in a directory' do
3+
$ScratchPad = []
4+
require_tree '../fixtures/require_tree_files'
5+
$ScratchPad.sort.should == ['file 1', 'file 2', 'file 3', 'file 4', 'file 5']
6+
end
7+
end

‎spec/spec_helper.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ def at_exit(&block)
2727
end
2828
end
2929

30-
formatter_class = `!!window.OPAL_SPEC_PHANTOM` ? PhantomFormatter : BrowserFormatter
30+
if `!!window.OPAL_SPEC_PHANTOM`
31+
require 'phantomjs'
32+
formatter_class = PhantomFormatter
33+
else
34+
formatter_class = BrowserFormatter
35+
end
3136

3237
# Uncomment the following to see example titles when they're executed.
3338
# (useful to relate debug output to the example that generated it)

‎stdlib/file.rb

+1-52
Original file line numberDiff line numberDiff line change
@@ -1,52 +1 @@
1-
class File < IO
2-
Separator = SEPARATOR = '/'
3-
4-
class << self
5-
def expand_path(path, basedir = nil)
6-
path = [basedir, path].compact.join(SEPARATOR)
7-
parts = path.split(SEPARATOR)
8-
new_parts = []
9-
parts[0] = Dir.home if parts.first == '~'
10-
11-
parts.each do |part|
12-
if part == '..'
13-
new_parts.pop
14-
else
15-
new_parts << part
16-
end
17-
end
18-
new_parts.join(SEPARATOR)
19-
end
20-
21-
def dirname(path)
22-
split(path)[-2]
23-
end
24-
25-
def exist? path
26-
`Opal.modules[#{path}] != null`
27-
end
28-
alias exists? exist?
29-
30-
def directory?(path)
31-
files = []
32-
%x{
33-
for (var key in Opal.modules) {
34-
#{files}.push(key)
35-
}
36-
}
37-
path = path.gsub(%r{(^.#{SEPARATOR}+|#{SEPARATOR}+$)})
38-
file = files.find do |file|
39-
file =~ /^#{path}/
40-
end
41-
file
42-
end
43-
44-
def join(*paths)
45-
paths.join(SEPARATOR).gsub(%r{#{SEPARATOR}+}, SEPARATOR)
46-
end
47-
48-
def split(path)
49-
path.split(SEPARATOR)
50-
end
51-
end
52-
end
1+
warn "File is already part of corelib now, you don't need to require it anymore."

‎stdlib/phantomjs.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module Kernel
22
def exit status = 0
3-
`callPhantom(["exit", #{status}]);`
3+
`callPhantom(['exit', status]);`
44
end
55
end
6+
7+
STDOUT.write_proc = `function(str){callPhantom(['stdout', str])}`
8+
STDERR.write_proc = `function(str){callPhantom(['stderr', str])}`

0 commit comments

Comments
 (0)
Please sign in to comment.