spade 0.1.0 → 0.1.1.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.
- data/.gitignore +0 -11
- data/.gitmodules +3 -6
- data/Gemfile +10 -0
- data/bin/spade +3 -1
- data/lib/spade.rb +70 -0
- data/lib/spade/bundle.rb +180 -0
- data/lib/spade/cli.rb +1 -17
- data/lib/spade/cli/base.rb +182 -0
- data/lib/spade/console.rb +39 -0
- data/lib/spade/context.rb +107 -0
- data/lib/spade/evaluator.rb +34 -0
- data/lib/spade/exports.rb +70 -0
- data/lib/spade/loader.rb +208 -0
- data/lib/spade/package/.gitignore +1 -0
- data/lib/spade/package/Gemfile +15 -0
- data/lib/spade/package/lib/spade.js +1283 -0
- data/lib/spade/package/lib/wrapper.js +15 -0
- data/lib/spade/package/package.json +17 -0
- data/lib/spade/package/spec/javascript/async-test.js +123 -0
- data/lib/spade/package/spec/javascript/compiler/javascript.js +13 -0
- data/lib/spade/package/spec/javascript/compiler/ruby.js +14 -0
- data/lib/spade/package/spec/javascript/loader-test.js +64 -0
- data/lib/spade/package/spec/javascript/normalize-test.js +73 -0
- data/lib/spade/package/spec/javascript/packages-test.js +50 -0
- data/lib/spade/package/spec/javascript/relative-require-test.js +72 -0
- data/lib/spade/package/spec/javascript/require-test.js +117 -0
- data/lib/spade/package/spec/javascript/sandbox/creation.js +44 -0
- data/lib/spade/package/spec/javascript/sandbox/evaluate.js +37 -0
- data/lib/spade/package/spec/javascript/sandbox/format.js +79 -0
- data/lib/spade/package/spec/javascript/sandbox/misc.js +58 -0
- data/lib/spade/package/spec/javascript/sandbox/preprocessor.js +81 -0
- data/lib/spade/package/spec/javascript/sandbox/require.js +48 -0
- data/lib/spade/package/spec/javascript/sandbox/run-command.js +21 -0
- data/lib/spade/package/spec/javascript/spade/externs.js +14 -0
- data/lib/spade/package/spec/javascript/spade/load-factory.js +15 -0
- data/lib/spade/package/spec/javascript/spade/misc.js +23 -0
- data/lib/spade/package/spec/javascript/spade/ready.js +12 -0
- data/lib/spade/package/spec/javascript/spade/register.js +13 -0
- data/lib/spade/package/spec/javascript_spec.rb +7 -0
- data/lib/spade/package/spec/spec_helper.rb +3 -0
- data/lib/spade/package/spec/support/core_test.rb +67 -0
- data/lib/spade/reactor.rb +159 -0
- data/lib/spade/server.rb +66 -0
- data/lib/spade/shell.rb +85 -0
- data/lib/spade/version.rb +1 -1
- data/spade.gemspec +15 -4
- data/spec/cli/update_spec.rb +65 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/cli.rb +103 -0
- data/spec/support/matchers.rb +12 -0
- data/spec/support/path.rb +66 -0
- metadata +146 -78
- data/.rspec +0 -1
- data/Buildfile +0 -18
- data/README.md +0 -152
- data/Rakefile +0 -9
- data/examples/format-app/lib/hello.coffee +0 -1
- data/examples/format-app/lib/main.js +0 -6
- data/examples/format-app/package.json +0 -10
- data/examples/format-app/resources/README.txt +0 -1
- data/examples/format-app/resources/config.json +0 -3
- data/examples/path-test/lib/hello.js +0 -1
- data/examples/path-test/lib/main.js +0 -1
- data/examples/path-test/package.json +0 -5
- data/examples/sc-app/index.html +0 -13
- data/examples/sc-app/lib/main.js +0 -24
- data/examples/sc-app/package.json +0 -8
- data/examples/single-file.js +0 -22
- data/examples/todos/index.html +0 -11
- data/examples/todos/lib/main.js +0 -11
- data/examples/todos/lib/todos.js +0 -93
- data/examples/todos/package.json +0 -10
- data/examples/todos/resources/stylesheets/todos.css +0 -162
- data/examples/todos/resources/templates/todos.handlebars +0 -31
- data/examples/web-app/README.md +0 -83
- data/examples/web-app/index.html +0 -12
- data/examples/web-app/lib/main.js +0 -3
- data/examples/web-app/package.json +0 -6
- data/examples/web-app/tests.html +0 -12
- data/examples/web-app/tests/ct-example-test.js +0 -39
- data/examples/web-app/tests/qunit-test.js +0 -23
@@ -0,0 +1,21 @@
|
|
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
|
+
var Ct = require('core-test/sync'),
|
8
|
+
Spade = require('spade').Spade,
|
9
|
+
Sandbox = require('spade').Sandbox;
|
10
|
+
|
11
|
+
Ct.module('spade: Sandbox runCommand');
|
12
|
+
|
13
|
+
// TODO: Add the next 3 tests when adding Ruby and node.js support
|
14
|
+
Ct.test('success');
|
15
|
+
|
16
|
+
Ct.test('failure');
|
17
|
+
|
18
|
+
Ct.test('not supported');
|
19
|
+
|
20
|
+
// Not really sure how to test this, other than a bunch of stubbing
|
21
|
+
Ct.test('browser');
|
@@ -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: Spade externs');
|
11
|
+
|
12
|
+
Ct.test('works');
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,15 @@
|
|
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: Spade loadFactory');
|
11
|
+
|
12
|
+
Ct.test('works');
|
13
|
+
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,23 @@
|
|
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: Spade miscellaneous');
|
11
|
+
|
12
|
+
Ct.test('globalize works');
|
13
|
+
|
14
|
+
Ct.test('noConflict works');
|
15
|
+
|
16
|
+
Ct.test('sandbox works');
|
17
|
+
|
18
|
+
Ct.test('factoryExists works');
|
19
|
+
|
20
|
+
Ct.test('package works');
|
21
|
+
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,12 @@
|
|
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: Spade ready');
|
11
|
+
|
12
|
+
Ct.test('works');
|
@@ -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: Spade miscellaneous');
|
11
|
+
|
12
|
+
Ct.test('register works');
|
13
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spade/context'
|
2
|
+
|
3
|
+
module Spade
|
4
|
+
def self.jspath
|
5
|
+
File.expand_path("../../../lib/spade.js", __FILE__)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Matchers.define :be_ct_success do
|
10
|
+
match do |actual|
|
11
|
+
actual.first == 'passed'
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message_for_should do |actual|
|
15
|
+
actual.last
|
16
|
+
end
|
17
|
+
|
18
|
+
failure_message_for_should_not do |actual|
|
19
|
+
"expected not to be a success"
|
20
|
+
end
|
21
|
+
|
22
|
+
description do
|
23
|
+
"be a success"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module RSpecCoreTest
|
28
|
+
def run_core_tests(path, &block)
|
29
|
+
describe "#{path}" do
|
30
|
+
rootdir = File.expand_path(File.join(__FILE__, '/../../../'));
|
31
|
+
context = Spade::MainContext.new(:rootdir => rootdir) do |ctx|
|
32
|
+
ctx['checkRSpec'] = lambda do |status, test_info, message|
|
33
|
+
it "#{test_info.module.name}: #{test_info.name}" do
|
34
|
+
if status == 'warnings' && message == "Not Yet Implemented"
|
35
|
+
pending
|
36
|
+
else
|
37
|
+
[status.to_s, message.to_s].should be_ct_success
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
ctx.eval <<END
|
43
|
+
var Ct;
|
44
|
+
try {
|
45
|
+
Ct = require('core-test');
|
46
|
+
} catch (e) { }
|
47
|
+
|
48
|
+
if (Ct) {
|
49
|
+
RubyLogger = require('core-test/utils').extend(Ct.DefaultLogger, {
|
50
|
+
add: function(status, testInfo, message){
|
51
|
+
checkRSpec(status, testInfo, message);
|
52
|
+
}
|
53
|
+
});
|
54
|
+
Ct.defaultLogger = new RubyLogger('ruby');
|
55
|
+
|
56
|
+
require('file:#{path}');
|
57
|
+
|
58
|
+
Ct.run();
|
59
|
+
} else {
|
60
|
+
console.log("CoreTest is not installed. Use `spade install core-test`.");
|
61
|
+
}
|
62
|
+
END
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
RSpec::Core::ExampleGroup.extend(RSpecCoreTest)
|
@@ -0,0 +1,159 @@
|
|
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
|
+
require 'eventmachine'
|
8
|
+
|
9
|
+
module Spade
|
10
|
+
|
11
|
+
# The reactor exposes some API
|
12
|
+
class Reactor
|
13
|
+
|
14
|
+
attr_reader :timers, :running, :holds, :stopped
|
15
|
+
|
16
|
+
def initialize(ctx)
|
17
|
+
@timers = []
|
18
|
+
@running = false
|
19
|
+
@stopped = false
|
20
|
+
@holds = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
# Starts the event loop
|
24
|
+
def start
|
25
|
+
return if @running
|
26
|
+
|
27
|
+
@running = true
|
28
|
+
add_hold # release when finish is called
|
29
|
+
|
30
|
+
EventMachine.run do
|
31
|
+
@running = true
|
32
|
+
@timers.each { |t| t.start unless t.running }
|
33
|
+
|
34
|
+
yield if block_given?
|
35
|
+
|
36
|
+
@stopped = true
|
37
|
+
release_hold
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def exit(status=0)
|
43
|
+
stop_loop
|
44
|
+
Kernel.exit(status)
|
45
|
+
end
|
46
|
+
|
47
|
+
def next_tick(&block)
|
48
|
+
if @running
|
49
|
+
add_hold
|
50
|
+
EventMachine.next_tick do
|
51
|
+
yield
|
52
|
+
release_hold
|
53
|
+
end
|
54
|
+
else
|
55
|
+
add_timer(0) { yield }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
######################################################
|
60
|
+
## Holds
|
61
|
+
##
|
62
|
+
## Prevents the loop from exiting
|
63
|
+
|
64
|
+
def add_hold
|
65
|
+
@holds = @holds + 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def release_hold
|
69
|
+
@holds = @holds - 1
|
70
|
+
stop_loop if @stopped && @holds <= 0
|
71
|
+
end
|
72
|
+
|
73
|
+
def stop_loop
|
74
|
+
@running = false
|
75
|
+
EventMachine.stop_event_loop
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
######################################################
|
80
|
+
## Timers
|
81
|
+
##
|
82
|
+
|
83
|
+
def add_timer(interval, periodic = false, &block)
|
84
|
+
add_hold
|
85
|
+
Timer.new(self).tap do |timer|
|
86
|
+
timer.periodic = periodic
|
87
|
+
timer.interval = interval
|
88
|
+
timer.callback = block
|
89
|
+
@timers << timer
|
90
|
+
timer.start if @running
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_timer(timer)
|
95
|
+
'remove_timer'
|
96
|
+
release_hold if @timers.delete(timer)
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_timeout(callback, interval)
|
100
|
+
add_timer interval, false do
|
101
|
+
callback.methodcall(self)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_interval(callback, interval)
|
106
|
+
add_timer interval, true do
|
107
|
+
callback.methodcall(self)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def clear_timeout(timer)
|
112
|
+
timer.cancel
|
113
|
+
end
|
114
|
+
|
115
|
+
def clear_interval(timer)
|
116
|
+
timer.cancel
|
117
|
+
end
|
118
|
+
|
119
|
+
class Timer
|
120
|
+
|
121
|
+
attr_accessor :periodic, :interval, :callback
|
122
|
+
attr_reader :running
|
123
|
+
|
124
|
+
def initialize(reactor)
|
125
|
+
@interval = 0
|
126
|
+
@periodic = false
|
127
|
+
@callback = nil
|
128
|
+
@reactor = reactor
|
129
|
+
@running = false
|
130
|
+
end
|
131
|
+
|
132
|
+
def start
|
133
|
+
@running = true
|
134
|
+
if @periodic
|
135
|
+
@timer = EventMachine.add_periodic_timer(@interval.to_f / 1000) do
|
136
|
+
@callback.call
|
137
|
+
end
|
138
|
+
else
|
139
|
+
@timer = EventMachine.add_timer(@interval.to_f / 1000) do
|
140
|
+
@callback.call
|
141
|
+
@timer = nil
|
142
|
+
@reactor.remove_timer(self)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def cancel
|
148
|
+
EventMachine.cancel_timer(@timer) if @timer
|
149
|
+
@timer = nil
|
150
|
+
@reactor.remove_timer(self)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
data/lib/spade/server.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/static'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'child_labor'
|
5
|
+
|
6
|
+
module Spade
|
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
|
data/lib/spade/shell.rb
ADDED
@@ -0,0 +1,85 @@
|
|
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
|
+
require 'readline'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
# Global object used for the shell.
|
11
|
+
module Spade
|
12
|
+
class Shell
|
13
|
+
|
14
|
+
METHODS = [:to_s, :exit, :quit, :help, :evalrb, :inspectjs]
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@history_path = File.expand_path("~/.spadehistory")
|
18
|
+
load_history
|
19
|
+
end
|
20
|
+
|
21
|
+
def inject(ctx)
|
22
|
+
@ctx = ctx
|
23
|
+
METHODS.each{|meth| @ctx[meth.to_s] = method(meth) }
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"[object Shell]"
|
29
|
+
end
|
30
|
+
|
31
|
+
def exit(status=0)
|
32
|
+
save_history
|
33
|
+
ensure
|
34
|
+
@ctx.reactor.exit(status)
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :quit, :exit
|
38
|
+
|
39
|
+
def help(*args)
|
40
|
+
<<-HELP
|
41
|
+
print(msg)
|
42
|
+
print msg to STDOUT
|
43
|
+
|
44
|
+
exit(status = 0)
|
45
|
+
exit the shell
|
46
|
+
also: quit()
|
47
|
+
|
48
|
+
evalrb(source)
|
49
|
+
evaluate some ruby source
|
50
|
+
HELP
|
51
|
+
end
|
52
|
+
|
53
|
+
def evalrb(str)
|
54
|
+
Kernel.eval str, binding
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspectjs(obj)
|
58
|
+
# check for exact class match so we don't match things like arrays
|
59
|
+
spacer = (obj.class == V8::Object) ? 2 : nil
|
60
|
+
# the self[] uses the JS version of JSON
|
61
|
+
json = @ctx['JSON'].stringify(obj, nil, spacer)
|
62
|
+
# Some things can't be converted into json
|
63
|
+
json || obj.inspect
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def load_history
|
69
|
+
return unless File.exist?(@history_path)
|
70
|
+
File.readlines(@history_path).each{|l| Readline::HISTORY << l.chomp }
|
71
|
+
end
|
72
|
+
|
73
|
+
def save_history
|
74
|
+
FileUtils.mkdir_p(File.dirname(@history_path))
|
75
|
+
File.open(@history_path, 'w') do |f|
|
76
|
+
Readline::HISTORY.to_a.last(100).each do |l|
|
77
|
+
l.chomp!
|
78
|
+
next if l.empty?
|
79
|
+
next if l =~ /^(exit|quit)\(/
|
80
|
+
f.puts l
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|