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.
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