Class: Capybara::Poltergeist::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/capybara/poltergeist/client.rb

Constant Summary collapse

PHANTOMJS_SCRIPT =
File.expand_path('../client/compiled/main.js', __FILE__)
PHANTOMJS_VERSION =
['>= 1.8.1', '< 3.0']
PHANTOMJS_NAME =
'phantomjs'
KILL_TIMEOUT =

seconds

2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, options = {}) ⇒ Client

Returns a new instance of Client.



50
51
52
53
54
55
56
57
58
59
60
# File 'lib/capybara/poltergeist/client.rb', line 50

def initialize(server, options = {})
  @server            = server
  @path              = Cliver::detect((options[:path] || PHANTOMJS_NAME), *['>=2.1.0', '< 3.0'])
  @path            ||= Cliver::detect!((options[:path] || PHANTOMJS_NAME), *PHANTOMJS_VERSION).tap do
    warn "You're running an old version of PhantomJS, update to >= 2.1.1 for a better experience."
  end

  @window_size       = options[:window_size]       || [1024, 768]
  @phantomjs_options = options[:phantomjs_options] || []
  @phantomjs_logger  = options[:phantomjs_logger]  || $stdout
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



48
49
50
# File 'lib/capybara/poltergeist/client.rb', line 48

def path
  @path
end

#phantomjs_optionsObject (readonly)

Returns the value of attribute phantomjs_options.



48
49
50
# File 'lib/capybara/poltergeist/client.rb', line 48

def phantomjs_options
  @phantomjs_options
end

#pidObject (readonly)

Returns the value of attribute pid.



48
49
50
# File 'lib/capybara/poltergeist/client.rb', line 48

def pid
  @pid
end

#serverObject (readonly)

Returns the value of attribute server.



48
49
50
# File 'lib/capybara/poltergeist/client.rb', line 48

def server
  @server
end

#window_sizeObject (readonly)

Returns the value of attribute window_size.



48
49
50
# File 'lib/capybara/poltergeist/client.rb', line 48

def window_size
  @window_size
end

Class Method Details

.process_killer(pid) ⇒ Object

Returns a proc, that when called will attempt to kill the given process. This is because implementing ObjectSpace.define_finalizer is tricky. Hat-Tip to @mperham for describing in detail: www.mikeperham.com/2010/02/24/the-trouble-with-ruby-finalizers/



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/capybara/poltergeist/client.rb', line 25

def self.process_killer(pid)
  proc do
    begin
      if Capybara::Poltergeist.windows?
        Process.kill('KILL', pid)
      else
        Process.kill('TERM', pid)
        start = Time.now
        while Process.wait(pid, Process::WNOHANG).nil?
          sleep 0.05
          if (Time.now - start) > KILL_TIMEOUT
            Process.kill('KILL', pid)
            Process.wait(pid)
            break
          end
        end
      end
    rescue Errno::ESRCH, Errno::ECHILD
      # Zed's dead, baby
    end
  end
end

.start(*args) ⇒ Object



15
16
17
18
19
# File 'lib/capybara/poltergeist/client.rb', line 15

def self.start(*args)
  client = new(*args)
  client.start
  client
end

Instance Method Details

#commandObject



94
95
96
97
98
99
100
101
102
# File 'lib/capybara/poltergeist/client.rb', line 94

def command
  parts = [path]
  parts.concat phantomjs_options
  parts << PHANTOMJS_SCRIPT
  parts << server.port
  parts.concat window_size
  parts << server.host
  parts
end

#restartObject



89
90
91
92
# File 'lib/capybara/poltergeist/client.rb', line 89

def restart
  stop
  start
end

#startObject



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/capybara/poltergeist/client.rb', line 62

def start
  @read_io, @write_io = IO.pipe
  @out_thread = Thread.new {
    while !@read_io.eof? && data = @read_io.readpartial(1024)
      @phantomjs_logger.write(data)
    end
  }

  process_options = {in: File::NULL}
  process_options[:pgroup] = true unless Capybara::Poltergeist.windows?
  process_options[:out] = @write_io if Capybara::Poltergeist.mri?

  redirect_stdout do
    @pid = Process.spawn(*command.map(&:to_s), process_options)
    ObjectSpace.define_finalizer(self, self.class.process_killer(@pid))
  end
end

#stopObject



80
81
82
83
84
85
86
87
# File 'lib/capybara/poltergeist/client.rb', line 80

def stop
  if pid
    kill_phantomjs
    @out_thread.kill
    close_io
    ObjectSpace.undefine_finalizer(self)
  end
end