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
data/.gitignore CHANGED
@@ -1,13 +1,2 @@
1
1
  tmp
2
- .bundle
3
2
  devbin
4
- spade-boot.js
5
- .spade
6
- examples/web-app/spade-boot.js
7
- examples/web-app/tests/ct-runner.js
8
- examples/web-app/.spade
9
- tests/ct-runner.js
10
- packages/sproutcore-runtime/tests/ct-runner.js
11
- *.swp
12
- .DS_Store
13
- node_modules
@@ -1,6 +1,3 @@
1
- [submodule "vendor/spade-packager/packages/optparse"]
2
- path = vendor/spade-packager/packages/optparse
3
- url = https://github.com/qrush/optparse-js.git
4
- [submodule "vendor/spade-packager/packages/coffee-script"]
5
- path = vendor/spade-packager/packages/coffee-script
6
- url = https://github.com/charlesjolley/coffee-script.git
1
+ [submodule "lib/spade/package"]
2
+ path = lib/spade/package
3
+ url = git://github.com/sproutcore/spade
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ if ENV["BPM_PATH"]
4
+ gem 'bpm', :path => ENV["BPM_PATH"]
5
+ else
6
+ gem 'bpm', :git => "git://github.com/sproutcore/bpm"
7
+ end
8
+
9
+ gemspec
10
+
data/bin/spade CHANGED
@@ -2,6 +2,8 @@
2
2
  lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
3
  $:.unshift(lib) if File.exists?(lib)
4
4
 
5
- require 'spade/cli'
5
+ require 'spade'
6
6
 
7
7
  Spade::CLI::Base.start
8
+
9
+
@@ -1,2 +1,72 @@
1
+ require 'spade/version'
2
+
3
+ begin
4
+ require 'bpm'
5
+ rescue LoadError
6
+ # BPM isn't necessary, but we should use it if available
7
+ end
8
+
1
9
  module Spade
10
+ SPADE_DIR = '.spade'
11
+
12
+ autoload :Bundle, 'spade/bundle'
13
+ autoload :Context, 'spade/context'
14
+ autoload :MainContext,'spade/context'
15
+ autoload :Server, 'spade/server'
16
+ autoload :Shell, 'spade/shell'
17
+ autoload :CLI, 'spade/cli'
18
+ autoload :Namespace, 'spade/exports'
19
+ autoload :Exports, 'spade/exports'
20
+ autoload :Packager, 'spade/packager'
21
+ autoload :Reactor, 'spade/reactor'
22
+ autoload :Console, 'spade/console'
23
+ autoload :Loader, 'spade/loader'
24
+ autoload :Evaluator, 'spade/evaluator'
25
+
26
+ def self.jspath
27
+ File.expand_path("../spade/package/lib/spade.js", __FILE__)
28
+ end
29
+
30
+ def self.boot_path
31
+ File.dirname(Spade.jspath)
32
+ end
33
+
34
+ # find the current path with a package.json or .packages or cur_path
35
+ def self.discover_root(cur_path)
36
+ ret = File.expand_path(cur_path)
37
+ while ret != '/' && ret != '.'
38
+ return ret if File.exists?(File.join(ret,'package.json')) || File.exists?(File.join(ret,'.spade'))
39
+ ret = File.dirname ret
40
+ end
41
+
42
+ return cur_path
43
+ end
44
+
45
+ def self.current_context
46
+ @current_context
47
+ end
48
+
49
+ def self.current_context=(ctx)
50
+ @current_context = ctx
51
+ end
52
+
53
+ def self.exports=(klass)
54
+ exports(klass, nil)
55
+ end
56
+
57
+ def self.exports(klass, path = nil)
58
+ path = @current_path if path.nil?
59
+ @exports ||= {}
60
+ @exports[path] = klass
61
+ end
62
+
63
+ def self.exports_for(path)
64
+ @current_path = path
65
+ require path
66
+ @current_path = nil
67
+
68
+ @exports ||= {}
69
+ @exports[path]
70
+ end
71
+
2
72
  end
