artwork 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e51d5060c17f4737eda437c0f9ce39f16d0ae83
4
- data.tar.gz: da1b48d509a9ddc8809f8a1f750fbf25d9f9c388
3
+ metadata.gz: eea1f0b27e394aabf472e48645693cb62f95df54
4
+ data.tar.gz: 493fdce70015ab3c194a9502542e43f08f3f8da8
5
5
  SHA512:
6
- metadata.gz: 4db0e6456851055b2c9e952ffe8d57c368978425bc4d5e909436f6e6f59055c5fb28414f0ede41835883f0867ccfcbf30125d603e15097e99ebe287575a7c9a1
7
- data.tar.gz: 7e1b104e52d173e01e9c1abe5deba6b574f7a22779070fd8918260513f27bbcec87714d457970648f4799283544023244da91336868496c21a04a04c44cc65d1
6
+ metadata.gz: 939897e270a6b5f0354763b544be4d9bd991c96021c3d0bc8921f749f9eb42e9830bf54cff7e31086dbedabf8b151a1dd59ff677c9607c8016ae63c20f803aed
7
+ data.tar.gz: 097fd8418344ae6ee63f5bc49e20e81b92d805381b57f8a484fd2f51b958e07733303b7ad1997490b8d7ecfcf9ae816f7c10b19468eaf85f80878a63f50658cc
data/README.md CHANGED
@@ -101,6 +101,39 @@ the `artwork_tag` view helper. Example:
101
101
  <%= artwork_tag @film, :board, :'1440x', :image => {:class => 'poster'} %>
102
102
  <%= artwork_tag @gallery, :cover, :'900x' %>
103
103
 
104
+ ## Thumb Selection Algorithm
105
+
106
+ The following criteria are taken into account for picking up the appropriate
107
+ thumb name:
108
+
109
+ - The `default_resolution` specified in the Artwork configuration file.
110
+ - The current resolition, approximated to the nearest largest supported
111
+ resolution.
112
+ - Whether or not the screen is retina.
113
+ - The width of the requested thumb size (e.g. `400` for `400x300_crop`).
114
+ - The label of the requested thumb (e.g. `crop` for `400x300_crop`); the label
115
+ will be ignored, if it is not specified, e.g. for `400x300` or `400x`. The
116
+ label will be locked to a blank one if the request is for a thumb like this:
117
+ `400x300_`.
118
+ - The aspect ratio of the requested thumb (e.g. `4/3` for `400x300_crop`); the
119
+ aspect ratio will be ignored if there is no height specified in the requested
120
+ thumb, e.g. for a request like `400x_crop`.
121
+
122
+ For a thumb to be returned as matching, all of the following must be true:
123
+
124
+ - It must me the smallest thumb which is still larger than the requested width,
125
+ scaled for the current resolution.
126
+ - If the requested thumb has a label (including a blank one, like in `400x_`),
127
+ the thumb must match the requested label.
128
+ - If the requested thumb specifies an aspect ratio, the matching thumb must
129
+ have the same aspect ratio, rounded to the second decimal. If no aspect ratio
130
+ is specified in the request, aspect ratio checks will not be performed.
131
+ - If the current device is a retina device, a retina thumb will be preferred.
132
+ If no retuna thumb exists, a non-retina one will be selected.
133
+
134
+ If no such thumb exist, the largest one will match.
135
+
136
+
104
137
  ## Contributing
105
138
 
