mini_magick 4.0.0.rc → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mini_magick might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e11b9e22bbabb55096ee32c8635e5302459b234
4
- data.tar.gz: ed3df8df5bd3c55605760ce4d68eb070180fd890
3
+ metadata.gz: 65e1d54473e9a429c269d44123e8a6977bf489fe
4
+ data.tar.gz: 7b2b4762e6ee9d6d47ade148b65df993c3b9e08e
5
5
  SHA512:
6
- metadata.gz: e97b6cce0e021ab9f21a31e74e9b8afe9aca5e95c722fcd1230d31a3ece8310bed90fe91f2dc131a783a3e9c987217cc962b6fc296926c6f73fbb8ab263ce06d
7
- data.tar.gz: 7f489774f7ce93a2e63d5fce3d12ddea5f70aa2a98b6343ff5f49df3cf66f67d9f8fbcd135f9eb9d3214e5160af7bfcc82d425895e5491dbe5194228b66a2b50
6
+ metadata.gz: 4852bcf9522da52f7603a2ef96635312b91fef2e72dbcaa77dbec94dddd8e949e4c34d3e6ccc3da8588e42efe6c43b01cace0166d840f40c478966252f0390d0
7
+ data.tar.gz: 77bd9eac7c1a015ad7e6cc6de77657a210fc6b7bbb907928aafb08a0bb0b0c237e85a2ca4cd7ecd75cdfda7b55732352ebda096f46adb699ea62b52695385feb
@@ -149,6 +149,16 @@ module MiniMagick
149
149
  combine_options(&block) if block
150
150
  end
151
151
 
152
+ def eql?(other)
153
+ self.class.equal?(other.class) &&
154
+ signature == other.signature
155
+ end
156
+ alias == eql?
157
+
158
+ def hash
159
+ signature.hash
160
+ end
161
+
152
162
  ##
153
163
  # Returns raw image data.
154
164
  #
@@ -232,6 +242,18 @@ module MiniMagick
232
242
  # @return [Array<Integer>]
233
243
  #
234
244
  attribute :resolution
245
+ ##
246
+ # Returns the message digest of this image as a SHA-256, hexidecimal
247
+ # encoded string. This signature uniquely identifies the image and is
248
+ # convenient for determining if an image has been modified or whether two
249
+ # images are identical.
250
+ #
251
+ # @example
252
+ # image.signature #=> "60a7848c4ca6e36b8e2c5dea632ecdc29e9637791d2c59ebf7a54c0c6a74ef7e"
253
+ # @see http://www.imagemagick.org/api/signature.php
254
+ # @return [String]
255
+ #
256
+ attribute :signature
235
257
 
236
258
  ##
237
259
  # Use this method if you want to access raw Identify's format API.
@@ -358,6 +380,10 @@ module MiniMagick
358
380
  end
359
381
  end
360
382
 
383
+ def respond_to_missing?(method_name, include_private = false)
384
+ MiniMagick::Tool::Mogrify.new.respond_to?(method_name, include_private)
385
+ end
386
+
361
387
  ##
362
388
  # Writes the temporary file out to either a file location (by passing in a
363
389
  # String) or by passing in a Stream that you can #write(chunk) to
@@ -2,6 +2,7 @@ module MiniMagick
2
2
  class Image
3
3
  # @private
4
4
  class Info
5
+ ASCII_ENCODED_EXIF_KEYS = %w[ExifVersion FlashPixVersion]
5
6
 
6
7
  def initialize(path)
7
8
  @path = path
@@ -18,6 +19,8 @@ module MiniMagick
18
19
  mime_type
19
20
  when "resolution"
20
21
  resolution(*args)
22
+ when "signature"
23
+ signature
21
24
  when /^EXIF\:/i
22
25
  raw_exif(value)
23
26
  when "exif"
@@ -76,11 +79,11 @@ module MiniMagick
76
79
  output = self["%[EXIF:*]"]
77
80
  pairs = output.gsub(/^exif:/, "").split("\n").map { |line| line.split("=") }
78
81
  exif = Hash[pairs].tap do |hash|
79
- hash.each do |key, value|
80
- if value.include?(",")
81
- # Sometimes exif comes in a comma-separated list of character values
82
- hash[key] = value.scan(/\d+/).map(&:to_i).map(&:chr).join
83
- end
82
+ ASCII_ENCODED_EXIF_KEYS.each do |key|
83
+ next unless hash.has_key?(key)
84
+
85
+ value = hash[key]
86
+ hash[key] = decode_comma_separated_ascii_characters(value)
84
87
  end
85
88
  end
86
89
 
@@ -89,7 +92,16 @@ module MiniMagick
89
92
  end
90
93
 
91
94
  def raw(value)
92
- identify { |b| b.format(value) }
95
+ key = "raw:#{value}"
96
+ @info.fetch(key) do
97
+ @info[key] = identify { |b| b.format(value) }
98
+ end
99
+ end
100
+
101
+ def signature
102
+ @info.fetch("signature") do
103
+ @info["signature"] = self["%#"]
104
+ end
93
105
  end
94
106
 
95
107
  def identify
@@ -99,6 +111,12 @@ module MiniMagick
99
111
  end
100
112
  end
101
113
 
114
+ def decode_comma_separated_ascii_characters(encoded_value)
115
+ return encoded_value unless encoded_value.include?(',')
116
+
117
+ encoded_value.scan(/\d+/).map(&:to_i).map(&:chr).join
118
+ end
119
+
102
120
  end
103
121
  end
104
122
  end
@@ -26,6 +26,8 @@ module MiniMagick
26
26
  fail MiniMagick::Error, stderr
27
27
  end if @whiny
28
28
 
29
+ $stderr.print(stderr)
30
+
29
31
  stdout
30
32
  end
31
33
 
@@ -59,9 +59,16 @@ module MiniMagick
59
59
  # @private
60
60
  attr_reader :name, :args
61
61
 
62
- def initialize(name)
63
- @name = name
64
- @args = []
62
+ # @param whiny [Boolean] Whether to raise errors on exit codes different
63
+ # than 0.
64
+ # @example
65
+ # MiniMagick::Tool::Identify.new(false) do |identify|
66
+ # identify.help # returns exit status 1, which would otherwise throw an error
67
+ # end
68
+ def initialize(name, whiny = true)
69
+ @name = name
70
+ @whiny = whiny
71
+ @args = []
65
72
  end
66
73
 
67
74
  ##
@@ -80,7 +87,7 @@ module MiniMagick
80
87
  #
81
88
  # @return [String] Output of the command
82
89
  #
83
- def call(whiny = true)
90
+ def call(whiny = @whiny)
84
91
  shell = MiniMagick::Shell.new(whiny)
85
92
  shell.run(command).strip
86
93
  end
@@ -128,6 +135,16 @@ module MiniMagick
128
135
  self
129
136
  end
130
137
 
138
+ ##
139
+ # Merges a list of raw options.
140
+ #
141
+ # @return [self]
142
+ #
143
+ def merge!(new_args)
144
+ new_args.each { |arg| self << arg }
145
+ self
146
+ end
147
+
131
148
  ##
132
149
  # Changes the last operator to its "plus" form.
133
150
  #
@@ -139,9 +156,9 @@ module MiniMagick
139
156
  #
140
157
  # @return [self]
141
158
  #
142
- def +(value = nil)
143
- args.last.sub!(/^-/, '+')
144
- args << value.to_s if value
159
+ def +(*values)
160
+ args[-1] = args[-1].sub(/^-/, '+')
161
+ self.merge!(values)
145
162
  self
146
163
  end
147
164
 
@@ -155,23 +172,20 @@ module MiniMagick
155
172
  #
156
173
  # @private
157
174
  #
158
- class OptionMethods < Module
175
+ class OptionMethods < Module # think about it for a minute
159
176
 
160
177
  def self.instances
161
178
  @instances ||= []
162
179
  end
163
180
 
