httpimagestore 0.2.0 → 0.2.1

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.
data/Gemfile CHANGED
@@ -11,7 +11,7 @@ gem "mime-types", "~> 1.17.2"
11
11
  # Add dependencies to develop your gem here.
12
12
  # Include everything needed to run rake, tests, features, etc.
13
13
  group :development do
14
- gem "rspec", "~> 2.3.0"
14
+ gem "rspec", "~> 2.8.0"
15
15
  gem "cucumber", ">= 0"
16
16
  gem "bundler", "~> 1.0.0"
17
17
  gem "jeweler", "~> 1.6.4"
data/Gemfile.lock CHANGED
@@ -56,14 +56,14 @@ GEM
56
56
  rdoc (3.11)
57
57
  json (~> 1.4)
58
58
  rmagick (2.13.1)
59
- rspec (2.3.0)
60
- rspec-core (~> 2.3.0)
61
- rspec-expectations (~> 2.3.0)
62
- rspec-mocks (~> 2.3.0)
63
- rspec-core (2.3.1)
64
- rspec-expectations (2.3.0)
59
+ rspec (2.8.0)
60
+ rspec-core (~> 2.8.0)
61
+ rspec-expectations (~> 2.8.0)
62
+ rspec-mocks (~> 2.8.0)
63
+ rspec-core (2.8.0)
64
+ rspec-expectations (2.8.0)
65
65
  diff-lcs (~> 1.1.2)
66
- rspec-mocks (2.3.0)
66
+ rspec-mocks (2.8.0)
67
67
  ruby-ip (0.9.0)
68
68
  s3 (0.3.9)
69
69
  proxies (~> 0.2.0)
@@ -90,7 +90,7 @@ DEPENDENCIES
90
90
  prawn (= 0.8.4)
91
91
  rcov
92
92
  rdoc (~> 3.9)
93
- rspec (~> 2.3.0)
93
+ rspec (~> 2.8.0)
94
94
  ruby-ip (~> 0.9)
95
95
  s3 (~> 0.3)
96
96
  sinatra (>= 1.2.6)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
data/bin/httpimagestore CHANGED
@@ -17,13 +17,13 @@ options = CLI.new do
17
17
  end.parse!
18
18
 
19
19
  require 'sinatra/base'
20
- require 's3'
21
20
  require 'httpthumbnailer-client'
22
21
  require 'digest/sha2'
23
22
 
24
23
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
25
24
  require 'httpimagestore/configuration'
26
- require 'httpimagestore/pathname'
25
+ require 'httpimagestore/image_path'
26
+ require 'httpimagestore/s3_service'
27
27
 
28
28
  sinatra = Sinatra.new
29
29
 
@@ -43,33 +43,19 @@ sinatra.set :uri_encode, (not options.no_uri_encode)
43
43
 
44
44
  Configuration.from_file(options.config).put(sinatra)
45
45
 
46
- class S3Put
47
- def initialize(key_id, key_secret, bucket, options = {})
48
- @options = options
49
- @logger = (options[:logger] or Logger.new('/dev/null'))
50
-
51
- @s3 = S3::Service.new(:access_key_id => key_id, :secret_access_key => key_secret)
52
-
53
- @logger.info "Getting bucket: #{bucket}"
54
- @bucket = @s3.buckets.find(bucket) or fail "no buckte '#{bucket}' found"
46
+ class ThumbnailingError < RuntimeError
47
+ def initialize(thumbnail_class, remote_error)
48
+ @remote_error = remote_error
49
+ super "Thumbnailing for class '#{thumbnail_class.name}' failed: #{remote_error.message}"
55
50
  end
56
51
 
57
- def put_image(image_path, content_type, data)
58
- @logger.info "Putting image in bucket '#{@bucket.name}': #{image_path}"
59
-
60
- file = @bucket.objects.build(image_path)
61
- file.content_type = content_type
62
- file.content = data
63
- file.save
64
-
65
- "http://#{@bucket.name}.s3.amazonaws.com/#{image_path}"
66
- end
52
+ attr_reader :remote_error
67
53
  end
68
54
 
69
55
  sinatra.before do
70
56
  logger.level = Logger::DEBUG if settings.logging and settings.debug
