discourse_image_optim 0.24.4

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.
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