spade 0.1.0 → 0.1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/.gitignore +0 -11
  2. data/.gitmodules +3 -6
  3. data/Gemfile +10 -0
  4. data/bin/spade +3 -1
  5. data/lib/spade.rb +70 -0
  6. data/lib/spade/bundle.rb +180 -0
  7. data/lib/spade/cli.rb +1 -17
  8. data/lib/spade/cli/base.rb +182 -0
  9. data/lib/spade/console.rb +39 -0
  10. data/lib/spade/context.rb +107 -0
  11. data/lib/spade/evaluator.rb +34 -0
  12. data/lib/spade/exports.rb +70 -0
  13. data/lib/spade/loader.rb +208 -0
  14. data/lib/spade/package/.gitignore +1 -0
  15. data/lib/spade/package/Gemfile +15 -0
  16. data/lib/spade/package/lib/spade.js +1283 -0
  17. data/lib/spade/package/lib/wrapper.js +15 -0
  18. data/lib/spade/package/package.json +17 -0
  19. data/lib/spade/package/spec/javascript/async-test.js +123 -0
  20. data/lib/spade/package/spec/javascript/compiler/javascript.js +13 -0
  21. data/lib/spade/package/spec/javascript/compiler/ruby.js +14 -0
  22. data/lib/spade/package/spec/javascript/loader-test.js +64 -0
  23. data/lib/spade/package/spec/javascript/normalize-test.js +73 -0
  24. data/lib/spade/package/spec/javascript/packages-test.js +50 -0
  25. data/lib/spade/package/spec/javascript/relative-require-test.js +72 -0
  26. data/lib/spade/package/spec/javascript/require-test.js +117 -0
  27. data/lib/spade/package/spec/javascript/sandbox/creation.js +44 -0
  28. data/lib/spade/package/spec/javascript/sandbox/evaluate.js +37 -0
  29. data/lib/spade/package/spec/javascript/sandbox/format.js +79 -0
  30. data/lib/spade/package/spec/javascript/sandbox/misc.js +58 -0
  31. data/lib/spade/package/spec/javascript/sandbox/preprocessor.js +81 -0
  32. data/lib/spade/package/spec/javascript/sandbox/require.js +48 -0
  33. data/lib/spade/package/spec/javascript/sandbox/run-command.js +21 -0
  34. data/lib/spade/package/spec/javascript/spade/externs.js +14 -0
  35. data/lib/spade/package/spec/javascript/spade/load-factory.js +15 -0
  36. data/lib/spade/package/spec/javascript/spade/misc.js +23 -0
  37. data/lib/spade/package/spec/javascript/spade/ready.js +12 -0
  38. data/lib/spade/package/spec/javascript/spade/register.js +13 -0
  39. data/lib/spade/package/spec/javascript_spec.rb +7 -0
  40. data/lib/spade/package/spec/spec_helper.rb +3 -0
  41. data/lib/spade/package/spec/support/core_test.rb +67 -0
  42. data/lib/spade/reactor.rb +159 -0
  43. data/lib/spade/server.rb +66 -0
  44. data/lib/spade/shell.rb +85 -0
  45. data/lib/spade/version.rb +1 -1
  46. data/spade.gemspec +15 -4
  47. data/spec/cli/update_spec.rb +65 -0
  48. data/spec/spec_helper.rb +22 -0
  49. data/spec/support/cli.rb +103 -0
  50. data/spec/support/matchers.rb +12 -0
  51. data/spec/support/path.rb +66 -0
  52. metadata +146 -78
  53. data/.rspec +0 -1
  54. data/Buildfile +0 -18
  55. data/README.md +0 -152
  56. data/Rakefile +0 -9
  57. data/examples/format-app/lib/hello.coffee +0 -1
  58. data/examples/format-app/lib/main.js +0 -6
  59. data/examples/format-app/package.json +0 -10
  60. data/examples/format-app/resources/README.txt +0 -1
  61. data/examples/format-app/resources/config.json +0 -3
  62. data/examples/path-test/lib/hello.js +0 -1
  63. data/examples/path-test/lib/main.js +0 -1
  64. data/examples/path-test/package.json +0 -5
  65. data/examples/sc-app/index.html +0 -13
  66. data/examples/sc-app/lib/main.js +0 -24
  67. data/examples/sc-app/package.json +0 -8
  68. data/examples/single-file.js +0 -22
  69. data/examples/todos/index.html +0 -11
  70. data/examples/todos/lib/main.js +0 -11
  71. data/examples/todos/lib/todos.js +0 -93
  72. data/examples/todos/package.json +0 -10
  73. data/examples/todos/resources/stylesheets/todos.css +0 -162
  74. data/examples/todos/resources/templates/todos.handlebars +0 -31
  75. data/examples/web-app/README.md +0 -83
  76. data/examples/web-app/index.html +0 -12
  77. data/examples/web-app/lib/main.js +0 -3
  78. data/examples/web-app/package.json +0 -6
  79. data/examples/web-app/tests.html +0 -12
  80. data/examples/web-app/tests/ct-example-test.js +0 -39
  81. data/examples/web-app/tests/qunit-test.js +0 -23
