stitch-rb 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  .DS_Store
6
+ test/jasmine/index.js
data/Gemfile CHANGED
@@ -2,3 +2,9 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in stitch.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'json'
9
+ gem 'coffee-script'
10
+ end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Stitch
2
2
 
3
- This is a port of Sam Stephenson's [Stich](https://github.com/sstephenson/stitch) to Ruby. Stitch allows you to:
3
+ This is a port of Sam Stephenson's [Stitch](https://github.com/sstephenson/stitch) to Ruby. Stitch allows you to:
4
4
 
5
5
  > Develop and test your JavaScript applications as CommonJS modules in Node.js. Then __Stitch__ them together to run in the browser.
6
6
 
@@ -9,16 +9,16 @@ In other words, this is a [CommonJS](http://dailyjs.com/2010/10/18/modules/) Jav
9
9
  ##Usage
10
10
 
11
11
  Install the gem, or add it to your Gemfile:
12
-
12
+
13
13
  gem 'stitch-rb'
14
14
 
15
15
  You can compile your application like this:
16
16
 
17
17
  Stitch::Package.new(:paths => ["app"], :dependencies => ["lib/jquery.js"]).compile
18
-
18
+
19
19
  It returns a JavaScript file that you can serve to your users, or write to disk and cache.
20
20
 
21
- You should give `Stitch::Package` an array of `:paths`, the relative directories your JavaScript application is served from. You can also specify an array of `:dependencies`, JavaScript files which will be concatenated without being wrapped in CommonJS modules.
21
+ You should give `Stitch::Package` an array of `:paths`, the relative directories your JavaScript application is served from. You can also specify an array of `:dependencies`, JavaScript files which will be concatenated without being wrapped in CommonJS modules.
22
22
 
23
23
  ##Rails & Rack
24
24
 
@@ -33,8 +33,8 @@ Compilers need to inherit from `Stitch::Compiler`. They're very simple, for exam
33
33
  class TmplCompiler < Stitch::Compiler
34
34
  # List of supported extensions
35
35
  extensions :tmpl
36
-
37
- # A compile method which takes a file path,
36
+
37
+ # A compile method which takes a file path,
38
38
  # and returns a compiled string
39
39
  def compile(path)
40
40
  content = File.read(path)
data/Rakefile CHANGED
@@ -1 +1,9 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = FileList['test/test_helper.rb', 'test/test_*.rb']
6
+ t.libs << "."
7
+ end
8
+
9
+ task :default => :test
@@ -1,7 +1,7 @@
1
1
  module Stitch
2
2
  class TmplCompiler < Compiler
3
3
  extensions :tmpl
4
-
4
+
5
5
  def compile(path)
6
6
  content = File.read(path)
7
7
  %{var template = jQuery.template(#{content.to_json});
@@ -1,3 +1,5 @@
1
+ require "erb"
2
+
1
3
  module Stitch
2
4
  class Package
3
5
  DEFAULTS = {
@@ -39,71 +41,21 @@ module Stitch
39
41
  Source.from_file(@root, file)
40
42
  }.flatten
41
43
 
44
+ sources.uniq!
45
+
42
46
  if sources.any?
43
47
  stitch(sources)
44
48
  end
45
49
  end
46
50
 
47
- def stitch(sources)
48
- result = <<-EOF
49
- (function(/*! Stitch !*/) {
50
- if (!this.#{@identifier}) {
51
- var modules = {}, cache = {}, require = function(name, root) {
52
- var module = cache[name], path = expand(root, name), fn;
53
- if (module) {
54
- return module;
55
- } else if (fn = modules[path] || modules[path = expand(path, './index')]) {
56
- module = {id: name, exports: {}};
57
- try {
58
- cache[name] = module.exports;
59
- fn(module.exports, function(name) {
60
- return require(name, dirname(path));
61
- }, module);
62
- return cache[name] = module.exports;
63
- } catch (err) {
64
- delete cache[name];
65
- throw err;
66
- }
67
- } else {
68
- throw 'module \\'' + name + '\\' not found';
69
- }
70
- }, expand = function(root, name) {
71
- var results = [], parts, part;
72
- if (/^\\.\\.?(\\/|$)/.test(name)) {
73
- parts = [root, name].join('/').split('/');
74
- } else {
75
- parts = name.split('/');
76
- }
77
- for (var i = 0, length = parts.length; i < length; i++) {
78
- part = parts[i];
79
- if (part == '..') {
80
- results.pop();
81
- } else if (part != '.' && part != '') {
82
- results.push(part);
83
- }
84
- }
85
- return results.join('/');
86
- }, dirname = function(path) {
87
- return path.split('/').slice(0, -1).join('/');
88
- };
89
- this.#{@identifier} = function(name) {
90
- return require(name, '');
91
- }
92
- this.#{@identifier}.define = function(bundle) {
93
- for (var key in bundle)
94
- modules[key] = bundle[key];
95
- };
96
- }
97
- return this.#{@identifier}.define;
98
- }).call(this)({
99
- EOF
100
- sources.each_with_index do |source, i|
101
- result += i == 0 ? "" : ", "
102
- result += source.name.to_json
103
- result += ": function(exports, require, module) {\n#{source.compile}\n}"
104
- end
51
+ def stitch(modules)
52
+ # ERB binding variables
53
+ identifier = @identifier
54
+ modules = modules
105
55
 
106
- result += "});\n"
56
+ template = File.read(File.join(File.dirname(__FILE__), "stitch.js.erb"))
57
+ template = ERB.new(template)
58
+ template.result(binding)
107
59
  end
108
60
  end
109
61
  end
data/lib/stitch/server.rb CHANGED
@@ -3,7 +3,7 @@ module Stitch
3
3
  def initialize(options = {})
4
4
  @package = Package.new(options)
5
5
  end
6
-
6
+
7
7
  def call(env)
8
8
  [200, {"Content-Type" => "text/javascript"}, [@package.compile]]
9
9
  end
data/lib/stitch/source.rb CHANGED
@@ -3,6 +3,10 @@ require "pathname"
3
3
  module Stitch
4
4
  class Source
5
5
  class << self
6
+ # Recursively load all the sources from a given directory
7
+ # Usage:
8
+ # sources = Source.from_path("./app")
9
+ #
6
10
  def from_path(root, path = nil, result = [])
7
11
  path ||= root
8
12
  path = Pathname.new(path)
@@ -18,7 +22,14 @@ module Stitch
18
22
  result
19
23
  end
20
24
 
25
+ # Recursively resolve sources from a given file,
26
+ # dynamically resolving its dependencies
27
+ # Usage:
28
+ # sources = Source.from_file("./app/index.js")
29
+ #
21
30
  def from_file(root, path = nil, result = [])
31
+ root = Pathname.new(root)
32
+
22
33
  unless path
23
34
  path = root
24
35
  root = root.dirname
@@ -29,10 +40,13 @@ module Stitch
29
40
  from_file(root, child, result)
30
41
  end
31
42
 
32
- raise "Recursive" if result.include?(source)
33
43
  result << source
34
44
  end
35
45
 
46
+ # Resolve a require call to an absolute path
47
+ # Usage:
48
+ # path = Source.resolve("../index.js", "/my/file.js")
49
+ #
36
50
  def resolve(path, relative_to)
37
51
  path = Pathname.new(path)
38
52
  relative_to = Pathname.new(relative_to)
@@ -77,12 +91,23 @@ module Stitch
77
91
  !!compiler
78
92
  end
79
93
 
94
+ # Return an array of resolved paths
95
+ # specifying this source's dependencies
80
96
  def requires
81
97
  return [] unless source?
82
98
  requires = path.read.scan(/require\(("|')(.+)\1\)/)
83
99
  requires.map {|(_, pn)| self.class.resolve(pn, root) }
84
100
  end
85
101
 
102
+ def hash
103
+ self.path.hash
104
+ end
105
+
106
+ def eql?(source)
107
+ source.is_a?(Source) &&
108
+ source.path.to_s == self.path.to_s
109
+ end
110
+
86
111
  protected
87
112
  def source?
88
113
  valid? && compiler.source?
@@ -0,0 +1,59 @@
1
+ (function(/*! Stitch !*/) {
2
+ if (!this.<%= identifier %>) {
3
+ var modules = {}, cache = {};
4
+ var require = function(name, root) {
5
+ var path = expand(root, name), indexPath = expand(path, './index'), module, fn;
6
+ module = cache[path] || cache[indexPath];
7
+ if (module) {
8
+ return module;
9
+ } else if (fn = modules[path] || modules[path = indexPath]) {
10
+ module = {id: path, exports: {}};
11
+ cache[path] = module.exports;
12
+ fn(module.exports, function(name) {
13
+ return require(name, dirname(path));
14
+ }, module);
15
+ return cache[path] = module.exports;
16
+ } else {
17
+ throw 'module ' + name + ' not found';
18
+ }
19
+ };
20
+ var expand = function(root, name) {
21
+ var results = [], parts, part;
22
+ // If path is relative
23
+ if (/^\.\.?(\/|$)/.test(name)) {
24
+ parts = [root, name].join('/').split('/');
25
+ } else {
26
+ parts = name.split('/');
27
+ }
28
+ for (var i = 0, length = parts.length; i < length; i++) {
29
+ part = parts[i];
30
+ if (part == '..') {
31
+ results.pop();
32
+ } else if (part != '.' && part != '') {
33
+ results.push(part);
34
+ }
35
+ }
36
+ return results.join('/');
37
+ };
38
+ var dirname = function(path) {
39
+ return path.split('/').slice(0, -1).join('/');
40
+ };
41
+ this.<%= identifier %> = function(name) {
42
+ return require(name, '');
43
+ };
44
+ this.<%= identifier %>.define = function(bundle) {
45
+ for (var key in bundle) {
46
+ modules[key] = bundle[key];
47
+ }
48
+ };
49
+ this.<%= identifier %>.modules = modules;
50
+ this.<%= identifier %>.cache = cache;
51
+ }
52
+ return this.<%= identifier %>.define;
53
+ }).call(this)({
54
+ <%=
55
+ modules.map do |mod|
56
+ "#{mod.name.to_json}: function(exports, require, module) {\n#{mod.compile}\n}"
57
+ end.join(', ')
58
+ %>
59
+ });
@@ -1,3 +1,3 @@
1
1
  module Stitch
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1 @@
1
+ someCoffeeScript = true
@@ -0,0 +1,4 @@
1
+ require('models/user');
2
+ require('models/person');
3
+
4
+ // Do some stuff
@@ -0,0 +1,4 @@
1
+ module.exports = {orm: true};
2
+
3
+ window.ormCount = window.ormCount || 0;
4
+ window.ormCount += 1;
@@ -0,0 +1 @@
1
+ var ORM = require('models/orm');
@@ -0,0 +1,9 @@
1
+ var ORM = require('models/orm');
2
+
3
+ var User = function(name){
4
+ this.name = name;
5
+ };
6
+
7
+ User.ORM = ORM;
8
+
9
+ module.exports = User;
@@ -0,0 +1 @@
1
+ // A dependency - jquery.js
@@ -0,0 +1,3 @@
1
+ # Another dependency
2
+
3
+ window.test = -> alert("test")
@@ -0,0 +1,186 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Jasmine Test Runner</title>
5
+ <script type="text/javascript" src="https://raw.github.com/pivotal/jasmine/v1.1.0.rc4/lib/jasmine-core/jasmine.js"></script>
6
+ <script type="text/javascript" src="https://raw.github.com/pivotal/jasmine/v1.1.0.rc4/lib/jasmine-core/jasmine-html.js"></script>
7
+
8
+ <script src="index.js" type="text/javascript" charset="utf-8"></script>
9
+ <script src="specs.js" type="text/javascript" charset="utf-8"></script>
10
+
11
+ <style type="text/css" media="screen">
12
+ body {
13
+ font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
14
+ }
15
+
16
+
17
+ .jasmine_reporter a:visited, .jasmine_reporter a {
18
+ color: #303;
19
+ }
20
+
21
+ .jasmine_reporter a:hover, .jasmine_reporter a:active {
22
+ color: blue;
23
+ }
24
+
25
+ .run_spec {
26
+ float:right;
27
+ padding-right: 5px;
28
+ font-size: .8em;
29
+ text-decoration: none;
30
+ }
31
+
32
+ .jasmine_reporter {
33
+ margin: 0 5px;
34
+ }
35
+
36
+ .banner {
37
+ color: #303;
38
+ background-color: #fef;
39
+ padding: 5px;
40
+ }
41
+
42
+ .logo {
43
+ float: left;
44
+ font-size: 1.1em;
45
+ padding-left: 5px;
46
+ }
47
+
48
+ .logo .version {
49
+ font-size: .6em;
50
+ padding-left: 1em;
51
+ }
52
+
53
+ .runner.running {
54
+ background-color: yellow;
55
+ }
56
+
57
+
58
+ .options {
59
+ text-align: right;
60
+ font-size: .8em;
61
+ }
62
+
63
+
64
+
65
+
66
+ .suite {
67
+ border: 1px outset gray;
68
+ margin: 5px 0;
69
+ padding-left: 1em;
70
+ }
71
+
72
+ .suite .suite {
73
+ margin: 5px;
74
+ }
75
+
76
+ .suite.passed {
77
+ background-color: #dfd;
78
+ }
79
+
80
+ .suite.failed {
81
+ background-color: #fdd;
82
+ }
83
+
84
+ .spec {
85
+ margin: 5px;
86
+ padding-left: 1em;
87
+ clear: both;
88
+ }
89
+
90
+ .spec.failed, .spec.passed, .spec.skipped {
91
+ padding-bottom: 5px;
92
+ border: 1px solid gray;
93
+ }
94
+
95
+ .spec.failed {
96
+ background-color: #fbb;
97
+ border-color: red;
98
+ }
99
+
100
+ .spec.passed {
101
+ background-color: #bfb;
102
+ border-color: green;
103
+ }
104
+
105
+ .spec.skipped {
106
+ background-color: #bbb;
107
+ }
108
+
109
+ .messages {
110
+ border-left: 1px dashed gray;
111
+ padding-left: 1em;
112
+ padding-right: 1em;
113
+ }
114
+
115
+ .passed {
116
+ background-color: #cfc;
117
+ display: none;
118
+ }
119
+
120
+ .failed {
121
+ background-color: #fbb;
122
+ }
123
+
124
+ .skipped {
125
+ color: #777;
126
+ background-color: #eee;
127
+ display: none;
128
+ }
129
+
130
+
131
+ /*.resultMessage {*/
132
+ /*white-space: pre;*/
133
+ /*}*/
134
+
135
+ .resultMessage span.result {
136
+ display: block;
137
+ line-height: 2em;
138
+ color: black;
139
+ }
140
+
141
+ .resultMessage .mismatch {
142
+ color: black;
143
+ }
144
+
145
+ .stackTrace {
146
+ white-space: pre;
147
+ font-size: .8em;
148
+ margin-left: 10px;
149
+ max-height: 5em;
150
+ overflow: auto;
151
+ border: 1px inset red;
152
+ padding: 1em;
153
+ background: #eef;
154
+ }
155
+
156
+ .finished-at {
157
+ padding-left: 1em;
158
+ font-size: .6em;
159
+ }
160
+
161
+ .show-passed .passed,
162
+ .show-skipped .skipped {
163
+ display: block;
164
+ }
165
+
166
+
167
+ #jasmine_content {
168
+ position:fixed;
169
+ right: 100%;
170
+ }
171
+
172
+ .runner {
173
+ border: 1px solid gray;
174
+ display: block;
175
+ margin: 5px 0;
176
+ padding: 2px 0 2px 10px;
177
+ }
178
+ </style>
179
+ </head>
180
+ <body>
181
+ <script type="text/javascript">
182
+ jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
183
+ jasmine.getEnv().execute();
184
+ </script>
185
+ </body>
186
+ </html>
@@ -0,0 +1,27 @@
1
+ describe("Stitch", function(){
2
+ it("should have require function", function(){
3
+ expect(typeof require).toBe("function");
4
+ });
5
+
6
+ it("should be able to require modules", function(){
7
+ expect(typeof require("models/user")).toBe("function");
8
+ });
9
+
10
+ it("should recursively find modules", function(){
11
+ var obj = require("models/orm");
12
+
13
+ expect(obj).toEqual({orm: true});
14
+ expect(obj).toBe(require("models/orm"));
15
+ });
16
+
17
+ it("should transitively require dependencies", function(){
18
+ expect(require("models/user").ORM).toEqual({orm: true});
19
+ });
20
+
21
+ it("should not load the same module twice", function(){
22
+ require("models/user");
23
+ require("models/person");
24
+
25
+ expect(window.ormCount).toBe(1);
26
+ });
27
+ });
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/stitch'
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+
3
+ class TestSource < Test::Unit::TestCase
4
+ FIXTURES = Pathname.new(File.join(File.dirname(__FILE__), "fixtures"))
5
+
6
+ def setup
7
+ end
8
+
9
+ def test_from_file
10
+ sources = Stitch::Source.from_file(FIXTURES + "app" + "index.js")
11
+ sources = sources.map {|s| s.path.relative_path_from(FIXTURES).to_s }
12
+ assert_equal [
13
+ "app/models/orm.js",
14
+ "app/models/user.js",
15
+ "app/models/orm.js",
16
+ "app/models/person.js",
17
+ "app/index.js"
18
+ ], sources
19
+ end
20
+
21
+ def test_from_path
22
+ sources = Stitch::Source.from_path(FIXTURES + "app")
23
+ sources = sources.map {|s| s.path.relative_path_from(FIXTURES).to_s }
24
+ assert_equal [
25
+ "app/controllers/users.coffee",
26
+ "app/index.js",
27
+ "app/models/orm.js",
28
+ "app/models/person.js",
29
+ "app/models/user.js"
30
+ ], sources
31
+ end
32
+
33
+ def test_resolve
34
+ path = Stitch::Source.resolve("index.js", FIXTURES + "app")
35
+ assert_equal path.relative_path_from(FIXTURES).to_s, "app/index.js"
36
+
37
+ path = Stitch::Source.resolve("index", FIXTURES + "app")
38
+ assert_equal path.relative_path_from(FIXTURES).to_s, "app/index.js"
39
+ end
40
+
41
+ def test_require
42
+ source = Stitch::Source.new(FIXTURES + "app", FIXTURES + "app" + "index.js")
43
+ sources = source.requires.map {|s| s.relative_path_from(FIXTURES).to_s }
44
+ assert_equal ["app/models/user.js", "app/models/person.js"], sources
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestJasmine < Test::Unit::TestCase
4
+ def setup
5
+ end
6
+
7
+ def test_stitch
8
+ root = File.dirname(__FILE__)
9
+ File.open(root + '/jasmine/index.js', 'w+') do |f|
10
+ f.write Stitch::Package.new(
11
+ :files => [root + '/fixtures/app/index.js'],
12
+ :root => root + '/fixtures/app'
13
+ ).compile
14
+ end
15
+ system 'open', root + '/jasmine/index.html'
16
+ end
17
+ end
metadata CHANGED
@@ -1,29 +1,39 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: stitch-rb
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.6
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 7
10
+ version: 0.0.7
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Alex MacCaw
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2011-12-03 00:00:00.000000000Z
17
+
18
+ date: 2011-12-07 00:00:00 -08:00
19
+ default_executable:
13
20
  dependencies: []
21
+
14
22
  description: A JavaScript package manager
15
- email:
23
+ email:
16
24
  - maccman@gmail.com
17
25
  executables: []
26
+
18
27
  extensions: []
28
+
19
29
  extra_rdoc_files: []
20
- files:
30
+
31
+ files:
21
32
  - .gitignore
22
33
  - Gemfile
23
34
  - LICENSE
24
35
  - README.md
25
36
  - Rakefile
26
- - examples/.DS_Store
27
37
  - examples/app/controllers/users.coffee
28
38
  - examples/app/index.js
29
39
  - examples/app/models/orm.js
@@ -41,30 +51,67 @@ files:
41
51
  - lib/stitch/package.rb
42
52
  - lib/stitch/server.rb
43
53
  - lib/stitch/source.rb
54
+ - lib/stitch/stitch.js.erb
44
55
  - lib/stitch/version.rb
45
56
  - stitch.gemspec
46
- homepage: ''
57
+ - test/fixtures/app/controllers/users.coffee
58
+ - test/fixtures/app/index.js
59
+ - test/fixtures/app/models/orm.js
60
+ - test/fixtures/app/models/person.js
61
+ - test/fixtures/app/models/user.js
62
+ - test/fixtures/lib/jquery.js
63
+ - test/fixtures/lib/lib.coffee
64
+ - test/jasmine/index.html
65
+ - test/jasmine/index.js
66
+ - test/jasmine/specs.js
67
+ - test/test_helper.rb
68
+ - test/test_source.rb
69
+ - test/test_stitch.rb
70
+ has_rdoc: true
71
+ homepage: ""
47
72
  licenses: []
73
+
48
74
  post_install_message:
49
75
  rdoc_options: []
50
- require_paths:
76
+
77
+ require_paths:
51
78
  - lib
52
- required_ruby_version: !ruby/object:Gem::Requirement
79
+ required_ruby_version: !ruby/object:Gem::Requirement
53
80
  none: false
54
- requirements:
55
- - - ! '>='
56
- - !ruby/object:Gem::Version
57
- version: '0'
58
- required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
89
  none: false
60
- requirements:
61
- - - ! '>='
62
- - !ruby/object:Gem::Version
63
- version: '0'
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
64
97
  requirements: []
98
+
65
99
  rubyforge_project:
66
- rubygems_version: 1.8.10
100
+ rubygems_version: 1.6.2
67
101
  signing_key:
68
102
  specification_version: 3
69
103
  summary: Stitch ported to Ruby
70
- test_files: []
104
+ test_files:
105
+ - test/fixtures/app/controllers/users.coffee
106
+ - test/fixtures/app/index.js
107
+ - test/fixtures/app/models/orm.js
108
+ - test/fixtures/app/models/person.js
109
+ - test/fixtures/app/models/user.js
110
+ - test/fixtures/lib/jquery.js
111
+ - test/fixtures/lib/lib.coffee
112
+ - test/jasmine/index.html
113
+ - test/jasmine/index.js
114
+ - test/jasmine/specs.js
115
+ - test/test_helper.rb
116
+ - test/test_source.rb
117
+ - test/test_stitch.rb