shutterbug 0.0.11 → 0.1.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.
Files changed (49) hide show
  1. data/.ruby-version +1 -1
  2. data/.travis.yml +2 -3
  3. data/Guardfile +5 -0
  4. data/README.md +59 -10
  5. data/config.ru +5 -3
  6. data/demo/{withIframe.html → iframe_example.html} +0 -0
  7. data/demo/index.html +7 -24
  8. data/demo/oil-and-water/heatbath.svg +20 -0
  9. data/demo/oil-and-water/ke-gradient.svg +27 -0
  10. data/demo/oil-and-water/oil-and-water.svg +487 -0
  11. data/demo/simple_example.html +35 -0
  12. data/demo/svg_example.html +571 -0
  13. data/images/shutterbug.jpg +0 -0
  14. data/lib/shutterbug.rb +4 -6
  15. data/lib/shutterbug/cache_manager.rb +6 -0
  16. data/lib/shutterbug/cache_manager/cache_entry.rb +19 -0
  17. data/lib/shutterbug/cache_manager/no_cache.rb +19 -0
  18. data/lib/shutterbug/configuration.rb +20 -24
  19. data/lib/shutterbug/handlers.rb +7 -0
  20. data/lib/shutterbug/handlers/convert_handler.rb +38 -0
  21. data/lib/shutterbug/handlers/file_handlers.rb +9 -0
  22. data/lib/shutterbug/handlers/file_handlers/base.rb +39 -0
  23. data/lib/shutterbug/handlers/file_handlers/html_file.rb +22 -0
  24. data/lib/shutterbug/handlers/file_handlers/png_file.rb +23 -0
  25. data/lib/shutterbug/handlers/js_file_handler.rb +27 -0
  26. data/lib/shutterbug/{shutterbug.js → handlers/shutterbug.js} +26 -3
  27. data/lib/shutterbug/phantom_job.rb +17 -12
  28. data/lib/shutterbug/rackapp.rb +33 -31
  29. data/lib/shutterbug/storage.rb +6 -0
  30. data/lib/shutterbug/storage/file_storage.rb +20 -0
  31. data/lib/shutterbug/storage/s3_storage.rb +75 -0
  32. data/shutterbug.gemspec +3 -0
  33. data/spec/shared_examples_for_file_handlers.rb +16 -0
  34. data/spec/shared_examples_for_handlers.rb +26 -0
  35. data/spec/shared_examples_for_storage.rb +17 -0
  36. data/spec/shutterbug/configuration_spec.rb +83 -0
  37. data/spec/shutterbug/convert_handler_spec.rb +29 -0
  38. data/spec/shutterbug/file_storage_spec.rb +5 -0
  39. data/spec/shutterbug/html_file_handler_spec.rb +10 -0
  40. data/spec/shutterbug/js_file_handler_spec.rb +4 -0
  41. data/spec/shutterbug/png_file_handler_spec.rb +10 -0
  42. data/spec/shutterbug/rackapp_spec.rb +49 -41
  43. data/spec/shutterbug/s3_storage_spec.rb +12 -0
  44. metadata +205 -105
  45. data/lib/shutterbug/bug_file.rb +0 -22
  46. data/lib/shutterbug/html_file.rb +0 -3
  47. data/lib/shutterbug/js_file.rb +0 -11
  48. data/lib/shutterbug/png_file.rb +0 -3
  49. data/lib/shutterbug/service.rb +0 -39
Binary file
data/lib/shutterbug.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  module Shutterbug
2
- VERSION = "0.0.11"
3
- autoload :Service, "shutterbug/service"
2
+ VERSION = "0.1.0"
4
3
  autoload :Rackapp, "shutterbug/rackapp"
5
4
  autoload :Configuration, "shutterbug/configuration"
6
- autoload :BugFile, "shutterbug/bug_file"
7
- autoload :HtmlFile, "shutterbug/html_file"
8
- autoload :PngFile, "shutterbug/png_file"
9
- autoload :JsFile, "shutterbug/js_file"
5
+ autoload :Storage, "shutterbug/storage"
6
+ autoload :Handlers, "shutterbug/handlers"
10
7
  autoload :PhantomJob, "shutterbug/phantom_job"
