openstreetmap-image_optim 0.21.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rubocop.yml +65 -0
  4. data/.travis.yml +42 -0
  5. data/CHANGELOG.markdown +272 -0
  6. data/CONTRIBUTING.markdown +10 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.markdown +344 -0
  10. data/Vagrantfile +33 -0
  11. data/bin/image_optim +28 -0
  12. data/image_optim.gemspec +29 -0
  13. data/lib/image_optim.rb +228 -0
  14. data/lib/image_optim/bin_resolver.rb +144 -0
  15. data/lib/image_optim/bin_resolver/bin.rb +105 -0
  16. data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
  17. data/lib/image_optim/bin_resolver/error.rb +6 -0
  18. data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
  19. data/lib/image_optim/cmd.rb +49 -0
  20. data/lib/image_optim/config.rb +205 -0
  21. data/lib/image_optim/configuration_error.rb +3 -0
  22. data/lib/image_optim/handler.rb +57 -0
  23. data/lib/image_optim/hash_helpers.rb +45 -0
  24. data/lib/image_optim/image_meta.rb +25 -0
  25. data/lib/image_optim/image_path.rb +68 -0
  26. data/lib/image_optim/non_negative_integer_range.rb +11 -0
  27. data/lib/image_optim/option_definition.rb +32 -0
  28. data/lib/image_optim/option_helpers.rb +17 -0
  29. data/lib/image_optim/railtie.rb +38 -0
  30. data/lib/image_optim/runner.rb +139 -0
  31. data/lib/image_optim/runner/glob_helpers.rb +45 -0
  32. data/lib/image_optim/runner/option_parser.rb +227 -0
  33. data/lib/image_optim/space.rb +29 -0
  34. data/lib/image_optim/true_false_nil.rb +16 -0
  35. data/lib/image_optim/worker.rb +159 -0
  36. data/lib/image_optim/worker/advpng.rb +35 -0
  37. data/lib/image_optim/worker/class_methods.rb +91 -0
  38. data/lib/image_optim/worker/gifsicle.rb +63 -0
  39. data/lib/image_optim/worker/jhead.rb +43 -0
  40. data/lib/image_optim/worker/jpegoptim.rb +58 -0
  41. data/lib/image_optim/worker/jpegrecompress.rb +44 -0
  42. data/lib/image_optim/worker/jpegtran.rb +46 -0
  43. data/lib/image_optim/worker/optipng.rb +45 -0
  44. data/lib/image_optim/worker/pngcrush.rb +54 -0
  45. data/lib/image_optim/worker/pngout.rb +38 -0
  46. data/lib/image_optim/worker/pngquant.rb +51 -0
  47. data/lib/image_optim/worker/svgo.rb +32 -0
  48. data/script/template/jquery-2.1.3.min.js +4 -0
  49. data/script/template/sortable-0.6.0.min.js +2 -0
  50. data/script/template/worker_analysis.erb +254 -0
  51. data/script/update_worker_options_in_readme +60 -0
  52. data/script/worker_analysis +599 -0
  53. data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
  54. data/spec/image_optim/bin_resolver/simple_version_spec.rb +57 -0
  55. data/spec/image_optim/bin_resolver_spec.rb +272 -0
  56. data/spec/image_optim/cmd_spec.rb +66 -0
  57. data/spec/image_optim/config_spec.rb +217 -0
  58. data/spec/image_optim/handler_spec.rb +95 -0
  59. data/spec/image_optim/hash_helpers_spec.rb +76 -0
  60. data/spec/image_optim/image_path_spec.rb +54 -0
  61. data/spec/image_optim/railtie_spec.rb +121 -0
  62. data/spec/image_optim/runner/glob_helpers_spec.rb +25 -0
  63. data/spec/image_optim/runner/option_parser_spec.rb +99 -0
  64. data/spec/image_optim/space_spec.rb +25 -0
  65. data/spec/image_optim/worker_spec.rb +192 -0
  66. data/spec/image_optim_spec.rb +242 -0
  67. data/spec/images/comparison.png +0 -0
  68. data/spec/images/decompressed.jpeg +0 -0
  69. data/spec/images/icecream.gif +0 -0
  70. data/spec/images/image.jpg +0 -0
  71. data/spec/images/invisiblepixels/generate +24 -0
  72. data/spec/images/invisiblepixels/image.png +0 -0
  73. data/spec/images/lena.jpg +0 -0
  74. data/spec/images/orient/0.jpg +0 -0
  75. data/spec/images/orient/1.jpg +0 -0
  76. data/spec/images/orient/2.jpg +0 -0
  77. data/spec/images/orient/3.jpg +0 -0
  78. data/spec/images/orient/4.jpg +0 -0
  79. data/spec/images/orient/5.jpg +0 -0
  80. data/spec/images/orient/6.jpg +0 -0
  81. data/spec/images/orient/7.jpg +0 -0
  82. data/spec/images/orient/8.jpg +0 -0
  83. data/spec/images/orient/generate +23 -0
  84. data/spec/images/orient/original.jpg +0 -0
  85. data/spec/images/quant/64.png +0 -0
  86. data/spec/images/quant/generate +25 -0
  87. data/spec/images/rails.png +0 -0
  88. data/spec/images/test.svg +3 -0
  89. data/spec/images/transparency1.png +0 -0
  90. data/spec/images/transparency2.png +0 -0
  91. data/spec/images/vergroessert.jpg +0 -0
  92. data/spec/spec_helper.rb +64 -0
  93. data/vendor/jpegrescan +143 -0
  94. metadata +308 -0
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/handler'
3
+
4
+ describe ImageOptim::Handler do
5
+ before do
6
+ stub_const('Handler', ImageOptim::Handler)
7
+ end
8
+
9
+ it 'uses original as source for first conversion '\
10
+ 'and two temp files for further conversions' do
11
+ original = double(:original)
12
+ allow(original).to receive(:temp_path) do
13
+ fail 'temp_path called unexpectedly'
14
+ end
15
+
16
+ handler = Handler.new(original)
17
+ temp_a = double(:temp_a)
18
+ temp_b = double(:temp_b)
19
+ expect(original).to receive(:temp_path).once.and_return(temp_a)
20
+ expect(original).to receive(:temp_path).once.and_return(temp_b)
21
+
22
+ # first unsuccessful run
23
+ handler.process do |src, dst|
24
+ expect([src, dst]).to eq([original, temp_a]); false
25
+ end
26
+ expect(handler.result).to be_nil
27
+
28
+ # first successful run
29
+ handler.process do |src, dst|
30
+ expect([src, dst]).to eq([original, temp_a]); true
31
+ end
32
+ expect(handler.result).to eq(temp_a)
33
+
34
+ # second unsuccessful run
35
+ handler.process do |src, dst|
36
+ expect([src, dst]).to eq([temp_a, temp_b]); false
37
+ end
38
+ expect(handler.result).to eq(temp_a)
39
+
40
+ # second successful run
41
+ handler.process do |src, dst|
42
+ expect([src, dst]).to eq([temp_a, temp_b]); true
43
+ end
44
+ expect(handler.result).to eq(temp_b)
45
+
46
+ # third successful run
47
+ handler.process do |src, dst|
48
+ expect([src, dst]).to eq([temp_b, temp_a]); true
49
+ end
50
+ expect(handler.result).to eq(temp_a)
51
+
52
+ # forth successful run
53
+ handler.process do |src, dst|
54
+ expect([src, dst]).to eq([temp_a, temp_b]); true
55
+ end
56
+ expect(handler.result).to eq(temp_b)
57
+
58
+ expect(temp_a).to receive(:unlink).once
59
+ handler.cleanup
60
+ handler.cleanup
61
+ end
62
+
63
+ describe :open do
64
+ it 'yields instance, runs cleanup and returns result' do
65
+ original = double
66
+ handler = double
67
+ result = double
68
+
69
+ expect(Handler).to receive(:new).
70
+ with(original).and_return(handler)
71
+ expect(handler).to receive(:process)
72
+ expect(handler).to receive(:cleanup)
73
+ expect(handler).to receive(:result).and_return(result)
74
+
75
+ expect(Handler.for(original) do |h|
76
+ h.process
77
+ end).to eq(result)
78
+ end
79
+
80
+ it 'cleans up if exception is raised' do
81
+ original = double
82
+ handler = double
83
+
84
+ expect(Handler).to receive(:new).
85
+ with(original).and_return(handler)
86
+ expect(handler).to receive(:cleanup)
87
+
88
+ expect do
89
+ Handler.for(original) do
90
+ fail 'hello'
91
+ end
92
+ end.to raise_error 'hello'
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/hash_helpers'
3
+
4
+ describe ImageOptim::HashHelpers do
5
+ before do
6
+ stub_const('HashHelpers', ImageOptim::HashHelpers)
7
+ end
8
+
9
+ context 'stringify/simbolyze' do
10
+ symbol_keys = {
11
+ :a => 1,
12
+ :b => {
13
+ :c => [:a, 'a'],
14
+ :d => {},
15
+ },
16
+ }
17
+
18
+ string_keys = {
19
+ 'a' => 1,
20
+ 'b' => {
21
+ 'c' => [:a, 'a'],
22
+ 'd' => {},
23
+ },
24
+ }
25
+
26
+ it 'deep stringifies hash keys' do
27
+ expect(HashHelpers.deep_stringify_keys(symbol_keys)).to eq(string_keys)
28
+ expect(HashHelpers.deep_stringify_keys(string_keys)).to eq(string_keys)
29
+ end
30
+
31
+ it 'deep symbolises hash keys' do
32
+ expect(HashHelpers.deep_symbolise_keys(string_keys)).to eq(symbol_keys)
33
+ expect(HashHelpers.deep_symbolise_keys(symbol_keys)).to eq(symbol_keys)
34
+ end
35
+ end
36
+
37
+ it 'deep merges hashes' do
38
+ merge_a = {
39
+ :a => {
40
+ :b => 1,
41
+ :c => {
42
+ :d => 2,
43
+ :e => {
44
+ :f => true,
45
+ },
46
+ },
47
+ },
48
+ :y => 10,
49
+ }
50
+
51
+ merge_b = {
52
+ :a => {
53
+ :b => 2,
54
+ :c => {
55
+ :d => 3,
56
+ :e => false,
57
+ },
58
+ },
59
+ 'z' => 20,
60
+ }
61
+
62
+ merge_result = {
63
+ :a => {
64
+ :b => 2,
65
+ :c => {
66
+ :d => 3,
67
+ :e => false,
68
+ },
69
+ },
70
+ :y => 10,
71
+ 'z' => 20,
72
+ }
73
+
74
+ expect(HashHelpers.deep_merge(merge_a, merge_b)).to eq(merge_result)
75
+ end
76
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/image_path'
3
+
4
+ describe ImageOptim::ImagePath do
5
+ before do
6
+ stub_const('ImagePath', ImageOptim::ImagePath)
7
+ end
8
+
9
+ describe :convert do
10
+ it 'returns ImagePath for string' do
11
+ path = 'a'
12
+
13
+ expect(ImagePath.convert(path)).to be_a(ImagePath)
14
+ expect(ImagePath.convert(path)).to eq(ImagePath.new(path))
15
+
16
+ expect(ImagePath.convert(path)).not_to eq(path)
17
+ expect(ImagePath.convert(path)).not_to be(path)
18
+ end
19
+
20
+ it 'returns ImagePath for Pathname' do
21
+ pathname = Pathname.new('a')
22
+
23
+ expect(ImagePath.convert(pathname)).to be_a(ImagePath)
24
+ expect(ImagePath.convert(pathname)).to eq(ImagePath.new(pathname))
25
+
26
+ expect(ImagePath.convert(pathname)).to eq(pathname)
27
+ expect(ImagePath.convert(pathname)).not_to be(pathname)
28
+ end
29
+
30
+ it 'returns same instance for ImagePath' do
31
+ image_path = ImagePath.new('a')
32
+
33
+ expect(ImagePath.convert(image_path)).to be_a(ImagePath)
34
+ expect(ImagePath.convert(image_path)).to eq(ImagePath.new(image_path))
35
+
36
+ expect(ImagePath.convert(image_path)).to eq(image_path)
37
+ expect(ImagePath.convert(image_path)).to be(image_path)
38
+ end
39
+ end
40
+
41
+ describe :binread do
42
+ it 'reads binary data' do
43
+ data = (0..255).to_a.pack('c*')
44
+
45
+ path = ImagePath.temp_file_path
46
+ path.write(data)
47
+
48
+ expect(path.binread).to eq(data)
49
+ if ''.respond_to?(:encoding)
50
+ expect(path.binread.encoding).to eq(Encoding.find('ASCII-8BIT'))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ImageOptim::Railtie' do
4
+ require 'rails/all'
5
+ require 'image_optim/railtie'
6
+
7
+ def init_rails_app
8
+ Class.new(Rails::Application) do
9
+ # Rails 4 requires application class to have name
10
+ def self.name
11
+ 'Dummy'
12
+ end
13
+
14
+ config.active_support.deprecation = :stderr
15
+ config.eager_load = false
16
+
17
+ config.logger = Logger.new('/dev/null')
18
+
19
+ config.assets.tap do |assets|
20
+ assets.enabled = true
21
+ assets.version = '1.0'
22
+ assets.cache_store = :null_store
23
+ assets.paths = %w[spec/images]
24
+
25
+ assets.delete(:compress)
26
+ assets.delete(:image_optim)
27
+ end
28
+
29
+ yield config if block_given?
30
+ end.initialize!
31
+ end
32
+
33
+ after do
34
+ Rails.application = nil
35
+ end
36
+
37
+ describe :initialization do
38
+ it 'initializes by default' do
39
+ expect(ImageOptim).to receive(:new)
40
+ init_rails_app
41
+ end
42
+
43
+ it 'initializes if config.assets.image_optim is nil' do
44
+ expect(ImageOptim).to receive(:new)
45
+ init_rails_app do |config|
46
+ config.assets.image_optim = nil
47
+ end
48
+ end
49
+
50
+ it 'does not initialize if config.assets.image_optim is false' do
51
+ expect(ImageOptim).not_to receive(:new)
52
+ init_rails_app do |config|
53
+ config.assets.image_optim = false
54
+ end
55
+ end
56
+
57
+ it 'does not initialize if config.assets.compress is false' do
58
+ expect(ImageOptim).not_to receive(:new)
59
+ init_rails_app do |config|
60
+ config.assets.compress = false
61
+ end
62
+ end
63
+
64
+ describe 'options' do
65
+ it 'initializes with empty hash by default' do
66
+ expect(ImageOptim).to receive(:new).with({})
67
+ init_rails_app
68
+ end
69
+
70
+ it 'initializes with empty hash if config.assets.image_optim is true' do
71
+ expect(ImageOptim).to receive(:new).with({}).and_call_original
72
+ init_rails_app do |config|
73
+ config.assets.image_optim = true
74
+ end
75
+ end
76
+
77
+ it 'initializes with empty hash if config.assets.image_optim is nil' do
78
+ expect(ImageOptim).to receive(:new).with({}).and_call_original
79
+ init_rails_app do |config|
80
+ config.assets.image_optim = nil
81
+ end
82
+ end
83
+
84
+ it 'initializes with hash assigned to config.assets.image_optim' do
85
+ hash = double
86
+ expect(ImageOptim).to receive(:new).with(hash)
87
+ init_rails_app do |config|
88
+ config.assets.image_optim = hash
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ describe :assets do
95
+ before do
96
+ stub_const('ImagePath', ImageOptim::ImagePath)
97
+ end
98
+
99
+ %w[
100
+ icecream.gif
101
+ lena.jpg
102
+ rails.png
103
+ test.svg
104
+ ].each do |asset_name|
105
+ it "optimizes #{asset_name}" do
106
+ asset = init_rails_app.assets.find_asset(asset_name)
107
+
108
+ asset_data = asset.source
109
+ original = ImagePath.convert(asset.pathname)
110
+
111
+ expect(asset_data).to be_smaller_than(original)
112
+
113
+ ImagePath.temp_file_path %W[spec .#{original.format}] do |temp|
114
+ temp.write(asset_data)
115
+
116
+ expect(temp).to be_similar_to(original, 0)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end if ENV['RAILS_VERSION']
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/runner/glob_helpers'
3
+
4
+ describe ImageOptim::Runner::GlobHelpers do
5
+ before do
6
+ stub_const('GlobHelpers', ImageOptim::Runner::GlobHelpers)
7
+ end
8
+
9
+ describe :expand_braces do
10
+ {
11
+ 'hello.world' => %w[hello.world],
12
+ '{hello,.world}' => %w[hello .world],
13
+ 'hello{.,!}world' => %w[hello.world hello!world],
14
+ '{a,b},{c,d}' => %w[a,c b,c a,d b,d],
15
+ '{{a,b},{c,d}}' => %w[a b c d],
16
+ '{a,b,{c,d}}' => %w[a b c d],
17
+ '{\{a,b\},\{c,d\}}' => %w[\\{a b\\} \\{c d\\}],
18
+ 'test{ing,}' => %w[testing test],
19
+ }.each do |glob, expected|
20
+ it "expands #{glob}" do
21
+ expect(GlobHelpers.expand_braces(glob)).to match_array(expected)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/runner/option_parser'
3
+
4
+ describe ImageOptim::Runner::OptionParser do
5
+ before do
6
+ stub_const('OptionParser', ImageOptim::Runner::OptionParser)
7
+ end
8
+
9
+ describe :parse! do
10
+ it 'returns empty hash for arguments without options' do
11
+ args = %w[foo bar]
12
+ expect(OptionParser.parse!(args)).to eq({})
13
+ expect(args).to eq(%w[foo bar])
14
+ end
15
+
16
+ it 'removes options from arguments' do
17
+ args = %w[-r foo bar]
18
+ OptionParser.parse!(args)
19
+ expect(args).to eq(%w[foo bar])
20
+ end
21
+
22
+ it 'stops parsing optiosn after --' do
23
+ args = %w[-- -r foo bar]
24
+ OptionParser.parse!(args)
25
+ expect(args).to eq(%w[-r foo bar])
26
+ end
27
+
28
+ describe 'boolean option recursive' do
29
+ %w[-r -R --recursive].each do |flag|
30
+ it "is parsed from #{flag}" do
31
+ args = %W[#{flag} foo bar]
32
+ expect(OptionParser.parse!(args)).to eq(:recursive => true)
33
+ expect(args).to eq(%w[foo bar])
34
+ end
35
+ end
36
+ end
37
+
38
+ describe 'numeric option threads' do
39
+ it 'is parsed with space separator' do
40
+ args = %w[--threads 616 foo bar]
41
+ expect(OptionParser.parse!(args)).to eq(:threads => 616)
42
+ expect(args).to eq(%w[foo bar])
43
+ end
44
+
45
+ it 'is parsed with equal separator' do
46
+ args = %w[--threads=616 foo bar]
47
+ expect(OptionParser.parse!(args)).to eq(:threads => 616)
48
+ expect(args).to eq(%w[foo bar])
49
+ end
50
+
51
+ it 'is parsed with no- prefix' do
52
+ args = %w[--no-threads 616 foo bar]
53
+ expect(OptionParser.parse!(args)).to eq(:threads => false)
54
+ expect(args).to eq(%w[616 foo bar])
55
+ end
56
+ end
57
+
58
+ describe 'help option' do
59
+ it 'prints help text to stdout and exits' do
60
+ parser = OptionParser.new({})
61
+ expect(OptionParser).to receive(:new).and_return(parser)
62
+
63
+ help = double
64
+ expect(parser).to receive(:help).and_return(help)
65
+
66
+ expect do
67
+ OptionParser.parse!(%w[--help])
68
+ end.to output("#{help}\n").to_stdout &
69
+ raise_error(SystemExit){ |e| expect(e.status).to eq(0) }
70
+ end
71
+ end
72
+
73
+ describe 'wrong option' do
74
+ it 'prints help text to stdout and exits' do
75
+ parser = OptionParser.new({})
76
+ expect(OptionParser).to receive(:new).and_return(parser)
77
+
78
+ help = double
79
+ expect(parser).to receive(:help).and_return(help)
80
+
81
+ expect do
82
+ OptionParser.parse!(%w[--unknown-option])
83
+ end.to output("invalid option: --unknown-option\n\n#{help}\n").
84
+ to_stderr & raise_error(SystemExit){ |e| expect(e.status).to eq(1) }
85
+ end
86
+ end
87
+ end
88
+
89
+ describe :help do
90
+ it 'returns wrapped text' do
91
+ parser = OptionParser.new({})
92
+
93
+ allow(parser).to receive(:terminal_columns).and_return(80)
94
+
95
+ expect(parser.help.split("\n")).
96
+ to all(satisfy{ |line| line.length <= 80 })
97
+ end
98
+ end
99
+ end