spade-runtime 0.1.0.1

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.
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
+ });