stitch-plus 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODQ4NjliZmJmZjhhNjlkZGEwOTBiYTBmOTIwYzZjZDQwNGQzNWU1Mg==
5
+ data.tar.gz: !binary |-
6
+ ODliZTkyMTRhZWMzMjBlYTNhYzRhNTQwOWQ4MTZhODEwM2Q1MjhjNQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZDA3ODVlYjhmMzFmYzQ5ZWFmYzA5ODdjNzkxZWNlYWE3OGU4OTJmZWQ3Zjlj
10
+ YWJmNjE5MDcwNWQ3ZTA4OGY5NmM2MTQ0YzA1Nzk2NzU5ZDY5ZGU2ZWE1ZjJm
11
+ YTcyODllZWMwMWI3MGY1ZjQ1Y2VjNjhiYjNjNDY4MDBjZTg3OGU=
12
+ data.tar.gz: !binary |-
13
+ MGY0ZWUzOTQ5YTQ3ZTFhNzk5YmMyNjM0ZjVhNzc2NGQ5ZTJmYmY4N2Q5NWQ2
14
+ ZjFmNjhlNDYxMGQzNGM4YWZkZTBlMTQwYWMyMzQ4NDUyN2EyYTZhYTg4ODk0
15
+ Y2MxOGMxMzY5ZDQ3MTVlN2NmY2MzZDAxOWY0YWIzYWU2NzAxYmI=
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ test/all.js
19
+ .DS_Store
20
+ test/javascripts/*.js
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+ - initial release
5
+
6
+ ## 1.0.1
7
+ - Fixed fingerprints.
8
+ - set_options is now a public method
9
+ - changed option `write` to `output`
10
+
11
+ ## 1.0.2
12
+ - Renamed 'build' method to 'compile' to be consistent with Stitch and Uglify.
13
+ - Renamed old 'compile' to 'write' since it actually writes files.
14
+ - Options can be accessed now for easier inspection
15
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stitchplus.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brandon Mathis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # Stitch Plus
2
+
3
+ A CommonJS JavaScript package management solution powered by [Stitch-rb](https://github.com/maccman/stitch-rb). Stitch Plus adds some nice features including:
4
+
5
+ - Optionally [uglify](https://github.com/lautis/uglifier) javascript output.
6
+ - Each build is fingerprinted with a comment to avoid unnecessary compiling.
7
+ - Easily fingerprint the file name for cache busting power.
8
+ - Remove previously generated files with each compile.
9
+ - Designed to integrate with Guard via [guard-stitch-plus](https://github.com/imathis/guard-stitch-plus).
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'stitch-plus'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install stitch-plus
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ # options can be a hash or a path to a yaml file
29
+ s = StitchPlus.new(options)
30
+
31
+ # Returns compiled javascript
32
+ s.compile
33
+
34
+ # Writes compiled javascript to disk (`output` config determines filename)
35
+ s.write
36
+
37
+ # Get compiled filename
38
+ s.output_file #> javascripts/app-f1408932717b4b16eb97969d34961213.js
39
+
40
+ # Return the array of javascripts to be compiled
41
+ s.all_files
42
+
43
+ # Return the fingerprint to be used
44
+ s.file_fingerprint
45
+
46
+ # Permanently modify the config options
47
+ s.set_options({output: 'foo.js'})
48
+
49
+ # Return a hash of the options
50
+ s.options
51
+
52
+ ```
53
+
54
+ All methods will accept an options hash which will temporarily override previous options options, for example:
55
+
56
+
57
+ ```
58
+ s.write({fingerprint: 'false'})
59
+ ```
60
+
61
+ This will disable fingerprinting of the filename temporarily and write to app.js instead of the fingerprinted filename.
62
+
63
+
64
+ ## Configuration
65
+
66
+ You can configure StichPlus as like this.
67
+
68
+ | Config | Description | Default |
69
+ |:-----------------|:---------------------------------------------------------------------------|:------------|
70
+ | `dependencies` | Array of files/directories to be added first as global javascripts | nil |
71
+ | `paths` | Array of directories where javascripts will be wrapped as CommonJS modules | nil |
72
+ | `output` | A path to write the compiled javascript | 'all.js' |
73
+ | `fingerprint` | Add a fingerprint to the file name for super cache busting power | false |
74
+ | `cleanup` | Automatically remove previously compiled files | true |
75
+ | `uglify` | Smash javascript using the Uglifier gem | false |
76
+ | `uglify_options` | Options for the Uglifier gem. See the [Uglifier docs](https://github.com/lautis/uglifier#usage) for details. | {} |
77
+
78
+ ### Reading configuration from a file
79
+
80
+ Stitch can also read configurations from a YAML file. For example, you could
81
+ create a `stitch.yml` containing the following:
82
+
83
+ ```yaml
84
+ stitch:
85
+ dependencies: ['javascripts/dependencies']
86
+ paths: ['javascripts/modules']
87
+ output: 'javascripts/app.js'
88
+ fingerprint: true
89
+ ```
90
+
91
+ Then you could call stitch like this:
92
+
93
+ ```ruby
94
+ js = StitchPlus.new('stitch.yml').compile
95
+ ```
96
+
97
+ ### Regarding "Dependencies"
98
+
99
+ When using `dependencies`, order matters, directories are globbed, and files will only be included once for each listing. For example, if you are working on something with jQuery and Backbone.js, your dependencies might look like this:
100
+
101
+ ```
102
+ dependencies: ['js/deps/jquery.js', 'js/deps/underscore.js', 'js/deps/backbone.js', 'js/deps']
103
+ ```
104
+
105
+ This will add—in order—jQuery, Underscore.js and Backbone.js, followed by any other files in the `js/deps` directory.
106
+
107
+
108
+ ### Regarding "Paths"
109
+
110
+ Javascrpts which are included as paths will be added to the output javascript, after any dependencies, and will be wrapped up as CommonJS modules. Stitch will add its
111
+ own require function which allows these scripts to be loaded as modules, then it will write each script as a member of a hash, with the file path as the key. For
112
+ example.
113
+
114
+ A the script `js/deps/test-module.js` containing the following:
115
+
116
+ ```js
117
+ var Test = {
118
+ init: function(){
119
+ console.log('initialized!');
120
+ }
121
+ }
122
+
123
+ module.exports = Test;
124
+ ```
125
+
126
+ will be added to the hash and surrounded with the following:
127
+
128
+ ```js
129
+ "test-module": function(exports, require, module) {
130
+ // the original script
131
+ }
132
+ ```
133
+
134
+ This allows other scripts to load the module with
135
+
136
+ ```js
137
+ test = require('test-module')
138
+ test.init() // logs 'initialized!' to the console
139
+ ```
140
+
141
+ Author's note: I feel like `paths` is a stupid name for this option, but I have left it as-is to be consistent with Stitch.
142
+
143
+ ## Contributing
144
+
145
+ 1. Fork it
146
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
147
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
148
+ 4. Push to the branch (`git push origin my-new-feature`)
149
+ 5. Create new Pull Request
150
+
151
+ ## License
152
+
153
+ Copyright (c) 2013 Brandon Mathis
154
+
155
+ MIT License
156
+
157
+ Permission is hereby granted, free of charge, to any person obtaining
158
+ a copy of this software and associated documentation files (the
159
+ "Software"), to deal in the Software without restriction, including
160
+ without limitation the rights to use, copy, modify, merge, publish,
161
+ distribute, sublicense, and/or sell copies of the Software, and to
162
+ permit persons to whom the Software is furnished to do so, subject to
163
+ the following conditions:
164
+
165
+ The above copyright notice and this permission notice shall be
166
+ included in all copies or substantial portions of the Software.
167
+
168
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
169
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
171
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
172
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
173
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
174
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
175
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ module StitchPlusVersion
2
+ VERSION = "1.0.2"
3
+ end
@@ -0,0 +1,226 @@
1
+ require 'digest/md5'
2
+ require 'stitch-rb'
3
+ require 'colorator'
4
+ require 'yaml'
5
+
6
+ class StitchPlus
7
+ attr_accessor :options
8
+
9
+ def initialize(options={})
10
+
11
+ @options = {
12
+ :dependencies => nil,
13
+ :paths => nil,
14
+ :output => 'all.js',
15
+ :fingerprint => false,
16
+ :cleanup => true,
17
+ :uglify => false,
18
+ :uglify_options => {}
19
+ }
20
+
21
+ set_options(options)
22
+
23
+ begin
24
+ require 'coffee-script'
25
+ @has_coffee = true
26
+ rescue LoadError
27
+ end
28
+
29
+ end
30
+
31
+ # Set or temporarily set options
32
+ def set_options(options={}, temporary=false)
33
+ @old_options = @options if temporary
34
+
35
+ # If options is a file path, read options from yaml
36
+ if options.class == String and File.exist? options
37
+ options = load_options(options)
38
+ end
39
+
40
+ @options = @options.merge symbolize_keys(options)
41
+
42
+ if @options[:uglify]
43
+ begin
44
+ require 'uglifier'
45
+ @uglifier = Uglifier.new(@options[:uglify_options])
46
+ rescue LoadError
47
+ end
48
+ end
49
+
50
+ @options
51
+ end
52
+
53
+ def temp_options(options)
54
+ set_options(options, true)
55
+ end
56
+
57
+ # Compile javascripts, uglifying if necessary
58
+ def compile
59
+
60
+ if all_files.join().match(/\.coffee/) and !@has_coffee
61
+ error "Cannot compile coffeescript".red
62
+ error "Add ".white + "gem 'coffee-script'".yellow + " to your Gemfile."
63
+ end
64
+
65
+ if @options[:uglify] and !@uglifier
66
+ error "Cannot uglify javascript".red
67
+ error "Add ".white + "gem 'uglifier'".yellow + " to your Gemfile."
68
+ end
69
+
70
+ begin
71
+ js = Stitch::Package.new(:dependencies => dependencies, :paths => @options[:paths]).compile
72
+ js = @uglifier.compile(js) if @uglifier
73
+ js
74
+ rescue StandardError => e
75
+ error "Stitch failed to compile".red
76
+ error e
77
+ false
78
+ end
79
+ end
80
+
81
+ # Write compiled javascripts to disk
82
+ def write(options=nil)
83
+ temp_options(options) if options
84
+
85
+ @fingerprint = file_fingerprint
86
+ @file = output_file
87
+
88
+ js = "/* Build fingerprint: #{@fingerprint} */\n" + build
89
+
90
+ if has_fingerprint(@file, @fingerprint)
91
+ info "Stitch " + "identical ".green + @file
92
+ reset_options if options
93
+ true
94
+ else
95
+ begin
96
+ write_msg = (File.exists?(@file) ? "overwrite " : "created ").yellow + @file
97
+ cleanup(@file) if @options[:cleanup]
98
+
99
+ File.open(@file, 'w') { |f| f.write js }
100
+
101
+ info "Stitch " + write_msg
102
+ true
103
+ rescue StandardError => e
104
+ error "Stitch failed to write #{@file}".red
105
+ error e
106
+ reset_options if options
107
+ false
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ # return the compiled js path including fingerprint if necessary
114
+ def output_file(options=nil)
115
+ temp_options(options) if options
116
+ file = @options[:output]
117
+
118
+ if @options[:fingerprint]
119
+ @fingerprint ||= file_fingerprint
120
+ basename = File.basename(file).split(/(\..+)$/).join("-#{@fingerprint}")
121
+ dir = File.dirname(file)
122
+ file = File.join(dir, basename)
123
+ end
124
+
125
+ reset_options if options
126
+ file
127
+ end
128
+
129
+ # Get a list of all files to be stitched
130
+ def all_files(options=nil)
131
+ temp_options(options) if options
132
+ files = []
133
+ files << dependencies if @options[:dependencies]
134
+ files << Dir.glob(File.join(@options[:paths], '**/*')) if @options[:paths]
135
+ reset_options if options
136
+ files.flatten.uniq
137
+ end
138
+
139
+ # Get and MD5 hash of files including order of dependencies
140
+ def file_fingerprint(options=nil)
141
+ temp_options(options) if options
142
+ fingerprint = Digest::MD5.hexdigest(all_files.map! { |path| "#{File.mtime(path).to_i}" }.join + @options.to_s)
143
+ reset_options if options
144
+ fingerprint
145
+ end
146
+
147
+ private
148
+
149
+ # Remove existing generated files with the same options[:output] name
150
+ def cleanup(file)
151
+ match = File.basename(@options[:output]).split(/(\..+)$/).map { |i| i.gsub(/\./, '\.')}
152
+ Dir.glob(File.join(File.dirname(@options[:output]), '**/*')).each do |item|
153
+ if File.basename(item) != File.basename(file) and File.basename(item).match /^#{match[0]}(-.+)?#{match[1]}/i
154
+ info "Stitch " + "deleted ".red + item
155
+ FileUtils.rm(item)
156
+ end
157
+ end
158
+ end
159
+
160
+
161
+ # Determine if the file has a fingerprint
162
+ def has_fingerprint(file, fingerprint)
163
+ File.size?(file) && File.open(file) {|f| f.readline} =~ /#{fingerprint}/
164
+ end
165
+
166
+ # Return all files included as dependencies, globbing as necessary
167
+ def dependencies
168
+ if @options[:dependencies]
169
+ deps = [] << @options[:dependencies]
170
+ deps.flatten.collect { |item|
171
+ item = File.join(item,'**/*') if File.directory?(item)
172
+ Dir.glob item
173
+ }.flatten.uniq.collect { |item|
174
+ File.directory?(item) ? nil : item
175
+ }.compact
176
+ else
177
+ false
178
+ end
179
+ end
180
+
181
+ def info(message)
182
+ if defined?(Guard::UI)
183
+ Guard::UI.info message
184
+ else
185
+ puts message
186
+ end
187
+ end
188
+
189
+ def error(message)
190
+ if defined?(Guard::UI)
191
+ Guard::UI.error message
192
+ else
193
+ puts message
194
+ end
195
+ end
196
+
197
+ def reset_options
198
+ if @old_options
199
+ @options = @old_options
200
+ @old_options = nil
201
+ end
202
+ end
203
+
204
+ def load_options(file)
205
+ options = YAML::load(File.open(file)) if File.exist? file
206
+ options = options['stitch'] unless options['stitch'].nil?
207
+ options
208
+ end
209
+
210
+ def symbolize_keys(hash)
211
+ hash.inject({}){|result, (key, value)|
212
+ new_key = case key
213
+ when String then key.to_sym
214
+ else key
215
+ end
216
+ new_value = case value
217
+ when Hash then symbolize_keys(value)
218
+ else value
219
+ end
220
+ result[new_key] = new_value
221
+ result
222
+ }
223
+ end
224
+
225
+ end
226
+
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stitch-plus/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "stitch-plus"
8
+ gem.version = StitchPlusVersion::VERSION
9
+ gem.authors = ["Brandon Mathis"]
10
+ gem.email = ["brandon@imathis.com"]
11
+ gem.description = %q{A nicer way to combine and uglify javascript with fingerprinting and modularization. Powered by Stitch.}
12
+ gem.summary = %q{A nicer way to combine and uglify javascript with fingerprinting and modularization. Powered by Stitch.}
13
+ gem.homepage = "https://github.com/imathis/stitch-plus"
14
+ gem.license = "MIT"
15
+
16
+ gem.add_runtime_dependency 'stitch-rb', '>= 0.0.8'
17
+ gem.add_runtime_dependency 'colorator', '>= 0.1'
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.require_paths = ["lib"]
21
+ end
data/test/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'stitch-plus', :path => "../"
4
+ gem 'coffee-script'
5
+ gem 'uglifier'
6
+
7
+
@@ -0,0 +1,3 @@
1
+ unless window.awesome?
2
+ console.log 'hi guys'
3
+
@@ -0,0 +1,4 @@
1
+ var test = function (message){
2
+ console.log(message || 'test');
3
+ }
4
+
@@ -0,0 +1,7 @@
1
+ var Widget = {
2
+ init: function(){
3
+ console.log('new widget!');
4
+ }
5
+ }
6
+
7
+ module.exports = Widget;
data/test/stitch.yml ADDED
@@ -0,0 +1,5 @@
1
+ stitch:
2
+ dependencies: ['javascripts/dependencies']
3
+ paths: ['javascripts/modules']
4
+ output: 'javascripts/app.js'
5
+ fingerprint: true
data/test/test.rb ADDED
@@ -0,0 +1,9 @@
1
+ require '../lib/stitch-plus'
2
+
3
+
4
+ s = StitchPlus.new('stitch.yml')
5
+
6
+ puts "Javascripts to be compiled:"
7
+ puts s.all_files.map { |f| " #{f}"}
8
+
9
+ puts s.compile
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stitch-plus
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Brandon Mathis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: stitch-rb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.8
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.8
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ description: A nicer way to combine and uglify javascript with fingerprinting and
42
+ modularization. Powered by Stitch.
43
+ email:
44
+ - brandon@imathis.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - CHANGELOG.md
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - lib/stitch-plus.rb
56
+ - lib/stitch-plus/version.rb
57
+ - stitchplus.gemspec
58
+ - test/Gemfile
59
+ - test/javascripts/dependencies/foo.coffee
60
+ - test/javascripts/dependencies/test.js
61
+ - test/javascripts/modules/test-module.js
62
+ - test/stitch.yml
63
+ - test/test.rb
64
+ homepage: https://github.com/imathis/stitch-plus
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.0.7
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: A nicer way to combine and uglify javascript with fingerprinting and modularization.
88
+ Powered by Stitch.
89
+ test_files: []