diff --git a/lib/gastly.rb b/lib/gastly.rb index 41d5e3d..a759625 100644 --- a/lib/gastly.rb +++ b/lib/gastly.rb @@ -1,3 +1,8 @@ +require 'phantomjs' +require 'mini_magick' +require 'active_support/core_ext/hash/keys' +require 'active_support/core_ext/object/blank' + require_relative 'gastly/image' require_relative 'gastly/screenshot' require_relative 'gastly/exceptions' diff --git a/lib/gastly/exceptions.rb b/lib/gastly/exceptions.rb index 0b3eda2..44e44d6 100644 --- a/lib/gastly/exceptions.rb +++ b/lib/gastly/exceptions.rb @@ -8,4 +8,5 @@ def initialize(url) end PhantomJSError = Class.new(RuntimeError) + UnknownError = Class.new(RuntimeError) end diff --git a/lib/gastly/image.rb b/lib/gastly/image.rb index dd3b322..b775ed7 100644 --- a/lib/gastly/image.rb +++ b/lib/gastly/image.rb @@ -1,33 +1,29 @@ -require 'mini_magick' - module Gastly class Image - attr_reader :file + attr_reader :image - # @param tempfile [Tempfile] Screenshot - def initialize(tempfile) - @file = MiniMagick::Image.open(tempfile.path) - tempfile.unlink + # @param image [MiniMagick::Image] Instance of MiniMagick::Image + def initialize(image) + @image = image end - # @param [Hash] - # @option width [Fixnum] Image width - # @option height [Fixnum] Image height + # @param width [Fixnum] Image width + # @param height [Fixnum] Image height def resize(width:, height:) dimensions = "#{width}x#{height}" - @file.resize(dimensions) + image.resize(dimensions) end # @param ext [String] Image extension # @return [MiniMagick::Image] Instance def format(ext) - @file.format(ext) + image.format(ext) end - # @param output [String] Full path to file - # @return [String] Full path to file + # @param output [String] Full path to image + # @return [String] Full path to image def save(output) - @file.write(output) + image.write(output) output end end diff --git a/lib/gastly/screenshot.rb b/lib/gastly/screenshot.rb index f249a72..ad85bac 100644 --- a/lib/gastly/screenshot.rb +++ b/lib/gastly/screenshot.rb @@ -1,17 +1,12 @@ -require 'phantomjs' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/object/blank' - module Gastly class Screenshot SCRIPT_PATH = File.expand_path('../script.js', __FILE__) DEFAULT_TIMEOUT = 0 DEFAULT_BROWSER_WIDTH = 1440 DEFAULT_BROWSER_HEIGHT = 900 - DEFAULT_FILE_NAME = 'output'.freeze DEFAULT_FILE_FORMAT = '.png'.freeze - attr_reader :tempfile + attr_reader :image attr_writer :timeout, :browser_width, :browser_height attr_accessor :url, :selector, :cookies, :proxy_host, :proxy_port @@ -22,12 +17,11 @@ def initialize(url, **kwargs) @url = url @cookies = kwargs.delete(:cookies) - @tempfile = Tempfile.new([DEFAULT_FILE_NAME, DEFAULT_FILE_FORMAT]) # TODO: Use MiniMagick::Image.create instead + @image = MiniMagick::Image.create(DEFAULT_FILE_FORMAT, false) # Disable validation kwargs.each { |key, value| instance_variable_set(:"@#{key}", value) } end - # # Capture image via PhantomJS and save to output file # # @return [Gastly::Image] Instance of Gastly::Image @@ -37,10 +31,9 @@ def capture Phantomjs.proxy_port = proxy_port if proxy_port output = Phantomjs.run(proxy_options, SCRIPT_PATH.to_s, *prepared_params) + handle_output(output) - handle_exception(output) if output.present? # TODO: Add test - - Gastly::Image.new(tempfile) # TODO: Add test + Gastly::Image.new(image) end %w(timeout browser_width browser_height).each do |name| @@ -63,26 +56,28 @@ def prepared_params timeout: timeout, width: browser_width, height: browser_height, - output: tempfile.path + output: image.path } params[:selector] = selector if selector.present? - params[:cookies] = hash_to_array(cookies).join(',') if cookies.present? + params[:cookies] = parameterize(cookies).join(',') if cookies.present? - hash_to_array(params) + parameterize(params) end - # TODO: Rename method to parameterize - def hash_to_array(data) - data.map { |key, value| "#{key}=#{value}" } + # @param hash [Hash] + # @return [Array] Array of parameterized strings + def parameterize(hash) + hash.map { |key, value| "#{key}=#{value}" } end - # TODO: Rename to handle_output - def handle_exception(output) + def handle_output(output) + return unless output.present? + error = case output when /^FetchError:(.+)/ then Gastly::FetchError when /^RuntimeError:(.+)/m then Gastly::PhantomJSError - # TODO: Return unknown error + else UnknownError end fail error, Regexp.last_match(1) diff --git a/spec/gastly/image_spec.rb b/spec/gastly/image_spec.rb index fd7785c..0f42ee3 100644 --- a/spec/gastly/image_spec.rb +++ b/spec/gastly/image_spec.rb @@ -1,5 +1,37 @@ require 'spec_helper' RSpec.describe Gastly::Image do + let(:image) { MiniMagick::Image.new('test.png') } + subject { Gastly::Image.new(image) } + context '#resize' do + it 'invokes method #resize with arguments' do + width, height = 100, 100 + expect_any_instance_of(MiniMagick::Image).to receive(:resize).with("#{width}x#{height}") + subject.resize(width: 100, height: 100) + end + end + + context '#format' do + it 'invokes method #format' do + ext = 'png' + expect_any_instance_of(MiniMagick::Image).to receive(:format).with(ext) + subject.format(ext) + end + end + + context '#save' do + let(:output) { 'output.png' } + before do + expect_any_instance_of(MiniMagick::Image).to receive(:write).with(output) + end + + it 'invokes method #write' do + subject.save(output) + end + + it 'returns a string' do + expect(subject.save(output)).to eq output + end + end end \ No newline at end of file diff --git a/spec/gastly/screenshot_spec.rb b/spec/gastly/screenshot_spec.rb index 4946126..b5a0296 100644 --- a/spec/gastly/screenshot_spec.rb +++ b/spec/gastly/screenshot_spec.rb @@ -20,7 +20,6 @@ it { expect(Gastly::Screenshot::DEFAULT_TIMEOUT).to eq 0 } it { expect(Gastly::Screenshot::DEFAULT_BROWSER_WIDTH).to eq 1440 } it { expect(Gastly::Screenshot::DEFAULT_BROWSER_HEIGHT).to eq 900 } - it { expect(Gastly::Screenshot::DEFAULT_FILE_NAME).to eq 'output' } it { expect(Gastly::Screenshot::DEFAULT_FILE_FORMAT).to eq '.png' } context '#initialize' do @@ -57,7 +56,7 @@ "timeout=#{params[:timeout]}", "width=#{params[:browser_width]}", "height=#{params[:browser_height]}", - "output=#{screenshot.tempfile.path}", + "output=#{screenshot.image.path}", "selector=#{params[:selector]}", "cookies=#{cookies}" ] @@ -65,6 +64,29 @@ expect(Phantomjs).to receive(:run).with(*args) screenshot.capture end + + it 'raises an exception if fetch error' do + url = 'h11p://google.com' + screenshot = Gastly::Screenshot.new(url) + expect { screenshot.capture }.to raise_error(Gastly::FetchError, "Unable to load #{url}") + end + + it 'raises an exception if runtime error' do + expect(Phantomjs).to receive(:run).and_return('RuntimeError:test runtime error') + screenshot = Gastly::Screenshot.new(url) + expect { screenshot.capture }.to raise_error(Gastly::PhantomJSError, 'test runtime error') + end + + it 'raises an exception if unknown error' do + expect(Phantomjs).to receive(:run).and_return('unknown error') + screenshot = Gastly::Screenshot.new(url) + expect { screenshot.capture }.to raise_error(Gastly::UnknownError) + end + + it 'returns an instance of Gastly::Image' do + screenshot = Gastly::Screenshot.new(url) + expect(screenshot.capture).to be_instance_of Gastly::Image + end end context '#timeout' do diff --git a/spec/gastly_spec.rb b/spec/gastly_spec.rb index 90e6c2b..5988556 100644 --- a/spec/gastly_spec.rb +++ b/spec/gastly_spec.rb @@ -1,4 +1,22 @@ require 'spec_helper' describe Gastly do + let(:url) { 'http://google.com' } + + context '#screenshot' do + it 'returns an instance of Gastly::Screenshot' do + expect(Gastly.screenshot(url, timeout: 1000)).to be_instance_of Gastly::Screenshot + end + end + + context '#capture' do + it 'creates a screenshot' do + tmp = 'spec/support/tmp' + path = "#{tmp}/output.png" + expect(Dir.glob("#{tmp}/*").length).to eq 0 + Gastly.capture(url, path) + expect(Dir.glob("#{tmp}/*").length).to eq 1 + FileUtils.rm Dir.glob("#{tmp}/*") + end + end end