discourse_image_optim 0.24.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.appveyor.yml +46 -0
  3. data/.gitignore +18 -0
  4. data/.rubocop.yml +110 -0
  5. data/.travis.yml +42 -0
  6. data/CHANGELOG.markdown +316 -0
  7. data/CONTRIBUTING.markdown +11 -0
  8. data/Gemfile +16 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.markdown +358 -0
  11. data/Vagrantfile +38 -0
  12. data/bin/image_optim +28 -0
  13. data/image_optim.gemspec +34 -0
  14. data/lib/image_optim.rb +267 -0
  15. data/lib/image_optim/bin_resolver.rb +142 -0
  16. data/lib/image_optim/bin_resolver/bin.rb +115 -0
  17. data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
  18. data/lib/image_optim/bin_resolver/error.rb +6 -0
  19. data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
  20. data/lib/image_optim/cache.rb +72 -0
  21. data/lib/image_optim/cache_path.rb +16 -0
  22. data/lib/image_optim/cmd.rb +122 -0
  23. data/lib/image_optim/config.rb +219 -0
  24. data/lib/image_optim/configuration_error.rb +3 -0
  25. data/lib/image_optim/handler.rb +57 -0
  26. data/lib/image_optim/hash_helpers.rb +45 -0
  27. data/lib/image_optim/image_meta.rb +20 -0
  28. data/lib/image_optim/non_negative_integer_range.rb +11 -0
  29. data/lib/image_optim/optimized_path.rb +25 -0
  30. data/lib/image_optim/option_definition.rb +38 -0
  31. data/lib/image_optim/option_helpers.rb +17 -0
  32. data/lib/image_optim/path.rb +70 -0
  33. data/lib/image_optim/runner.rb +139 -0
  34. data/lib/image_optim/runner/glob_helpers.rb +45 -0
  35. data/lib/image_optim/runner/option_parser.rb +246 -0
  36. data/lib/image_optim/space.rb +29 -0
  37. data/lib/image_optim/true_false_nil.rb +16 -0
  38. data/lib/image_optim/worker.rb +170 -0
  39. data/lib/image_optim/worker/advpng.rb +37 -0
  40. data/lib/image_optim/worker/class_methods.rb +107 -0
  41. data/lib/image_optim/worker/gifsicle.rb +65 -0
  42. data/lib/image_optim/worker/jhead.rb +47 -0
  43. data/lib/image_optim/worker/jpegoptim.rb +63 -0
  44. data/lib/image_optim/worker/jpegrecompress.rb +49 -0
  45. data/lib/image_optim/worker/jpegtran.rb +48 -0
  46. data/lib/image_optim/worker/optipng.rb +53 -0
  47. data/lib/image_optim/worker/pngcrush.rb +56 -0
  48. data/lib/image_optim/worker/pngout.rb +40 -0
  49. data/lib/image_optim/worker/pngquant.rb +61 -0
  50. data/lib/image_optim/worker/svgo.rb +34 -0
  51. data/script/template/jquery-2.1.3.min.js +4 -0
  52. data/script/template/sortable-0.6.0.min.js +2 -0
  53. data/script/template/worker_analysis.erb +254 -0
  54. data/script/update_worker_options_in_readme +59 -0
  55. data/script/worker_analysis +589 -0
  56. data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
  57. data/spec/image_optim/bin_resolver/simple_version_spec.rb +65 -0
  58. data/spec/image_optim/bin_resolver_spec.rb +290 -0
  59. data/spec/image_optim/cache_path_spec.rb +57 -0
  60. data/spec/image_optim/cache_spec.rb +162 -0
  61. data/spec/image_optim/cmd_spec.rb +93 -0
  62. data/spec/image_optim/config_spec.rb +254 -0
  63. data/spec/image_optim/handler_spec.rb +90 -0
  64. data/spec/image_optim/hash_helpers_spec.rb +74 -0
  65. data/spec/image_optim/image_meta_spec.rb +61 -0
  66. data/spec/image_optim/optimized_path_spec.rb +58 -0
  67. data/spec/image_optim/option_definition_spec.rb +138 -0
  68. data/spec/image_optim/option_helpers_spec.rb +25 -0
  69. data/spec/image_optim/path_spec.rb +103 -0
  70. data/spec/image_optim/runner/glob_helpers_spec.rb +21 -0
  71. data/spec/image_optim/runner/option_parser_spec.rb +105 -0
  72. data/spec/image_optim/space_spec.rb +23 -0
  73. data/spec/image_optim/worker/optipng_spec.rb +102 -0
  74. data/spec/image_optim/worker/pngquant_spec.rb +67 -0
  75. data/spec/image_optim/worker_spec.rb +303 -0
  76. data/spec/image_optim_spec.rb +259 -0
  77. data/spec/images/broken_jpeg +1 -0
  78. data/spec/images/comparison.png +0 -0
  79. data/spec/images/decompressed.jpeg +0 -0
  80. data/spec/images/icecream.gif +0 -0
  81. data/spec/images/image.jpg +0 -0
  82. data/spec/images/invisiblepixels/generate +24 -0
  83. data/spec/images/invisiblepixels/image.png +0 -0
  84. data/spec/images/lena.jpg +0 -0
  85. data/spec/images/orient/0.jpg +0 -0
  86. data/spec/images/orient/1.jpg +0 -0
  87. data/spec/images/orient/2.jpg +0 -0
  88. data/spec/images/orient/3.jpg +0 -0
  89. data/spec/images/orient/4.jpg +0 -0
  90. data/spec/images/orient/5.jpg +0 -0
  91. data/spec/images/orient/6.jpg +0 -0
  92. data/spec/images/orient/7.jpg +0 -0
  93. data/spec/images/orient/8.jpg +0 -0
  94. data/spec/images/orient/generate +23 -0
  95. data/spec/images/orient/original.jpg +0 -0
  96. data/spec/images/quant/64.png +0 -0
  97. data/spec/images/quant/generate +25 -0
  98. data/spec/images/rails.png +0 -0
  99. data/spec/images/test.svg +3 -0
  100. data/spec/images/transparency1.png +0 -0
  101. data/spec/images/transparency2.png +0 -0
  102. data/spec/images/vergroessert.jpg +0 -0
  103. data/spec/spec_helper.rb +93 -0
  104. metadata +281 -0
