photograph 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea0a5dcbf3a353549a0009a793780daeeed56e2a
4
+ data.tar.gz: 648222a1f1475cc98c87c7ae1ab2efd67204cc1c
5
+ SHA512:
6
+ metadata.gz: f54b2bbc8a8fb484674a6b646458dfd690da18c670b8f2244473bcdaa292e23420c940f93b752c84e525223c5a69ac2d7790765d6626763067d8f267fc6bf871
7
+ data.tar.gz: 091f1490bd3c72f2a2bd243c2dc2a734ee68fc3f563ab1e8c8c4f96556786cee5e3513c249bf4354b7b59e6b293c6324e302c3b4082df7c3c5104bd2d371fc65
data/README.md CHANGED
@@ -1,20 +1,13 @@
1
1
  # Photograph
2
2
 
3
- Photograph solves the issue of generating previews or thumbnails of
4
- web-based documents. Think of generating a preview of a Google
5
- Spreadsheet. As a such document is dom based, it may be difficult to get a preview
6
- that truly reflects the original content.
3
+ Photograph allows to take screenshots of webpages, the rendering being
4
+ done by Chrome.
7
5
 
8
- Photograph solves that problem by firing a chrome instance thanks to
9
- capybara-webkit and sinatra to provides an easy way to interface it to
10
- your needs.
6
+ Typically, this can be used to generate screenshots for DOM based
7
+ documents.
11
8
 
12
- Obviously, it supports cropping to avoid reworking the image afterward.
13
-
14
- Please remind that having a chrome instance, even if it is being reused
15
- by all requests is still taking some time, aroung 600ms after the first
16
- request on my development machine. *Consider using photograph only if
17
- you expect the same exact rendering of your 'web documents'*.
9
+ Please remind that having a chrome instance doing the rendering, even if it is launched only once,
10
+ is slow, around 600ms.
18
11
 
19
12
  ## Installation
20
13
 
@@ -32,14 +25,19 @@ Or install it yourself as:
32
25
 
33
26
  ## Usage
34
27
 
28
+ **Using `Artist.shoot!` without a block had been deprecated in 0.3 and
29
+ will raise an exception.**
30
+
35
31
  Photograph can be used either directly through the Photograph::Artist
36
- class or by its little sinata app.
32
+ class or by its little sinatra app.
37
33
 
38
- @artist = Photograph::Artist.new("http://github.com")
39
- @artist.shoot!
34
+ @artist = Photograph::Artist.new(:url => "http://github.com")
35
+ @artist.shoot! do |image|
36
+ image # => MiniMagick instance you can toy with
40
37
 
41
- @artist.image
42
- # => MiniMagick instance you can toy with
38
+ send_file image.path,
39
+ :type => :png
40
+ end
43
41
 
44
42
  Or
45
43
 
@@ -53,17 +51,11 @@ Or
53
51
  4. Push to the branch (`git push origin my-new-feature`)
54
52
  5. Create new Pull Request
55
53
 
56
- ## Credits
57
-
58
-
59
- Photograph is maintained and funded by Tactilize.
60
-
61
- Contributors :
54
+ ## Authors
62
55
 
63
56
  * Jean-Hadrien Chabran
64
-
65
- The names and logos for Tactilize are trademarks of Tactilize.
57
+ * Danial Pearce
66
58
 
67
59
  ## License
68
60
 
69
- Photograph is Copyright © 2012 Tactilize. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
61
+ Photograph is Copyright © 2013 JHCHABRAN. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
@@ -1,7 +1,6 @@
1
1
  require 'capybara/poltergeist'
2
2
  require 'mini_magick'
3
3
 
4
-
5
4
  Capybara.default_wait_time = 15
6
5
 
7
6
  module Photograph
@@ -9,45 +8,77 @@ module Photograph
9
8
  attr_accessor :options
10
9
  attr_reader :image
11
10
 
12
- MissingUrlError = Class.new(Exception)
11
+ class MissingUrlError < ArgumentError; end
12
+ class DeprecationError < RuntimeError; end
13
+
13
14
  DefaultOptions = {
14
15
  :x => 0, # top left position
15
16
  :y => 0,
16
- :w => 1280, # bottom right position
17
- :h => 1024,
17
+ :w => 1280, # width
18
+ :h => 1024, # height
18
19
 
19
20
  :wait => 0.5, # if selector is nil, wait 1 seconds before taking the screenshot
20
21
  :selector => nil # wait until the selector matches to take the screenshot
21
22
  }
22
23
 
23
- def self.browser
24
- @browser ||= Capybara::Session.new :poltergeist
24
+ ##
25
+ # Instanciate a browser instance.
26
+ #
27
+ # Typically it's used to supply a Photograph instance your own browser session,
28
+ # allowing you to reuse it if you're using multiples +Photograph::Artist+
29
+ # instances.
30
+ def self.create_browser
31
+ Capybara::Session.new :poltergeist
25
32
  end
26
33
 
34
+ ##
35
+ # Returns current browser instance.
36
+ #
37
+ # If none had been supplied, it creates a new one.
27
38
  def browser
28
- self.class.browser
39
+ @options[:browser] ||= self.class.create_browser
29
40
  end
30
41
 
42
+ ##
43
+ # Normalize urls, allowing you to use "google.com" instead of "http://google.com"
44
+ def normalize_url url
45
+ unless url.match(/https?:\/\//)
46
+ url = "http://#{url}"
47
+ end
48
+
49
+ url
50
+ end
51
+
52
+ ##
53
+ # Creates a new +Photograph::Artist+ and configures it through +options+.
54
+ #
55
+ # Cropping is supported through the +x+, +y+, +w+ and +h+ options.
56
+ #
57
+ # Options:
58
+ # * +url+ mandatory, location you want to screenshot
59
+ # * +wait+ wait amount of seconds before screenshotting. *this is option is ignored if +selector+ is provided.
60
+ # * +selector+ wait until the provided +selector+ matches a dom node before screenshotting. Typically faster than an arbritrary +wait+ amount, used when your page has some dynamically inserted nodes.
61
+ # * +x+ top coordinate of the screenshot, default to 0
62
+ # * +y+ left coordinate of the screenshot, default to 0
63
+ # * +w+ width of the screenshot, default to 1280
64
+ # * +h+ height of the screenshot, default to 1024
65
+ # * +browser+ Capybara instance to use, typically instanciated by +Artist.create_browser+
31
66
  def initialize options={}
32
- raise MissingUrlError unless options[:url]
67
+ raise MissingUrlError.new('missing argument :url') unless options[:url]
33
68
 
34
69
  @options = DefaultOptions.merge(options)
70
+ @options[:url] = normalize_url(options[:url])
35
71
  end
36
72
 
73
+ ##
74
+ # Takes a screenshot and yield the resulting image.
37
75
  def shoot! &block
38
- @image = capture
76
+ raise DeprecationError.new('Using Artist#shoot! without a block had been deprecated') unless block_given?
39
77
 
40
- if block_given?
41
- yield @image
42
- clean!
43
- else
44
- @image
45
- end
46
- end
47
-
48
- def capture
49
78
  browser.visit @options[:url]
50
79
 
80
+ @before_hook.call(browser) if @before_hook
81
+
51
82
  if @options[:selector]
52
83
  browser.wait_until do
53
84
  browser.has_css? @options[:selector]
@@ -56,30 +87,32 @@ module Photograph
56
87
  sleep @options[:wait]
57
88
  end
58
89
 
59
- @tempfile = Tempfile.new(['photograph','.png'])
90
+ tempfile = Tempfile.new(['photograph','.png'])
60
91
 
61
- browser.driver.render @tempfile.path,
92
+ browser.driver.render tempfile.path,
62
93
  :width => options[:w] + options[:x],
63
94
  :height => options[:h] + options[:y]
64
95
 
65
- @image = adjust_image
96
+ yield adjust_image(tempfile)
97
+ ensure
98
+ tempfile.unlink if tempfile
66
99
  end
67
100
 
68
- def adjust_image
69
- image = MiniMagick::Image.read @tempfile
101
+ ##
102
+ # Crops a given +tempfile+ according to initially given +options+
103
+ def adjust_image tempfile
104
+ image = MiniMagick::Image.read tempfile
70
105
 
71
106
  if options[:h] && options[:w]
72
107
  image.crop "#{options[:w]}x#{options[:h]}+#{options[:x]}+#{options[:y]}"
73
-
74
- image.write @tempfile
75
-
108
+ image.write tempfile
76
109
  end
77
110
 
78
111
  image
79
112
  end
80
113
 
81
- def clean!
82
- @tempfile.unlink
114
+ def before &block
115
+ @before_hook = block
83
116
  end
84
117
  end
85
118
  end
@@ -2,12 +2,14 @@ require 'sinatra/base'
2
2
  require 'sinatra/json'
3
3
 
4
4
  module Photograph
5
- # Preload the chrome instance
6
- Artist.browser
7
-
8
5
  class Service < ::Sinatra::Base
9
6
  helpers Sinatra::JSON
10
7
 
8
+ # Reuse the same browser instance between requests.
9
+ def browser
10
+ @browser ||= Artist.create_browser
11
+ end
12
+
11
13
  get '/' do
12
14
  json :version => Photograph::VERSION
13
15
  end
@@ -19,7 +21,8 @@ module Photograph
19
21
  :w => params["w"].to_i,
20
22
  :h => params["h"].to_i,
21
23
  :wait => params["wait"].to_f,
22
- :selector => params["selector"]
24
+ :selector => params["selector"],
25
+ :browser => browser
23
26
 
24
27
  artist.shoot! do |image|
25
28
  send_file image.path,
@@ -1,3 +1,3 @@
1
1
  module Photograph
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
data/photograph.gemspec CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency 'sinatra-contrib'
22
22
  gem.add_dependency 'thin'
23
23
 
24
- gem.add_development_dependency 'rspec', '~> 2.6'
24
+ gem.add_development_dependency 'rspec', '~> 2.14'
25
25
  gem.add_development_dependency 'rake'
26
+
27
+ gem.post_install_message = 'DEPRECATION: Artist#shoot! cannot be used without a block anymore. Please check your code, thank you.'
26
28
  end
@@ -2,47 +2,81 @@ require 'spec_helper'
2
2
 
3
3
  module Photograph
4
4
  describe Artist do
5
- URL = "http://rubygems.org"
5
+ let(:url) { 'http://rubygems.org' }
6
+ subject { Artist.new :url => url }
6
7
 
7
- it "should instanciate a new artist" do
8
- Artist.new :url => URL
9
- end
8
+ describe '.new' do
9
+ it { expect(subject).to be_kind_of(Artist) }
10
+
11
+ it('raises an error when not given a url') do
12
+ expect{ Artist.new }.to raise_error(Artist::MissingUrlError)
13
+ end
14
+
15
+ it('should leave http version of url untouched as it is already valid') do
16
+ expect(subject.options[:url]).to eq(url)
17
+ end
18
+
19
+ it('should leave https version of url untouched as it is already valid') do
20
+ expect(Artist.new(:url => 'https://rubygems.org').options[:url]).to eq('https://rubygems.org')
21
+ end
10
22
 
11
- it "should accept a block when shooting" do
12
- Artist.new(:url => URL).shoot! do |image|
13
- image.should respond_to(:path)
23
+ it('should prepend http:// to the url if protocol is not present') do
24
+ expect(Artist.new(:url => 'github.com').options[:url]).to eq('http://github.com')
14
25
  end
15
26
  end
16
27
 
17
- it "should raise an error without an url" do
18
- expect { Artist.new }.to raise_error(Artist::MissingUrlError)
28
+ describe '#options' do
29
+ it('should have default value for x') { expect(subject.options[:x]).to eq(0) }
30
+ it('should have default value for y') { expect(subject.options[:y]).to eq(0) }
31
+ it('should have default value for w') { expect(subject.options[:w]).to eq(1280) }
32
+ it('should have default value for h') { expect(subject.options[:h]).to eq(1024) }
19
33
  end
20
34
 
21
- describe "Default size values" do
22
- before(:each) { @artist = Artist.new :url => URL }
35
+ describe '#shoot!' do
36
+ context 'when browser has been provided' do
37
+ let(:browser) { Capybara::Session.new(:poltergeist) }
38
+ subject { Artist.new(:url => url, :browser => browser) }
23
39
 
24
- it "should have default values for x,y : 0,0" do
25
- @artist.options[:x].should == 0
26
- @artist.options[:y].should == 0
40
+ it 're-uses the browser provided to Artist#new' do
41
+ browser.should_receive(:visit)
42
+ subject.shoot! {}
43
+ end
27
44
  end
28
45
 
29
- it"should have default values for h,w : 1280, 1024" do
30
- @artist.options[:w].should == 1280
31
- @artist.options[:h].should == 1024
46
+ it('should accept a block when shooting') do
47
+ subject.shoot!{|image| image.should respond_to(:path) }
48
+ end
49
+
50
+ it('should raise an exception if no block was given when shooting') do
51
+ expect{ subject.shoot! }.to raise_error(Artist::DeprecationError)
32
52
  end
33
- end
34
53
 
35
- describe "Cropping" do
36
- before(:each) { @artist = Artist.new :url => URL }
54
+ describe 'Cropping' do
55
+ subject { Artist.new :url => url, :x => 200, :y => 100, :h => 400, :w => 400 }
56
+ before { subject.browser.driver.stub(:render) }
37
57
 
38
- it "should take a screenshot large enough to crop later" do
39
- pending
58
+ xit 'should take a screenshot large enough to crop later' do
59
+ subject.shoot!
60
+ end
61
+ end
62
+ end
40
63
 
41
- @artist = Artist.new :url => URL, :x => 200, :y => 100, :h => 400, :w => 400
64
+ describe "#before" do
65
+ subject { Artist.new :url => url }
66
+ before do
67
+ subject.browser.driver.stub(:visit)
68
+ subject.browser.driver.stub(:click_link)
69
+ subject.browser.driver.stub(:render)
70
+ subject.stub(:adjust_image)
71
+ end
42
72
 
43
- Artist.browser.driver.stub :render
73
+ it('should call the before hook before shooting') do
74
+ subject.before do |browser|
75
+ browser.click_link "Use the API"
76
+ end
44
77
 
45
- @artist.shoot!
78
+ allow(subject.browser).to receive(:click_link)
79
+ subject.shoot! {}
46
80
  end
47
81
  end
48
82
  end
metadata CHANGED
@@ -1,126 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: photograph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - JH. Chabran
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-10 00:00:00.000000000 Z
11
+ date: 2013-12-28 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: poltergeist
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: mini_magick
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: sinatra
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: sinatra-contrib
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: thin
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ~>
100
88
  - !ruby/object:Gem::Version
101
- version: '2.6'
89
+ version: '2.14'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ~>
108
95
  - !ruby/object:Gem::Version
109
- version: '2.6'
96
+ version: '2.14'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: rake
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - '>='
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - '>='
124
109
  - !ruby/object:Gem::Version
125
110
  version: '0'
126
111
  description: Webservice that screenshots any url
@@ -149,33 +134,27 @@ files:
149
134
  - spec/spec_helper.rb
150
135
  homepage: https://github.com/jhchabran/photograph
151
136
  licenses: []
152
- post_install_message:
137
+ metadata: {}
138
+ post_install_message: 'DEPRECATION: Artist#shoot! cannot be used without a block anymore.
139
+ Please check your code, thank you.'
153
140
  rdoc_options: []
154
141
  require_paths:
155
142
  - lib
156
143
  required_ruby_version: !ruby/object:Gem::Requirement
157
- none: false
158
144
  requirements:
159
- - - ! '>='
145
+ - - '>='
160
146
  - !ruby/object:Gem::Version
161
147
  version: '0'
162
- segments:
163
- - 0
164
- hash: -3056213331410753270
165
148
  required_rubygems_version: !ruby/object:Gem::Requirement
166
- none: false
167
149
  requirements:
168
- - - ! '>='
150
+ - - '>='
169
151
  - !ruby/object:Gem::Version
170
152
  version: '0'
171
- segments:
172
- - 0
173
- hash: -3056213331410753270
174
153
  requirements: []
175
154
  rubyforge_project:
176
- rubygems_version: 1.8.23
155
+ rubygems_version: 2.0.3
177
156
  signing_key:
178
- specification_version: 3
157
+ specification_version: 4
179
158
  summary: Webservice that screenshots any url
180
159
  test_files:
181
160
  - spec/photograph/artist_spec.rb