spade-runtime 0.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +2 -0
  2. data/bin/spaderun +9 -0
  3. data/lib/spade-runtime.rb +1 -0
  4. data/lib/spade/runtime.rb +20 -0
  5. data/lib/spade/runtime/bundle.rb +173 -0
  6. data/lib/spade/runtime/cli.rb +7 -0
  7. data/lib/spade/runtime/cli/base.rb +181 -0
  8. data/lib/spade/runtime/compiler.rb +34 -0
  9. data/lib/spade/runtime/console.rb +39 -0
  10. data/lib/spade/runtime/context.rb +114 -0
  11. data/lib/spade/runtime/exports.rb +86 -0
  12. data/lib/spade/runtime/loader.rb +209 -0
  13. data/lib/spade/runtime/reactor.rb +159 -0
  14. data/lib/spade/runtime/server.rb +66 -0
  15. data/lib/spade/runtime/shell.rb +36 -0
  16. data/lib/spade/runtime/version.rb +5 -0
  17. data/spade-runtime.gemspec +36 -0
  18. data/spec/cli/update_spec.rb +64 -0
  19. data/spec/javascript/async-test.js +123 -0
  20. data/spec/javascript/compiler/javascript.js +13 -0
  21. data/spec/javascript/compiler/ruby.js +14 -0
  22. data/spec/javascript/loader-test.js +64 -0
  23. data/spec/javascript/normalize-test.js +73 -0
  24. data/spec/javascript/packages-test.js +44 -0
  25. data/spec/javascript/relative-require-test.js +72 -0
  26. data/spec/javascript/require-test.js +117 -0
  27. data/spec/javascript/sandbox/compile.js +37 -0
  28. data/spec/javascript/sandbox/creation.js +44 -0
  29. data/spec/javascript/sandbox/format.js +79 -0
  30. data/spec/javascript/sandbox/misc.js +57 -0
  31. data/spec/javascript/sandbox/preprocessor.js +81 -0
  32. data/spec/javascript/sandbox/require.js +48 -0
  33. data/spec/javascript/sandbox/run-command.js +21 -0
  34. data/spec/javascript/spade/externs.js +14 -0
  35. data/spec/javascript/spade/load-factory.js +15 -0
  36. data/spec/javascript/spade/misc.js +23 -0
  37. data/spec/javascript/spade/ready.js +12 -0
  38. data/spec/javascript/spade/register.js +13 -0
  39. data/spec/javascript_spec.rb +7 -0
  40. data/spec/spec_helper.rb +23 -0
  41. data/spec/support/cli.rb +109 -0
  42. data/spec/support/core_test.rb +61 -0
  43. data/spec/support/matchers.rb +12 -0
  44. data/spec/support/path.rb +62 -0
  45. metadata +218 -0