8
+ autoload :CacheManager, "shutterbug/cache_manager"
11
9
  end
@@ -0,0 +1,6 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ autoload :NoCache, "shutterbug/cache_manager/no_cache"
4
+ autoload :CacheEntry, "shutterbug/cache_manager/cache_entry"
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ class CacheEntry
4
+ attr_accessor :key
5
+ attr_accessor :url
6
+ attr_accessor :preview_url
7
+
8
+ def initialize(storage)
9
+ @key = storage.filename
10
+ @url = storage.url
11
+ @preview_url = storage.url
12
+ end
13
+
14
+ def image_tag
15
+ "<img src='#{self.preview_url}' alt='#{self.preview_url}'>"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ class NoCache
4
+ attr_accessor :entries
5
+ def initialize
6
+ @entries = {}
7
+ end
8
+
9
+ def find(key)
10
+ return @entries[key]
11
+ end
12
+
13
+ def add_entry(cache_entry)
14
+ @entries[cache_entry.key] = cache_entry
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,4 @@
1
+ require 'tmpdir'
1
2
  module Shutterbug
2
3
  class Configuration
3
4
 
@@ -5,6 +6,10 @@ module Shutterbug
5
6
  attr_accessor :path_prefix
6
7
  attr_accessor :resource_dir
7
8
  attr_accessor :phantom_bin_path
9
+ attr_accessor :s3_bin
10
+ attr_accessor :s3_key
11
+ attr_accessor :s3_secret
12
+ attr_accessor :cache_manager
8
13
 
9
14
  def self.instance(opts={})
10
15
  return @instance || @instance = self.new(opts)
@@ -15,43 +20,34 @@ module Shutterbug
15
20
  self.path_prefix = opts[:path_prefix] || "/shutterbug"
16
21
  self.resource_dir = opts[:resource_dir] || Dir.tmpdir
17
22
  self.phantom_bin_path = opts[:phantom_bin_path] || "phantomjs"
23
+ self.s3_bin = opts[:s3_bin]
24
+ self.s3_key = opts[:s3_key]
25
+ self.s3_secret = opts[:s3_secret]
26
+ self.cache_manager = opts[:cache_manager] || Shutterbug::CacheManager::NoCache.new
18
27
  end
19
28
 
20
- def js_path
21
- "#{uri_prefix}#{path_prefix}/shutterbug.js"
29
+ def fs_path_for(filename)
30
+ File.join(resource_dir,"phantom_#{filename}")
22
31
  end
23
32
 
24
- def js_regex
25
- /#{path_prefix}\/shutterbug.js/
26
- end
27
-
28
- def js_file
29
- File.join(File.dirname(__FILE__),"shutterbug.js")
33
+ def url_prefix
34
+ "#{uri_prefix}#{path_prefix}"
30
35
  end
31
36
 
32
37
  def convert_path
33
- "#{uri_prefix}#{path_prefix}/make_snapshot"
34
- end
35
- def convert_regex
36
- /#{path_prefix}\/make_snapshot/
38
+ "#{url_prefix}/make_snapshot"
37
39
  end
38
40
 
39
- def png_path(sha='')
40
- "#{uri_prefix}#{path_prefix}/get_png/#{sha}"
41
- end
42
- def png_regex
43
- /#{path_prefix}\/get_png\/([^\/]+)/
41
+ def base_url(req)
42
+ req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
44
43
  end
45
44
 
46
- def html_path(sha='')
47
- "#{uri_prefix}#{path_prefix}/get_html/#{sha}"
48
- end
49
- def html_regex
50
- /#{path_prefix}\/get_html\/([^\/]+)/
45
+ def storage
46
+ use_s3? ? Storage::S3Storage : Storage::FileStorage
51
47
  end
52
48
 
53
- def base_url(req)
54
- req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
49
+ def use_s3?
50
+ return (self.s3_bin && self.s3_key && self.s3_secret)
55
51
  end
56
52
  end
57
53
  end
