stitch-rb 0.0.6 → 0.0.7

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