lib/boojs.rb in boojs-0.0.18 vs lib/boojs.rb in boojs-0.0.19

- old
+ new

@@ -1,8 +1,10 @@ require 'tempfile' require 'securerandom' require 'greenletters' +require "net/http" +require "uri" module BooJS def self.verify str phantom = Phantomjs.path @@ -57,17 +59,129 @@ if cmd js += "\n#{cmd}" js += "\nphantom.exit(1)" unless will_timeout else - js += "\nwhile (true) { var line = system.stdin.readLine(); eval(line); }" + #You can not use $stdin here, PhantomJS blocks on readLine + js += PhantomAsyncInput.code + #js += "\nwhile (true) { var line = system.stdin.readLine(); eval(line); }" end + #Create file to load tmp = Tempfile.new(SecureRandom.hex) tmp.puts js tmp.close - ret = system("#{$phantomjs_path} #{tmp.path}") + @input_sender_r, @input_sender_w = IO.pipe + + #Phantom JS Process + p = IO.popen("#{$phantomjs_path} #{tmp.path}") + loop do + rr, _ = select([p, STDIN]); e = rr[0] + #PhantomJS has written something + if e == p + res = e.readline + + if res =~ /STDIN_PORT/ + port = res.split(" ")[1].to_i + start_server(port, @input_sender_r) + else + puts res + $stdout.flush + end + end + + #User has written to this program + if e == STDIN + @input_sender_w.puts e.readline + end + end + tmp.unlink exit ret + rescue EOFError => e + exit 1 + end + + def self.start_server port, pipe + #Server that manages inputs + Thread.new do + begin + loop do + rr, __ = IO.select([@input_sender_r], []); e = rr[0] + + uri = URI.parse("http://localhost:#{port}") + Net::HTTP.post_form(uri, {:str => e.readline}) + end + rescue Exception => e + $stderr.puts "Input server exception: #{e.inspect}" + end + end + end + + #Show the lines of somethingl ike a source file will + #show around center_num where it has n_expand lines around + #the center_num. If you pass msg, it will output the + #information next to the arrow + # ----------------------------------------------- + # my_source.js + # ----------------------------------------------- + # 2| pretend_to_do_something(); + # 3| console.log("hello world"); + # 4| console.log("hello world again"]; <-------- [optional msg] + # 5| var x = 4; + # 6| var y = 3; + # ----------------------------------------------- + def dump_lines fn, center_num, n_expand, msg=nil + f = File.open(fn) + range = (center_num-n_expand)..(center_num+n_expand) + + puts "------------------------------------------------------------" + puts "#{File.basename(fn)}:#{center_num}" + puts "------------------------------------------------------------" + f.each_line.with_index do |line, index| + line.strip! + if range.include? index + if index == center_num + puts "#{index}| #{line} <------ " + (msg ? "[#{msg}]" : "") + else + puts "#{index}| #{line}" + end + end + end + puts "------------------------------------------------------------" + end +end + +#You can not use stdin readLine from PhantomJS because it blocks. This is a workaround where +#commands are queued via the built-in server and then evaluated asynchronously via setInterval. +#This method is used because exceptions that occur inside the calling context of the server response +#cause the server to crash without notifying the application via phantom.onError +module PhantomAsyncInput + def self.code + %{ + __async_stdin_queue = [] + __webserver = require('webserver'); + __server = __webserver.create(); + __port = Math.floor((Math.random() * 3000) + 3000); + console.log("STDIN_PORT " + __port) + __service = __server.listen(__port, function(req, res) { + //Reply + var str = req.post.str + __async_stdin_queue.unshift(str) + res.write("ok"); + res.close(); + }); + + function __async_stdin_dequeue() { + //Nothing to process + if (__async_stdin_queue.length == 0) { + return; + } + + var str = __async_stdin_queue.pop() + eval(str); + } + setInterval(__async_stdin_dequeue, 50); + } end end