@@ -0,0 +1,7 @@
1
+ require "shutterbug/handlers/file_handlers"
2
+ module Shutterbug
3
+ module Handlers
4
+ autoload :ConvertHandler, "shutterbug/handlers/convert_handler"
5
+ autoload :JsFileHandler, "shutterbug/handlers/js_file_handler"
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ require 'stringio'
2
+ module Shutterbug
3
+ module Handlers
4
+ class ConvertHandler
5
+
6
+ def initialize(_config = Configuration.instance)
7
+ @config = _config
8
+ end
9
+
10
+ def regex
11
+ /#{@config.path_prefix}\/make_snapshot/
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ response_text = convert(req).image_tag
16
+ helper.good_response(response_text,'text/plain')
17
+ end
18
+
19
+ def convert(req)
20
+ html = req.POST()['content'] || ""
21
+ width = req.POST()['width'] || 1000
22
+ height = req.POST()['height'] || 700
23
+ css = req.POST()['css'] || ""
24
+ job = PhantomJob.new(@config.base_url(req), html, css, width, height)
25
+ unless (cache_entry = @config.cache_manager.find(job.cache_key))
26
+ job.rasterize
27
+ html_entry = Shutterbug::CacheManager::CacheEntry.new(job.html_file)
28
+ png_entry = Shutterbug::CacheManager::CacheEntry.new(job.png_file)
29
+ html_entry.preview_url = png_entry.preview_url
30
+ @config.cache_manager.add_entry(html_entry)
31
+ cache_entry = @config.cache_manager.add_entry(png_entry)
32
+ end
33
+ # return the image tag
34
+ return cache_entry
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ require "shutterbug/handlers/file_handlers/base"
5
+ require "shutterbug/handlers/file_handlers/html_file"
6
+ require "shutterbug/handlers/file_handlers/png_file"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ require 'tmpdir'
2
+ module Shutterbug
3
+ module Handlers
4
+ module FileHandlers
5
+ class Base
6
+ attr_accessor :config
7
+
8
+ def self.instance
9
+ return @instance || self.new
10
+ end
11
+
12
+ def initialize(_config = Configuration.instance)
13
+ self.config = _config
14
+ end
15
+
16
+ def urlify(name)
17
+ "#{self.path_prefix}/#{name}"
18
+ end
19
+
20
+ def path_prefix
21
+ "#{self.config.path_prefix}/get_#{file_extension}"
22
+ end
23
+
24
+ def filename_matcher
25
+ "(([^\/|\.]+)\.?([^\/]+))?"
26
+ end
27
+
28
+ def regex
29
+ /#{path_prefix}\/#{filename_matcher}/
30
+ end
31
+
32
+ def filename(base)
33
+ "#{base}.#{file_extension}"
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ class HtmlFile < Base
5
+
6
+ def file_extension
7
+ "html"
8
+ end
9
+
10
+ def mime_type
11
+ "text/html"
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ sha = regex.match(req.path)[1]
16
+ file = @config.storage.new(filename(sha),self)
17
+ helper.good_response(file.get_content, self.mime_type)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ class PngFile < Base
5
+
6
+ def file_extension
7
+ "png"
8
+ end
9
+
10
+ def mime_type
11
+ "image/png"
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ local_filename = regex.match(req.path)[1]
16
+ file = @config.storage.new(local_filename,self)
17
+ helper.good_response(file.get_content, self.mime_type)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,27 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ class JsFileHandler
4
+
5
+ def self.js_path
6
+ "#{Configuration.instance.url_prefix}/shutterbug.js"
7
+ end
8
+
9
+ def regex
10
+ /#{@config.path_prefix}\/shutterbug.js/
11
+ end
12
+
13
+ def js_file
14
+ File.join(File.dirname(__FILE__),"shutterbug.js")
15
+ end
16
+
17
+ def initialize(_config=Configuration.instance())
18
+ @config = _config
19
+ @javascript = File.read(js_file).gsub(/CONVERT_PATH/,@config.convert_path)
20
+ end
21
+
22
+ def handle(helper, req, env)
23
+ helper.good_response(@javascript, 'application/javascript')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,5 +1,6 @@
1
1
  /*global $ */