71
57
  # singletons
72
- $s3 ||= S3Put.new(settings.s3_key_id, settings.s3_key_secret, settings.s3_bucket, :logger => logger)
58
+ $s3 ||= S3Service.new(settings.s3_key_id, settings.s3_key_secret, settings.s3_bucket, :logger => logger)
73
59
  $thumbnailer ||= HTTPThumbnailerClient.new(settings.thumbnailer_url)
74
60
  end
75
61
 
@@ -87,54 +73,42 @@ sinatra.helpers do
87
73
  def digest(data)
88
74
  Digest::SHA2.new.update(data).to_s[0,16]
89
75
  end
90
-
91
- class BadRequestError < RuntimeError
92
- end
93
-
94
- class ThumbnailingError < RuntimeError
95
- def initialize(thumbnail_class, remote_error)
96
- @remote_error = remote_error
97
- super "Thumbnailing for class '#{thumbnail_class.name}' failed: #{remote_error.message}"
98
- end
99
-
100
- attr_reader :remote_error
101
- end
102
76
  end
103
77
 
104
78
  sinatra.get '/' do
105
79
  "hello"
106
80
  end
107
81
 
108
- sinatra.put %r{/thumbnail/([^/]*)/?(.*)} do |classes, image_path|
109
- if image_path.empty?
110
- image_path = Pathname.new(image_path).extend(Pathname::AutoPath)
111
- else
112
- image_path = Pathname.new(image_path).extend(Pathname::CustomPath)
113
- end
82
+ sinatra.put %r{/thumbnail/([^/]*)/?(.*)} do |thumbnail_classes, image_path|
83
+ thumbnail_classes = thumbnail_classes.split(',').map{|thumbnail_class| settings.thumbnail_classes[thumbnail_class]}
114
84
 
115
- classes = classes.split(',').map{|tc| settings.thumbnail_classes[tc]}
116
85
  image = request.body.read
86
+ image_hash = digest(image)
87
+
88
+ unless image_path.empty?
89
+ image_path = ImagePath::Custom.new(image_hash, image_path)
90
+ else
91
+ image_path = ImagePath::Auto.new(image_hash)
92
+ end
117
93
 
118
- thumbs = $thumbnailer.thumbnail(image) do
119
- classes.each do |tc|
120
- thumbnail tc.method, tc.width, tc.height, tc.format, tc.options
94
+ thumbnails = $thumbnailer.thumbnail(image) do
95
+ thumbnail_classes.each do |thumbnail_class|
96
+ thumbnail thumbnail_class.method, thumbnail_class.width, thumbnail_class.height, thumbnail_class.format, thumbnail_class.options
121
97
  end
122
98
  end
123
99
 
124
100
  # check for errors
125
- thumbs.zip(classes).each do |thumb, thumbnail_class|
126
- raise ThumbnailingError.new(thumbnail_class, thumb) if thumb.kind_of? HTTPThumbnailerClient::ThumbnailingError
101
+ thumbnails.zip(thumbnail_classes).each do |thumbnail, thumbnail_class|
102
+ raise ThumbnailingError.new(thumbnail_class, thumbnail) if thumbnail.kind_of? HTTPThumbnailerClient::ThumbnailingError
127
103
  end
128
104
 
129
105
  urls = []
130
106
 
131
- image_hash = digest(image)
132
-
133
107
  # store all images
134
- urls << $s3.put_image(image_path.original_image(image_hash, thumbs.input_mime_type).to_s, thumbs.input_mime_type, image)
108
+ urls << $s3.put_image(image_path.original_image(thumbnails.input_mime_type), thumbnails.input_mime_type, image)
135
109
 
136
- thumbs.zip(classes).each do |thumb, thumbnail_class|
137
- urls << $s3.put_image(image_path.thumbnail_image(image_hash, thumb.mime_type, thumbnail_class.name).to_s, thumb.mime_type, thumb.data)
110
+ thumbnails.zip(thumbnail_classes).each do |thumbnail, thumbnail_class|
111
+ urls << $s3.put_image(image_path.thumbnail_image(thumbnail.mime_type, thumbnail_class.name), thumbnail.mime_type, thumbnail.data)
138
112
  end
139
113
 
140
114
  status 200
@@ -162,10 +136,6 @@ sinatra.error ThumbnailingError do
162
136
  end
163
137
  end
164
138
 
165
- sinatra.error BadRequestError do
166
- halt_exception(400, env['sinatra.error'])
167
- end
168
-
169
139
  sinatra.error Configuration::ThumbnailClassDoesNotExistError do
170
140
  halt_exception(404, env['sinatra.error'])
171
141
  end
@@ -12,7 +12,7 @@ Feature: Storing of original image and specified classes of its thumbnails on S3
12
12
 
13
13
  thumbnail_class 'small', 'crop', 128, 128
14
14
  thumbnail_class 'tiny', 'crop', 32, 32
15
- thumbnail_class 'png', 'crop', 32, 32, 'PNG'
15
+ thumbnail_class 'tiny_png', 'crop', 32, 32, 'PNG'
16
16
  thumbnail_class 'bad', 'crop', 0, 0
17
17
  thumbnail_class 'superlarge', 'crop', 16000, 16000
18
18
  thumbnail_class 'large_png', 'crop', 7000, 7000, 'PNG'
@@ -24,84 +24,74 @@ Feature: Storing of original image and specified classes of its thumbnails on S3
24
24
  Scenario: Putting original and its thumbnails to S3 bucket
25
25
  Given there is no 4006450256177f4a.jpg file in S3 bucket
26
26
  And there is no 4006450256177f4a/small.jpg file in S3 bucket
27
- And there is no 4006450256177f4a/tiny.jpg file in S3 bucket
27
+ And there is no 4006450256177f4a/tiny_png.png file in S3 bucket
28
28
  Given test.jpg file content as request body
29
- When I do PUT request http://localhost:3000/thumbnail/small,tiny
29
+ When I do PUT request http://localhost:3000/thumbnail/small,tiny_png
30
30
  Then response status will be 200
31
31
  And response content type will be text/uri-list
32
32
  And response body will be CRLF ended lines
33
33
  """
34
34
  http://issthumbtest.s3.amazonaws.com/4006450256177f4a.jpg
35
35
  http://issthumbtest.s3.amazonaws.com/4006450256177f4a/small.jpg
36
- http://issthumbtest.s3.amazonaws.com/4006450256177f4a/tiny.jpg
37
- """
38
- And http://issthumbtest.s3.amazonaws.com/4006450256177f4a.jpg will contain JPEG image of size 509x719
39
- And http://issthumbtest.s3.amazonaws.com/4006450256177f4a/small.jpg will contain JPEG image of size 128x128
40
- And http://issthumbtest.s3.amazonaws.com/4006450256177f4a/tiny.jpg will contain JPEG image of size 32x32
36
+ http://issthumbtest.s3.amazonaws.com/4006450256177f4a/tiny_png.png
37
+ """
38
+ Then http://issthumbtest.s3.amazonaws.com/4006450256177f4a.jpg will contain JPEG image of size 509x719
39
+ And http://issthumbtest.s3.amazonaws.com/4006450256177f4a.jpg content type will be image/jpeg
40
+ Then http://issthumbtest.s3.amazonaws.com/4006450256177f4a/small.jpg will contain JPEG image of size 128x128
41
+ And http://issthumbtest.s3.amazonaws.com/4006450256177f4a/small.jpg content type will be image/jpeg
42
+ Then http://issthumbtest.s3.amazonaws.com/4006450256177f4a/tiny_png.png will contain PNG image of size 32x32
43
+ And http://issthumbtest.s3.amazonaws.com/4006450256177f4a/tiny_png.png content type will be image/png
41
44
 
42
45
  Scenario: Putting original and its thumbnails to S3 bucket under custom path
43
46
  Given there is no test/image/4006450256177f4a/test.jpg file in S3 bucket
44
47
  And there is no test/image/4006450256177f4a/test-small.jpg file in S3 bucket
45
- And there is no test/image/4006450256177f4a/test-tiny.jpg file in S3 bucket
48
+ And there is no test/image/4006450256177f4a/test-tiny_png.png file in S3 bucket
46
49
  Given test.jpg file content as request body
47
- When I do PUT request http://localhost:3000/thumbnail/small,tiny/test/image/test.jpg
50
+ When I do PUT request http://localhost:3000/thumbnail/small,tiny_png/test/image/test
48
51
  Then response status will be 200
49
52
  And response content type will be text/uri-list
50
53
  And response body will be CRLF ended lines
51
54
  """
52
55
  http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg
53
56
  http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-small.jpg
54
- http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg
55
- """
56
- And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg will contain JPEG image of size 509x719
57
- And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-small.jpg will contain JPEG image of size 128x128
58
- And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg will contain JPEG image of size 32x32
59
-
60
- Scenario: Putting original and its thumbnails to S3 bucket under custom path with UTF characters (encoded) in the path and name
61
- Given there is no test/图像/4006450256177f4a/测试.jpg file in S3 bucket
62
- And there is no test/图像/4006450256177f4a/测试-small.jpg file in S3 bucket
63
- Given test.jpg file content as request body
64
- When I do PUT request http://localhost:3000/thumbnail/small/test/图像/测试.jpg
65
- Then response status will be 200
66
- And response content type will be text/uri-list
67
- And response body will be CRLF ended lines
68
- """
69
- http://issthumbtest.s3.amazonaws.com/test/%E5%9B%BE%E5%83%8F/4006450256177f4a/%E6%B5%8B%E8%AF%95.jpg
70
- http://issthumbtest.s3.amazonaws.com/test/%E5%9B%BE%E5%83%8F/4006450256177f4a/%E6%B5%8B%E8%AF%95-small.jpg
57
+ http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny_png.png
71
58
  """
72
- And http://issthumbtest.s3.amazonaws.com/test/图像/4006450256177f4a/测试.jpg will contain JPEG image of size 509x719
73
- And http://issthumbtest.s3.amazonaws.com/test/图像/4006450256177f4a/测试-small.jpg will contain JPEG image of size 128x128
59
+ Then http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg will contain JPEG image of size 509x719
60
+ And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg content type will be image/jpeg
61
+ Then http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-small.jpg will contain JPEG image of size 128x128
62
+ And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-small.jpg content type will be image/jpeg
63
+ Then http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny_png.png will contain PNG image of size 32x32
64
+ And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny_png.png content type will be image/png
74
65
 
75
- Scenario: Input image content type determined from content
66
+ Scenario: Custom path name can contain file name extension that may be used as failback to content based detection
76
67
  Given there is no test/image/4006450256177f4a/test.jpg file in S3 bucket
68
+ And there is no test/image/4006450256177f4a/test-tiny_png.jpg file in S3 bucket
77
69
  Given test.jpg file content as request body
78
- And Content-Type header set to application/octet-stream
79
- When I do PUT request http://localhost:3000/thumbnail/tiny/test/image/test.jpg
70
+ When I do PUT request http://localhost:3000/thumbnail/tiny_png/test/image/test.jpg
80
71
  Then response status will be 200
81
72
  And response content type will be text/uri-list
82
73
  And response body will be CRLF ended lines
83
74
  """
84
75
  http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg
85
- http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg
76
+ http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny_png.png
86
77
  """
87
78
  And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg content type will be image/jpeg
79
+ And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny_png.png content type will be image/png
88
80
 
89
- Scenario: Thumbnail image content type and file extension determined from configured format
90
- Given there is no test/image/4006450256177f4a/test.jpg file in S3 bucket
91
- And there is no test/image/4006450256177f4a/test-tiny.jpg file in S3 bucket
92
- And there is no test/image/4006450256177f4a/test-png.png file in S3 bucket
81
+ Scenario: Custom path name encoding when UTF-8 characters can be used
82
+ Given there is no test/图像/4006450256177f4a/测试.jpg file in S3 bucket
83
+ And there is no test/图像/4006450256177f4a/测试-small.jpg file in S3 bucket
93
84
  Given test.jpg file content as request body
94
- When I do PUT request http://localhost:3000/thumbnail/tiny,png/test/image/test.jpg
85
+ When I do PUT request http://localhost:3000/thumbnail/small/test/图像/测试
95
86
  Then response status will be 200
96
87
  And response content type will be text/uri-list
97
88
  And response body will be CRLF ended lines
98
89
  """
