mini_magick 4.0.0.rc → 4.0.0

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.

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: