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