@@ -0,0 +1,180 @@
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
+ module Spade
10
+ module Bundle
11
+ class << self
12
+
13
+ def update(rootdir, opts ={})
14
+
15
+ verbose = opts[:verbose]
16
+ spade_path = File.join(rootdir, Spade::SPADE_DIR)
17
+ spade_package_path = File.join(spade_path, 'packages')
18
+ FileUtils.rm_r(spade_path) if File.exists? spade_path
19
+
20
+ FileUtils.mkdir_p File.join(spade_package_path)
21
+
22
+ FileUtils.ln_s Spade.boot_path, File.join(spade_path, 'boot')
23
+
24
+ installed = []
25
+ package_dirs = []
26
+
27
+ # In order of precedence
28
+ package_dirs += %w[packages vendor/packages vendor/cache].map{|p| File.join(rootdir, p.split('/')) }
29
+ package_dirs << File.join(LibGems.dir, 'gems') if defined?(BPM)
30
+
31
+ for package_dir in package_dirs
32
+ Dir.glob(File.join(package_dir, '*')).each do |path|
33
+ json_file = File.join(path, 'package.json')
34
+ next unless File.exists?(json_file)
35
+
36
+ # How would this happen?
37
+ next if installed.include? path
38
+ installed << path
39
+
40
+ json = JSON.load File.read(json_file)
41
+ package_name = json['name']
42
+ package_version = json['version']
43
+
44
+ local = path.index(rootdir) == 0
45
+
46
+ # Use relative paths if embedded
47
+ old_path = if local
48
+ # Figure out how many levels deep the spade_path is in the project
49
+ levels = spade_package_path.sub(rootdir, '').split(File::SEPARATOR).reject{|p| p.empty? }.count
50
+ # Build relative path
51
+ File.join(['..'] * levels, path.sub(rootdir, ''))
52
+ else
53
+ path
54
+ end
55
+
56
+ new_path = File.join(spade_path, 'packages', package_name)
57
+
58
+ unless File.exist?(new_path)
59
+ FileUtils.ln_s old_path, new_path, :force => true
60
+
61
+ puts "Installing #{local ? "local" : "remote"} package #{package_name}" if verbose
62
+ end
63
+ end
64
+ end
65
+
66
+ File.open(File.join(rootdir, 'spade-boot.js'), 'w+') do |fp|
67
+ fp.write gen_spade_boot(rootdir, opts)
68
+ end
69
+ puts "Wrote spade-boot.js" if verbose
70
+
71
+
72
+ end
73
+
74
+ def gen_spade_boot(rootdir, opts={})
75
+ verbose = opts[:verbose]
76
+ spade_path = File.join(rootdir, Spade::SPADE_DIR, 'packages', '*')
77
+ known_packages = Dir.glob(spade_path).map do |path|
78
+ package_name = File.basename path
79
+ info = JSON.load File.read(File.join(path, 'package.json'))
80
+ info["sync"] = true
81
+ info["root"] = "#{Spade::SPADE_DIR}/packages/#{package_name}"
82
+ info["files"] = package_file_list(path)
83
+ info
84
+ end
85
+
86
+ if File.exists? File.join(rootdir, 'package.json')
87
+ info = JSON.load File.read(File.join(rootdir, 'package.json'))
88
+ else
89
+ info = {
90
+ "name" => File.basename(rootdir),
91
+ "directories" => { "lib" => "lib" }
92
+ }
93
+ end
94
+
95
+ info["root"] = '.'
96
+ info["sync"] = true
97
+ info["files"] = package_file_list('.')
98
+
99
+ packages = resolve_dependencies(info, known_packages)
100
+
101
+ %[// GENERATED: #{Time.now.to_s}
102
+ // This file is automatically generated by spade. To update run
103
+ // 'spade update'. To use this file, reference it in your HTML file. Base
104
+ // sure that your base URL is to the top level directory containing all of
105
+ // your files.
106
+
107
+ /*globals spade */
108
+ //@ begin boot
109
+ (function() {
110
+ // load spade itself
111
+ var script = document.createElement('script');
112
+ script.src = "#{Spade::SPADE_DIR}/boot/spade.js";
113
+
114
+ function boot() {
115
+ // Register remaining packages with spade
116
+ #{packages.map{|p| %[spade.register("#{p["name"]}", #{JSON.pretty_generate(p)});\n] } * "\n"}
117
+
118
+ // find the main module to run
119
+ var main = null;
120
+ var scripts = document.scripts || document.getElementsByTagName("script"),
121
+ len = scripts.length;
122
+ for(var idx=0;!main && idx<len;idx++) {
123
+ main = scripts[idx].getAttribute('data-require');
124
+ }
125
+ scripts = null; // avoid memory leaks in IE
126
+
127
+ if (main) spade.ready(function() { spade.require(main); });
128
+ };
129
+
130
+ script.onload = boot;
131
+ // IE doesn't support onload for scripts
132
+ script.onreadystatechange = function(){
133
+ if (script.readyState === 'loaded' || script.readyState === 'complete') {
134
+ boot();
135
+ script = null; // avoid memory leaks in IE
136
+ }
137
+ };
138
+
139
+ var head = document.head || document.body || document;
140
+ head.appendChild(script);
141
+
142
+ head = null; // avoid memory leaks in IE
143
+ })();
144
+ //@ end boot
145
+ ]
146
+
147
+ end
148
+
149
+ private
150
+
151
+ def package_file_list(path)
152
+ get_all_files(path).map{|p| p.sub(path+File::SEPARATOR, '') }.reject{|p| p =~ %r{packages/} } - %w(package.json spade-boot.js)
153
+ end
154
+
155
+ # Supports recursive, be careful
156
+ def get_all_files(path)
157
+ Dir.glob(File.join(path, '**', '*')).
158
+ map{|p| File.symlink?(p) ? get_all_files(p) : p }.
159
+ flatten.
160
+ reject{|p| File.extname(p).empty? }
161
+ end
162
+
163
+ def resolve_dependencies(package, available)
164
+ # TODO: Should available be a hash to speed lookup?
165
+ if package["dependencies"]
166
+ # TODO: Check version numbers
167
+ dependencies = package["dependencies"].keys
168
+ packages = available.select{|p| dependencies.include?(p["name"]) }.
169
+ map{|p| resolve_dependencies(p, available) }.
170
+ flatten
171
+ (packages << package).uniq
172
+ else
173
+ [package]
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+ end
180
+ end
@@ -1,21 +1,5 @@
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 'thor'
8
- require 'spade/packager'
9
- require 'spade/runtime'
10
-
11
1
  module Spade
12
2
  module CLI
13
- class Base < Thor
14
- desc "package", "Manage packages"
15
- subcommand "package", Spade::Packager::CLI::Base
16
-
17
- desc "runtime", "Run Spade packages and applications"
18
- subcommand "runtime", Spade::Runtime::CLI::Base
19
- end
3
+ autoload :Base, 'spade/cli/base'
20
4
  end
21
5
  end
@@ -0,0 +1,182 @@
1
+ require 'thor'
2
+
3
+ module Spade
4
+ module CLI
5
+ class Base < Thor
6
+
7
+ class_option :working, :required => false,
8
+ :default => Spade.discover_root(Dir.pwd),
9
+ :aliases => ['-w'],
10
+ :desc => 'Root working directory.'
11
+
12
+ class_option :verbose, :type => :boolean, :default => false,
13
+ :aliases => ['-V'],
14
+ :desc => 'Show additional debug information while running'
15
+
16
+ class_option :require, :type => :array, :required => false,
17
+ :aliases => ['-r'],
18
+ :desc => "optional JS files to require before invoking main command"
19
+
20
+ map "-i" => "console", "--interactive" => "console"
21
+ desc "console", "Opens an interactive JavaScript console"
22
+ def console
23
+ require 'readline'
24
+
25
+ shell = Spade::Shell.new
26
+
27
+ context do |ctx|
28
+ shell.inject(ctx)
29
+ puts "help() for help. quit() to quit."
30
+ puts "Spade #{Spade::VERSION} (V8 #{V8::VERSION})"
31
+ puts "WORKING=#{options[:working]}" if options[:verbose]
32
+
33
+ trap("SIGINT") { puts "^C" }
34
+ repl ctx
35
+ end
36
+ end
37
+
38
+ map "-e" => "exec"
39
+ desc "exec [FILENAME]", "Executes filename or stdin"
40
+ def exec(*)
41
+ exec_args = ARGV.dup
42
+ arg = exec_args.shift while arg != "exec" && !exec_args.empty?
43
+
44
+ filename = exec_args.shift
45
+ puts "Filename: #{filename}" if options[:verbose]
46
+
47
+ if filename
48
+ puts "Working: #{options[:working]}" if options[:verbose]
49
+ filename = File.expand_path filename, Dir.pwd
50
+ throw "#{filename} not found" unless File.exists?(filename)
51
+ fp = File.open filename
52
+ source = File.basename filename
53
+ rootdir = Spade.discover_root filename
54
+
55
+ caller_id = nil
56
+ if rootdir
57
+ json_path = File.join(rootdir, 'package.json')
58
+ if File.exist?(json_path)
59
+ package_json = JSON.parse(File.read(json_path))
60
+ caller_id = "#{package_json['name']}/main"
61
+ end
62
+ end
63
+
64
+ # peek at first line. If it is poundhash, skip. else rewind file
65
+ unless fp.readline =~ /^\#\!/
66
+ fp.rewind
67
+ end
68
+
69
+ # Can't set pos on STDIN so we can only do this for files
70
+ if options[:verbose]
71
+ pos = fp.pos
72
+ puts fp.read
73
+ fp.pos = pos
74
+ end
75
+ else
76
+ fp = $stdin
77
+ source = '<stdin>'
78
+ rootdir = options[:working]
79
+ caller_id = nil
80
+ end
81
+
82
+ if options[:verbose]
83
+ puts "source: #{source}"
84
+ puts "rootdir: #{rootdir}"
85
+ puts "caller_id: #{caller_id}"
86
+ end
87
+
88
+ begin
89
+ # allow for poundhash
90
+ context(:argv => exec_args, :rootdir => rootdir, :caller_id => caller_id) do |ctx|
91
+ ctx.eval(fp, source) # eval the rest
92
+ end
93
+ rescue Interrupt => e
94
+ puts; exit
95
+ end
96
+ end
97
+
98
+ map "server" => "preview"
99
+ desc "preview", "Starts a preview server for testing"
100
+ long_desc %[
101
+ The preview command starts a simple file server that can be used to
102
+ load JavaScript-based apps in the browser. This is a convenient way to
103
+ run apps in the browser instead of having to setup Apache on your
104
+ local machine. If you are already loading apps through your own web
105
+ server (for ex using Rails) the preview server is not required.
106
+ ]
107
+ method_option :port, :type => :string, :default => '4020',
108
+ :aliases => ['-p'],
109
+ :desc => 'Port number'
110
+ def preview
111
+ require 'spade/server'
112
+ trap("SIGINT") { Spade::Server.shutdown }
113
+ Spade::Server.run(options[:working], options[:port]);
114
+ end
115
+
116
+ desc "update", "Update package info in the current project"
117
+ def update
118
+ Spade::Bundle.update(options[:working], :verbose => options[:verbose])
119
+ end
120
+
121
+ private
122
+
123
+ def repl(ctx)
124
+ ctx.reactor.next_tick do
125
+ line = Readline.readline("spade> ", true)
126
+ unless line.chomp.empty?
127
+ begin
128
+ result = ctx.eval(line, '<console>')
129
+ puts ctx['inspectjs'].call(result)
130
+ rescue V8::JSError => e
131
+ puts e.message
132
+ puts e.backtrace(:javascript)
133
+ rescue StandardError => e
134
+ puts e
135
+ puts e.backtrace.join("\n")
136
+ end
137
+ end
138
+ repl(ctx)
139
+ end
140
+ end
141
+
142
+ # Loads a JS file into the context. This is not a require; just load
143
+ def load(cxt, libfile)
144
+ begin
145
+ content = File.readlines(libfile)
146
+ content.shift if content.first && (content.first =~ /^\#\!/)
147
+ cxt.eval(content*'')
148
+ #cxt.load(libfile)
149
+ rescue V8::JSError => e
150
+ puts e.message
151
+ puts e.backtrace(:javascript)
152
+ rescue StandardError => e
153
+ puts e
154
+ end
155
+ end
156
+
157
+ # Initialize a context to work against. This will load also handle
158
+ # autorequires
159
+ def context(opts={})
160
+ opts[:rootdir] ||= options[:working]
161
+ opts[:verbose] = options[:verbose]
162
+ Spade::MainContext.new(opts) do |ctx|
163
+
164
+ requires = opts[:require]
165
+ requires.each { |r| load(ctx, r) } if requires
166
+
167
+ yield(ctx) if block_given?
168
+ end
169
+ end
170
+
171
+ def method_missing(meth, *)
172
+ if File.exist?(meth.to_s)
173
+ ARGV.unshift("exec")
174
+ invoke :exec
175
+ else
176
+ super
177
+ end
178
+ end
179
+
180
+ end
181
+ end
182
+ end