@@ -0,0 +1,39 @@
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
+
8
+ module Spade
9
+
10
+ class Console
11
+
12
+ def debug(*args)
13
+ puts "\033[35mDEBUG: #{args * ','}\033[m"
14
+ nil
15
+ end
16
+
17
+ def info(*args)
18
+ puts args * ','
19
+ nil
20
+ end
21
+
22
+ def error(*args)
23
+ puts "\033[31mERROR: #{args * ','}\033[m"
24
+ nil
25
+ end
26
+
27
+ def warn(*args)
28
+ puts "\033[33mWARN: #{args * ','}\033[m"
29
+ nil
30
+ end
31
+
32
+ def log(*args)
33
+ puts args * ','
34
+ nil
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,107 @@
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 'v8'
8
+
9
+ module Spade
10
+
11
+ # Creates a basic context suitable for running modules. The environments
12
+ # setup in this context will mimic a browser worker thread context,
13
+ # including timeouts and a console. A navigator object is also defined
14
+ # that provides some general information about the context.
15
+ class Context < V8::Context
16
+
17
+ attr_reader :reactor
18
+ attr_reader :verbose
19
+
20
+ def require(mod_name)
21
+ self.eval("require('#{mod_name}');");
22
+ end
23
+
24
+ # Load the spade and racer-loader.
25
+ def initialize(opts={})
26
+ @reactor = opts[:reactor]
27
+ @verbose = opts[:verbose]
28
+ super(opts) do |ctx|
29
+ ctx['reactor'] = @reactor
30
+ ctx['console'] = Console.new
31
+ ctx['window'] = ctx.scope
32
+ ctx.eval %[
33
+ (function() {
34
+ var r = reactor;
35
+ setTimeout = function(c,i) { return r.set_timeout(c,i); };
36
+ setInterval = function(c,i) { return r.set_interval(c,i); };
37
+ clearTimeout = function(t) { return r.clear_timeout(t); };
38
+ clearInterval = function(t) { return r.clear_interval(t); };
39
+ navigator = {
40
+ appName: 'spade',
41
+ appVersion: "#{Spade::VERSION}",
42
+ platform: "#{RUBY_PLATFORM}",
43
+ userAgent: 'spade #{Spade::VERSION}; #{RUBY_PLATFORM}'
44
+ }
45
+
46
+ exit = function(status) { return r.exit(status || 0); };
47
+ })();
48
+ ]
49
+
50
+ ctx['reactor'] = nil
51
+
52
+ yield(ctx) if block_given?
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ # The primary context created when running spade exec or spade console.
59
+ # This context will also automatically start a reactor loop.
60
+ class MainContext < Context
61
+
62
+ attr_accessor :rootdir
63
+ attr_accessor :caller_id
64
+
65
+ # Load the spade and racer-loader.
66
+ def initialize(opts={})
67
+ env = opts[:env] || ENV
68
+ @rootdir = opts[:rootdir] || opts['rootdir']
69
+ @caller_id = opts[:caller_id] || opts['caller_id']
70
+ @reactor = opts[:reactor] ||= Reactor.new(self)
71
+ lang = opts[:language] ||= (env['LANG']||'en_US').gsub(/\..*/, '')
72
+ lang = lang.gsub '_', '-'
73
+
74
+
75
+ super(opts) do |ctx|
76
+ ctx['ENV'] = env.to_hash
77
+ ctx['ENV']['SPADE_PLATFORM'] = { 'ENGINE' => 'spade-ruby' }
78
+ ctx['ENV']['LANG'] = lang
79
+
80
+ ctx['ARGV'] = opts[:argv] || ARGV
81
+
82
+ # Load spade and patch in evaluator and loader plugins
83
+ ctx.load(Spade.jspath)
84
+ ctx['rubyLoader'] = Loader.new(self)
85
+ ctx['rubyEvaluator'] = Evaluator.new(self)
86
+
87
+ ctx.eval %[
88
+ spade.loader = rubyLoader;
89
+ spade.evaluator = rubyEvaluator;
90
+ spade.defaultSandbox.rootdir = #{@rootdir.to_json};
91
+ spade.globalize();
92
+ ]
93
+
94
+ ctx.eval("spade.defaultSandbox.callerId = #{@caller_id.to_json};") if @caller_id
95
+
96
+ ctx['rubyLoader'] = ctx['rubyEvaluator'] = nil
97
+
98
+ @reactor.start do
99
+ yield(self) if block_given?
100
+ end
101
+
102
+ end
103
+ end
104
+
105
+ end
106
+ end
107
+
@@ -0,0 +1,34 @@
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
+ module Spade
8
+
9
+ # Evaluator plugin for the default context. Know how to create a new
10
+ # isolated context for the object
11
+ class Evaluator
12
+
13
+ def initialize(ctx)
14
+ @ctx = ctx
15
+ end
16
+
17
+ def setup(sandbox)
18
+ if sandbox['isIsolated']
19
+ sandbox['ctx'] = Context.new :reactor => @ctx.reactor
20
+ end
21
+ end
22
+
23
+ def evaluate(data, sandbox, filename)
24
+ ctx = sandbox['ctx'] || @ctx
25
+ ctx.eval(data, filename)
26
+ end
27
+
28
+ def teardown(sandbox)
29
+ sandbox['ctx'] = nil
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,70 @@
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
+ module Spade
8
+ module Namespace
9
+
10
+ def [](name)
11
+ begin
12
+ self.class.const_defined?(name) ? self.class.const_get(name) : yield
13
+ rescue NameError => e
14
+ yield
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ class Exports
21
+
22
+ attr_reader :context
23
+
24
+ def initialize(ctx)
25
+ @context = ctx
26
+ end
27
+
28
+ def [](name)
29
+
30
+ begin
31
+ if self.class.const_defined?(name)
32
+ ret = self.class.const_get(name)
33
+
34
+ # If we are returning a class, create a custom subclass the first
35
+ # time that also exposes the current context.
36
+ if ret.instance_of? Class
37
+ @klass_cache ||= {}
38
+ unless @klass_cache[name]
39
+
40
+ proc1 = proc { @context }
41
+ @klass_cache[name] = Class.new(ret) do
42
+
43
+ @context = proc1.call
44
+
45
+ def self.context
46
+ @context
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ @klass_cache[name]
54
+ else
55
+ ret
56
+ end
57
+
58
+ else
59
+ yield
60
+ end
61
+
62
+ rescue NameError => e
63
+ yield
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
@@ -0,0 +1,208 @@
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 'json'
8
+
9
+
10
+ module Spade
11
+
12
+ class Loader
13
+
14
+ def initialize(ctx)
15
+ @ctx = ctx
16
+ end
17
+
18
+ def discoverRoot(path)
19
+ Spade.discover_root path
20
+ end
21
+
22
+ def root(path=nil)
23
+ return @ctx.rootdir if path.nil?
24
+ @ctx.rootdir = path
25
+ @packages = nil
26
+ end
27
+
28
+ # exposed to JS. Find the JS file on disk and register the module
29
+ def loadFactory(spade, id, formats, done=nil)
30
+ formats = formats.to_a # We may get a V8::Array, we want a normal one
31
+
32
+ # load individual files
33
+ if id =~ /^file:\//
34
+ js_path = id[5..-1]
35
+ if File.exists? js_path
36
+ load_module id, js_path, ['js'], js_path
37
+ end
38
+ return nil
39
+ end
40
+
41
+ parts = id.split '/'
42
+ package_name = parts.shift
43
+ package_info = packages[package_name]
44
+ skip_module = false
45
+
46
+ return nil if package_info.nil?
47
+
48
+ if parts.size==1 && parts[0] == '~package'
49
+ skip_module = true
50
+ elsif parts.size==1 && parts[0] == 'main'
51
+ parts = (package_info[:json]['main'] || 'lib/main').split('/')
52
+ dirs = [parts[0...-1]]
53
+ parts = [parts[-1]]
54
+ else
55
+ dirs = extract_dirs(parts, package_info)
56
+ end
57
+
58
+ # register the package first - also make sure dependencies are
59
+ # registered since they are needed for loading plugins
60
+ unless package_info[:registered]
61
+ package_info[:registered] = true
62
+ @ctx.eval "spade.register('#{package_name}', #{package_info[:json].to_json});"
63
+
64
+ deps = package_info[:json]['dependencies'] || [];
65
+ deps.each do |dep_name, ignored|
66
+ dep_package_info = packages[dep_name]
67
+ next unless dep_package_info && !dep_package_info[:registered]
68
+ dep_package_info[:registered] = true
69
+ @ctx.eval "spade.register('#{dep_name}', #{dep_package_info[:json].to_json});"
70
+
71
+ # Add new formats if they are specified in our dependencies
72
+ dep_formats = dep_package_info[:json]['plugin:formats']
73
+ formats.unshift(*dep_formats.keys).uniq! if dep_formats
74
+ end
75
+
76
+ end
77
+
78
+ unless skip_module
79
+ filename = parts.pop
80
+ base_path = package_info[:path]
81
+ formats << ['js'] if formats.empty?
82
+
83
+ dirs.each do |dirname|
84
+ formats.each do |fmt|
85
+ cur_path = File.join(base_path, dirname, parts, filename+'.'+fmt)
86
+ if File.exist? cur_path
87
+ load_module id, cur_path, fmt, cur_path
88
+ return nil
89
+ end
90
+ end
91
+
92
+ rb_path = File.join(package_info[:path],dirname,parts, filename+'.rb')
93
+ if File.exists? rb_path
94
+ load_ruby id, rb_path
95
+ return nil
96
+ end
97
+ end
98
+ end
99
+
100
+ return nil
101
+ end
102
+
103
+ # exposed to JS. Determines if the named id exists in the system
104
+ def exists(spade, id, formats)
105
+
106
+ # individual files
107
+ return File.exists?(id[5..-1]) if id =~ /^file:\//
108
+
109
+ parts = id.split '/'
110
+ package_name = parts.shift
111
+ package_info = packages[package_name]
112
+
113
+ return false if package_info.nil?
114
+ return true if parts.size==1 && parts[0] == '~package'
115
+
116
+ dirs = extract_dirs(parts, package_info)
117
+
118
+
119
+ filename = parts.pop
120
+ base_path = package_info[:path]
121
+ formats = ['js'] if formats.nil?
122
+ dirs.each do |dirname|
123
+ formats.each do |fmt|
124
+ cur_path = File.join(base_path, dirname, parts, filename+'.'+fmt)
125
+ return true if File.exist? cur_path
126
+ end
127
+
128
+ rb_path = File.join(package_info[:path],dirname,parts, filename+'.rb')
129
+ return File.exists? rb_path
130
+ end
131
+ end
132
+
133
+ def load_module(id, module_path, format, path)
134
+ module_contents = File.read(module_path).to_json # encode as string
135
+ @ctx.eval("spade.register('#{id}',#{module_contents}, { format: #{format.to_s.to_json}, filename: #{path.to_s.to_json} });")
136
+ nil
137
+ end
138
+
139
+ def load_ruby(id, rb_path)
140
+
141
+ klass = Spade.exports_for rb_path
142
+ exports = klass.nil? ? {} : klass.new(@ctx)
143
+ @ctx['$__rb_exports__'] = exports
144
+
145
+ @ctx.eval(%[(function() {
146
+ var exp = $__rb_exports__;
147
+ spade.register('#{id}', function(r,e,m) { m.exports = exp; });
148
+ })();])
149
+
150
+ @ctx['$__rb_exports__'] = nil
151
+ end
152
+
153
+ def packages
154
+ @packages unless @packages.nil?
155
+ @packages = {}
156
+
157
+ if defined?(BPM)
158
+ package_paths = Dir.glob(File.join(LibGems.dir, 'gems', '*'))
159
+ package_paths.each{|path| add_package(path) }
160
+ end
161
+
162
+ # in reverse order of precedence
163
+ %w[.spade/packages vendor/cache vendor/packages packages].each do |p|
164
+ package_paths = Dir.glob File.join(@ctx.rootdir, p.split('/'), '*')
165
+ package_paths.each { |path| add_package(path) }
166
+ end
167
+
168
+ # add self
169
+ add_package @ctx.rootdir
170
+
171
+ @packages
172
+ end
173
+
174
+ private
175
+
176
+ def extract_dirs(parts, package_info)
177
+ dirname = (parts.size > 0 && parts.first.chars.first == '~') ?
178
+ parts.shift[1..-1] : 'lib'
179
+
180
+ dirs = package_info[:directories][dirname]
181
+ raise "Can't require from unknown directory: #{dirname}" unless dirs
182
+ dirs = [dirs] unless dirs.is_a?(Array)
183
+
184
+ dirs
185
+ end
186
+
187
+ def add_package(path)
188
+ json_package = File.join(path, 'package.json')
189
+ return unless File.exists?(json_package)
190
+
191
+ json = JSON.load(File.read(json_package)) rescue nil
192
+ return if json.nil?
193
+
194
+ directories = json["directories"] || { "lib" => "lib" }
195
+ json["root"] = "file:/"+File.split(path).join('/')
196
+ @packages[json["name"]] = {
197
+ :registered => false,
198
+ :path => path,
199
+ :directories => directories,
200
+ :json => json
201
+ }
202
+
203
+ end
204
+
205
+ end
206
+
207
+
208
+ end