@@ -0,0 +1,66 @@
1
+ require 'rack'
2
+ require 'rack/static'
3
+ require 'tempfile'
4
+ require 'child_labor'
5
+
6
+ module Spade::Runtime
7
+ module Server
8
+ def self.run(working, port)
9
+ rootdir = Spade.discover_root(working)
10
+ static = Rack::Static.new(nil, :urls => ['/'], :root => rootdir)
11
+ static = CommandRunner.new(static)
12
+ static = Rack::ShowStatus.new(Rack::ShowExceptions.new(Rack::Chunked.new(Rack::ContentLength.new(static))))
13
+
14
+ Rack::Handler::WEBrick.run static, :Port => port.to_i
15
+ end
16
+
17
+ def self.shutdown
18
+ Rack::Handler::WEBrick.shutdown
19
+ end
20
+
21
+ class CommandRunner
22
+ def initialize(app)
23
+ @app = app
24
+ end
25
+
26
+ #FIXME: This is not very safe, we should have some restrictions
27
+ def call(env)
28
+ if env['PATH_INFO'] == '/_spade/command'
29
+ rack_input = env["rack.input"].read
30
+ params = Rack::Utils.parse_query(rack_input, "&")
31
+
32
+ command_path = params['command']
33
+ return [500, {}, "command required"] if command_path.nil? || command_path.empty?
34
+
35
+ if ((root = params['pkgRoot']) && !root.nil?)
36
+ command_path = File.expand_path(File.join(command_path), root)
37
+ end
38
+
39
+ tempfile = Tempfile.new('spade-server')
40
+ tempfile.write(params['code'])
41
+ tempfile.close
42
+
43
+
44
+ puts "Running: #{command_path}"
45
+
46
+ output, error = nil
47
+ process = ChildLabor.subprocess("#{command_path} < #{tempfile.path}") do |p|
48
+ output = p.read
49
+ error = p.read_stderr
50
+ end
51
+
52
+ tempfile.delete
53
+
54
+ if process.exit_status == 0
55
+ [200, {}, output]
56
+ else
57
+ [500, {}, error]
58
+ end
59
+ else
60
+ env['PATH_INFO'] == '/index.html' if env['PATH_INFO'] == '/'
61
+ @app.call(env)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ # ==========================================================================
2
+ # Project: Spade - CommonJS Runtime
3
+ # Copyright: ©2010 Strobe Inc. All rights reserved.
4
+ # License: Licened under MIT license (see LICENSE)
5
+ # ==========================================================================
6
+
7
+ # Global object used for the shell.
8
+ module Spade::Runtime
9
+ class Shell
10
+ attr_accessor :ctx
11
+
12
+ def to_s
13
+ "[object Shell]"
14
+ end
15
+
16
+ def exit(status=0)
17
+ ctx.reactor.exit(status)
18
+ end
19
+
20
+ alias_method :quit, :exit
21
+
22
+ def help(*args)
23
+ <<-HELP
24
+ print(msg)
25
+ print msg to STDOUT
26
+
27
+ exit(status = 0)
28
+ exit the shell
29
+ also: quit()
30
+
31
+ evalrb(source)
32
+ evaluate some ruby source
33
+ HELP
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ module Spade
2
+ module Runtime
3
+ VERSION = '0.1.0.1'
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require 'spade/runtime/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "spade-runtime"
9
+ s.version = Spade::Runtime::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["Charles Jolley", "Peter Wagenet"]
12
+ s.email = ["charles@sproutcore.com", "peterw@strobecorp.com"]
13
+ s.homepage = "http://github.com/strobecorp/spade"
14
+ s.summary = s.description = "Unified JavaScript runner for browser and command line"
15
+
16
+ mswin = RbConfig::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw)!
17
+ mri = !mswin && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby")
18
+
19
+ s.add_dependency "spade-core", "~> 0.1.0"
20
+ s.add_dependency "eventmachine", "~> 0.12.10"
21
+ s.add_dependency "json_pure", "~> 1.4.6"
22
+ s.add_dependency "rack", "~> 1.2.1"
23
+ s.add_dependency "thor", "~> 0.14.3"
24
+ s.add_dependency "childlabor", "~> 0.0.3"
25
+ s.add_dependency "therubyracer", "~> 0.8.0" if mri
26
+
27
+ s.add_development_dependency "rspec"
28
+ s.add_development_dependency "spade-packager", "~> 0.1.0"
29
+
30
+ s.files = `git ls-files`.split("\n")
31
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
32
+
33
+ s.executables = ['spaderun']
34
+ s.require_paths = ["lib"]
35
+ end
36
+
@@ -0,0 +1,64 @@
1
+ require "spec_helper"
2
+
3
+ describe "spade update" do
4
+ before do
5
+ # prep the application
6
+ goto_home
7
+
8
+ FileUtils.mkdir_p (@app_path = tmp.join("update_test"))
9
+ FileUtils.mkdir_p (@app_packages_path = @app_path.join("packages"))
10
+ FileUtils.mkdir_p (@app_vendor_packages_path = @app_path.join("vendor/packages"))
11
+ app_package_file_path = @app_path.join("package.json")
12
+ File.open(app_package_file_path, 'w') do |f2|
13
+ f2.puts '{"name":"update_test","dependencies":{"fake_package": null}}'
14
+ end
15
+ cd(@app_path)
16
+
17
+ end
18
+ after do
19
+ cd(home)
20
+ FileUtils.rm_r @app_path
21
+ end
22
+
23
+ it "should use required packages if they are in the application's packages folder" do
24
+ FileUtils.mkdir_p (package_path = @app_packages_path.join("fake_package"))
25
+ package_file_path = package_path.join("package.json")
26
+ File.open(package_file_path, 'w') do |f|
27
+ f.puts '{"name": "fake_package"}'
28
+ end
29
+ spade("runtime","update", "--working=#{@app_path.to_s}")
30
+ wait()
31
+ "fake_package".should be_linked_to("../../packages/fake_package")
32
+ end
33
+
34
+ it "should use required packages if they are in the application's vendor/packages folder" do
35
+ FileUtils.mkdir_p (package_path = @app_vendor_packages_path.join("fake_package"))
36
+ package_file_path = package_path.join("package.json")
37
+ File.open(package_file_path, 'w') do |f|
38
+ f.puts '{"name": "fake_package"}'
39
+ end
40
+ spade("runtime","update", "--working=#{@app_path.to_s}")
41
+ wait()
42
+ "fake_package".should be_linked_to("../../vendor/packages/fake_package")
43
+ end
44
+ it "should use required packages if they are in the home spade directory" do
45
+ FileUtils.mkdir_p (package_path = spade_dir.join("gems","fake_package"))
46
+ package_file_path = package_path.join("package.json")
47
+ File.open(package_file_path, 'w') do |f|
48
+ f.puts '{"name": "fake_package"}'
49
+ end
50
+ unthreaded_spade("runtime","update", "--working=#{@app_path.to_s}")
51
+ "fake_package".should be_linked_to(package_path)
52
+ end
53
+
54
+ it "shoudl not try to choose from the home spade directory if Packager is not installed"
55
+ it "should install from the network repository if it does not exist elsewhere"
56
+ it "should raise an error if the package is in none of the locations"
57
+ it "should not link to a package if it is the incorrect version"
58
+ it "shoudl not try to install the package if Packager is not installed"
59
+ it "should install the correct version"
60
+ it "should raise an error if the package is only available in the wrong version"
61
+ it "should select packages in the correct order if there are multiple equal editions"
62
+ it "should create a spade-boot.js"
63
+ it "should record the versions in spade-boot.js"
64
+ end
@@ -0,0 +1,123 @@
1
+ // ==========================================================================
2
+ // Project: Spade - CommonJS Runtime
3
+ // Copyright: ©2010 Strobe Inc. All rights reserved.
4
+ // License: Licened under MIT license (see __preamble__.js)
5
+ // ==========================================================================
6
+ /*globals Ct */
7
+
8
+ require('core-test');
9
+
10
+ var Spade = require('spade').Spade;
11
+
12
+ // ..........................................................
13
+ // BASIC REQUIRE
14
+ //
15
+
16
+ Ct.module('spade: async require');
17
+
18
+ Ct.setup(function(t, done) {
19
+ t.spade = new Spade();
20
+
21
+ // preload a module
22
+ t.spade.register('foo/baz', function(require,e) {
23
+ e.id = 'foo/baz';
24
+ e.async = require.async; // export for testing
25
+ });
26
+
27
+ // dummy loader loads only foo/bar on demand after delay
28
+ t.spade.loader = {
29
+
30
+ requests: 0,
31
+
32
+ loadFactory: function(spade, id, formats, done) {
33
+ this.requests++;
34
+ if (id === 'foo/bar') {
35
+ setTimeout(function() {
36
+ spade.register(id, function(r,e) { e.id='foo/bar'; });
37
+ done();
38
+ }, 10);
39
+
40
+ } else {
41
+ done('Not Found'); // immediately
42
+ }
43
+ }
44
+ };
45
+
46
+ done();
47
+ });
48
+
49
+ Ct.teardown(function(t, done) {
50
+ delete t.spade;
51
+ done();
52
+ });
53
+
54
+ Ct.test('should not talk to loader if registered', function(t, done) {
55
+ var spade = t.spade;
56
+
57
+ t.timeout(1000);
58
+
59
+ spade.async('foo/baz', function(err) {
60
+ t.equal(err, null);
61
+ t.equal(spade.loader.requests, 0, 'loader should not have been called');
62
+ t.equal(spade.require('foo/baz').id, 'foo/baz', 'should find foo');
63
+ done();
64
+ });
65
+
66
+ });
67
+
68
+ Ct.test('should let loader register', function(t, done) {
69
+ var spade = t.spade;
70
+ t.timeout(1000);
71
+ spade.async('foo/bar', function(err) {
72
+ t.equal(err, null);
73
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
74
+ t.equal(spade.require('foo/bar').id, 'foo/bar', 'should find foo');
75
+ done();
76
+ });
77
+ });
78
+
79
+
80
+ Ct.test('should normalize id', function(t, done) {
81
+ var spade = t.spade;
82
+ t.timeout(1000);
83
+ spade.async('/./foo/baz/../bar', function(err) {
84
+ t.equal(err, null);
85
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
86
+ t.equal(spade.require('foo/bar').id, 'foo/bar', 'should find foo');
87
+ done();
88
+ });
89
+ });
90
+
91
+
92
+ Ct.test('should expose async inside of module', function(t, done) {
93
+ var spade = t.spade;
94
+ t.timeout(1000);
95
+
96
+ var async = spade.require('foo/baz').async;
97
+ t.ok(async, 'should have an async function');
98
+
99
+ // normalize relative to async
100
+ async('./bar', function(err) {
101
+ t.equal(err, null);
102
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
103
+ t.equal(spade.require('foo/bar').id, 'foo/bar', 'should find foo');
104
+ done();
105
+ });
106
+ });
107
+
108
+
109
+ Ct.test('should return err if loader does not register', function(t, done) {
110
+ var spade = t.spade;
111
+ t.timeout(1000);
112
+ spade.async('imaginary/bar', function(err) {
113
+ t.equal(err, 'Not Found');
114
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
115
+
116
+ t.throws(function() {
117
+ spade.require('imaginary/bar');
118
+ });
119
+ done();
120
+ });
121
+
122
+ });
123
+
@@ -0,0 +1,13 @@
1
+ // ==========================================================================
2
+ // Project: Spade - CommonJS Runtime
3
+ // Copyright: ©2011 Strobe Inc. All rights reserved.
4
+ // License: Licened under MIT license (see __preamble__.js)
5
+ // ==========================================================================
6
+ //
7
+
8
+ var Ct = require('core-test/sync');
9
+
10
+ Ct.module('spade: Compiler JavaScript');
11
+
12
+ Ct.test('works');
13
+
@@ -0,0 +1,14 @@
1
+ // ==========================================================================
2
+ // Project: Spade - CommonJS Runtime
3
+ // Copyright: ©2011 Strobe Inc. All rights reserved.
4
+ // License: Licened under MIT license (see __preamble__.js)
5
+ // ==========================================================================
6
+ //
7
+
8
+ var Ct = require('core-test/sync');
9
+
10
+ Ct.module('spade: Compiler Ruby');
11
+
12
+ Ct.test('works');
13
+
14
+
@@ -0,0 +1,64 @@
1
+ // ==========================================================================
2
+ // Project: Spade - CommonJS Runtime
3
+ // Copyright: ©2010 Strobe Inc. All rights reserved.
4
+ // License: Licened under MIT license (see __preamble__.js)
5
+ // ==========================================================================
6
+
7
+ var Ct = require('core-test/sync'),
8
+ Spade = require('spade').Spade;
9
+
10
+ // ..........................................................
11
+ // BASIC REQUIRE
12
+ //
13
+
14
+ Ct.module('spade: basic require');
15
+
16
+ Ct.setup(function(t) {
17
+ t.spade = new Spade();
18
+
19
+ // preload a module
20
+ t.spade.register('foo/main', function(r, e) { e.id = 'foo'; });
21
+
22
+ // dummy loader loads only foo/bar on demand
23
+ t.spade.loader = {
24
+
25
+ requests: 0,
26
+
27
+ loadFactory: function(spade, id, formats, done) {
28
+ this.requests++;
29
+ if (id === 'foo/bar') {
30
+ spade.register(id, function(r,e) { e.id='foo/bar'; });
31
+ }
32
+ if (done) throw "should not be passed done"
33
+ }
34
+ };
35
+
36
+ });
37
+
38
+ Ct.teardown(function(t) {
39
+ delete t.spade;
40
+ });
41
+
42
+ Ct.test('should not talk to loader if module is registered', function(t) {
43
+ var spade = t.spade;
44
+ t.equal(spade.require('foo').id, 'foo', 'should find foo');
45
+ t.equal(spade.loader.requests, 0, 'loader should not have been called');
46
+ });
47
+
48
+ Ct.test('should let loader register', function(t) {
49
+ var spade = t.spade;
50
+ t.equal(spade.require('foo/bar').id, 'foo/bar', 'should find foo');
51
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
52
+ });
53
+
54
+ Ct.test('should throw if loader does not register', function(t) {
55
+ var spade = t.spade;
56
+ t.throws(function() {
57
+ spade.require('imaginary/bar');
58
+ });
59
+ t.equal(spade.loader.requests, 1, 'loader should have been called');
60
+ });
61
+
62
+
63
+
64
+ Ct.run();
@@ -0,0 +1,73 @@
1
+ // ==========================================================================
2
+ // Project: Spade - CommonJS Runtime
3
+ // Copyright: ©2010 Strobe Inc. All rights reserved.
4
+ // License: Licened under MIT license (see __preamble__.js)
5
+ // ==========================================================================
6
+
7
+ var Ct = require('core-test/sync'),
8
+ Spade = require('spade').Spade;
9
+
10
+ // ..........................................................
11
+ // BASIC REQUIRE
12
+ //
13
+
14
+ Ct.module('spade: normalize');
15
+
16
+ Ct.setup(function(t) {
17
+ t.spade = new Spade();
18
+ });
19
+
20
+ Ct.teardown(function(t) {
21
+ delete t.spade;
22
+ });
23
+
24
+ Ct.test('normalize', function(t) {
25
+ var spade = t.spade;
26
+ t.equal(spade.normalize('foo/bar'), 'foo/bar');
27
+ t.equal(spade.normalize('./foo', 'bar/baz'), 'bar/foo');
28
+ t.equal(spade.normalize('../foo', 'bar/baz'), 'foo/main');
29
+ t.equal(spade.normalize('foo/../bar//foo/./baz', 'bar/baz'), 'bar/foo/baz');
30
+
31
+ t.equal(spade.normalize('/foo/./bar'), 'foo/bar');
32
+ t.equal(spade.normalize('foo/../bar/'), 'bar/main');
33
+ t.equal(spade.normalize('/foo/../bar/'), 'bar/main');
34
+
35
+ t.equal(spade.normalize('/foo/bar'), 'foo/bar');
36
+ t.equal(spade.normalize('foo/bar/'), 'foo/bar');
37
+ t.equal(spade.normalize('/foo/bar/'), 'foo/bar');
38
+
39
+ t.equal(spade.normalize('PKG/foo/bar'), 'PKG/foo/bar');
40
+ t.equal(spade.normalize('BAR/foo', 'PKG/bar/baz'), 'BAR/foo');
41
+ t.equal(spade.normalize('./foo', 'PKG/bar/baz'), 'PKG/bar/foo');
42
+ t.equal(spade.normalize('../foo', 'PKG/bar/baz'), 'PKG/foo');
43
+ t.equal(spade.normalize('./foo/../../bar//foo/./baz', 'PKG/bar/baz'), 'PKG/bar/foo/baz');
44
+
45
+ });
46
+
47
+ Ct.test('normalize package', function(t) {
48
+ var spade = t.spade;
49
+ spade.register('sproutcore', {}); // register as a package
50
+ t.equal(spade.normalize('sproutcore'), 'sproutcore/main');
51
+ t.equal(spade.normalize('foo/sproutcore'), 'foo/sproutcore');
52
+ });
53
+
54
+ Ct.test('normalize relative require from main', function(t) {
55
+ // I think this is a valid test, but not certain
56
+ var spade = t.spade, mainRequire, otherRequire;
57
+ spade.register('foo', { main: './lib/foo', directories: { lib: './lib/foo' } });
58
+ spade.register('foo/main', 'return require;');
59
+ spade.register('foo/other/main', 'return require;');
60
+ mainRequire = spade.require('foo/main');
61
+ otherRequire = spade.require('foo/other/main');
62
+ t.equal(mainRequire.normalize('./foo/adfadf'), 'foo/adfadf', 'works for real main');
63
+ t.equal(otherRequire.normalize('./foo/core'), 'foo/other/foo/core', "no difference for fake main");
64
+ });
65
+
66
+ Ct.test('normalize tilde paths with lib', function(t){
67
+ var spade = t.spade, fooRequire;
68
+ spade.register('foo', { directories: { lib: './lib' }}); // register as a package
69
+ spade.register('foo/main', 'return require;');
70
+ fooRequire = spade.require('foo');
71
+ t.equal(fooRequire.normalize('foo/~lib/main'), 'foo/main');
72
+ t.equal(fooRequire.normalize('foo/~lib/core'), 'foo/core');
73
+ });