lash 0.1.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +10 -0
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/Gemfile +2 -1
- data/LICENSE.md +48 -0
- data/README.md +117 -5
- data/Rakefile +1 -0
- data/lib/lash.rb +17 -4
- data/lib/lash/assets_host.rb +74 -0
- data/lib/lash/bundle_helper.rb +6 -24
- data/lib/lash/capistrano.rb +2 -0
- data/lib/lash/closure_minifier.rb +20 -0
- data/lib/lash/files.rb +56 -0
- data/lib/lash/java_script_bundler.rb +117 -0
- data/lib/lash/java_script_minifier.rb +67 -0
- data/lib/lash/railtie.rb +4 -33
- data/lib/lash/sprite_bundler.rb +132 -0
- data/lib/lash/tasks/lash.rake +50 -181
- data/lib/lash/version.rb +1 -1
- data/spec/lib/assets_host_spec.rb +56 -0
- data/spec/lib/bundle_helper_spec.rb +99 -0
- data/spec/lib/closure_minifier_spec.rb +67 -0
- data/spec/lib/java_script_bundler_spec.rb +46 -0
- data/spec/lib/lash_files_spec.rb +68 -0
- data/spec/spec_helper.rb +15 -25
- data/spec/support/rails_fake.rb +31 -0
- data/spec/test_app/.gitignore +4 -0
- data/spec/test_app/Rakefile +8 -0
- data/spec/test_app/public/images/rails.png +0 -0
- data/spec/test_app/public/images/ui-sprite.png +0 -0
- data/spec/test_app/public/images/ui-sprite.png.sprite +3 -0
- data/spec/test_app/public/javascripts/application/README +0 -0
- data/spec/test_app/public/javascripts/application/application.bundleVersion.js +1 -0
- data/spec/test_app/public/javascripts/application/application.js +3 -0
- data/spec/test_app/public/javascripts/application/application2.js +3 -0
- data/spec/test_app/public/javascripts/application/tools/validate.js +3 -0
- data/spec/test_app/public/javascripts/bundle_application.js +1 -0
- data/spec/test_app/public/javascripts/bundle_application.js.gz +0 -0
- data/spec/test_app/public/javascripts/cdn/jquery.js +1 -0
- data/spec/test_app/public/javascripts/cdn/jquery.js.gz +0 -0
- data/spec/test_app/public/javascripts/cdn/jquery.min.js +1 -0
- data/spec/test_app/public/javascripts/cdn/jquery.min.js.gz +0 -0
- data/spec/test_app/public/javascripts/demand/huge.js +0 -0
- data/spec/test_app/public/javascripts/demand/huge.js.gz +0 -0
- data/spec/test_app/public/javascripts/demand/huge.min.js +1 -0
- data/spec/test_app/public/javascripts/demand/huge.min.js.gz +0 -0
- data/spec/test_app/public/sprites/ui/accept.png +0 -0
- data/spec/test_app/public/sprites/ui/add.png +0 -0
- data/spec/test_app/public/stylesheets/.gitkeep +0 -0
- data/spec/test_app/public/stylesheets/sass/_ui-sprite.scss +20 -0
- data/spec/test_app/public/stylesheets/sass/_version.scss +1 -0
- metadata +81 -10
data/.autotest
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Autotest.add_hook(:initialize) do |at|
|
2
|
+
at.clear_mappings
|
3
|
+
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
|
4
|
+
["spec/lib/#{m[1]}_spec.rb"]
|
5
|
+
}
|
6
|
+
at.add_mapping(%r%^spec/(models|controllers|routing|views|helpers|mailers|requests|lib)/.*rb$%) { |filename, _|
|
7
|
+
filename
|
8
|
+
}
|
9
|
+
nil
|
10
|
+
end
|
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --debug
|
data/Gemfile
CHANGED
data/LICENSE.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# License Notices
|
2
|
+
|
3
|
+
## Lash
|
4
|
+
|
5
|
+
Copyright (C) 2011 Apps In Your Pants.
|
6
|
+
|
7
|
+
Dual licensed under MIT and GPLv3
|
8
|
+
|
9
|
+
|
10
|
+
## Google Closure Compiler
|
11
|
+
|
12
|
+
Copyright 2009 The Closure Compiler Authors.
|
13
|
+
|
14
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
15
|
+
you may not use this file except in compliance with the License.
|
16
|
+
You may obtain a copy of the License at
|
17
|
+
|
18
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
19
|
+
|
20
|
+
Unless required by applicable law or agreed to in writing, software
|
21
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
22
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
23
|
+
See the License for the specific language governing permissions and
|
24
|
+
limitations under the License.
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
## Optipng
|
29
|
+
|
30
|
+
Copyright (C) 2001-2011 Cosmin Truta.
|
31
|
+
|
32
|
+
This software is provided 'as-is', without any express or implied
|
33
|
+
warranty. In no event will the author(s) be held liable for any damages
|
34
|
+
arising from the use of this software.
|
35
|
+
|
36
|
+
Permission is granted to anyone to use this software for any purpose,
|
37
|
+
including commercial applications, and to alter it and redistribute it
|
38
|
+
freely, subject to the following restrictions:
|
39
|
+
|
40
|
+
1. The origin of this software must not be misrepresented; you must not
|
41
|
+
claim that you wrote the original software. If you use this software
|
42
|
+
in a product, an acknowledgment in the product documentation would be
|
43
|
+
appreciated but is not required.
|
44
|
+
|
45
|
+
2. Altered source versions must be plainly marked as such, and must not
|
46
|
+
be misrepresented as being the original software.
|
47
|
+
|
48
|
+
3. This notice may not be removed or altered from any source distribution.
|
data/README.md
CHANGED
@@ -15,10 +15,10 @@ Based on ["Optimizing asset bundling and serving with Rails"](https://github.com
|
|
15
15
|
|
16
16
|
# Gemfile
|
17
17
|
gem 'lash'
|
18
|
-
|
19
|
-
or as a plugin
|
20
18
|
|
21
|
-
|
19
|
+
|
20
|
+
|
21
|
+
|
22
22
|
|
23
23
|
## Bundling Assets
|
24
24
|
|
@@ -29,6 +29,10 @@ Lash includes several rake tasks to bundle loose, development versions of your s
|
|
29
29
|
|
30
30
|
Individual assets can be bundled on demand using their respective `lash:asset_type` tasks.
|
31
31
|
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
32
36
|
## JavaScript
|
33
37
|
|
34
38
|
Lash expects to find JavaScript assets as subfolders of the public/javascripts folder like so
|
@@ -60,6 +64,19 @@ __public/javascripts/demand__
|
|
60
64
|
|
61
65
|
### CDN JavaScripts and Developer Mode
|
62
66
|
|
67
|
+
Shared CDN hosts are great for optimizing your site's user experience but there are two issues that developers regularly have to deal with - developing offline and accounting for CDN unavailability. Lash handles both of these cases with ease.
|
68
|
+
|
69
|
+
During development, Lash will use the copies of the libraries found in your public/javascripts/cdn directory. This makes it easy to work offline.
|
70
|
+
|
71
|
+
In production, Lash will use the CDN versions of the scripts and if a runtime test is provided, fallback to the local version if the CDN is unavailable.
|
72
|
+
|
73
|
+
<%= javascript_cdn 'jquery', '//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js', 'jQuery' -%>
|
74
|
+
|
75
|
+
# => <script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type="text/javascript"></script>
|
76
|
+
# => <script type="text/javascript">
|
77
|
+
# => if(typeof jQuery === "undefined" )
|
78
|
+
# => document.write( unescape("<script src=\"/javascripts/cdn/jquery.min.js?1297459967\" type=\"text/javascript\"><\/script>") );
|
79
|
+
# => </script>
|
63
80
|
|
64
81
|
### Referencing JavaScript Bundles in Layouts
|
65
82
|
|
@@ -72,9 +89,15 @@ When {Lash::BundleHelper#bundle_files?} is true (on by default in production), l
|
|
72
89
|
|
73
90
|
See {Lash::BundleHelper#javascript_bundle} for details.
|
74
91
|
|
92
|
+
### application.bundleVersion.js
|
75
93
|
|
94
|
+
When referring to assets in your javascripts you loose the convenience of the rails cache busting asset tags. During bundling, lash will generate an `public/javascripts/application/application.bundleVersion.js` which gets bundled into the application script. This script simply declares a global variable `bundleVersion` which you can append to asset urls in your scripts.
|
76
95
|
|
77
|
-
####
|
96
|
+
#### Example
|
97
|
+
|
98
|
+
$('#waiting-div').append( $('<img src="/images/wainting.gif?' + bundleVersion + '" />' ) )
|
99
|
+
|
100
|
+
### JavaScript bundling tasks
|
78
101
|
|
79
102
|
rake lash:js # Bundles and minifies javascripts
|
80
103
|
rake lash:js_bundle # Bundles javascripts folders into single minified files
|
@@ -84,8 +107,97 @@ See {Lash::BundleHelper#javascript_bundle} for details.
|
|
84
107
|
|
85
108
|
|
86
109
|
|
110
|
+
|
111
|
+
|
87
112
|
## CSS Sprites
|
88
113
|
|
114
|
+
CSS sprites is are an effective optimization technique, but can be very time consuming to produce. Lash makes it easy. Just drop the desired images into a folder, run a rake task and you've got a highly optimized sprite image and accompanying CSS file.
|
115
|
+
|
116
|
+
Lash looks for sprite images in `public/sprites`. Each sub folder will be bundled into a single image and css file. Given the following folder structure:
|
117
|
+
|
118
|
+
* public/sprites/ui
|
119
|
+
* accept.png
|
120
|
+
* add.png
|
121
|
+
|
122
|
+
Lash will generate a sprite image `public/images/ui-sprite.png` and corresponding css file `public/stylesheets/sass/_ui-sprite.scss`.
|
123
|
+
|
124
|
+
#### To generate your apps sprites
|
125
|
+
|
126
|
+
rake lash:sprites
|
127
|
+
|
128
|
+
|
129
|
+
### _version.scss
|
130
|
+
|
131
|
+
When referring to assets in your css scripts you loose the convenience of the rails cache busting asset tags. During bundling, lash will generate an `public/stylesheets/sass/_version.scss`. You can include this into any of your SASS scripts when you reference static assets like images.
|
132
|
+
|
133
|
+
#### Example
|
134
|
+
|
135
|
+
@import 'version';
|
136
|
+
.smiley { background-image: url(/images/smiley.png?#{$bundle-version})}
|
137
|
+
|
138
|
+
### CSS bundling tasks
|
139
|
+
|
140
|
+
rake lash:css # Process CSS scripts
|
141
|
+
rake lash:css_gzip # Compresses stylesheets for use with nginx gzip_static
|
142
|
+
rake lash:sass # Pre-generate sass scripts
|
143
|
+
rake lash:sprites # Generate CSS sprites from the public/sprites folders
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
## Optimizing PNG Images
|
150
|
+
|
151
|
+
Most image editors will compress PNG files using a very basic compression algorithm. However the PNG format
|
152
|
+
allows for much more aggressive optimization at the cost of speed. Since image resources are some of the
|
153
|
+
heaviest assets downloaded from your site, optimizing them is often worth the effort.
|
154
|
+
|
155
|
+
See [A guide to PNG optimization](http://optipng.sourceforge.net/pngtech/optipng.html) for a more detailed discussion.
|
156
|
+
|
157
|
+
#### To optimize your pngs
|
158
|
+
|
159
|
+
rake lash:png
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
|
89
165
|
## Integrating With Capistrano
|
90
166
|
|
91
|
-
|
167
|
+
Lash was designed to work with capistrano to easily run static asset bundling during the deployment process. This makes
|
168
|
+
sure that all assets are primed for static serving from your website without interfering with any existing requests
|
169
|
+
that are currently being served.
|
170
|
+
|
171
|
+
#### To run bundling tasks during deployment
|
172
|
+
|
173
|
+
# in config/deploy.rb
|
174
|
+
require 'lash/capistrano'
|
175
|
+
|
176
|
+
If you use capistrano to publish your app (and really who isn't?) you'll want to add some additional filters to your .gitignore file
|
177
|
+
|
178
|
+
# lash asset helpers
|
179
|
+
public/javascripts/common/application.bundleVersion.js
|
180
|
+
public/stylesheets/sass/_version.scss
|
181
|
+
|
182
|
+
# lash generated filed
|
183
|
+
public/javascripts/bundle_*.js
|
184
|
+
public/stylesheets/*.css
|
185
|
+
public/stylesheets/sass/_*-sprite.scss
|
186
|
+
public/javascripts/**/*.min.js
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
## License
|
196
|
+
|
197
|
+
### Lash
|
198
|
+
|
199
|
+
Copyright (C) 2011 Apps In Your Pants.
|
200
|
+
|
201
|
+
Dual licensed under MIT and GPLv3
|
202
|
+
|
203
|
+
[Other License Notices](LICENSE.md)
|
data/Rakefile
CHANGED
data/lib/lash.rb
CHANGED
@@ -3,17 +3,30 @@ module Lash
|
|
3
3
|
# from the Lash::ViewHelpers.lash_options hash. You can write
|
4
4
|
# to this hash to override default options on the global level:
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# Lash.lash_options[:unicorns] = 'run free'
|
7
7
|
#
|
8
8
|
def self.lash_options() @lash_options; end
|
9
|
+
|
9
10
|
# Overrides the default {lash_options}
|
10
|
-
|
11
|
+
#
|
12
|
+
# @option options [String] :use_asset_servers Use asset server subdomain hack to allow multiple simultaenous connections. See {Lash::AssetsHost.resolve_static_asset_server_for_source}.
|
13
|
+
# @option options [String] :use_asset_servers_in_ssl Use asset server subdomain hack even over SSL. Requires a wildcard certificate.
|
14
|
+
# @option options [String] :use_sass Support SASS
|
15
|
+
# @option options [String] :use_git_asset_id Use GIT repro id for cachebusting asset id
|
16
|
+
# @option options [String] :closure_compiler Path to custom version of google's closure compiler.
|
17
|
+
def self.lash_options=(options) @lash_options = options; end
|
11
18
|
|
12
19
|
self.lash_options = {
|
13
20
|
:use_asset_servers => true,
|
14
21
|
:use_asset_servers_in_ssl => true,
|
15
|
-
:use_sass => Gem.available?('sass')
|
22
|
+
:use_sass => Gem.available?('sass'),
|
23
|
+
:use_git_asset_id => true,
|
24
|
+
:closure_compiler => File.expand_path( "../../bin/closure-compiler/compiler.jar", __FILE__ )
|
16
25
|
}
|
17
26
|
end
|
18
27
|
|
19
|
-
require 'lash/railtie' if defined?(::Rails::Railtie)
|
28
|
+
require 'lash/railtie' if defined?(Rails) && Rails === Class and defined?(::Rails::Railtie)
|
29
|
+
require 'lash/java_script_bundler'
|
30
|
+
require 'lash/sprite_bundler'
|
31
|
+
require 'lash/files'
|
32
|
+
require 'lash/assets_host'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'grit'
|
2
|
+
require 'lash'
|
3
|
+
|
4
|
+
module Lash
|
5
|
+
module AssetsHost
|
6
|
+
|
7
|
+
# Configures Rails to use the most recent GIT repo id for public/(javascripts|stylesheets|images) for the
|
8
|
+
# asset id used for cache busting.
|
9
|
+
def self.use_git_asset_id
|
10
|
+
return unless Lash.lash_options[:use_git_asset_id]
|
11
|
+
|
12
|
+
repo = Grit::Repo.new( Rails.root.to_s )
|
13
|
+
|
14
|
+
ENV['RAILS_ASSET_ID'] = \
|
15
|
+
[:javascripts, :stylesheets, :images] \
|
16
|
+
.map { |folder| repo.log( 'master', "spec/test_app/public/#{folder}", :max_count => 1 ).first } \
|
17
|
+
.max_by { |log| log && log.committed_date }
|
18
|
+
.id
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates an asset id for the given file used for cache-busting
|
22
|
+
def self.asset_id( file )
|
23
|
+
if Lash.lash_options[:use_git_asset_id]
|
24
|
+
repo = Grit::Repo.new( Rails.root.to_s )
|
25
|
+
[:javascripts, :stylesheets, :images] \
|
26
|
+
.map { |folder| repo.log( 'master', "spec/test_app/public/#{folder}", :max_count => 1 ).first } \
|
27
|
+
.max_by { |log| log && log.committed_date }
|
28
|
+
.id
|
29
|
+
elsif ::File.exist?( file )
|
30
|
+
File.mtime( file ).to_i.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Method used to map an asset to a static asset server. This method simply generates a semi-random domain
|
35
|
+
# prefix based on the filename of the source. The asset server should resolve to the same server as
|
36
|
+
# the rails app. This is a basic browser hack to allow more than 4 connections to the server so that the
|
37
|
+
# browser can download multiple assets simultaneously.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# request.host # => lvh.me
|
41
|
+
# resolve_static_asset_server_for_source "smiles", request
|
42
|
+
# # => assets1.lvh.me
|
43
|
+
#
|
44
|
+
# # from terminal
|
45
|
+
# nslookup lvh.me # => 127.0.0.1
|
46
|
+
# nslookup assets1.lvh.me # => 127.0.0.1
|
47
|
+
|
48
|
+
def self.resolve_static_asset_server_for_source( source, request )
|
49
|
+
if /\/\// =~ source
|
50
|
+
nil
|
51
|
+
elsif request.ssl? and ! Lash.lash_options[:use_asset_servers_in_ssl]
|
52
|
+
nil
|
53
|
+
elsif !Lash.lash_options[:use_asset_servers]
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
|
57
|
+
# Change the host name to include a randomized asset name at the same domain
|
58
|
+
# level. This is required so that HTTPS requests can use a wildcard domain
|
59
|
+
# without using subject alt name.
|
60
|
+
|
61
|
+
host = request.host_with_port
|
62
|
+
parts = host.split( /\./ )
|
63
|
+
if parts.length > 2
|
64
|
+
parts[0] = "#{parts[0]}-assets#{source.hash % 4}"
|
65
|
+
else
|
66
|
+
parts.unshift "assets#{source.hash % 4}"
|
67
|
+
end
|
68
|
+
|
69
|
+
"http#{'s' if request.ssl?}://#{parts.join('.')}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
data/lib/lash/bundle_helper.rb
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
require '
|
1
|
+
require 'lash/files'
|
2
2
|
|
3
3
|
module Lash
|
4
4
|
module BundleHelper
|
5
5
|
|
6
|
-
unloadable if Rails.env.development?
|
7
|
-
|
8
6
|
# Root folder where application javascript files can be found
|
9
7
|
def javascript_root
|
10
8
|
File.join( ::Rails.root, 'public', 'javascripts', '' )
|
11
9
|
end
|
12
10
|
|
13
11
|
# Determines if the processed bundle files should be used, or the loose files used to build those bundles.
|
14
|
-
# By default bundled
|
12
|
+
# By default bundled files are used in production or if the request includes a `:bundle` param or cookie.
|
13
|
+
# @return [Boolean] true if bundled assets should be used.
|
15
14
|
def bundle_files?
|
16
15
|
if params.has_key? :bundle
|
17
|
-
return
|
16
|
+
return /^t(rue)?|y(es)?|1$/i.match( params[:bundle] ) != nil
|
18
17
|
end
|
19
18
|
Rails.env.production? || cookies[:bundle] == "yes"
|
20
19
|
end
|
@@ -71,28 +70,11 @@ module Lash
|
|
71
70
|
end
|
72
71
|
|
73
72
|
private
|
74
|
-
# Collects an array of all files in `{basedir}` with the given `{ext}`.
|
75
|
-
def recursive_file_list( basedir, ext )
|
76
|
-
files = []
|
77
|
-
return files unless File.exist? basedir
|
78
|
-
Find.find( basedir ) do |path|
|
79
|
-
if FileTest.directory?( path )
|
80
|
-
if File.basename( path )[0] == ?. # Skip dot directories
|
81
|
-
Find.prune
|
82
|
-
else
|
83
|
-
next
|
84
|
-
end
|
85
|
-
end
|
86
|
-
files << path if File.extname( path ) == ext
|
87
|
-
end
|
88
|
-
files.sort
|
89
|
-
end
|
90
|
-
|
91
73
|
# Generates javscript include tags for the actual bundled javascript for each named bundle
|
92
74
|
def javascript_include_bundles( bundles )
|
93
75
|
output = ""
|
94
76
|
bundles.each do |bundle|
|
95
|
-
output << javascript_src_tag( "bundle_#{bundle}", {} )
|
77
|
+
output << javascript_src_tag( "bundle_#{bundle}.js", {} )
|
96
78
|
end
|
97
79
|
output.html_safe
|
98
80
|
end
|
@@ -101,7 +83,7 @@ module Lash
|
|
101
83
|
def javascript_include_files( bundles )
|
102
84
|
output = "\n"
|
103
85
|
bundles.each do |bundle|
|
104
|
-
files = recursive_file_list( File.join( javascript_root, bundle ), '.js' )
|
86
|
+
files = Lash::Files.recursive_file_list( File.join( javascript_root, bundle ), '.js' )
|
105
87
|
files.each do |file|
|
106
88
|
file = file.gsub( javascript_root, '' )
|
107
89
|
output << javascript_src_tag( file, {} ) + "\n"
|
data/lib/lash/capistrano.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'lash/java_script_minifier'
|
2
|
+
|
3
|
+
module Lash
|
4
|
+
# Minifies a collection of scripts using Google's closure compiler.
|
5
|
+
class ClosureMinifier < JavaScriptMinifier
|
6
|
+
|
7
|
+
private
|
8
|
+
def minify_scripts( files, target )
|
9
|
+
tmp = "#{target}.tmp"
|
10
|
+
`java -jar \"#{Lash.lash_options[:closure_compiler]}\" #{command_options} --warning_level QUIET --js \"#{files.join("\" --js \"")}\" --js_output_file \"#{tmp}\"`
|
11
|
+
if $?.exitstatus == 0
|
12
|
+
File.delete target if File.exist? target
|
13
|
+
File.rename tmp, target
|
14
|
+
end
|
15
|
+
ensure
|
16
|
+
File.delete tmp if File.exist? tmp
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/lash/files.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
module Lash
|
4
|
+
module Files
|
5
|
+
|
6
|
+
# Collects an array of all files in {basedir} with the given ext.
|
7
|
+
#
|
8
|
+
# @param [String] basedir the root directory to search
|
9
|
+
# @param [String] ext extension to filter results by
|
10
|
+
# @return [Array] an array of expanded paths for each file in {basedir} and any of it's sub directories
|
11
|
+
def self.recursive_file_list( basedir, ext )
|
12
|
+
unless ext.is_a? Regexp
|
13
|
+
ext = ".#{ext}" if ext && ext[0] != ?.
|
14
|
+
ext ||= ""
|
15
|
+
end
|
16
|
+
|
17
|
+
files = []
|
18
|
+
return files unless File.exist? basedir
|
19
|
+
Find.find( basedir ) do |path|
|
20
|
+
if FileTest.directory?( path )
|
21
|
+
if File.basename( path )[0] == ?. # Skip dot directories
|
22
|
+
Find.prune
|
23
|
+
else
|
24
|
+
next
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if ext.is_a? Regexp
|
28
|
+
files << path if ext.match( path )
|
29
|
+
else
|
30
|
+
files << path if File.extname( path ) == ext
|
31
|
+
end
|
32
|
+
end
|
33
|
+
files.sort
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gets all the top level directories in the given base_path
|
37
|
+
#
|
38
|
+
# @param [String] basedir the root directory to search
|
39
|
+
# @return [Array] an array of expanded paths for all directories found
|
40
|
+
def self.get_top_level_directories( basedir )
|
41
|
+
Dir.entries( basedir ).collect do |path|
|
42
|
+
path = File.join( basedir, path )
|
43
|
+
File.basename( path )[0] == ?. || !File.directory?( path ) ? nil : path # not dot directories or files
|
44
|
+
end - [nil]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Gets the relative path from root to path of path is a subdirectory of root, otherwise returns path
|
48
|
+
def self.relative_to( path, root )
|
49
|
+
path = File.expand_path( path )
|
50
|
+
root = File.expand_path( root )
|
51
|
+
return path unless path.start_with? root
|
52
|
+
path[ root.length + 1, path.length ]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|