@@ -0,0 +1,90 @@
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(:respond_to?).with(:temp_path).and_return(true)
13
+
14
+ handler = Handler.new(original)
15
+ temp_a = double(:temp_a)
16
+ temp_b = double(:temp_b)
17
+ expect(original).to receive(:temp_path).and_return(temp_a, temp_b)
18
+
19
+ # first unsuccessful run
20
+ handler.process do |src, dst|
21
+ expect([src, dst]).to eq([original, temp_a]); false
22
+ end
23
+ expect(handler.result).to be_nil
24
+
25
+ # first successful run
26
+ handler.process do |src, dst|
27
+ expect([src, dst]).to eq([original, temp_a]); true
28
+ end
29
+ expect(handler.result).to eq(temp_a)
30
+
31
+ # second unsuccessful run
32
+ handler.process do |src, dst|
33
+ expect([src, dst]).to eq([temp_a, temp_b]); false
34
+ end
35
+ expect(handler.result).to eq(temp_a)
36
+
37
+ # second successful run
38
+ handler.process do |src, dst|
39
+ expect([src, dst]).to eq([temp_a, temp_b]); true
40
+ end
41
+ expect(handler.result).to eq(temp_b)
42
+
43
+ # third successful run
44
+ handler.process do |src, dst|
45
+ expect([src, dst]).to eq([temp_b, temp_a]); true
46
+ end
47
+ expect(handler.result).to eq(temp_a)
48
+
49
+ # forth successful run
50
+ handler.process do |src, dst|
51
+ expect([src, dst]).to eq([temp_a, temp_b]); true
52
+ end
53
+ expect(handler.result).to eq(temp_b)
54
+
55
+ expect(temp_a).to receive(:unlink).once
56
+ handler.cleanup
57
+ handler.cleanup
58
+ end
59
+
60
+ describe '.for' do
61
+ it 'yields instance, runs cleanup and returns result' do
62
+ original = double
63
+ handler = double
64
+ result = double
65
+
66
+ expect(Handler).to receive(:new).
67
+ with(original).and_return(handler)
68
+ expect(handler).to receive(:process)
69
+ expect(handler).to receive(:cleanup)
70
+ expect(handler).to receive(:result).and_return(result)
71
+
72
+ expect(Handler.for(original, &:process)).to eq(result)
73
+ end
74
+
75
+ it 'cleans up if exception is raised' do
76
+ original = double
77
+ handler = double
78
+
79
+ expect(Handler).to receive(:new).
80
+ with(original).and_return(handler)
81
+ expect(handler).to receive(:cleanup)
82
+
83
+ expect do
84
+ Handler.for(original) do
85
+ fail 'hello'
86
+ end
87
+ end.to raise_error 'hello'
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,74 @@
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 => {:f => true},
44
+ },
45
+ },
46
+ :y => 10,
47
+ }
48
+
49
+ merge_b = {
50
+ :a => {
51
+ :b => 2,
52
+ :c => {
53
+ :d => 3,
54
+ :e => false,
55
+ },
56
+ },
57
+ 'z' => 20,
58
+ }
59
+
60
+ merge_result = {
61
+ :a => {
62
+ :b => 2,
63
+ :c => {
64
+ :d => 3,
65
+ :e => false,
66
+ },
67
+ },
68
+ :y => 10,
69
+ 'z' => 20,
70
+ }
71
+
72
+ expect(HashHelpers.deep_merge(merge_a, merge_b)).to eq(merge_result)
73
+ end
74
+ end
@@ -0,0 +1,61 @@
1
+ require 'image_optim/image_meta'
2
+
3
+ describe ImageOptim::ImageMeta do
4
+ let(:image_path){ 'spec/images/lena.jpg' }
5
+ let(:non_image_path){ __FILE__ }
6
+ let(:broken_image_path){ 'spec/images/broken_jpeg' }
7
+
8
+ describe '.format_for_path' do
9
+ context 'for an image' do
10
+ it 'returns format' do
11
+ expect(described_class.format_for_path(image_path)).
12
+ to eq(:jpeg)
13
+ end
14
+ end
15
+
16
+ context 'for broken image' do
17
+ it 'warns and returns nil' do
18
+ expect(described_class).to receive(:warn)
19
+
20
+ expect(described_class.format_for_path(broken_image_path)).
21
+ to eq(nil)
22
+ end
23
+ end
24
+
25
+ context 'for not an image' do
26
+ it 'does not warn and returns nil' do
27
+ expect(described_class).not_to receive(:warn)
28
+
29
+ expect(described_class.format_for_path(non_image_path)).
30
+ to eq(nil)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '.format_for_data' do
36
+ context 'for image data' do
37
+ it 'returns format' do
38
+ expect(described_class.format_for_data(File.read(image_path))).
39
+ to eq(:jpeg)
40
+ end
41
+ end
42
+
43
+ context 'for broken image data' do
44
+ it 'warns and returns nil' do
45
+ expect(described_class).to receive(:warn)
46
+
47
+ expect(described_class.format_for_data(File.read(broken_image_path))).
48
+ to eq(nil)
49
+ end
50
+ end
51
+
52
+ context 'for not an image data' do
53
+ it 'does not warn and returns nil' do
54
+ expect(described_class).not_to receive(:warn)
55
+
56
+ expect(described_class.format_for_data(File.read(non_image_path))).
57
+ to eq(nil)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,58 @@
1
+ require 'image_optim/optimized_path'
2
+
3
+ describe ImageOptim::OptimizedPath do
4
+ describe '#initialize' do
5
+ context 'when second argument is original' do
6
+ subject{ described_class.new('a', 'b') }
7
+
8
+ before do
9
+ allow_any_instance_of(ImageOptim::Path).
10
+ to receive(:size).and_return(616)
11
+ end
12
+
13
+ it 'delegates to optimized path as Path' do
14
+ is_expected.to eq(ImageOptim::Path.new('a'))
15
+ end
16
+
17
+ it 'returns original path as Path for original' do
18
+ expect(subject.original).to eq(ImageOptim::Path.new('b'))
19
+ end
20
+
21
+ it 'returns original size for original_size' do
22
+ expect(subject.original_size).to eq(616)
23
+ end
24
+ end
25
+
26
+ context 'when second argument is size' do
27
+ subject{ described_class.new('a', 616) }
28
+
29
+ it 'delegates to optimized path as Path' do
30
+ is_expected.to eq(ImageOptim::Path.new('a'))
31
+ end
32
+
33
+ it 'returns optimized path as Path for original' do
34
+ expect(subject.original).to eq(ImageOptim::Path.new('a'))
35
+ end
36
+
37
+ it 'returns size for original_size' do
38
+ expect(subject.original_size).to eq(616)
39
+ end
40
+ end
41
+
42
+ context 'when no second argument' do
43
+ subject{ described_class.new('a') }
44
+
45
+ it 'delegates to optimized path as Path' do
46
+ is_expected.to eq(ImageOptim::Path.new('a'))
47
+ end
48
+
49
+ it 'returns nil for original' do
50
+ expect(subject.original).to eq(nil)
51
+ end
52
+
53
+ it 'returns nil for original_size' do
54
+ expect(subject.original_size).to eq(nil)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/option_definition'
3
+
4
+ describe ImageOptim::OptionDefinition do
5
+ describe 'initialization' do
6
+ context 'when type is not specified explicitly' do
7
+ subject{ described_class.new('abc', :def, 'desc') }
8
+
9
+ describe '#name' do
10
+ it{ expect(subject.name).to eq(:abc) }
11
+ end
12
+
13
+ describe '#default' do
14
+ it{ expect(subject.default).to eq(:def) }
15
+ end
16
+
17
+ describe '#type' do
18
+ it{ expect(subject.type).to eq(Symbol) }
19
+ end
20
+
21
+ describe '#description' do
22
+ it{ expect(subject.description).to eq('desc') }
23
+ end
24
+ end
25
+
26
+ context 'when type is specified explicitly' do
27
+ subject{ described_class.new('abc', :def, Hash, 'desc') }
28
+
29
+ describe '#name' do
30
+ it{ expect(subject.name).to eq(:abc) }
31
+ end
32
+
33
+ describe '#default' do
34
+ it{ expect(subject.default).to eq(:def) }
35
+ end
36
+
37
+ describe '#type' do
38
+ it{ expect(subject.type).to eq(Hash) }
39
+ end
40
+
41
+ describe '#description' do
42
+ it{ expect(subject.description).to eq('desc') }
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#value' do
48
+ context 'when proc not given' do
49
+ subject{ described_class.new('abc', :def, 'desc') }
50
+
51
+ context 'when option not provided' do
52
+ it 'returns default' do
53
+ expect(subject.value(nil, {})).to eq(:def)
54
+ end
55
+ end
56
+
57
+ context 'when option is nil' do
58
+ it 'returns nil' do
59
+ expect(subject.value(nil, :abc => nil)).to eq(nil)
60
+ end
61
+ end
62
+
63
+ context 'when option is set' do
64
+ it 'returns value' do
65
+ expect(subject.value(nil, :abc => 123)).to eq(123)
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when proc given' do
71
+ subject do
72
+ # not using &:inspect due to ruby Bug #13087
73
+ # to_s is just to calm rubocop
74
+ described_class.new('abc', :def, 'desc'){ |o| o.inspect.to_s }
75
+ end
76
+
77
+ context 'when option not provided' do
78
+ it 'returns default passed through proc' do
79
+ expect(subject.value(nil, {})).to eq(':def')
80
+ end
81
+ end
82
+
83
+ context 'when option is nil' do
84
+ it 'returns nil passed through proc' do
85
+ expect(subject.value(nil, :abc => nil)).to eq('nil')
86
+ end
87
+ end
88
+
89
+ context 'when option is set' do
90
+ it 'returns value passed through proc' do
91
+ expect(subject.value(nil, :abc => 123)).to eq('123')
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when proc with arity 2 given' do
97
+ subject do
98
+ described_class.new('abc', :def, 'desc'){ |a, b| [a.inspect, b] }
99
+ end
100
+
101
+ context 'when option not provided' do
102
+ it 'returns default passed through proc' do
103
+ expect(subject.value(nil, {})).to eq([':def', subject])
104
+ end
105
+ end
106
+
107
+ context 'when option is nil' do
108
+ it 'returns nil passed through proc' do
109
+ expect(subject.value(nil, :abc => nil)).to eq(['nil', subject])
110
+ end
111
+ end
112
+
113
+ context 'when option is set' do
114
+ it 'returns value passed through proc' do
115
+ expect(subject.value(nil, :abc => 123)).to eq(['123', subject])
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#default_description' do
122
+ context 'when default is not a string' do
123
+ subject{ described_class.new('abc', :def, 'desc') }
124
+
125
+ it 'returns inspected value in backticks' do
126
+ expect(subject.default_description).to eq('`:def`')
127
+ end
128
+ end
129
+
130
+ context 'when default is a string' do
131
+ subject{ described_class.new('abc', '`1`', 'desc') }
132
+
133
+ it 'returns it as is' do
134
+ expect(subject.default_description).to eq('`1`')
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/option_helpers'
3
+
4
+ describe ImageOptim::OptionHelpers do
5
+ describe '.limit_with_range' do
6
+ {
7
+ 2..4 => 'inclusive',
8
+ 2...5 => 'exclusive',
9
+ }.each do |range, type|
10
+ context "for an end #{type} range" do
11
+ it 'returns number when it is in range' do
12
+ expect(described_class.limit_with_range(4, range)).to eq(4)
13
+ end
14
+
15
+ it 'returns begin when it is less than minimum' do
16
+ expect(described_class.limit_with_range(1, range)).to eq(2)
17
+ end
18
+
19
+ it 'returns end when it is more than maximum' do
20
+ expect(described_class.limit_with_range(10, range)).to eq(4)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end