99
- http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg
100
- http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg
101
- http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-png.png
90
+ http://issthumbtest.s3.amazonaws.com/test/%E5%9B%BE%E5%83%8F/4006450256177f4a/%E6%B5%8B%E8%AF%95.jpg
91
+ http://issthumbtest.s3.amazonaws.com/test/%E5%9B%BE%E5%83%8F/4006450256177f4a/%E6%B5%8B%E8%AF%95-small.jpg
102
92
  """
103
- And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg content type will be image/jpeg
104
- And http://issthumbtest.s3.amazonaws.com/test/image/4006450256177f4a/test-png.png content type will be image/png
93
+ And http://issthumbtest.s3.amazonaws.com/test/图像/4006450256177f4a/测试.jpg will contain JPEG image of size 509x719
94
+ And http://issthumbtest.s3.amazonaws.com/test/图像/4006450256177f4a/测试-small.jpg will contain JPEG image of size 128x128
105
95
 
106
96
  Scenario: Reporting of missing resource
107
97
  When I do GET request http://localhost:3000/blah
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "httpimagestore"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jakub Pastuszek"]
@@ -35,10 +35,11 @@ Gem::Specification.new do |s|
35
35
  "features/support/test.txt",
36
36
  "httpimagestore.gemspec",
37
37
  "lib/httpimagestore/configuration.rb",
38
- "lib/httpimagestore/pathname.rb",
38
+ "lib/httpimagestore/image_path.rb",
39
+ "lib/httpimagestore/s3_service.rb",
39
40
  "lib/httpimagestore/thumbnail_class.rb",
40
41
  "spec/configuration_spec.rb",
41
- "spec/pathname_spec.rb",
42
+ "spec/image_path_spec.rb",
42
43
  "spec/spec_helper.rb",
43
44
  "spec/test.cfg"
44
45
  ]
@@ -59,7 +60,7 @@ Gem::Specification.new do |s|
59
60
  s.add_runtime_dependency(%q<ruby-ip>, ["~> 0.9"])
60
61
  s.add_runtime_dependency(%q<cli>, ["~> 1.1.0"])
61
62
  s.add_runtime_dependency(%q<mime-types>, ["~> 1.17.2"])
62
- s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
63
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
63
64
  s.add_development_dependency(%q<cucumber>, [">= 0"])
64
65
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
65
66
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -76,7 +77,7 @@ Gem::Specification.new do |s|
76
77
  s.add_dependency(%q<ruby-ip>, ["~> 0.9"])
77
78
  s.add_dependency(%q<cli>, ["~> 1.1.0"])
78
79
  s.add_dependency(%q<mime-types>, ["~> 1.17.2"])
79
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
80
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
80
81
  s.add_dependency(%q<cucumber>, [">= 0"])
81
82
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
82
83
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -94,7 +95,7 @@ Gem::Specification.new do |s|
94
95
  s.add_dependency(%q<ruby-ip>, ["~> 0.9"])
95
96
  s.add_dependency(%q<cli>, ["~> 1.1.0"])
96
97
  s.add_dependency(%q<mime-types>, ["~> 1.17.2"])
97
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
98
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
98
99
  s.add_dependency(%q<cucumber>, [">= 0"])
99
100
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
100
101
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -0,0 +1,54 @@
1
+ require 'mime/types'
2
+ require 'pathname'
3
+
4
+ class ImagePath
5
+ class CouldNotDetermineFileExtensionError < ArgumentError
6
+ def initialize(mime_type)
7
+ super "could not determine file extension for mime type: #{mime_type}"
8
+ end
9
+ end
10
+
11
+ def initialize(id)
12
+ @id = id.to_s
13
+ end
14
+
15
+ private
16
+
17
+ def mime_extension(mime_type)
18
+ mime = MIME::Types[mime_type].first or raise CouldNotDetermineFileExtensionError, mime_type
19
+ '.' + (mime.extensions.select{|e| e.length == 3}.first or mime.extensions.first)
20
+ end
21
+
22
+ class Auto < ImagePath
23
+ def original_image(mime_type)
24
+ "#{@id}#{mime_extension(mime_type)}"
25
+ end
26
+
27
+ def thumbnail_image(mime_type, thumbnail_class)
28
+ "#{@id}/#{thumbnail_class}#{mime_extension(mime_type)}"
29
+ end
30
+ end
31
+
32
+ class Custom < ImagePath
33
+ def initialize(id, path)
34
+ super(id)
35
+ @path = Pathname.new(path)
36
+ end
37
+
38
+ def original_image(mime_type)
39
+ extension = begin
40
+ mime_extension(mime_type)
41
+ rescue CouldNotDetermineFileExtensionError
42
+ raise if @path.extname.empty?
43
+ @path.extname
44
+ end
45
+
46
+ (@path.dirname + @id + "#{@path.basename(@path.extname)}#{extension}").to_s
47
+ end
48
+
49
+ def thumbnail_image(mime_type, thumbnail_class)
50
+ (@path.dirname + @id + "#{@path.basename(@path.extname)}-#{thumbnail_class}#{mime_extension(mime_type)}").to_s
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,25 @@
1
+ require 's3'
2
+
3
+ class S3Service
4
+ def initialize(key_id, key_secret, bucket, options = {})
5
+ @options = options
6
+ @logger = (options[:logger] or Logger.new('/dev/null'))
7
+
8
+ @s3 = S3::Service.new(:access_key_id => key_id, :secret_access_key => key_secret)
9
+
10
+ @logger.info "Getting bucket: #{bucket}"
11
+ @bucket = @s3.buckets.find(bucket) or fail "no buckte '#{bucket}' found"
12
+ end
13
+
14
+ def put_image(image_path, content_type, data)
15
+ @logger.info "Putting image in bucket '#{@bucket.name}': #{image_path}"
16
+
17
+ file = @bucket.objects.build(image_path)
18
+ file.content_type = content_type
19
+ file.content = data
20
+ file.save
21
+
22
+ "http://#{@bucket.name}.s3.amazonaws.com/#{image_path}"
23
+ end
24
+ end
25
+
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'httpimagestore/image_path'
3
+ require 'pathname'
4
+
5
+ shared_examples "extension handling" do |image_path|
6
+ describe "#original_image" do
7
+ it "determines extension based on mime type" do
8
+ Pathname.new(image_path.original_image("image/jpeg")).extname.should == ".jpg"
9
+ Pathname.new(image_path.original_image("image/tiff")).extname.should == ".tif"
10
+ Pathname.new(image_path.original_image("image/png")).extname.should == ".png"
11
+ end
12
+
13
+ it "should fail if provided extension from mime type could not be determined" do
14
+ lambda {
15
+ image_path.original_image("image/xyz")
16
+ }.should raise_error ImagePath::CouldNotDetermineFileExtensionError, "could not determine file extension for mime type: image/xyz"
17
+ end
18
+ end
19
+
20
+ describe "#thumbnail_image" do
21
+ it "determines extension based on mime type" do
22
+ Pathname.new(image_path.thumbnail_image("image/jpeg", "small")).extname.should == ".jpg"
23
+ Pathname.new(image_path.thumbnail_image("image/tiff", "small")).extname.should == ".tif"
24
+ Pathname.new(image_path.thumbnail_image("image/png", "small")).extname.should == ".png"
25
+ end
26
+
27
+ it "should fail if provided extension from mime type could not be determined" do
28
+ lambda {
29
+ image_path.thumbnail_image("image/xyz", "small")
30
+ }.should raise_error ImagePath::CouldNotDetermineFileExtensionError, "could not determine file extension for mime type: image/xyz"
31
+ end
32
+ end
33
+ end
34
+
35
+ describe ImagePath do
36
+ describe ImagePath::Auto do
37
+ describe "#original_image" do
38
+ it "returns path in format <id>.<ext>" do
39
+ ImagePath::Auto.new(123).original_image("image/jpeg").should == "123.jpg"
40
+ end
41
+ end
42
+
43
+ describe "#thumbnail_image" do
44
+ it "returns path in format <id>/<class>.<ext>" do
45
+ ImagePath::Auto.new(123).thumbnail_image("image/jpeg", "small").should == "123/small.jpg"
46
+ end
47
+ end
48
+
49
+ include_examples "extension handling", ImagePath::Auto.new(123)
50
+ end
51
+
52
+ describe ImagePath::Custom do
53
+ describe "#original_image" do
54
+ it "returns path in format abc/<id>/xyz.<ext>" do
55
+ ImagePath::Custom.new(123, "test/file/path.jpg").original_image("image/jpeg").should == "test/file/123/path.jpg"
56
+ end
57
+
58
+ it "should fail back to provided extension if extension from mime type could not be determined" do
59
+ Pathname.new(ImagePath::Custom.new(123, "test/file/path.abc").original_image("image/xyz")).extname.should == ".abc"
60
+ end
61
+ end
62
+
63
+ describe "#thumbnail_image" do
64
+ it "returns path in format abc/<id>/xyz-<class>.<ext>" do
65
+ ImagePath::Custom.new(123, "test/file/path.jpg").thumbnail_image("image/jpeg", "small").should == "test/file/123/path-small.jpg"
66
+ end
67
+ end
68
+
69
+ include_examples "extension handling", ImagePath::Custom.new(123, "test/file/path")
70
+ end
71
+ end
72
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpimagestore
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
9
+ - 1
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jakub Pastuszek
@@ -134,12 +134,12 @@ dependencies:
134
134
  requirements:
135
135
  - - ~>
136
136
  - !ruby/object:Gem::Version
137
- hash: 3
137
+ hash: 47
138
138
  segments:
139
139
  - 2
140
- - 3
140
+ - 8
141
141
  - 0
142
- version: 2.3.0
142
+ version: 2.8.0
143
143
  prerelease: false
144
144
  name: rspec
145
145
  version_requirements: *id008
@@ -291,10 +291,11 @@ files:
291
291
  - features/support/test.txt
292
292
  - httpimagestore.gemspec
293
293
  - lib/httpimagestore/configuration.rb
294
- - lib/httpimagestore/pathname.rb
294
+ - lib/httpimagestore/image_path.rb
295
+ - lib/httpimagestore/s3_service.rb
295
296
  - lib/httpimagestore/thumbnail_class.rb
296
297
  - spec/configuration_spec.rb
297
- - spec/pathname_spec.rb
298
+ - spec/image_path_spec.rb
298
299
  - spec/spec_helper.rb
299
300
  - spec/test.cfg
300
301
  homepage: http://github.com/jpastuszek/httpimagestore
@@ -1,33 +0,0 @@
1
- require 'mime/types'
2
-
3
- class Pathname
4
- def mime_extension(mime_type)
5
- mime = MIME::Types[mime_type].first or return extname
6
- '.' + (mime.extensions.select{|e| e.length == 3}.first or mime.extensions.first)
7
- end
8
-
9
- module AutoPath
10
- # <id>.<ext>
11
- def original_image(id, mime_type)
12
- "#{id.to_s}#{mime_extension(mime_type)}"
13
- end
14
-
15
- # <id>/<class>.<ext>
16
- def thumbnail_image(id, mime_type, thumbnail_class)
17
- "#{id.to_s}/#{thumbnail_class}#{mime_extension(mime_type)}"
18
- end
19
- end
20
-
21
- module CustomPath
22
- # abc/xyz.jpg => abc/<id>/xyz.jpg
23
- def original_image(id, mime_type)
24
- dirname + id.to_s + basename
25
- end
26
-
27
- # abc/xyz.jpg => abc/<id>/xyz-<class>.jpg
28
- def thumbnail_image(id, mime_type, thumbnail_class)
29
- dirname + id.to_s + "#{basename(extname)}-#{thumbnail_class}#{mime_extension(mime_type)}"
30
- end
31
- end
32
- end
33
-
@@ -1,17 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'httpimagestore/pathname'
3
-
4
- describe Pathname do
5
- describe "#original_image" do
6
- it "returns path with tid" do
7
- Pathname.new("test/file/path.jpg").original_image(123).to_s.should == "test/file/123/path.jpg"
8
- end
9
- end
10
-
11
- describe "#thumbnail_image" do
12
- it "returns path with tid and thumbnail class name in file name" do
13
- Pathname.new("test/file/path.jpg").thumbnail_image(123, 'small').to_s.should == "test/file/123/path-small.jpg"
14
- end
15
- end
16
- end
17
-