106
139
  1. [Fork it](https://github.com/mitio/artwork/fork)
@@ -9,14 +9,17 @@ module Artwork
9
9
  if desired_thumb.compatible?
10
10
  desired_size = desired_thumb.width / ratio_for_current_resolution
11
11
 
12
- thumbs = attachment_styles_for(attachment_name) \
13
- .map { |thumb_name| Thumbnail.new(thumb_name) } \
12
+ thumbs = attachment_styles_for(attachment_name).map { |thumb_name| Thumbnail.new(thumb_name) }
13
+
14
+ thumbs = thumbs \
14
15
  .select(&:compatible?) \
15
16
  .reject(&:retina?) \
17
+ .select { |thumb| desired_thumb.label.nil? or desired_thumb.label == thumb.label.to_s } \
18
+ .select { |thumb| desired_thumb.aspect_ratio.nil? or desired_thumb.same_aspect_ratio_with?(thumb) } \
16
19
  .sort
17
20
 
18
21
  thumbs.each do |thumb|
19
- if desired_size <= thumb.width and thumb.label == desired_thumb.label
22
+ if desired_size <= thumb.width
20
23
  matching_thumb_name = thumb.name
21
24
  break
22
25
  end
@@ -25,6 +28,7 @@ module Artwork
25
28
  # If we did not find any matching attachment definitions,
26
29
  # the desired size is probably larger than all of our thumb widths,
27
30
  # So pick the last (largest) one we have.
31
+ return nil if thumbs.empty?
28
32
  matching_thumb_name ||= thumbs.last.name
29
33
  end
30
34
 
@@ -2,20 +2,26 @@ module Artwork
2
2
  class Thumbnail
3
3
  include Comparable
4
4
 
5
- NAME_PATTERN = /^(\d+)x(\w*?)(_2x)?$/i.freeze
5
+ NAME_PATTERN = /^(\d+)x(\d+)?((?!_2x)_\w*?)?(_2x)?$/i.freeze
6
6
 
7
7
  attr :name
8
8
  attr :width
9
+ attr :height
9
10
  attr :label
11
+ attr :aspect_ratio
10
12
 
11
13
  def initialize(name)
12
14
  @name = name.to_s
13
15
 
14
16
  if match = @name.match(NAME_PATTERN)
15
17
  @width = match[1].to_i
16
- @label = match[2].to_s.gsub(/^_|_$/, '')
17
- @retina_flag = match[3]
18
+ @height = match[2].to_i
19
+ @label = match[3] ? match[3].gsub(/^_|_$/, '') : nil
20
+ @retina_flag = match[4]
18
21
  end
22
+
23
+ @height = nil if @height == 0
24
+ @aspect_ratio = @width.to_f / @height if @height
19
25
  end
20
26
 
21
27
  def compatible?
@@ -26,6 +32,12 @@ module Artwork
26
32
  @retina_flag == '_2x'
27
33
  end
28
34
 
35
+ def same_aspect_ratio_with?(other_thumb)
36
+ return unless aspect_ratio and other_thumb.aspect_ratio
37
+
38
+ (0.0..0.1).include? (aspect_ratio - other_thumb.aspect_ratio).abs
39
+ end
40
+
29
41
  def <=>(other_thumb)
30
42
  width <=> other_thumb.width
31
43
  end
@@ -33,6 +45,7 @@ module Artwork
33
45
  def eq(other)
34
46
  name == other.name and \
35
47
  width == other.width and \
48
+ height == other.height and \
36
49
  label == other.label and \
37
50
  retina? == other.retina?
38
51
  end
@@ -1,3 +1,3 @@
1
1
  module Artwork
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -23,6 +23,9 @@ module Artwork
23
23
  :'320x500_2x' => '640x1000>',
24
24
  :'320x500_crop' => '320x500#',
25
25
  :'320x500_crop_2x' => '640x1000#',
26
+ :'400x500' => '400x500>',
27
+ :'400x500_2x' => '800x1000>',
28
+ :'320x_' => '320x>',
26
29
  :unsupported => '100x100>'
27
30
  },
28
31
  },
@@ -46,6 +49,9 @@ module Artwork
46
49
  :'320x500_2x',
47
50
  :'320x500_crop',
48
51
  :'320x500_crop_2x',
52
+ :'400x500',
53
+ :'400x500_2x',
54
+ :'320x_',
49
55
  :unsupported,
50
56
  ]
51
57
  end
@@ -137,7 +143,8 @@ module Artwork
137
143
  end
138
144
 
139
145
  it 'picks the nearest non-retina size to our desizred size' do
140
- expect_thumb '400x', :'640x'
146
+ expect_thumb '390x', :'400x500'
147
+ expect_thumb '420x', :'640x'
141
148
  end
142
149
 
143
150
  it 'picks the largest available size if requesting a too large thumb' do
@@ -154,16 +161,34 @@ module Artwork
154
161
  expect_thumb '200x_some_label', :'320x_some_label'
155
162
  end
156
163
 
157
- it 'distinguishes thumbs by the supplied numerical label, as a vertical height' do
158
- expect_thumb :'200x500', :'320x500'
164
+ it 'considers the aspect ratio of the desired thumb' do
165
+ expect_thumb '320x499', :'320x500'
166
+ expect_thumb '319x498', :'320x500'
159
167
  Artwork.load_2x_images = true
160
- expect_thumb :'200x500', :'320x500_2x'
168
+ expect_thumb '319x498', :'320x500_2x'
169
+ expect_thumb '319x498_crop', :'320x500_crop_2x'
170
+ Artwork.load_2x_images = false
171
+ expect_thumb '319x498_crop', :'320x500_crop'
161
172
  end
162
173
 
163
- it 'distinguishes thumbs by the supplied numerical label ignoring retina flags' do
164
- expect_thumb :'200x500_2x', :'320x500'
174
+ it 'returns the largest thumb with the requested label if no other suitable sizes are found' do
175
+ expect_thumb '20000x_crop', :'320x500_crop'
165
176
  Artwork.load_2x_images = true
166
- expect_thumb :'200x500_2x', :'320x500_2x'
177
+ expect_thumb '20000x_crop', :'320x500_crop_2x'
178
+ end
179
+
180
+ it 'returns the largest thumb with the requested aspect ratio if no other suitable sizes are found' do
181
+ expect_thumb '8000x10000', :'400x500'
182
+ Artwork.load_2x_images = true
183
+ expect_thumb '8000x10000', :'400x500_2x'
184
+ end
185
+
186
+ it 'returns nil if no thumbnail matches the requested aspect ratio' do
187
+ expect_thumb '319x200', nil
188
+ end
189
+
190
+ it 'returns nil if no thumbnail matches the requested label' do
191
+ expect_thumb '319x_nonexistant_label', nil
167
192
  end
168
193
  end
169
194
  end
@@ -5,20 +5,23 @@ module Artwork
5
5
  expected_defaults = {:compatible? => true}
6
6
 
7
7
  examples = {
8
- :'320x' => {:width => 320, :retina? => false, :label => ''},
9
- :'320x_2x' => {:width => 320, :retina? => true, :label => ''},
10
- :'640x_2x' => {:width => 640, :retina? => true, :label => ''},
11
- :'640x' => {:width => 640, :retina? => false, :label => ''},
12
- :'1280x' => {:width => 1280, :retina? => false, :label => ''},
13
- :'1280x_2x' => {:width => 1280, :retina? => true, :label => ''},
14
- :'2000x' => {:width => 2000, :retina? => false, :label => ''},
15
- :'1500x_2x' => {:width => 1500, :retina? => true, :label => ''},
16
- :'320x_some_label' => {:width => 320, :retina? => false, :label => 'some_label'},
17
- :'320x_some_label_2x' => {:width => 320, :retina? => true, :label => 'some_label'},
18
- :'320x500' => {:width => 320, :retina? => false, :label => '500'},
19
- :'320x500_2x' => {:width => 320, :retina? => true, :label => '500'},
20
- :'320x500_crop' => {:width => 320, :retina? => false, :label => '500_crop'},
21
- :'320x500_crop_2x' => {:width => 320, :retina? => true, :label => '500_crop'},
8
+ :'320x' => {:width => 320, :height => nil, :retina? => false, :label => nil},
9
+ :'320x_2x' => {:width => 320, :height => nil, :retina? => true, :label => nil},
10
+ :'640x_2x' => {:width => 640, :height => nil, :retina? => true, :label => nil},
11
+ :'640x' => {:width => 640, :height => nil, :retina? => false, :label => nil},
12
+ :'1280x' => {:width => 1280, :height => nil, :retina? => false, :label => nil},
13
+ :'1280x_2x' => {:width => 1280, :height => nil, :retina? => true, :label => nil},
14
+ :'2000x' => {:width => 2000, :height => nil, :retina? => false, :label => nil},
15
+ :'1500x_2x' => {:width => 1500, :height => nil, :retina? => true, :label => nil},
16
+ :'320x_some_label' => {:width => 320, :height => nil, :retina? => false, :label => 'some_label'},
17
+ :'320x_some_label_2x' => {:width => 320, :height => nil, :retina? => true, :label => 'some_label'},
18
+ :'320x500' => {:width => 320, :height => 500, :retina? => false, :label => nil},
19
+ :'320x500_2x' => {:width => 320, :height => 500, :retina? => true, :label => nil},
20
+ :'320x500_crop' => {:width => 320, :height => 500, :retina? => false, :label => 'crop'},
21
+ :'320x500_crop_2x' => {:width => 320, :height => 500, :retina? => true, :label => 'crop'},
22
+ :'320x_' => {:width => 320, :height => nil, :retina? => false, :label => ''},
23
+ :'320x500_' => {:width => 320, :height => 500, :retina? => false, :label => ''},
24
+ :'320x500__2x' => {:width => 320, :height => 500, :retina? => true, :label => ''},
22
25
  :unsupported => {:compatible? => false},
23
26
  'unsupported_thumb' => {:compatible? => false},
24
27
  }
@@ -39,18 +42,54 @@ module Artwork
39
42
  end
40
43
 
41
44
  describe '#eq' do
42
- it 'is true for different objects with the same width, label and retina flag' do
45
+ it 'is true for different objects with the same width, height, label and retina flag' do
43
46
  expect(Thumbnail.new(:'1200x500_crop_2x')).to eq Thumbnail.new('1200x500_crop_2x')
44
47
  expect(Thumbnail.new(:'1200x_2x')).to eq Thumbnail.new('1200x_2x')
45
48
  expect(Thumbnail.new(:'1200x')).to eq Thumbnail.new('1200x')
46
49
  expect(Thumbnail.new(:'1200x_black_and_white')).to eq Thumbnail.new('1200x_black_and_white')
47
50
  end
48
51
 
49
- it 'is false for different objects if any of the width, label or retina flag differ' do
52
+ it 'is false for different objects if any of the width, height, label or retina flag differ' do
50
53
  expect(Thumbnail.new(:'1200x500_crop_2x')).not_to eq Thumbnail.new('1200x500_crop')
51
54
  expect(Thumbnail.new(:'1200x500_crop_2x')).not_to eq Thumbnail.new('1200x500crop_2x')
52
55
  expect(Thumbnail.new(:'1200x500_crop_2x')).not_to eq Thumbnail.new('1201x500_crop_2x')
53
56
  expect(Thumbnail.new(:'1200x500_crop_2x')).not_to eq Thumbnail.new('1500x')
57
+ expect(Thumbnail.new(:'1200x500_crop_2x')).not_to eq Thumbnail.new('1200x400_crop_2x')
58
+ end
59
+ end
60
+
61
+ describe '#aspect_ratio' do
62
+ it 'is nil if height is not present or is zero' do
63
+ expect(Thumbnail.new('400x_label_2x').aspect_ratio).to be_nil
64
+ expect(Thumbnail.new('400x_2x').aspect_ratio).to be_nil
65
+ expect(Thumbnail.new('400x_').aspect_ratio).to be_nil
66
+ expect(Thumbnail.new('400x').aspect_ratio).to be_nil
67
+ expect(Thumbnail.new('400x0').aspect_ratio).to be_nil
68
+ end
69
+
70
+ it 'is calculated as a decimal when both a width and a height are present' do
71
+ expect(Thumbnail.new('400x300').aspect_ratio).to be_within(0.1).of(1.33)
72
+ expect(Thumbnail.new('1600x900').aspect_ratio).to be_within(0.1).of(1.78)
73
+ expect(Thumbnail.new('1600x900_with_label').aspect_ratio).to be_within(0.1).of(1.78)
74
+ expect(Thumbnail.new('1600x900_with_label_2x').aspect_ratio).to be_within(0.1).of(1.78)
75
+ end
76
+ end
77
+
78
+ describe '#same_aspect_ratio_with?' do
79
+ it 'returns nil if either thumbs have no clear height' do
80
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('400x'))).to be_nil
81
+ expect(Thumbnail.new('400x0').same_aspect_ratio_with?(Thumbnail.new('400x300'))).to be_nil
82
+ end
83
+
84
+ it 'returns true if thumbs have aspect ratios within 0.1 of one another' do
85
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('400x300'))).to be true
86
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('1600x1200_with_label_2x'))).to be true
87
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('400x301'))).to be true
88
+ end
89
+
90
+ it 'returns false if thumbs have different aspect ratios not within 0.1 of one another' do
91
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('400x200'))).to be false
92
+ expect(Thumbnail.new('400x300').same_aspect_ratio_with?(Thumbnail.new('5x10'))).to be false
54
93
  end
55
94
  end
56
95
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: artwork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitar Dimitrov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-15 00:00:00.000000000 Z
11
+ date: 2014-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler