httpimagestore 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "sinatra", ">= 1.2.6"
4
+ gem "mongrel", ">= 1.1.5"
5
+ gem "s3", "~> 0.3"
6
+ gem "httpthumbnailer-client", "~> 0.0.1"
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "rspec", "~> 2.3.0"
12
+ gem "cucumber", ">= 0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.6.4"
15
+ gem "rcov", ">= 0"
16
+ gem "rdoc", "~> 3.9"
17
+ gem "daemon", "~> 1"
18
+ gem "httpthumbnailer", "~> 0.0.1"
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ builder (3.0.0)
5
+ cgi_multipart_eof_fix (2.5.0)
6
+ cucumber (1.1.2)
7
+ builder (>= 2.1.2)
8
+ diff-lcs (>= 1.1.2)
9
+ gherkin (~> 2.6.2)
10
+ json (>= 1.4.6)
11
+ term-ansicolor (>= 1.0.6)
12
+ daemon (1.1.0)
13
+ daemons (1.1.4)
14
+ diff-lcs (1.1.3)
15
+ fastthread (1.0.7)
16
+ gem_plugin (0.2.3)
17
+ gherkin (2.6.5)
18
+ json (>= 1.4.6)
19
+ git (1.2.5)
20
+ haml (3.1.3)
21
+ httpclient (2.2.3)
22
+ httpthumbnailer (0.0.1)
23
+ haml (~> 3)
24
+ mongrel (>= 1.1.5)
25
+ rmagick (~> 2)
26
+ sinatra (>= 1.2.6)
27
+ httpthumbnailer-client (0.0.1)
28
+ httpclient (>= 2.2.1)
29
+ jeweler (1.6.4)
30
+ bundler (~> 1.0)
31
+ git (>= 1.2.5)
32
+ rake
33
+ json (1.6.1)
34
+ mongrel (1.1.5)
35
+ cgi_multipart_eof_fix (>= 2.4)
36
+ daemons (>= 1.0.3)
37
+ fastthread (>= 1.0.1)
38
+ gem_plugin (>= 0.2.3)
39
+ proxies (0.2.1)
40
+ rack (1.3.5)
41
+ rack-protection (1.1.4)
42
+ rack
43
+ rake (0.9.2.2)
44
+ rcov (0.9.11)
45
+ rdoc (3.9.4)
46
+ rmagick (2.13.1)
47
+ rspec (2.3.0)
48
+ rspec-core (~> 2.3.0)
49
+ rspec-expectations (~> 2.3.0)
50
+ rspec-mocks (~> 2.3.0)
51
+ rspec-core (2.3.1)
52
+ rspec-expectations (2.3.0)
53
+ diff-lcs (~> 1.1.2)
54
+ rspec-mocks (2.3.0)
55
+ s3 (0.3.9)
56
+ proxies (~> 0.2.0)
57
+ sinatra (1.3.1)
58
+ rack (~> 1.3, >= 1.3.4)
59
+ rack-protection (~> 1.1, >= 1.1.2)
60
+ tilt (~> 1.3, >= 1.3.3)
61
+ term-ansicolor (1.0.7)
62
+ tilt (1.3.3)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ bundler (~> 1.0.0)
69
+ cucumber
70
+ daemon (~> 1)
71
+ httpthumbnailer (~> 0.0.1)
72
+ httpthumbnailer-client (~> 0.0.1)
73
+ jeweler (~> 1.6.4)
74
+ mongrel (>= 1.1.5)
75
+ rcov
76
+ rdoc (~> 3.9)
77
+ rspec (~> 2.3.0)
78
+ s3 (~> 0.3)
79
+ sinatra (>= 1.2.6)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jakub Pastuszek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = httpimagestore
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to httpimagestore
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Jakub Pastuszek. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "httpimagestore"
18
+ gem.homepage = "http://github.com/jpastuszek/httpimagestore"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{HTTP based image storage and thumbnailer}
21
+ gem.description = %Q{Thumbnails images using httpthumbnailer and stored data on HTTP server (S3)}
22
+ gem.email = "jpastuszek@gmail.com"
23
+ gem.authors = ["Jakub Pastuszek"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ require 'cucumber/rake/task'
40
+ Cucumber::Rake::Task.new(:features)
41
+
42
+ task :default => :spec
43
+
44
+ require 'rdoc/task'
45
+ RDoc::Task.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "httpimagestore #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'sinatra/base'
4
+ require 'pathname'
5
+ require 's3'
6
+ require 'httpthumbnailer-client'
7
+ require 'digest/sha2'
8
+
9
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+ require 'httpimagestore/configuration'
11
+ require 'httpimagestore/pathname'
12
+
13
+ sinatra = Sinatra.new
14
+
15
+ sinatra.set :environment, 'production'
16
+ sinatra.set :server, ['mongrel']
17
+ sinatra.set :lock, true
18
+ sinatra.set :logging, true
19
+
20
+ conf_file = ARGV[0] or fail "no configuration file given (ARGV[0])"
21
+ Configuration.from_file(conf_file).put(sinatra)
22
+
23
+ class S3Put
24
+ def initialize(key_id, key_secret, bucket, options = {})
25
+ @options = options
26
+ @logger = (options[:logger] or Logger.new('/dev/null'))
27
+
28
+ @s3 = S3::Service.new(:access_key_id => key_id, :secret_access_key => key_secret)
29
+
30
+ @logger.info "Getting bucket: #{bucket}"
31
+ @bucket = @s3.buckets.find(bucket) or fail "no buckte '#{bucket}' found"
32
+ end
33
+
34
+ def put_image(image_path, content_type, data)
35
+ @logger.info "Putting image in bucket '#{@bucket.name}': #{image_path}"
36
+
37
+ file = @bucket.objects.build(image_path)
38
+ file.content_type = content_type
39
+ file.content = data
40
+ file.save
41
+
42
+ "http://#{@bucket.name}.s3.amazonaws.com/#{image_path}"
43
+ end
44
+ end
45
+
46
+ sinatra.before do
47
+ # singletons
48
+ @s3 ||= S3Put.new(settings.s3_key_id, settings.s3_key_secret, settings.s3_bucket, :logger => logger)
49
+ @thumbnailer ||= HTTPThumbnailerClient.new(settings.thumbnailer_url)
50
+ end
51
+
52
+ sinatra.helpers do
53
+ def plain_exception(exception)
54
+ headers "Content-Type" => "text/plain"
55
+ body "Error: #{exception.class.name}: #{exception}\n"
56
+ end
57
+
58
+ def digest(data)
59
+ Digest::SHA2.new.update(data).to_s[0,16]
60
+ end
61
+ end
62
+
63
+ sinatra.get '/' do
64
+ "hello"
65
+ end
66
+
67
+ sinatra.put %r{/thumbnail/([^/]*)/(.*)} do |classes, image_path|
68
+ urls = []
69
+
70
+ classes = classes.split(',').map{|tc| settings.thumbnail_classes[tc] or fail "Class '#{tc}' not configured"}
71
+ image = request.body.read
72
+ image_hash = digest(image)
73
+
74
+ urls << @s3.put_image(Pathname.new(image_path).original_image(image_hash).to_s, response.headers['Content-Type'], image)
75
+
76
+ thumbs = @thumbnailer.thumbnail(image) do
77
+ classes.each do |tc|
78
+ thumbnail tc.method, tc.width, tc.height, tc.format, tc.options
79
+ end
80
+ end
81
+
82
+ thumbs.zip(classes).each do |thumb, thumbnail_class|
83
+ urls << @s3.put_image(Pathname.new(image_path).thumbnail_image(image_hash, thumbnail_class.name).to_s, thumb.mime_type, thumb.data)
84
+ end
85
+
86
+ return urls.join("\n")
87
+ end
88
+
89
+ sinatra.error do
90
+ plain_exception(env['sinatra.error'])
91
+ end
92
+
93
+ sinatra.run!
94
+
@@ -0,0 +1,25 @@
1
+ Feature: Original image and it's thumnails generation and storing on S2
2
+ In order to store original image and it's thumbnails in configured S3 buckte
3
+ A user must PUT image data to URI representing it's pathi with bucket
4
+ The respons will be paths to files storred in S3
5
+
6
+ Background:
7
+ Given httpimagestore server is running at http://localhost:3000/ with the following configuration
8
+ """
9
+ s3_key 'AKIAJMUYVYOSACNXLPTQ', 'MAeGhvW+clN7kzK3NboASf3/kZ6a81PRtvwMZj4Y'
10
+ s3_bucket 'rhthumbnails'
11
+
12
+ thumbnail_class 'small', 'crop', 128, 128
13
+ thumbnail_class 'tiny', 'crop', 32, 32
14
+ """
15
+ Given httpthumbnailer server is running at http://localhost:3100/
16
+
17
+ Scenario: Putting thumbnails and original to S3 bucket
18
+ Given test.jpg file content as request body
19
+ When I do PUT request http://localhost:3000/thumbnail/small,tiny/test/image/test.jpg
20
+ Then I will get the following response body
21
+ """
22
+ http://rhthumbnails.s3.amazonaws.com/test/image/4006450256177f4a/test.jpg
23
+ http://rhthumbnails.s3.amazonaws.com/test/image/4006450256177f4a/test-small.jpg
24
+ http://rhthumbnails.s3.amazonaws.com/test/image/4006450256177f4a/test-tiny.jpg
25
+ """
@@ -0,0 +1,42 @@
1
+ Given /httpimagestore server is running at (.*) with the following configuration/ do |url, config|
2
+ cfile = Tempfile.new('httpimagestore.conf')
3
+ cfile.write(config)
4
+ cfile.close
5
+
6
+ begin
7
+ start_server(
8
+ "bundle exec #{script('httpimagestore')} #{cfile.path}",
9
+ '/tmp/httpimagestore.pid',
10
+ support_dir + 'server.log',
11
+ url
12
+ )
13
+ ensure
14
+ cfile.unlink
15
+ end
16
+ end
17
+
18
+ Given /httpthumbnailer server is running at (.*)/ do |url|
19
+ start_server(
20
+ "httpthumbnailer",
21
+ '/tmp/httpthumbnailer.pid',
22
+ support_dir + 'thumbniler.log',
23
+ url
24
+ )
25
+ end
26
+
27
+ Given /(.*) file content as request body/ do |file|
28
+ @request_body = File.open(support_dir + file){|f| f.read }
29
+ end
30
+
31
+ When /I do (.*) request (.*)/ do |method, uri|
32
+ @response = HTTPClient.new.request(method, uri, nil, @request_body)
33
+ end
34
+
35
+ Then /I will get matching response body/ do |body|
36
+ @response.body.should =~ Regexp.new(/^#{body}$/m)
37
+ end
38
+
39
+ Then /I will get the following response body/ do |body|
40
+ @response.body.should == body
41
+ end
42
+
@@ -0,0 +1,81 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
+ require 'rspec/expectations'
12
+
13
+ require 'daemon'
14
+ require 'timeout'
15
+ require 'httpclient'
16
+ require "open3"
17
+ require "thread"
18
+ require 'tempfile'
19
+
20
+ def gem_dir
21
+ Pathname.new(__FILE__).dirname + '..' + '..'
22
+ end
23
+
24
+ def features_dir
25
+ gem_dir + 'features'
26
+ end
27
+
28
+ def support_dir
29
+ features_dir + 'support'
30
+ end
31
+
32
+ def script(file)
33
+ gem_dir + 'bin' + file
34
+ end
35
+
36
+ def get(url)
37
+ HTTPClient.new.get_content(url)
38
+ end
39
+
40
+ def start_server(cmd, pid_file, log_file, test_url)
41
+ stop_server(pid_file)
42
+
43
+ fork do
44
+ Daemon.daemonize(pid_file, log_file)
45
+ exec(cmd)
46
+ end
47
+ Process.wait
48
+
49
+ ppid = Process.pid
50
+ at_exit do
51
+ stop_server(pid_file) if Process.pid == ppid
52
+ end
53
+
54
+ Timeout.timeout(10) do
55
+ begin
56
+ get test_url
57
+ rescue Errno::ECONNREFUSED
58
+ sleep 0.1
59
+ retry
60
+ end
61
+ end
62
+ end
63
+
64
+ def stop_server(pid_file)
65
+ pid_file = Pathname.new(pid_file)
66
+ return unless pid_file.exist?
67
+
68
+ pid = pid_file.read.strip.to_i
69
+
70
+ Timeout.timeout(20) do
71
+ begin
72
+ loop do
73
+ Process.kill("TERM", pid)
74
+ sleep 0.1
75
+ end
76
+ rescue Errno::ESRCH
77
+ pid_file.unlink
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,6 @@
1
+ s3_key 'AKIAJMUYVYOSACNXLPTQ', 'MAeGhvW+clN7kzK3NboASf3/kZ6a81PRtvwMZj4Y'
2
+ s3_bucket 'rhthumbnails'
3
+
4
+ thumbnail_class 'small', 'crop', 128, 128
5
+ thumbnail_class 'tiny', 'crop', 32, 32
6
+
Binary file
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "httpimagestore"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jakub Pastuszek"]
12
+ s.date = "2011-11-25"
13
+ s.description = "Thumbnails images using httpthumbnailer and stored data on HTTP server (S3)"
14
+ s.email = "jpastuszek@gmail.com"
15
+ s.executables = ["httpimagestore"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "bin/httpimagestore",
30
+ "features/httpimagestore.feature",
31
+ "features/step_definitions/httpimagestore_steps.rb",
32
+ "features/support/env.rb",
33
+ "features/support/test.cfg",
34
+ "features/support/test.jpg",
35
+ "httpimagestore.gemspec",
36
+ "lib/httpimagestore/configuration.rb",
37
+ "lib/httpimagestore/pathname.rb",
38
+ "lib/httpimagestore/thumbnail_class.rb",
39
+ "spec/configuration_spec.rb",
40
+ "spec/pathname_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "spec/test.cfg"
43
+ ]
44
+ s.homepage = "http://github.com/jpastuszek/httpimagestore"
45
+ s.licenses = ["MIT"]
46
+ s.require_paths = ["lib"]
47
+ s.rubygems_version = "1.8.10"
48
+ s.summary = "HTTP based image storage and thumbnailer"
49
+
50
+ if s.respond_to? :specification_version then
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<sinatra>, [">= 1.2.6"])
55
+ s.add_runtime_dependency(%q<mongrel>, [">= 1.1.5"])
56
+ s.add_runtime_dependency(%q<s3>, ["~> 0.3"])
57
+ s.add_runtime_dependency(%q<httpthumbnailer-client>, ["~> 0.0.1"])
58
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
59
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
62
+ s.add_development_dependency(%q<rcov>, [">= 0"])
63
+ s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
64
+ s.add_development_dependency(%q<daemon>, ["~> 1"])
65
+ s.add_development_dependency(%q<httpthumbnailer>, ["~> 0.0.1"])
66
+ else
67
+ s.add_dependency(%q<sinatra>, [">= 1.2.6"])
68
+ s.add_dependency(%q<mongrel>, [">= 1.1.5"])
69
+ s.add_dependency(%q<s3>, ["~> 0.3"])
70
+ s.add_dependency(%q<httpthumbnailer-client>, ["~> 0.0.1"])
71
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
72
+ s.add_dependency(%q<cucumber>, [">= 0"])
73
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
75
+ s.add_dependency(%q<rcov>, [">= 0"])
76
+ s.add_dependency(%q<rdoc>, ["~> 3.9"])
77
+ s.add_dependency(%q<daemon>, ["~> 1"])
78
+ s.add_dependency(%q<httpthumbnailer>, ["~> 0.0.1"])
79
+ end
80
+ else
81
+ s.add_dependency(%q<sinatra>, [">= 1.2.6"])
82
+ s.add_dependency(%q<mongrel>, [">= 1.1.5"])
83
+ s.add_dependency(%q<s3>, ["~> 0.3"])
84
+ s.add_dependency(%q<httpthumbnailer-client>, ["~> 0.0.1"])
85
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
86
+ s.add_dependency(%q<cucumber>, [">= 0"])
87
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
88
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
89
+ s.add_dependency(%q<rcov>, [">= 0"])
90
+ s.add_dependency(%q<rdoc>, ["~> 3.9"])
91
+ s.add_dependency(%q<daemon>, ["~> 1"])
92
+ s.add_dependency(%q<httpthumbnailer>, ["~> 0.0.1"])
93
+ end
94
+ end
95
+
@@ -0,0 +1,57 @@
1
+ require 'httpimagestore/thumbnail_class'
2
+ require 'pathname'
3
+
4
+ class Configuration
5
+ def initialize(&block)
6
+ @thumbnail_classes = {}
7
+ @thumbnailer_url = "http://localhost:3100"
8
+
9
+ @port = 3000
10
+ @bind = 'localhost'
11
+
12
+ instance_eval &block
13
+ end
14
+
15
+ def self.from_file(file)
16
+ file = Pathname.pwd + file
17
+ Configuration.new do
18
+ eval(file.read, nil, file)
19
+ end
20
+ end
21
+
22
+ def thumbnail_class(name, method, width, height, format = 'JPEG', options = {})
23
+ @thumbnail_classes[name] = ThumbnailClass.new(name, method, width, height, format, options)
24
+ end
25
+
26
+ def s3_key(id, secret)
27
+ @s3_key_id = id
28
+ @s3_key_secret = secret
29
+ end
30
+
31
+ def s3_bucket(bucket)
32
+ @s3_bucket = bucket
33
+ end
34
+
35
+ def thumbnailer_url(url)
36
+ @thumbnailer_url = url
37
+ end
38
+
39
+ def port(no)
40
+ @port = no
41
+ end
42
+
43
+ def bind(address)
44
+ @bind = address
45
+ end
46
+
47
+ def get
48
+ Struct.new(:thumbnail_classes, :s3_key_id, :s3_key_secret, :s3_bucket, :thumbnailer_url, :port, :bind).new(@thumbnail_classes, @s3_key_id, @s3_key_secret, @s3_bucket, @thumbnailer_url, @port, @bind)
49
+ end
50
+
51
+ def put(sinatra)
52
+ get.each_pair do |key, value|
53
+ sinatra.set key, value
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,10 @@
1
+ class Pathname
2
+ def original_image(id)
3
+ dirname + id.to_s + basename
4
+ end
5
+
6
+ def thumbnail_image(id, thumbnail_class)
7
+ dirname + id.to_s + "#{basename(extname)}-#{thumbnail_class}#{extname}"
8
+ end
9
+ end
10
+
@@ -0,0 +1,13 @@
1
+ class ThumbnailClass
2
+ def initialize(name, method, width, height, format = 'JPEG', options = {})
3
+ @name = name
4
+ @method = method
5
+ @width = width
6
+ @height = height
7
+ @format = format
8
+ @options = options
9
+ end
10
+
11
+ attr_reader :name, :method, :width, :height, :format, :options
12
+ end
13
+
@@ -0,0 +1,132 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'httpimagestore/configuration'
3
+ require 'sinatra/base'
4
+
5
+ describe Configuration do
6
+ it "should provide thumbnail classes" do
7
+ c = Configuration.new do
8
+ thumbnail_class 'small', 'crop', 128, 128, 'JPEG', :magick => 'option', :number => 42
9
+ thumbnail_class 'tiny', 'pad', 32, 48, 'PNG'
10
+ thumbnail_class 'test', 'pad', 32, 48
11
+ end.get
12
+
13
+ tc = c.thumbnail_classes['small']
14
+ tc.name.should == 'small'
15
+ tc.method.should == 'crop'
16
+ tc.width.should == 128
17
+ tc.height.should == 128
18
+ tc.format.should == 'JPEG'
19
+ tc.options.should == { :magick => 'option', :number => 42}
20
+
21
+ tc = c.thumbnail_classes['tiny']
22
+ tc.name.should == 'tiny'
23
+ tc.method.should == 'pad'
24
+ tc.width.should == 32
25
+ tc.height.should == 48
26
+ tc.format.should == 'PNG'
27
+ tc.options.should == {}
28
+
29
+ tc = c.thumbnail_classes['test']
30
+ tc.name.should == 'test'
31
+ tc.method.should == 'pad'
32
+ tc.width.should == 32
33
+ tc.height.should == 48
34
+ tc.format.should == 'JPEG'
35
+ tc.options.should == {}
36
+ end
37
+
38
+ it "should provide S3 key id and secret" do
39
+ c = Configuration.new do
40
+ s3_key 'abc', 'xyz'
41
+ end.get
42
+
43
+ c.s3_key_id.should == 'abc'
44
+ c.s3_key_secret.should == 'xyz'
45
+ end
46
+
47
+ it "should provide S3 bucket" do
48
+ c = Configuration.new do
49
+ s3_bucket 'test'
50
+ end.get
51
+
52
+ c.s3_bucket.should == 'test'
53
+ end
54
+
55
+ it "should provide thumbnailer_url defaulting to http://localhost:3100" do
56
+ c = Configuration.new do
57
+ end.get
58
+
59
+ c.thumbnailer_url.should == 'http://localhost:3100'
60
+
61
+ c = Configuration.new do
62
+ thumbnailer_url 'http://test'
63
+ end.get
64
+
65
+ c.thumbnailer_url.should == 'http://test'
66
+ end
67
+
68
+ it "should provide port and bind address and defaults" do
69
+ c = Configuration.new do
70
+ end.get
71
+
72
+ c.port.should == 3000
73
+ c.bind.should == 'localhost'
74
+
75
+ c = Configuration.new do
76
+ port 123
77
+ bind 'blah'
78
+ end.get
79
+
80
+ c.port.should == 123
81
+ c.bind.should == 'blah'
82
+ end
83
+
84
+ it "can set sinatra settings with configured keys" do
85
+ sinatra = Sinatra.new
86
+ c = Configuration.new do
87
+ s3_key 'abc', 'xyz'
88
+ s3_bucket 'test'
89
+ thumbnailer_url 'http://test'
90
+ end.put(sinatra)
91
+
92
+ sinatra.settings.s3_key_id.should == 'abc'
93
+ sinatra.settings.s3_key_secret.should == 'xyz'
94
+ sinatra.settings.s3_bucket.should == 'test'
95
+ sinatra.settings.thumbnailer_url.should == 'http://test'
96
+ end
97
+
98
+ it "should load configuration from file" do
99
+ Dir.chdir(File.dirname(__FILE__))
100
+ c = Configuration.from_file('test.cfg').get
101
+
102
+ c.s3_key_id.should == 'abc'
103
+ c.s3_key_secret.should == 'xyz'
104
+ c.s3_bucket.should == 'test'
105
+ c.thumbnailer_url.should == 'http://test'
106
+
107
+ tc = c.thumbnail_classes['small']
108
+ tc.name.should == 'small'
109
+ tc.method.should == 'crop'
110
+ tc.width.should == 128
111
+ tc.height.should == 128
112
+ tc.format.should == 'JPEG'
113
+ tc.options.should == { :magick => 'option', :number => 42}
114
+
115
+ tc = c.thumbnail_classes['tiny']
116
+ tc.name.should == 'tiny'
117
+ tc.method.should == 'pad'
118
+ tc.width.should == 32
119
+ tc.height.should == 48
120
+ tc.format.should == 'PNG'
121
+ tc.options.should == {}
122
+
123
+ tc = c.thumbnail_classes['test']
124
+ tc.name.should == 'test'
125
+ tc.method.should == 'pad'
126
+ tc.width.should == 32
127
+ tc.height.should == 48
128
+ tc.format.should == 'JPEG'
129
+ tc.options.should == {}
130
+ end
131
+ end
132
+
@@ -0,0 +1,17 @@
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
+
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
8
+
9
+ RSpec.configure do |config|
10
+
11
+ end
data/spec/test.cfg ADDED
@@ -0,0 +1,8 @@
1
+ s3_key 'abc', 'xyz'
2
+ s3_bucket 'test'
3
+ thumbnailer_url 'http://test'
4
+
5
+ thumbnail_class 'small', 'crop', 128, 128, 'JPEG', :magick => 'option', :number => 42
6
+ thumbnail_class 'tiny', 'pad', 32, 48, 'PNG'
7
+ thumbnail_class 'test', 'pad', 32, 48
8
+
metadata ADDED
@@ -0,0 +1,270 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httpimagestore
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jakub Pastuszek
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-25 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 19
28
+ segments:
29
+ - 1
30
+ - 2
31
+ - 6
32
+ version: 1.2.6
33
+ prerelease: false
34
+ name: sinatra
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ type: :runtime
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 25
44
+ segments:
45
+ - 1
46
+ - 1
47
+ - 5
48
+ version: 1.1.5
49
+ prerelease: false
50
+ name: mongrel
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ type: :runtime
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 13
60
+ segments:
61
+ - 0
62
+ - 3
63
+ version: "0.3"
64
+ prerelease: false
65
+ name: s3
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ type: :runtime
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ hash: 29
75
+ segments:
76
+ - 0
77
+ - 0
78
+ - 1
79
+ version: 0.0.1
80
+ prerelease: false
81
+ name: httpthumbnailer-client
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ type: :development
85
+ requirement: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 2
93
+ - 3
94
+ - 0
95
+ version: 2.3.0
96
+ prerelease: false
97
+ name: rspec
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ type: :development
101
+ requirement: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ prerelease: false
111
+ name: cucumber
112
+ version_requirements: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ type: :development
115
+ requirement: &id007 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ~>
119
+ - !ruby/object:Gem::Version
120
+ hash: 23
121
+ segments:
122
+ - 1
123
+ - 0
124
+ - 0
125
+ version: 1.0.0
126
+ prerelease: false
127
+ name: bundler
128
+ version_requirements: *id007
129
+ - !ruby/object:Gem::Dependency
130
+ type: :development
131
+ requirement: &id008 !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ~>
135
+ - !ruby/object:Gem::Version
136
+ hash: 7
137
+ segments:
138
+ - 1
139
+ - 6
140
+ - 4
141
+ version: 1.6.4
142
+ prerelease: false
143
+ name: jeweler
144
+ version_requirements: *id008
145
+ - !ruby/object:Gem::Dependency
146
+ type: :development
147
+ requirement: &id009 !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ hash: 3
153
+ segments:
154
+ - 0
155
+ version: "0"
156
+ prerelease: false
157
+ name: rcov
158
+ version_requirements: *id009
159
+ - !ruby/object:Gem::Dependency
160
+ type: :development
161
+ requirement: &id010 !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ hash: 21
167
+ segments:
168
+ - 3
169
+ - 9
170
+ version: "3.9"
171
+ prerelease: false
172
+ name: rdoc
173
+ version_requirements: *id010
174
+ - !ruby/object:Gem::Dependency
175
+ type: :development
176
+ requirement: &id011 !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ~>
180
+ - !ruby/object:Gem::Version
181
+ hash: 1
182
+ segments:
183
+ - 1
184
+ version: "1"
185
+ prerelease: false
186
+ name: daemon
187
+ version_requirements: *id011
188
+ - !ruby/object:Gem::Dependency
189
+ type: :development
190
+ requirement: &id012 !ruby/object:Gem::Requirement
191
+ none: false
192
+ requirements:
193
+ - - ~>
194
+ - !ruby/object:Gem::Version
195
+ hash: 29
196
+ segments:
197
+ - 0
198
+ - 0
199
+ - 1
200
+ version: 0.0.1
201
+ prerelease: false
202
+ name: httpthumbnailer
203
+ version_requirements: *id012
204
+ description: Thumbnails images using httpthumbnailer and stored data on HTTP server (S3)
205
+ email: jpastuszek@gmail.com
206
+ executables:
207
+ - httpimagestore
208
+ extensions: []
209
+
210
+ extra_rdoc_files:
211
+ - LICENSE.txt
212
+ - README.rdoc
213
+ files:
214
+ - .document
215
+ - .rspec
216
+ - Gemfile
217
+ - Gemfile.lock
218
+ - LICENSE.txt
219
+ - README.rdoc
220
+ - Rakefile
221
+ - VERSION
222
+ - bin/httpimagestore
223
+ - features/httpimagestore.feature
224
+ - features/step_definitions/httpimagestore_steps.rb
225
+ - features/support/env.rb
226
+ - features/support/test.cfg
227
+ - features/support/test.jpg
228
+ - httpimagestore.gemspec
229
+ - lib/httpimagestore/configuration.rb
230
+ - lib/httpimagestore/pathname.rb
231
+ - lib/httpimagestore/thumbnail_class.rb
232
+ - spec/configuration_spec.rb
233
+ - spec/pathname_spec.rb
234
+ - spec/spec_helper.rb
235
+ - spec/test.cfg
236
+ homepage: http://github.com/jpastuszek/httpimagestore
237
+ licenses:
238
+ - MIT
239
+ post_install_message:
240
+ rdoc_options: []
241
+
242
+ require_paths:
243
+ - lib
244
+ required_ruby_version: !ruby/object:Gem::Requirement
245
+ none: false
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ hash: 3
250
+ segments:
251
+ - 0
252
+ version: "0"
253
+ required_rubygems_version: !ruby/object:Gem::Requirement
254
+ none: false
255
+ requirements:
256
+ - - ">="
257
+ - !ruby/object:Gem::Version
258
+ hash: 3
259
+ segments:
260
+ - 0
261
+ version: "0"
262
+ requirements: []
263
+
264
+ rubyforge_project:
265
+ rubygems_version: 1.8.10
266
+ signing_key:
267
+ specification_version: 3
268
+ summary: HTTP based image storage and thumbnailer
269
+ test_files: []
270
+