shutterbug 0.2.5 → 0.4.3

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.
Files changed (41) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +3 -3
  3. data/README.md +6 -0
  4. data/bower.json +1 -1
  5. data/demo/The_Scream.jpg +0 -0
  6. data/demo/canvas_example.html +36 -0
  7. data/demo/index.html +1 -0
  8. data/lib/shutterbug.rb +1 -1
  9. data/lib/shutterbug/cache_manager.rb +2 -2
  10. data/lib/shutterbug/configuration.rb +4 -8
  11. data/lib/shutterbug/handlers.rb +5 -4
  12. data/lib/shutterbug/handlers/convert_handler.rb +38 -16
  13. data/lib/shutterbug/handlers/direct_upload_handler.rb +30 -0
  14. data/lib/shutterbug/handlers/file_handler.rb +30 -0
  15. data/lib/shutterbug/handlers/js_file_handler.rb +13 -10
  16. data/lib/shutterbug/handlers/shutterbug.js +123 -32
  17. data/lib/shutterbug/phantom_job.rb +11 -10
  18. data/lib/shutterbug/rackapp.rb +15 -18
  19. data/lib/shutterbug/rasterize.js +4 -4
  20. data/lib/shutterbug/storage.rb +1 -1
  21. data/lib/shutterbug/storage/file_storage.rb +21 -8
  22. data/lib/shutterbug/storage/s3_storage.rb +26 -31
  23. data/shutterbug.gemspec +0 -1
  24. data/spec/shared_examples_for_handlers.rb +13 -9
  25. data/spec/shared_examples_for_storage.rb +14 -10
  26. data/spec/shutterbug/configuration_spec.rb +1 -11
  27. data/spec/shutterbug/convert_handler_spec.rb +5 -4
  28. data/spec/shutterbug/direct_upload_handler_spec.rb +7 -0
  29. data/spec/shutterbug/file_handler_spec.rb +7 -0
  30. data/spec/shutterbug/file_storage_spec.rb +2 -1
  31. data/spec/shutterbug/js_file_handler_spec.rb +2 -1
  32. data/spec/shutterbug/rackapp_spec.rb +14 -28
  33. data/spec/shutterbug/s3_storage_spec.rb +1 -1
  34. metadata +10 -12
  35. data/lib/shutterbug/handlers/file_handlers.rb +0 -9
  36. data/lib/shutterbug/handlers/file_handlers/base.rb +0 -39
  37. data/lib/shutterbug/handlers/file_handlers/html_file.rb +0 -22
  38. data/lib/shutterbug/handlers/file_handlers/png_file.rb +0 -23
  39. data/spec/shared_examples_for_file_handlers.rb +0 -16
  40. data/spec/shutterbug/html_file_handler_spec.rb +0 -10
  41. data/spec/shutterbug/png_file_handler_spec.rb +0 -10
@@ -1,7 +1,6 @@
1
1
  module Shutterbug
2
2
  class PhantomJob
3
-
4
- attr_accessor :png_file
3
+ attr_accessor :image_file
5
4
  attr_accessor :html_file
6
5
 
7
6
  def program
@@ -12,17 +11,19 @@ module Shutterbug
12
11
  File.join(File.dirname(__FILE__),'rasterize.js')
13
12
  end
14
13
 
15
- def initialize(base_url, html, css="", width=1000, height=700)
14
+ def initialize(base_url, html, css="", width=1000, height=700, format="png", quality=10)
16
15
  @base_url = base_url
17
16
  @html = html
18
17
  @css = css
19
18
  @width = width
20
19
  @height = height
20
+ @format = format
21
+ @quality = quality
21
22
  @config = Configuration.instance
22
23
  end
23
24
 
24
25
  def cache_key
25
- @cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
26
+ @cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}#{@format}#{@quality}")[0..10]
26
27
  end
27
28
 
28
29
  def document
@@ -47,8 +48,8 @@ module Shutterbug
47
48
  "#{cache_key}.html"
48
49
  end
49
50
 
50
- def png_file_name
51
- "#{cache_key}.png"
51
+ def image_file_name
52
+ "#{cache_key}.#{@format}"
52
53
  end
53
54
 
54
55
  def input_path
@@ -56,11 +57,11 @@ module Shutterbug
56
57
  end
57
58
 
58
59
  def output_path
59
- @config.fs_path_for(png_file_name)
60
+ @config.fs_path_for(image_file_name)
60
61
  end
61
62
 
62
63
  def rasterize_cl