164
- def self.new(*args, &block)
165
- super.tap do |instance|
166
- self.instances << instance
167
- end
181
+ def initialize(tool_name)
182
+ @tool_name = tool_name
183
+ reload_methods
184
+ self.class.instances << self
168
185
  end
169
186
 
170
- def initialize(tool_name)
171
- super() do
172
- @tool_name = tool_name
173
- reload_methods
174
- end
187
+ def to_s
188
+ "OptionMethods(#{@tool_name})"
175
189
  end
176
190
 
177
191
  ##
@@ -179,15 +193,12 @@ module MiniMagick
179
193
  #
180
194
  def reload_methods
181
195
  instance_methods(false).each { |method| undef_method(method) }
182
-
183
- self.creation_operator *%w[xc canvas logo rose gradient radial-gradient
184
- plasma tile pattern label caption text]
185
-
186
- help = (MiniMagick::Tool.new(@tool_name) << "-help").call(false)
187
- cli_options = help.scan(/^\s+-[a-z\-]+/).map(&:strip)
188
- self.option *cli_options
196
+ creation_operator *creation_operators
197
+ option *cli_options
189
198
  end
190
199
 
200
+ private
201
+
191
202
  ##
192
203
  # Creates method based on command-line option's name.
193
204
  #
@@ -199,10 +210,10 @@ module MiniMagick
199
210
  #
200
211
  def option(*options)
201
212
  options.each do |option|
202
- define_method(option[1..-1].gsub('-', '_')) do |value = nil|
203
- self << option
204
- self << value.to_s if value
205
- self
213
+ define_method(option[1..-1].gsub('-', '_')) do |*values|
214
+ self << option
215
+ self.merge!(values)
216
+ self
206
217
  end
207
218
  end
208
219
  end
@@ -223,8 +234,14 @@ module MiniMagick
223
234
  end
224
235
  end
225
236
 
226
- def to_s
227
- "OptionMethods(#{@tool_name})"
237
+ def creation_operators
238
+ %w[xc canvas logo rose gradient radial-gradient
239
+ plasma tile pattern label caption text]
240
+ end
241
+
242
+ def cli_options
243
+ help = MiniMagick::Tool.new(@tool_name, false) { |b| b << "-help" }
244
+ cli_options = help.scan(/^\s+-[a-z\-]+/).map(&:strip)
228
245
  end
229
246
 
