artwork 0.3.2 → 0.4.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.
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