63
- %x[#{self.program} --ignore-ssl-errors=true --ssl-protocol=any #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height}]
64
+ %x[#{self.program} --ignore-ssl-errors=true --ssl-protocol=any #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height} #{@quality}]
64
65
  end
65
66
 
66
67
  def rasterize
@@ -68,8 +69,8 @@ module Shutterbug
68
69
  f.write(document)
69
70
  end
70
71
  rasterize_cl()
71
- self.png_file = @config.storage.new(png_file_name, Shutterbug::Handlers::FileHandlers::PngFile.new)
72
- self.html_file = @config.storage.new(html_file_name, Shutterbug::Handlers::FileHandlers::HtmlFile.new)
72
+ self.image_file = @config.storage.new(image_file_name)
73
+ self.html_file = @config.storage.new(html_file_name)
73
74
  end
74
75
  end
75
76
  end
@@ -3,17 +3,16 @@ module Shutterbug
3
3
  class Rackapp
4
4
 
5
5
  DefaultHandlers = [
6
- Shutterbug::Handlers::ConvertHandler ,
6
+ Shutterbug::Handlers::ConvertHandler,
7
+ Shutterbug::Handlers::DirectUploadHandler,
7
8
  Shutterbug::Handlers::JsFileHandler,
8
- Shutterbug::Handlers::FileHandlers::PngFile,
9
- Shutterbug::Handlers::FileHandlers::HtmlFile
9
+ Shutterbug::Handlers::FileHandler
10
10
  ]
11
11
 
12
- attr_accessor :handlers
13
12
  def add_handler(klass)
14
- instance = klass.new(@config)
15
- log "adding handler for #{instance.regex} ➙ #{klass.name}"
16
- self.handlers[instance.regex] = instance
13
+ instance = klass.new
14
+ log "adding handler for #{klass.regex} ➙ #{klass.name}"
15
+ @handlers[klass.regex] = instance
17
16
  end
18
17
 
19
18
  def add_default_handlers
@@ -29,26 +28,25 @@ module Shutterbug
29
28
  log "initialized"
30
29
  end
31
30
 
32
- def call env
33
- req = Rack::Request.new(env)
34
- result = false
35
- handlers.keys.each do |path_regex|
31
+ def call(env)
32
+ req = Rack::Request.new(env)
33
+ result = false
34
+ @handlers.keys.each do |path_regex|
36
35
  if req.path =~ path_regex
37
- result = handlers[path_regex].handle(self, req, env)
36
+ result = @handlers[path_regex].handle(self, req, env)
38
37
  end
39
38
  end
40
39
  result || skip(env)
41
40
  end
42
41
 
43
- def good_response(content, type, cachable=true)
42
+ def response(content, type, status=200, cachable=true)
44
43
  headers = {}
45
44
  size = content.respond_to?(:bytesize) ? content.bytesize : content.size
46
45
  headers['Content-Length'] = size.to_s
47
46
  headers['Content-Type'] = type
48
47
  headers['Cache-Control'] = 'no-cache' unless cachable
49
- # content must be enumerable.
50
- content = [content] if content.kind_of? String
51
- return [200, headers, content]
48
+ content = [content] unless content.respond_to? 'each'
49
+ return [status, headers, content]
52
50
  end
53
51
 
54
52
  def log(string)
@@ -57,8 +55,7 @@ module Shutterbug
57
55
 
58
56
  def skip(env)
59
57
  # call the applicaiton default
60
- @app.call env if @app
58
+ @app.call(env) if @app
61
59
  end
62
-
63
60
  end
64
61
  end
@@ -2,11 +2,10 @@
2
2
 
3
3
  var page = require('webpage').create(),
4
4
  system = require('system'),
5
- address, output, size;
5
+ address, output, quality, size;
6
6
 
7
7
  if (system.args.length < 3 || system.args.length > 5) {
8
- console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
9
- console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
8
+ console.log('Usage: rasterize.js URL filename quality(0-100)');
10
9
  phantom.exit(1);
11
10
  } else {
12
11
  address = system.args[1];
@@ -15,6 +14,7 @@ if (system.args.length < 3 || system.args.length > 5) {
15
14
  if (system.args.length > 3) {
16
15
  size = system.args[3].split('*');
17
16
  page.viewportSize = { width: size[0], height: size[1] };
17
+ quality = system.args[4];
18
18
  }
19
19
 
20
20
  page.open(address, function (status) {
@@ -23,7 +23,7 @@ if (system.args.length < 3 || system.args.length > 5) {
23
23
  phantom.exit();
24
24
  } else {
25
25
  window.setTimeout(function () {
26
- page.render(output);
26
+ page.render(output, {quality: quality});
27
27
  phantom.exit();
28
28
  }, 200);
29
29
  }
@@ -3,4 +3,4 @@ module Shutterbug
3
3
  autoload :FileStorage, "shutterbug/storage/file_storage"
4
4
  autoload :S3Storage, "shutterbug/storage/s3_storage"
5
5
  end
6
- end
6
+ end
@@ -1,20 +1,33 @@
1
1
  module Shutterbug
2
2
  module Storage
3
3
  class FileStorage
4
- attr_accessor :filename
5
- attr_accessor :config
6
- attr_accessor :url
4
+ attr_reader :filename
5
+ attr_reader :url
7
6
 
8
- def initialize(filename, file_handler)
7
+ MIME_TYPES = {
8
+ '.png' => 'image/png',
9
+ '.jpeg' => 'image/jpeg',
10
+ '.jpg' => 'image/jpeg',
11
+ '.html' => 'text/html',
12
+ '' => 'text/html'
13
+ }
14
+
15
+ def self.get_url(name)
16
+ "#{Handlers::FileHandler.uri_prefix}/#{name}"
17
+ end
18
+
19
+ def initialize(filename)
9
20
  @filename = Configuration.instance.fs_path_for(filename)
10
- @url = file_handler.urlify(filename)
21
+ @url = self.class.get_url(filename)
11
22
  end
12
23
 
13
24
  def get_content
14
- file = File.open(@filename, 'r')
15
- return file
25
+ File.open(@filename, 'r')
16
26
  end
17
27
 
28
+ def mime_type
29
+ MIME_TYPES[File.extname(@filename)]
30
+ end
18
31
  end
19
32
  end
20
- end
33
+ end
@@ -3,15 +3,16 @@ module Shutterbug
3
3
  class S3Storage
4
4
  require 'fog'
5
5
 
6
- attr_accessor :filename
7
- attr_accessor :url
8
- attr_accessor :stream_file
6
+ attr_reader :filename
7
+ attr_reader :url
8
+
9
+ PUT_URL_EXP_TIME = 300 # seconds
9
10
 
10
11
  def self.connect!
11
12
  Fog::Storage.new({
12
- :provider => 'AWS',
13
- :aws_access_key_id => Configuration.instance.s3_key,
14
- :aws_secret_access_key => Configuration.instance.s3_secret
13
+ :provider => 'AWS',
14
+ :aws_access_key_id => Configuration.instance.s3_key,
15
+ :aws_secret_access_key => Configuration.instance.s3_secret
15
16
  })
16
17
  end
17
18
 
@@ -29,47 +30,41 @@ module Shutterbug
29
30
  @s3_bin ||= self.create_bin
30
31
  end
31
32
 
32
- def self.write(name, filename)
33
+ def self.write(filename)
33
34
  full_path = Configuration.instance.fs_path_for(filename)
34
35
  if self.fs_path_exists? full_path
35
36
  self.s3_bin.files.create(
36
- :key => name,
37
+ :key => filename,
37
38
  :body => File.open(full_path),
38
39
  :public => true)
39
40
  end
40
41
  end
41
42
 
42
- def self.find(path)
43
- self.s3_bin.files.get(path)
43
+ def self.fs_path_exists?(filename)
44
+ File.exists?(filename)
44
45
  end
45
46
 
46
- def self.fs_path_exists?(long_path)
47
- File.exists? long_path
47
+ def self.get_url(filename)
48
+ # Manual URL construction, no proper method implemented in FOG.
49
+ # But should be available soon, see: https://github.com/fog/fog/issues/3263
50
+ "https://#{Configuration.instance.s3_bin}.s3.amazonaws.com/#{filename}"
48
51
  end
49
52
 
50
- def self.handler_for(type)
51
- return self.handlers[type]
53
+ def self.put_url(filename)
54
+ expiry = (Time.now + PUT_URL_EXP_TIME).to_i
55
+ headers = {}
56
+ query = {
57
+ 'x-amz-acl' => 'public-read'
58
+ }
59
+ options = { path_style: true, query: query }
60
+ self.connection.put_object_url(Configuration.instance.s3_bin, filename, expiry, headers, options)
52
61
  end
53
62
 
54
- def initialize(long_path, filetype)
55
- @filename = File.basename(long_path)
56
- @source = long_path
57
- @stream_file = S3Storage.write(@filename, long_path)
63
+ def initialize(filename)
64
+ @filename = filename
65
+ @stream_file = S3Storage.write(filename)
58
66
  @url = @stream_file.public_url
59
67
  end
60
-
61
- def get_content
62
- @stream_file.body
63
- end
64
-
65
- def size
66
- @stream_file.content_length
67
- end
68
-
69
- def redirect_s3
70
- return [301, {"Location" => self.url}, []]
71
- end
72
-
73
68
  end
74
69
  end
75
70
  end
data/shutterbug.gemspec CHANGED
@@ -35,5 +35,4 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  spec.add_dependency "rack"
37
37
  spec.add_dependency "fog"
38
-
39
38
  end
@@ -1,26 +1,30 @@
1
1
  shared_examples "a request handler" do
2
- let(:config) { Shutterbug::Configuration.new()}
3
2
  let(:rackapp) { mock }
4
3
  let(:req) { mock }
5
4
  let(:env) { mock }
6
- let(:handler) { described_class.new(config) }
5
+ let(:handler) { described_class.new }
7
6
  let(:mock_storage) do
8
7
  mock({
9
8
  :new => mock({
10
- :get_content => "content"
9
+ :get_content => "content",
10
+ :mime_type => "text/plain",
11
+ :filename => "file",
12
+ :url => "url"
11
13
  })
12
14
  })
13
15
  end
14
16
  before(:each) do
15
- config.stub!(:storage => mock_storage)
17
+ Shutterbug::Configuration.instance.stub!(:storage => mock_storage)
16
18
  end
19
+
17
20
  it "should respond to regex" do
18
- handler.should respond_to :regex
19
- handler.regex.should be_kind_of Regexp
21
+ handler.class.should respond_to :regex
22
+ handler.class.regex.should be_kind_of Regexp
20
23
  end
24
+
21
25
  it "should respond to handle" do
22
26
  handler.should respond_to :handle
23
- rackapp.should_receive :good_response
24
- handler.handle(rackapp,req,env)
27
+ rackapp.should_receive :response
28
+ handler.handle(rackapp, req, env)
25
29
  end
26
- end
30
+ end
@@ -1,17 +1,21 @@
1
1
  shared_examples "a storage provider" do
2
- let(:filetype) { Shutterbug::Handlers::FileHandlers::HtmlFile.new}
3
2
  let(:filename) { "somefilename.html" }
4
- let(:provider) { described_class.new(filename,filetype) }
5
3
 
6
- it "should respond to filename" do
7
- provider.should respond_to :filename
4
+ describe "class" do
5
+ it "should respond to get_url(name)" do
6
+ described_class.should respond_to :get_url
7
+ end
8
8
  end
9
9
 
10
- it "should respond to url" do
11
- provider.should respond_to :url
12
- end
10
+ describe "instance" do
11
+ let(:instance) { described_class.new(filename) }
12
+
13
+ it "should respond to filename" do
14
+ instance.should respond_to :filename
15
+ end
13
16
 
14
- it "should respond to get_content" do
15
- provider.should respond_to :get_content
17
+ it "should respond to url" do
18
+ instance.should respond_to :url
19
+ end
16
20
  end
17
- end
21
+ end
@@ -1,6 +1,4 @@
1
-
2
1
  describe Shutterbug::Configuration do
3
-
4
2
  let(:uri_prefix) { "http://blah.com/" }
5
3
  let(:path_prefix) { "/shutterbug" }
6
4
  let(:resource_dir) { "resource_dir"}
@@ -20,10 +18,6 @@ describe Shutterbug::Configuration do
20
18
  }
21
19
  end
22
20
 
23
-
24
- # def js_file
25
-
26
-
27
21
  subject { Shutterbug::Configuration.new(opts) }
28
22
 
29
23
  describe "#fs_path_for(filename)" do |variable|
@@ -56,8 +50,6 @@ describe Shutterbug::Configuration do
56
50
  end
57
51
  end
58
52
 
59
-
60
-
61
53
  describe "use_s3?" do
62
54
  describe "with no S3 information" do
63
55
  its(:use_s3?) { should be_false }
@@ -78,6 +70,4 @@ describe Shutterbug::Configuration do
78
70
  end
79
71
  end
80
72
  end
81
-
82
-
83
- end
73
+ end
@@ -1,4 +1,5 @@
1
1
  require 'shared_examples_for_handlers'
2
+
2
3
  describe Shutterbug::Handlers::ConvertHandler do
3
4
  let(:mock_post) do
4
5
  mock(:POST => {},
@@ -14,16 +15,16 @@ describe Shutterbug::Handlers::ConvertHandler do
14
15
 
15
16
  describe "calling phantom" do
16
17
  let(:mock_results) { mock }
17
- let(:rackapp) { mock(:good_response => true )}
18
+ let(:rackapp) { mock(:response => true )}
18
19
  let(:env) { mock }
19
20
  let(:fake_file) { mock(:filename => "blub", :url => "glub")}
20
- let(:mock_fantom) { mock(:cache_key => "1", :html_file => fake_file, :png_file => fake_file) }
21
+ let(:mock_fantom) { mock(:cache_key => "1", :html_file => fake_file, :image_file => fake_file) }
21
22
  before(:each) do
22
23
  Shutterbug::PhantomJob.stub!(:new => mock_fantom)
23
24
  end
24
25
  it "should invoke phantom" do
25
26
  mock_fantom.should_receive(:rasterize).and_return(mock_results)
26
- subject.handle(rackapp,req,env)
27
+ subject.handle(rackapp, req, env)
27
28
  end
28
29
  end
29
- end
30
+ end