2
2
  (function(){
3
+ var $ = window.$;
3
4
 
4
5
  var getBaseUrl = function() {
5
6
  var base = window.location.href;
@@ -72,17 +73,31 @@
72
73
  }
73
74
  }
74
75
  var self = this;
76
+ var time = 0;
77
+ var counter = $("<span>");
78
+ counter.html(time);
79
+
80
+ $(self.imgDst).html("creating snapshot: ").append(counter);
81
+ var timer = setInterval(function(t) {
82
+ time = time + 1;
83
+ counter.html(time);
84
+ }, 1000);
85
+
75
86
  $.ajax({
76
87
  url: "CONVERT_PATH",
77
88
  type: "POST",
78
89
  data: html
79
- }).done(function(msg) {
90
+ }).success(function(msg) {
80
91
  if(self.imgDst) {
81
92
  $(self.imgDst).html(msg);
82
93
  }
83
94
  if (self.callback) {
84
95
  self.callback(msg);
85
96
  }
97
+ clearInterval(timer);
98
+ }).fail(function(e) {
99
+ $(self.imgDst).html("snapshot failed");
100
+ clearInterval(timer);
86
101
  });
87
102
  };
88
103
 
@@ -95,7 +110,16 @@
95
110
  destination.postMessage(JSON.stringify(message),"*");
96
111
  };
97
112
 
98
- window.Shutterbug = function(selector,imgDst,callback,id) {
113
+ window.Shutterbug = function(selector,imgDst,callback,id,jQuery) {
114
+ if (typeof(jQuery) != "undefined" && jQuery != null) {
115
+ $ = jQuery;
116
+ }
117
+ // If we still don't have a valid jQuery, try setting it from the global jQuery default.
118
+ // This can happen if shutterbug.js is included before jquery.js
119
+ if ((typeof($) == "undefined" || $ == null) && typeof(window.$) != "undefined" && window.$ != null) {
120
+ $ = window.$;
121
+ }
122
+
99
123
  var shutterbugInstance = {
100
124
  element: selector,
101
125
  imgDst: imgDst,
@@ -150,5 +174,4 @@
150
174
  });
151
175
  return shutterbugInstance;
152
176
  };
153
-
154
177
  })();
@@ -5,7 +5,7 @@ module Shutterbug
5
5
  attr_accessor :html_file
6
6
 
7
7
  def program
8
- Configuration.instance.phantom_bin_path
8
+ @config.phantom_bin_path
9
9
  end
10
10
 
11
11
  def rasterize_js
@@ -18,10 +18,11 @@ module Shutterbug
18
18
  @css = css
19
19
  @width = width
20
20
  @height = height
21
+ @config = Configuration.instance
21
22
  end
22
23
 
23
24
  def cache_key
24
- return @key || @key = Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
25
+ @cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
25
26
  end
26
27
 
27
28
  def document
@@ -42,29 +43,33 @@ module Shutterbug
42
43
  """
43
44
  end
44
45
 
45
- def base_path
46
- Configuration.instance.resource_dir
46
+ def html_file_name
47
+ "#{cache_key}.html"
47
48
  end
48
49
 
49
- def infilename
50
- File.join(base_path,"phantom_#{cache_key}.html")
50
+ def png_file_name
51
+ "#{cache_key}.png"
51
52
  end
52
53
 
53
- def outfilename
54
- File.join(base_path,"phantom_#{cache_key}.png")
54
+ def input_path
55
+ @config.fs_path_for(html_file_name)
56
+ end
57
+
58
+ def output_path
59
+ @config.fs_path_for(png_file_name)
55
60
  end
56
61
 
57
62
  def rasterize_cl
58
- %x[#{self.program} #{self.rasterize_js} #{self.infilename} #{self.outfilename} #{@width}*#{@height}]
63
+ %x[#{self.program} #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height}]
59
64
  end
60
65
 
61
66
  def rasterize
62
- File.open(infilename, 'w') do |f|
67
+ File.open(input_path, 'w') do |f|
63
68
  f.write(document)
64
69
  end
65
70
  rasterize_cl()
66
- self.png_file = PngFile.new(outfilename)
67
- self.html_file = HtmlFile.new(infilename)
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)
68
73
  end
69
74
  end
70
75
  end