openstreetmap-image_optim 0.21.0.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +65 -0
- data/.travis.yml +42 -0
- data/CHANGELOG.markdown +272 -0
- data/CONTRIBUTING.markdown +10 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +344 -0
- data/Vagrantfile +33 -0
- data/bin/image_optim +28 -0
- data/image_optim.gemspec +29 -0
- data/lib/image_optim.rb +228 -0
- data/lib/image_optim/bin_resolver.rb +144 -0
- data/lib/image_optim/bin_resolver/bin.rb +105 -0
- data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
- data/lib/image_optim/bin_resolver/error.rb +6 -0
- data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
- data/lib/image_optim/cmd.rb +49 -0
- data/lib/image_optim/config.rb +205 -0
- data/lib/image_optim/configuration_error.rb +3 -0
- data/lib/image_optim/handler.rb +57 -0
- data/lib/image_optim/hash_helpers.rb +45 -0
- data/lib/image_optim/image_meta.rb +25 -0
- data/lib/image_optim/image_path.rb +68 -0
- data/lib/image_optim/non_negative_integer_range.rb +11 -0
- data/lib/image_optim/option_definition.rb +32 -0
- data/lib/image_optim/option_helpers.rb +17 -0
- data/lib/image_optim/railtie.rb +38 -0
- data/lib/image_optim/runner.rb +139 -0
- data/lib/image_optim/runner/glob_helpers.rb +45 -0
- data/lib/image_optim/runner/option_parser.rb +227 -0
- data/lib/image_optim/space.rb +29 -0
- data/lib/image_optim/true_false_nil.rb +16 -0
- data/lib/image_optim/worker.rb +159 -0
- data/lib/image_optim/worker/advpng.rb +35 -0
- data/lib/image_optim/worker/class_methods.rb +91 -0
- data/lib/image_optim/worker/gifsicle.rb +63 -0
- data/lib/image_optim/worker/jhead.rb +43 -0
- data/lib/image_optim/worker/jpegoptim.rb +58 -0
- data/lib/image_optim/worker/jpegrecompress.rb +44 -0
- data/lib/image_optim/worker/jpegtran.rb +46 -0
- data/lib/image_optim/worker/optipng.rb +45 -0
- data/lib/image_optim/worker/pngcrush.rb +54 -0
- data/lib/image_optim/worker/pngout.rb +38 -0
- data/lib/image_optim/worker/pngquant.rb +51 -0
- data/lib/image_optim/worker/svgo.rb +32 -0
- data/script/template/jquery-2.1.3.min.js +4 -0
- data/script/template/sortable-0.6.0.min.js +2 -0
- data/script/template/worker_analysis.erb +254 -0
- data/script/update_worker_options_in_readme +60 -0
- data/script/worker_analysis +599 -0
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +57 -0
- data/spec/image_optim/bin_resolver_spec.rb +272 -0
- data/spec/image_optim/cmd_spec.rb +66 -0
- data/spec/image_optim/config_spec.rb +217 -0
- data/spec/image_optim/handler_spec.rb +95 -0
- data/spec/image_optim/hash_helpers_spec.rb +76 -0
- data/spec/image_optim/image_path_spec.rb +54 -0
- data/spec/image_optim/railtie_spec.rb +121 -0
- data/spec/image_optim/runner/glob_helpers_spec.rb +25 -0
- data/spec/image_optim/runner/option_parser_spec.rb +99 -0
- data/spec/image_optim/space_spec.rb +25 -0
- data/spec/image_optim/worker_spec.rb +192 -0
- data/spec/image_optim_spec.rb +242 -0
- data/spec/images/comparison.png +0 -0
- data/spec/images/decompressed.jpeg +0 -0
- data/spec/images/icecream.gif +0 -0
- data/spec/images/image.jpg +0 -0
- data/spec/images/invisiblepixels/generate +24 -0
- data/spec/images/invisiblepixels/image.png +0 -0
- data/spec/images/lena.jpg +0 -0
- data/spec/images/orient/0.jpg +0 -0
- data/spec/images/orient/1.jpg +0 -0
- data/spec/images/orient/2.jpg +0 -0
- data/spec/images/orient/3.jpg +0 -0
- data/spec/images/orient/4.jpg +0 -0
- data/spec/images/orient/5.jpg +0 -0
- data/spec/images/orient/6.jpg +0 -0
- data/spec/images/orient/7.jpg +0 -0
- data/spec/images/orient/8.jpg +0 -0
- data/spec/images/orient/generate +23 -0
- data/spec/images/orient/original.jpg +0 -0
- data/spec/images/quant/64.png +0 -0
- data/spec/images/quant/generate +25 -0
- data/spec/images/rails.png +0 -0
- data/spec/images/test.svg +3 -0
- data/spec/images/transparency1.png +0 -0
- data/spec/images/transparency2.png +0 -0
- data/spec/images/vergroessert.jpg +0 -0
- data/spec/spec_helper.rb +64 -0
- data/vendor/jpegrescan +143 -0
- metadata +308 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'image_optim/image_path'
|
|
2
|
+
|
|
3
|
+
class ImageOptim
|
|
4
|
+
# Handles processing of original to result using upto two temp files
|
|
5
|
+
class Handler
|
|
6
|
+
# Holds latest successful result
|
|
7
|
+
attr_reader :result
|
|
8
|
+
|
|
9
|
+
# original must respond to temp_path
|
|
10
|
+
def initialize(original)
|
|
11
|
+
unless original.respond_to?(:temp_path)
|
|
12
|
+
fail ArgumentError, 'original should respond to temp_path'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
@original = original
|
|
16
|
+
@result = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# with no associated block, works as new. Otherwise creates instance and
|
|
20
|
+
# passes it to block, runs cleanup and returns result of handler
|
|
21
|
+
def self.for(original)
|
|
22
|
+
handler = new(original)
|
|
23
|
+
if block_given?
|
|
24
|
+
begin
|
|
25
|
+
yield handler
|
|
26
|
+
handler.result
|
|
27
|
+
ensure
|
|
28
|
+
handler.cleanup
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
handler
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Yields two paths, one to latest successful result or original, second to
|
|
36
|
+
# temp path
|
|
37
|
+
def process
|
|
38
|
+
@src ||= @original
|
|
39
|
+
@dst ||= @original.temp_path
|
|
40
|
+
|
|
41
|
+
return unless yield @src, @dst
|
|
42
|
+
@result = @dst
|
|
43
|
+
if @src == @original
|
|
44
|
+
@src, @dst = @dst, nil
|
|
45
|
+
else
|
|
46
|
+
@src, @dst = @dst, @src
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Remove extra temp files
|
|
51
|
+
def cleanup
|
|
52
|
+
return unless @dst
|
|
53
|
+
@dst.unlink
|
|
54
|
+
@dst = nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class ImageOptim
|
|
2
|
+
# Helper methods to manipulate Hash, mainly used in config
|
|
3
|
+
module HashHelpers
|
|
4
|
+
class << self
|
|
5
|
+
# Returns a new hash with all keys of root and nested hashes converted to
|
|
6
|
+
# strings
|
|
7
|
+
def deep_stringify_keys(hash)
|
|
8
|
+
deep_transform_keys(hash, &:to_s)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Returns a new hash with all keys of root and nested hashes converted to
|
|
12
|
+
# symbols
|
|
13
|
+
def deep_symbolise_keys(hash)
|
|
14
|
+
deep_transform_keys(hash, &:to_sym)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns a new hash with recursive merge of all keys
|
|
18
|
+
def deep_merge(a, b)
|
|
19
|
+
a.merge(b) do |_k, v_a, v_b|
|
|
20
|
+
if v_a.is_a?(Hash) && v_b.is_a?(Hash)
|
|
21
|
+
deep_merge(v_a, v_b)
|
|
22
|
+
else
|
|
23
|
+
v_b
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Returns a new hash with all keys of root and nested hashes converted by
|
|
31
|
+
# provided block
|
|
32
|
+
def deep_transform_keys(hash, &block)
|
|
33
|
+
new_hash = {}
|
|
34
|
+
hash.each do |k, v|
|
|
35
|
+
new_hash[block.call(k)] = if v.is_a?(Hash)
|
|
36
|
+
deep_transform_keys(v, &block)
|
|
37
|
+
else
|
|
38
|
+
v
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
new_hash
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'image_size'
|
|
2
|
+
|
|
3
|
+
class ImageOptim
|
|
4
|
+
# Getting format of image at path or as data
|
|
5
|
+
class ImageMeta
|
|
6
|
+
def self.for_path(path)
|
|
7
|
+
is = ImageSize.path(path)
|
|
8
|
+
new(is.format)
|
|
9
|
+
rescue ImageSize::FormatError => e
|
|
10
|
+
warn "#{e} (detecting format of image at #{path})"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.for_data(data)
|
|
14
|
+
is = ImageSize.new(data)
|
|
15
|
+
new(is.format)
|
|
16
|
+
rescue ImageSize::FormatError => e
|
|
17
|
+
warn "#{e} (detecting format of image data)"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_reader :format
|
|
21
|
+
def initialize(format)
|
|
22
|
+
@format = format
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'fspath'
|
|
2
|
+
require 'image_optim/image_meta'
|
|
3
|
+
|
|
4
|
+
class ImageOptim
|
|
5
|
+
# FSPath with additional helpful methods
|
|
6
|
+
class ImagePath < FSPath
|
|
7
|
+
# Holds optimized image with reference to original and its size
|
|
8
|
+
class Optimized < DelegateClass(self)
|
|
9
|
+
def initialize(path, original_or_size = nil)
|
|
10
|
+
path = ImagePath.convert(path)
|
|
11
|
+
__setobj__(path)
|
|
12
|
+
if original_or_size.is_a?(Integer)
|
|
13
|
+
@original = path
|
|
14
|
+
@original_size = original_or_size
|
|
15
|
+
elsif original_or_size
|
|
16
|
+
@original = ImagePath.convert(original_or_size)
|
|
17
|
+
@original_size = @original.size
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Original path, use original_size to get its size as original can be
|
|
22
|
+
# overwritten
|
|
23
|
+
attr_reader :original
|
|
24
|
+
|
|
25
|
+
# Stored size of original
|
|
26
|
+
attr_reader :original_size
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get temp path for this file with same extension
|
|
30
|
+
def temp_path(*args, &block)
|
|
31
|
+
ext = extname
|
|
32
|
+
self.class.temp_file_path([basename(ext).to_s, ext], *args, &block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Copy file to dest preserving attributes
|
|
36
|
+
def copy(dst)
|
|
37
|
+
FileUtils.copy_file(self, dst, true)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Atomic replace src with self
|
|
41
|
+
def replace(src)
|
|
42
|
+
src = self.class.new(src)
|
|
43
|
+
src.temp_path(src.dirname) do |temp|
|
|
44
|
+
src.copy(temp)
|
|
45
|
+
temp.write(read)
|
|
46
|
+
temp.rename(src.to_s)
|
|
47
|
+
unlink
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Get format using ImageSize
|
|
52
|
+
def format
|
|
53
|
+
image_meta = ImageMeta.for_path(self)
|
|
54
|
+
image_meta && image_meta.format
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Read binary data
|
|
58
|
+
def binread
|
|
59
|
+
open('rb', &:read)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns path if it is already an instance of this class otherwise new
|
|
63
|
+
# instance
|
|
64
|
+
def self.convert(path)
|
|
65
|
+
path.is_a?(self) ? path : new(path)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class ImageOptim
|
|
2
|
+
# Denote range of non negative integers for worker option
|
|
3
|
+
class NonNegativeIntegerRange
|
|
4
|
+
# Add handling of range of non negative integers in OptionParser instance
|
|
5
|
+
def self.add_to_option_parser(option_parser)
|
|
6
|
+
option_parser.accept(self, /(\d+)(?:-|\.\.)(\d+)/) do |_, m, n|
|
|
7
|
+
m.to_i..n.to_i
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class ImageOptim
|
|
2
|
+
# Hold information about an option
|
|
3
|
+
class OptionDefinition
|
|
4
|
+
attr_reader :name, :default, :type, :description, :proc
|
|
5
|
+
|
|
6
|
+
def initialize(name, default, type_or_description, description = nil, &proc)
|
|
7
|
+
if type_or_description.is_a?(Class)
|
|
8
|
+
type = type_or_description
|
|
9
|
+
else
|
|
10
|
+
type, description = default.class, type_or_description
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@name = name.to_sym
|
|
14
|
+
@description = description.to_s
|
|
15
|
+
@default, @type, @proc = default, type, proc
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get value for worker from options
|
|
19
|
+
def value(worker, options)
|
|
20
|
+
value = options.key?(name) ? options[name] : default
|
|
21
|
+
if proc
|
|
22
|
+
if proc.arity == 2
|
|
23
|
+
worker.instance_exec(value, self, &proc)
|
|
24
|
+
else
|
|
25
|
+
worker.instance_exec(value, &proc)
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
value
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class ImageOptim
|
|
2
|
+
# Helper methods for options
|
|
3
|
+
module OptionHelpers
|
|
4
|
+
# Ensure number is in range
|
|
5
|
+
def self.limit_with_range(number, range)
|
|
6
|
+
if range.include?(number)
|
|
7
|
+
number
|
|
8
|
+
elsif number < range.first
|
|
9
|
+
range.first
|
|
10
|
+
elsif range.exclude_end?
|
|
11
|
+
range.last - 1
|
|
12
|
+
else
|
|
13
|
+
range.last
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'image_optim'
|
|
2
|
+
|
|
3
|
+
class ImageOptim
|
|
4
|
+
# Adds image_optim as preprocessor for gif, jpeg, png and svg images
|
|
5
|
+
class Railtie < Rails::Railtie
|
|
6
|
+
initializer 'image_optim.initializer' do |app|
|
|
7
|
+
register_preprocessor(app) if register_preprocessor?(app)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def register_preprocessor?(app)
|
|
11
|
+
return if app.config.assets.compress == false
|
|
12
|
+
return if app.config.assets.image_optim == false
|
|
13
|
+
|
|
14
|
+
app.assets
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def options(app)
|
|
18
|
+
if app.config.assets.image_optim == true
|
|
19
|
+
{}
|
|
20
|
+
else
|
|
21
|
+
app.config.assets.image_optim || {}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def register_preprocessor(app)
|
|
26
|
+
image_optim = ImageOptim.new(options(app))
|
|
27
|
+
|
|
28
|
+
processor = proc do |_context, data|
|
|
29
|
+
image_optim.optimize_image_data(data) || data
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
app.assets.register_preprocessor 'image/gif', :image_optim, &processor
|
|
33
|
+
app.assets.register_preprocessor 'image/jpeg', :image_optim, &processor
|
|
34
|
+
app.assets.register_preprocessor 'image/png', :image_optim, &processor
|
|
35
|
+
app.assets.register_preprocessor 'image/svg+xml', :image_optim, &processor
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require 'image_optim'
|
|
2
|
+
require 'image_optim/hash_helpers'
|
|
3
|
+
require 'image_optim/runner/glob_helpers'
|
|
4
|
+
require 'image_optim/space'
|
|
5
|
+
require 'progress'
|
|
6
|
+
require 'find'
|
|
7
|
+
require 'yaml'
|
|
8
|
+
|
|
9
|
+
class ImageOptim
|
|
10
|
+
# Handling optimization using image_optim binary
|
|
11
|
+
class Runner
|
|
12
|
+
# Collect and output results of optimization
|
|
13
|
+
class Results
|
|
14
|
+
def initialize
|
|
15
|
+
@lines = []
|
|
16
|
+
@original_size_sum = 0
|
|
17
|
+
@optimized_size_sum = 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def add(original, optimized)
|
|
21
|
+
original_size = optimized ? optimized.original_size : original.size
|
|
22
|
+
optimized_size = optimized ? optimized.size : original.size
|
|
23
|
+
@lines << "#{size_percent(original_size, optimized_size)} #{original}"
|
|
24
|
+
@original_size_sum += original_size
|
|
25
|
+
@optimized_size_sum += optimized_size
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def print
|
|
29
|
+
puts @lines
|
|
30
|
+
puts "Total: #{size_percent(@original_size_sum, @optimized_size_sum)}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def size_percent(size_a, size_b)
|
|
36
|
+
if size_a == size_b
|
|
37
|
+
"------ #{Space::EMPTY_SPACE}"
|
|
38
|
+
else
|
|
39
|
+
percent = 100 - 100.0 * size_b / size_a
|
|
40
|
+
space = Space.space(size_a - size_b)
|
|
41
|
+
format('%5.2f%% %s', percent, space)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def initialize(options)
|
|
47
|
+
options = HashHelpers.deep_symbolise_keys(options)
|
|
48
|
+
@recursive = options.delete(:recursive)
|
|
49
|
+
@progress = options.delete(:show_progress) != false
|
|
50
|
+
@exclude_dir_globs, @exclude_file_globs = %w[dir file].map do |type|
|
|
51
|
+
glob = options.delete(:"exclude_#{type}_glob") || '.*'
|
|
52
|
+
GlobHelpers.expand_braces(glob)
|
|
53
|
+
end
|
|
54
|
+
@image_optim = ImageOptim.new(options)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def run!(args)
|
|
58
|
+
to_optimize = find_to_optimize(args)
|
|
59
|
+
unless to_optimize.empty?
|
|
60
|
+
results = Results.new
|
|
61
|
+
|
|
62
|
+
optimize_images!(to_optimize).each do |original, optimized|
|
|
63
|
+
results.add(original, optimized)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
results.print
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
!@warnings
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def optimize_images!(to_optimize, &block)
|
|
75
|
+
to_optimize = to_optimize.with_progress('optimizing') if @progress
|
|
76
|
+
@image_optim.optimize_images!(to_optimize, &block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def find_to_optimize(paths)
|
|
80
|
+
to_optimize = []
|
|
81
|
+
paths.each do |path|
|
|
82
|
+
if File.file?(path)
|
|
83
|
+
if @image_optim.optimizable?(path)
|
|
84
|
+
to_optimize << path
|
|
85
|
+
else
|
|
86
|
+
warning "#{path} is not an image or there is no optimizer for it"
|
|
87
|
+
end
|
|
88
|
+
elsif File.directory?(path)
|
|
89
|
+
if @recursive
|
|
90
|
+
to_optimize += find_to_optimize_recursive(path)
|
|
91
|
+
else
|
|
92
|
+
warning "#{path} is a directory, use --recursive option"
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
warning "#{path} is not a file or a directory or does not exist"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
to_optimize
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def find_to_optimize_recursive(dir)
|
|
102
|
+
to_optimize = []
|
|
103
|
+
Find.find(dir) do |path|
|
|
104
|
+
if File.file?(path)
|
|
105
|
+
next if exclude_file?(dir, path)
|
|
106
|
+
next unless @image_optim.optimizable?(path)
|
|
107
|
+
to_optimize << path
|
|
108
|
+
elsif File.directory?(path)
|
|
109
|
+
Find.prune if dir != path && exclude_dir?(dir, path)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
to_optimize
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def exclude_dir?(dir, path)
|
|
116
|
+
exclude?(dir, path, @exclude_dir_globs)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def exclude_file?(dir, path)
|
|
120
|
+
exclude?(dir, path, @exclude_file_globs)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Check if any of globs matches either part of path relative from dir or
|
|
124
|
+
# just basename
|
|
125
|
+
def exclude?(dir, path, globs)
|
|
126
|
+
relative_path = Pathname(path).relative_path_from(Pathname(dir)).to_s
|
|
127
|
+
basename = File.basename(path)
|
|
128
|
+
globs.any? do |glob|
|
|
129
|
+
File.fnmatch(glob, relative_path, File::FNM_PATHNAME) ||
|
|
130
|
+
File.fnmatch(glob, basename, File::FNM_PATHNAME)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def warning(message)
|
|
135
|
+
@warnings = true
|
|
136
|
+
warn message
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|