230
247
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Animate < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("animate")
8
+ def initialize(*args)
9
+ super("animate", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Compare < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("compare")
8
+ def initialize(*args)
9
+ super("compare", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Composite < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("composite")
8
+ def initialize(*args)
9
+ super("composite", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Conjure < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("conjure")
8
+ def initialize(*args)
9
+ super("conjure", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Convert < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("convert")
8
+ def initialize(*args)
9
+ super("convert", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Display < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("display")
8
+ def initialize(*args)
9
+ super("display", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Identify < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("identify")
8
+ def initialize(*args)
9
+ super("identify", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Import < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("import")
8
+ def initialize(*args)
9
+ super("import", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Mogrify < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("mogrify")
8
+ def initialize(*args)
9
+ super("mogrify", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Montage < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("montage")
8
+ def initialize(*args)
9
+ super("montage", *args)
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module MiniMagick
5
5
  #
6
6
  class Stream < MiniMagick::Tool
7
7
 
8
- def initialize
9
- super("stream")
8
+ def initialize(*args)
9
+ super("stream", *args)
10
10
  end
11
11
 
12
12
  end
@@ -10,7 +10,7 @@ module MiniMagick
10
10
  MAJOR = 4
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = "rc"
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
16
16
  end
Binary file
@@ -119,6 +119,35 @@ require "stringio"
119
119
  end
120
120
  end
121
121
 
122
+ describe "equivalence" do
123
+ subject(:image) { described_class.new(image_path) }
124
+ let(:same_image) { described_class.new(image_path) }
125
+ let(:other_image) { described_class.new(image_path(:exif)) }
126
+
127
+ it "is #== and #eql? to itself" do
128
+ expect(image).to eq(image)
129
+ expect(image).to eql(image)
130
+ end
131
+
132
+ it "is #== and #eql? to an instance of the same image" do
133
+ expect(image).to eq(same_image)
134
+ expect(image).to eql(same_image)
135
+ end
136
+
137
+ it "is not #== nor #eql? to an instance of a different image" do
138
+ expect(image).not_to eq(other_image)
139
+ expect(image).not_to eql(other_image)
140
+ end
141
+
142
+ it "generates the same hash code for an instance of the same image" do
143
+ expect(image.hash).to eq(same_image.hash)
144
+ end
145
+
146
+ it "generates different same hash codes for a different image" do
147
+ expect(image.hash).not_to eq(other_image.hash)
148
+ end
149
+ end
150
+
122
151
  describe "#format" do
123
152
  subject { described_class.open(image_path(:jpg)) }
124
153
 
@@ -225,6 +254,7 @@ require "stringio"
225
254
  expect(subject[:dimensions]).to all(be_a(Fixnum))
226
255
  expect(subject[:colorspace]).to be_a(String)
227
256
  expect(subject[:format]).to match(/[A-Z]/)
257
+ expect(subject[:signature]).to match(/[[:alnum:]]{64}/)
228
258
  end
229
259
 
230
260
  it "supports string keys" do
@@ -233,11 +263,17 @@ require "stringio"
233
263
  expect(subject["dimensions"]).to all(be_a(Fixnum))
234
264
  expect(subject["colorspace"]).to be_a(String)
235
265
  expect(subject["format"]).to match(/[A-Z]/)
266
+ expect(subject['signature']).to match(/[[:alnum:]]{64}/)
236
267
  end
237
268
 
238
269
  it "reads exif" do
239
270
  subject = described_class.new(image_path(:exif))
271
+ gps_latitude = subject.exif["GPSLatitude"].split(/\s*,\s*/)
272
+ gps_longitude = subject.exif["GPSLongitude"].split(/\s*,\s*/)
273
+
240
274
  expect(subject["EXIF:ColorSpace"]).to eq "1"
275
+ expect(gps_latitude.size).to eq 3
276
+ expect(gps_longitude.size).to eq 3
241
277
  end
242
278
 
243
279
  it "passes unknown values directly to -format" do
@@ -254,6 +290,7 @@ require "stringio"
254
290
  expect(subject.size).to be_a(Fixnum).and be_nonzero
255
291
  expect(subject.colorspace).to be_a(String)
256
292
  expect(subject.resolution).to all(be_a(Fixnum))
293
+ expect(subject.signature).to match(/[[:alnum:]]{64}/)
257
294
  end
258
295
 
259
296
  describe "#exif" do
@@ -262,6 +299,10 @@ require "stringio"
262
299
  it "returns a hash of EXIF data" do
263
300
  expect(subject.exif["DateTimeOriginal"]).to be_a(String)
264
301
  end
302
+
303
+ it "decodes the ExifVersion" do
304
+ expect(subject.exif["ExifVersion"]).to eq("0221")
305
+ end
265
306
  end
266
307
 
267
308
  describe "#resolution" do
@@ -299,19 +340,31 @@ require "stringio"
299
340
  end
300
341
  end
301
342
 
302
- describe "#method_missing" do
303
- it "executes the command correctly" do
304
- expect { subject.resize '20x30!' }
305
- .to change { subject.dimensions }.to [20, 30]
306
- end
343
+ describe "missing methods" do
344
+ context "for a known method" do
345
+ it "is executed by #method_missing" do
346
+ expect { subject.resize '20x30!' }
347
+ .to change { subject.dimensions }.to [20, 30]
348
+ end
349
+
350
+ it "returns self" do
351
+ expect(subject.resize('20x30!')).to eq subject
352
+ end
307
353
 
308
- it "fails with a correct NoMethodError" do
309
- expect { subject.foo }
310
- .to raise_error(NoMethodError, /MiniMagick::Image/)
354
+ it "can be responed to" do
355
+ expect(subject.respond_to?(:resize)).to eq true
356
+ end
311
357
  end
312
358
 
313
- it "returns self" do
314
- expect(subject.resize('20x30!')).to eq subject
359
+ context "for an unknown method" do
360
+ it "fails with a NoMethodError" do
361
+ expect { subject.foo }
362
+ .to raise_error(NoMethodError, /MiniMagick::Image/)
363
+ end
364
+
365
+ it "cannot be responded to" do
366
+ expect(subject.respond_to?(:foo)).to eq false
367
+ end
315
368
  end
316
369
  end
317
370
 
@@ -32,6 +32,12 @@ RSpec.describe MiniMagick::Shell do
32
32
  allow(subject).to receive(:execute).and_return(["stdout", "", 127])
33
33
  expect(subject.run(%W[foo])).to eq "stdout"
34
34
  end
35
+
36
+ it "prints to stderr output to $stderr in non-whiny mode" do
37
+ subject = described_class.new(false)
38
+ allow(subject).to receive(:execute).and_return(["", "stderr", 1])
39
+ expect { subject.run(%W[foo]) }.to output("stderr").to_stderr
40
+ end
35
41
  end
36
42
 
37
43
  describe "#execute" do
@@ -40,12 +46,6 @@ RSpec.describe MiniMagick::Shell do
40
46
  expect(stdout).to match("GIF")
41
47
  end
42
48
 
43
- it "timeouts afer a period of time" do
44
- allow(MiniMagick).to receive(:timeout).and_return(0.001)
45
- expect { subject.execute(%W[identify -format %[EXIF:*] #{image_path(:exif)}]) }
46
- .to raise_error(Timeout::Error)
47
- end
48
-
49
49
  it "logs the command and execution time in debug mode" do
50
50
  allow(MiniMagick).to receive(:debug).and_return(true)
51
51
  expect { subject.execute(%W[identify #{image_path(:gif)}]) }.
@@ -48,16 +48,26 @@ RSpec.describe MiniMagick::Tool do
48
48
 
49
49
  describe "#<<" do
50
50
  it "adds argument to the args list" do
51
- subject << "foo" << "bar"
52
- expect(subject.args).to eq %W[foo bar]
51
+ subject << "foo" << "bar" << 123
52
+ expect(subject.args).to eq %W[foo bar 123]
53
+ end
54
+ end
55
+
56
+ describe "#merge!" do
57
+ it "adds arguments to the args list" do
58
+ subject << "pre-existing"
59
+ subject.merge! ["foo", 123]
60
+ expect(subject.args).to eq %W[pre-existing foo 123]
53
61
  end
54
62
  end
55
63
 
56
64
  describe "#+" do
57
65
  it "switches the last option to + form" do
66
+ subject.help
58
67
  subject.help.+
59
- subject.debug.+ 8
60
- expect(subject.args).to eq %W[+help +debug 8]
68
+ subject.debug.+ "foo"
69
+ subject.debug.+ 8, "bar"
70
+ expect(subject.args).to eq %W[-help +help +debug foo +debug 8 bar]
61
71
  end
62
72
  end
63
73
 
@@ -87,4 +97,11 @@ RSpec.describe MiniMagick::Tool do
87
97
  expect(subject).not_to respond_to(:quiet)
88
98
  expect(subject).to respond_to(:ping)
89
99
  end
100
+
101
+ it "doesn't raise errors when false is passed to the constructor" do
102
+ subject.help
103
+ subject.call(false)
104
+
105
+ MiniMagick::Tool::Identify.new(false, &:help)
106
+ end
90
107
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_magick
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.rc
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Corey Johnson
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-10-05 00:00:00.000000000 Z
15
+ date: 2014-11-14 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rake
@@ -104,9 +104,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - ">"
107
+ - - ">="
108
108
  - !ruby/object:Gem::Version
109
- version: 1.3.1
109
+ version: '0'
110
110
  requirements:
111
111
  - You must have ImageMagick or GraphicsMagick installed
112
112
  rubyforge_project: