capybara-paparazzi 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4e37b4dd76d939ff8af81d07dffd57b8bec00451
4
+ data.tar.gz: f0b32e133aae2070f4c533b645eca45b9de6dfe1
5
+ SHA512:
6
+ metadata.gz: 875d8f5a8f55c4c79435cd577fde4da551fda8a42b1b56f83bc1419ff3bea67b12100eb088fc13b7ccc5a95706a6a4945c7116efdabb575c2cc563b5772e6557
7
+ data.tar.gz: e15368acf07fe259bf8f7e7330a385e2cea4f83b1ff6ef5f594a48800f358b78cd9444230986c23f064ed5a6092d21de9e81c90a4e010954edc40473899b5204
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capybara-paparazzi.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Steven Bull
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,150 @@
1
+ # Capybara::Paparazzi
2
+
3
+ Capybara::Paparazzi simplifies and automates the task of capturing
4
+ screenshots of your app by snapping full-length photos of your pages
5
+ in various window widths during a run of your test suite. If you've
6
+ ever wanted to get screenshots of your user flows to check how
7
+ everything looks on a phone vs. on a tablet vs. on a desktop, this gem
8
+ is for you. This is particularly useful if you are using responsive
9
+ CSS. Additionally, it draws a line on the screenshot where the "fold"
10
+ would be, showing a user's first impression of a page.
11
+
12
+ Capybara::Paparazzi hooks into Capybara's feature tests and takes
13
+ pictures at significant user actions (like visiting a page, clicking
14
+ buttons, etc.). It relies on a driver that supports saving screenshots
15
+ and executing javascript, and was originally built with Poltergeist in
16
+ mind.
17
+
18
+ A few driving principles of Capybara::Paparazzi:
19
+
20
+ - **Unobtrusive**: You shouldn't need to edit your feature test scenarios
21
+ to get screenshots.
22
+ - **Easy**: Simple to set up, and out-of-the-box settings should get you far.
23
+ - **Customizable**: You should be able to tweak it to your needs easily,
24
+ without needing to re-invent too much to achieve what you want.
25
+ - **Exhaustive**: Taking extra screenshots is better than missing out on
26
+ important things. It's easy to delete or ignore unnecessary files later.
27
+
28
+ ## Installation
29
+
30
+ Add a line to your application's Gemfile:
31
+
32
+ group :test do
33
+ gem 'rspec-rails'
34
+ gem 'capybara'
35
+ gem 'poltergeist'
36
+ gem 'capybara-paparazzi' # <-- add this one
37
+ end
38
+
39
+ And then execute:
40
+
41
+ $ bundle
42
+
43
+ Or install it yourself as:
44
+
45
+ $ gem install capybara-paparazzi
46
+
47
+ ## Usage
48
+
49
+ ### Quick-Start
50
+
51
+ After getting the gem installed, using Capybara::Paparazzi is pretty simple.
52
+ In your test setup file (using rspec, probably `spec/spec_helper.rb`),
53
+ add something like this:
54
+
55
+ ```ruby
56
+ # Other rspec & capybara setup, such as:
57
+ # require 'rspec/rails'
58
+ # require 'capybara/rspec'
59
+
60
+ require 'capybara/poltergeist' # <-- Use a fancy driver.
61
+ Capybara.default_driver = :poltergeist # <-- Set it to be used for everything.
62
+
63
+ Capybara::Paparazzi.follow(:poltergeist) # <-- Take screenshots of everything the driver does.
64
+
65
+ ```
66
+
67
+ Now just run
68
+
69
+ $ rspec
70
+
71
+ or
72
+
73
+ $ rake
74
+
75
+ and you'll get screenshots in a `screenshots` folder.
76
+
77
+ ### Configuring
78
+
79
+ Use `Capybara::Paparazzi.follow(<driver_name>, ...)` to take screenshots
80
+ for a particular driver. You can also do `config.follow(<driver_name>, ...)`
81
+ inside of a configuration block, instead. It doesn't matter if this
82
+ happens before or after the driver itself is actually registered with
83
+ Capybara, just as long as the name matches.
84
+
85
+ Here's a fairly complete list of things you can do:
86
+
87
+ ```ruby
88
+ Capybara::Paparazzi.config do |config|
89
+ config.js_var_name = 'MY_DIV' # Name of the div used to draw the fold line.
90
+ config.js_var_style.merge!(color: 'red', fontWeight: 'bold')
91
+ config.screenshot_sizes = [ config.screenshot_sizes.first, (config.screenshot_sizes.last + [ :EXTRA_DATA ]) ]
92
+ config.file_dir = '../screenshots'
93
+ # config.js_setup_script = ->(shooter){ ... }
94
+ config.js_resize_script = ->(shooter, height) {
95
+ "#{shooter.js_var_name}.style.height = '#{height}px'; MY_DIV.textContent = #{shooter.screenshot_size.inspect.to_json}; MY_DIV.style.fontSize = '#{height/4}px';"
96
+ }
97
+ # config.js_cleanup_script = ->(shooter){}
98
+ config.before_save_callback = ->(shooter) {
99
+ shooter.resize_window(shooter.width * 2, shooter.height / 2)
100
+ shooter.do_shot = shooter.suffix.to_s.empty?
101
+ }
102
+ config.follow(:poltergeist)
103
+ end
104
+ ```
105
+
106
+ For the default settings, see [shooter.rb](https://github.com/sbull/capybara-paparazzi/blob/master/lib/capybara/paparazzi/shooter.rb).
107
+
108
+ ### Screenshot Sizes
109
+
110
+ Capybara::Paparazzi uses default screen sizes to represent common
111
+ phone, tablet, and desktop browser dimensions. The most important
112
+ feature is the width. The height is used to draw the "fold" line - the
113
+ default sizes attempt to take into account the browser chrome that
114
+ gets added to the top and bottom of browser windows, which results in
115
+ a shorter view than the actual device height.
116
+
117
+ ## Tips & Tricks
118
+
119
+ ### Turning Capybara::Paparazzi On and Off
120
+
121
+ Use an environment variable to turn screenshots on or off.
122
+ You probably don't want them running all the time, and only
123
+ need them on occasion:
124
+
125
+ Capybara::Paparazzi.follow(Capybara.default_driver, Capybara.javascript_driver) if ENV['CAPYBARA_PAPARAZZI_ENABLED']
126
+
127
+ ### Driver Setup
128
+
129
+ Poltergeist is a great headless driver to use, particularly due to its
130
+ ease of installation.
131
+ Here's a simple approach that could work for you:
132
+
133
+ 1. Install [PhantomJS](http://phantomjs.org/).
134
+ 1. Prereqs: install [nodejs](http://nodejs.org/) and npm.
135
+ Try something like: `sudo apt-get install nodejs`
136
+ 2. Use npm to install phantomjs: `sudo npm install -g phantomjs`
137
+ 2. Install [Poltergeist](https://github.com/teampoltergeist/poltergeist).
138
+ 1. Add poltergeist to your Gemfile: `gem 'poltergeist'`
139
+ 2. `bundle install`
140
+ 3. Use Poltergeist:
141
+ 1. `require 'capybara/poltergeist'`
142
+ 2. `Capybara.javascript_driver = :poltergeist`
143
+
144
+ ## Contributing
145
+
146
+ 1. Fork it
147
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
148
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
149
+ 4. Push to the branch (`git push origin my-new-feature`)
150
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capybara/paparazzi/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capybara-paparazzi"
8
+ spec.version = Capybara::Paparazzi::VERSION
9
+ spec.authors = ["Steven Bull"]
10
+ spec.email = ["steven@thebulls.us"]
11
+ spec.description = <<DESCRIPTION
12
+ Capybara::Paparazzi automatically takes screenshots of all of your pages,
13
+ in a variety of different window sizes. It clearly indicates where the
14
+ initial view of the page cuts off (the "fold"), and is easily configurable.
15
+ DESCRIPTION
16
+ spec.summary = 'Take responsive screenshots of your site.'
17
+ spec.homepage = 'https://github.com/sbull/capybara-paparazzi'
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files`.split($/)
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+
28
+ spec.add_runtime_dependency 'capybara', '~> 2.0'
29
+ end
@@ -0,0 +1,42 @@
1
+ require 'capybara'
2
+
3
+ require 'capybara/paparazzi/version'
4
+ require 'capybara/paparazzi/shooter'
5
+ require 'capybara/paparazzi/driver'
6
+ require 'capybara/paparazzi/element'
7
+ require 'capybara/paparazzi/session'
8
+
9
+ module Capybara::Paparazzi
10
+
11
+ module ClassMethods
12
+
13
+ def config(&block)
14
+ Capybara::Paparazzi::Shooter.config(&block)
15
+ end
16
+
17
+ def follow(*driver_names)
18
+ driver_names.each do |name|
19
+ used_drivers[name] = true
20
+ end
21
+ end
22
+
23
+ def used_drivers
24
+ @used_drivers ||= {}
25
+ end
26
+
27
+ def take_snapshots(driver, event_details=nil)
28
+ Capybara::Paparazzi::Shooter.take_snapshots(driver, event_details)
29
+ end
30
+
31
+ end # ClassMethods
32
+
33
+ extend ClassMethods
34
+ end
35
+
36
+ class Capybara::Node::Element
37
+ include Capybara::Paparazzi::Element
38
+ end
39
+
40
+ class Capybara::Session
41
+ include Capybara::Paparazzi::Session
42
+ end
@@ -0,0 +1,14 @@
1
+ module Capybara::Paparazzi::Driver
2
+
3
+ # TODO: go_back, go_forward
4
+
5
+ def visit(*args)
6
+ super(*args)
7
+ take_snapshots(:visit, args)
8
+ end
9
+
10
+ def take_snapshots(method, args)
11
+ Capybara::Paparazzi.take_snapshots(self, { method: method, args: args })
12
+ end
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ module Capybara::Paparazzi::Element
2
+
3
+ def click_with_paparazzi(*args)
4
+ response = click_without_paparazzi(*args)
5
+ if session.driver.respond_to?(:take_snapshots)
6
+ session.driver.take_snapshots(:click, args)
7
+ end
8
+ response
9
+ end
10
+
11
+ def self.included(mod)
12
+ mod.send(:alias_method, :click_without_paparazzi, :click)
13
+ mod.send(:alias_method, :click, :click_with_paparazzi)
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ module Capybara::Paparazzi::Session
2
+
3
+ def driver_with_paparazzi(*args)
4
+ driver = driver_without_paparazzi(*args)
5
+ if Capybara::Paparazzi.used_drivers[mode] && !driver.is_a?(Capybara::Paparazzi::Driver)
6
+ driver.extend(Capybara::Paparazzi::Driver)
7
+ end
8
+ driver
9
+ end
10
+
11
+ def self.included(mod)
12
+ mod.send(:alias_method, :driver_without_paparazzi, :driver)
13
+ mod.send(:alias_method, :driver, :driver_with_paparazzi)
14
+ end
15
+
16
+ end
@@ -0,0 +1,218 @@
1
+ class Capybara::Paparazzi::Shooter
2
+
3
+ DEFAULT_SCREENSHOT_SIZES =
4
+ [
5
+ [ 320, 444 ], # 568 - 124
6
+ [ 768, 900 ], # 1024 - 124
7
+ [ 1024, 644 ], # 768 - 124
8
+ [ 1336, 600 ],
9
+ ].freeze
10
+
11
+ DEFAULT_FOLD_STYLE = {
12
+ position: 'fixed',
13
+ top: '0',
14
+ left: '0',
15
+ width: '100%',
16
+ zIndex: 999999,
17
+ borderBottom: '1px solid red',
18
+ }.freeze
19
+
20
+ CONFIG_VARS = {
21
+ js_var_name: 'THE_FOLD',
22
+ js_var_style: {}.merge(DEFAULT_FOLD_STYLE),
23
+ screenshot_sizes: ([] + DEFAULT_SCREENSHOT_SIZES),
24
+ file_dir: 'screenshots',
25
+ js_setup_script: ->(shooter) {
26
+ var_name = shooter.js_var_name
27
+ script = "if (!window.#{var_name}) { #{var_name} = document.createElement('DIV');"
28
+ shooter.js_var_style.each do |prop_name, prop_val|
29
+ script += "#{var_name}.style.#{prop_name} = #{prop_val.to_json};"
30
+ end
31
+ script += "} document.body.appendChild(#{var_name});"
32
+ },
33
+ js_resize_script: ->(shooter, height) { "#{shooter.js_var_name}.style.height = '#{height}px';" },
34
+ before_save_callback: nil,
35
+ js_cleanup_script: ->(shooter) { "document.body.removeChild(#{shooter.js_var_name});" },
36
+ }.freeze
37
+
38
+
39
+ module ClassMethods
40
+
41
+ attr_accessor(*CONFIG_VARS.keys)
42
+
43
+ def config
44
+ @_configged ||=
45
+ begin
46
+ CONFIG_VARS.each do |cv, default|
47
+ send("#{cv}=".to_sym, default)
48
+ true
49
+ end
50
+ end
51
+ if block_given?
52
+ yield(self)
53
+ end
54
+ end
55
+
56
+ def follow(*args)
57
+ Capybara::Paparazzi.follow(*args)
58
+ end
59
+
60
+ def take_snapshots(driver, event_details=nil)
61
+ # TODO: Be smarter. One shooter per driver, but avoid memory leaks (be mindful of Guard, etc.).
62
+ new(driver, event_details).take_snapshots
63
+ end
64
+
65
+ def next_suffix_for_path!(path)
66
+ # TODO: Be smarter about this - multi-threaded, etc.
67
+ @path_nums ||= {}
68
+ num = @path_nums[path]
69
+ @path_nums[path] = num.to_i + 1
70
+ if num
71
+ suffix = ".#{num}"
72
+ if @path_nums[path+suffix]
73
+ suffix = next_suffix_for_path!(path)
74
+ end
75
+ else
76
+ suffix = ''
77
+ end
78
+ suffix
79
+ end
80
+
81
+ end # ClassMethods
82
+
83
+ extend ClassMethods
84
+
85
+
86
+ attr_accessor :driver, :event_details
87
+ attr_accessor :path, :suffix
88
+ attr_accessor :do_shot, :screenshot_size, :filename
89
+ attr_accessor :before_save_callback
90
+
91
+ attr_accessor(*CONFIG_VARS.keys)
92
+ # def cv; @cv ||= self.class.config[:cv]; end
93
+ CONFIG_VARS.each do |cv, default|
94
+ define_method(cv) do
95
+ iv_sym = "@#{cv}".to_sym
96
+ iv = instance_variable_get(iv_sym)
97
+ unless iv
98
+ iv = self.class.send(cv.to_sym)
99
+ instance_variable_set(iv_sym, iv)
100
+ end
101
+ iv
102
+ end
103
+ end
104
+
105
+
106
+ def initialize(driver, event_details=nil)
107
+ @driver = driver
108
+ @event_details = event_details
109
+ @config = self.class.config
110
+ end
111
+
112
+ def take_snapshots
113
+ set_path_and_suffix
114
+ execute_setup_script
115
+ save_snapshots
116
+ execute_cleanup_script
117
+ end
118
+
119
+ def width
120
+ @screenshot_size[0]
121
+ end
122
+
123
+ def height
124
+ @screenshot_size[1]
125
+ end
126
+
127
+ def resize_window(width, height)
128
+ begin
129
+ if driver.respond_to?(:resize) # Poltergeist
130
+ driver.resize(width, height)
131
+ elsif driver.respond_to?(:resize_window) # Poltergeist
132
+ driver.resize_window(width, height)
133
+ else # Capybara default / Selenium
134
+ driver.resize_window_to(driver.current_window_handle, width, height)
135
+ end
136
+ rescue => e
137
+ log("Error while resizing window: #{e}")
138
+ end
139
+ execute_resize_script(height)
140
+ end
141
+
142
+
143
+ private
144
+
145
+ def set_path_and_suffix
146
+ path, suffix = path_and_suffix_for_url(driver.current_url)
147
+ self.path = path
148
+ self.suffix = suffix
149
+ end
150
+
151
+ def execute_setup_script
152
+ exec_js(:js_setup_script, self)
153
+ end
154
+
155
+ def exec_js(script_name, *args)
156
+ begin
157
+ script = send(script_name)
158
+ if script
159
+ script_text = script.is_a?(Proc) ? script.call(*args) : script.to_s
160
+ driver.execute_script(script_text)
161
+ end
162
+ rescue => e
163
+ log("#{e.message}\nJavascript: #{script_text}")
164
+ end
165
+ end
166
+
167
+ def save_snapshots
168
+ screenshot_sizes.each do |w_h_rest|
169
+ save_snapshot(w_h_rest)
170
+ end
171
+ end
172
+
173
+ def save_snapshot(width_height_rest)
174
+ @do_shot = true
175
+ @screenshot_size = ([] + width_height_rest)
176
+ @filename = "#{file_dir}#{path}#{suffix}-#{width}.png"
177
+
178
+ resize_window(width, height)
179
+
180
+ before_save_callback.call(self) if before_save_callback
181
+
182
+ if @do_shot
183
+ save_screenshot
184
+ end
185
+ end
186
+
187
+ def execute_resize_script(height)
188
+ exec_js(:js_resize_script, self, height)
189
+ end
190
+
191
+ def execute_cleanup_script
192
+ exec_js(:js_cleanup_script, self)
193
+ end
194
+
195
+ def save_screenshot
196
+ driver.save_screenshot(*get_save_screenshot_args)
197
+ end
198
+
199
+ def get_save_screenshot_args
200
+ [ filename, { full: true } ]
201
+ end
202
+
203
+ def path_and_suffix_for_url(url)
204
+ path = URI.parse(url).path
205
+ path += 'index' if path[-1] == '/'
206
+ suffix = next_suffix_for_path!(path)
207
+ [ path, suffix ]
208
+ end
209
+
210
+ def next_suffix_for_path!(path)
211
+ self.class.next_suffix_for_path!(path)
212
+ end
213
+
214
+ def log(msg)
215
+ warn "Capybara::Paparazzi: #{msg}"
216
+ end
217
+
218
+ end
@@ -0,0 +1,5 @@
1
+ module Capybara
2
+ module Paparazzi
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capybara-paparazzi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Steven Bull
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capybara
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ description: |
56
+ Capybara::Paparazzi automatically takes screenshots of all of your pages,
57
+ in a variety of different window sizes. It clearly indicates where the
58
+ initial view of the page cuts off (the "fold"), and is easily configurable.
59
+ email:
60
+ - steven@thebulls.us
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - capybara-paparazzi.gemspec
71
+ - lib/capybara-paparazzi.rb
72
+ - lib/capybara/paparazzi/driver.rb
73
+ - lib/capybara/paparazzi/element.rb
74
+ - lib/capybara/paparazzi/session.rb
75
+ - lib/capybara/paparazzi/shooter.rb
76
+ - lib/capybara/paparazzi/version.rb
77
+ homepage: https://github.com/sbull/capybara-paparazzi
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.0.14
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Take responsive screenshots of your site.
101
+ test_files: []