phrender 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 092133a20cb9d29d3b2a8867224a38851c3dd891
4
- data.tar.gz: 0a2f321d07614c3e4e744419c1df287d93588772
3
+ metadata.gz: ed3ad1d4b44735e82d185bca486adb853fb15fba
4
+ data.tar.gz: 1f37c26795b0cacf96926f1a3ebae75f41b15f4b
5
5
  SHA512:
6
- metadata.gz: d4d79647ef74036f80da6c17ea500fea90893da54989e90146947180a3f2a40231a0c38e4b75c6160f8841ae38d9ee714cc8feea1f138b3ac1c89225e5b7154e
7
- data.tar.gz: 33e1fa532034a483a3a7e3342c41a66be0b12008be3be5a7fba43e0e4a8fb7002d0072f99b664812bb1b16f81e9e949db4f83ddef99744a1de5341c24419025d
6
+ metadata.gz: 9b1dbdae233a0fb2754378696a7757beee1c2ee197cc5aa5a0dac36be76be5b867d9649688c24c23f84b80dbf9a1ea269dc7b113085c1b0fd09459721c65b7ee
7
+ data.tar.gz: 42bbbaac4dd4aedae6504f5c972b02794dab825a368e00ec8b88accb65a6cc667dbb87ed2ac29ca9fcbde96c341d34a16ad0b96f9f71602272695ba5861da262
data/README.md CHANGED
@@ -22,8 +22,8 @@ Then install PhantomJS:
22
22
 
23
23
  ## Usage
24
24
 
25
- *NOTE*: Ember users, there is a driver for ember. See the [Ember Driver](#Ember
26
- Driver) section.
25
+ *NOTE*: Ember users, there is a driver for ember. See the [Ember Driver](#ember-driver)
26
+ section.
27
27
 
28
28
  ### For completely static javascript sites:
29
29
 
@@ -32,23 +32,33 @@ In your rackup file:
32
32
  ```ruby
33
33
  require 'phrender'
34
34
 
35
- # Available options are timeout, which gets passed on to PhantomJS. The asset
36
- # root should reflect where your app is stored, as well as all images, fonts,
37
- # css, and other assets.
38
- phrender = Phrender::RackStatic.new("asset_root", options)
35
+ # The asset root should reflect where your app is stored, as well as all images,
36
+ # fonts, css, and other static files.
37
+ asset_root = "./"
39
38
 
40
39
  # The index file should link to no javascript on its own, or include any script
41
40
  # tags.
42
- phrender.index_file 'phrender.html'
41
+ index_file = 'phrender.html'
43
42
 
44
43
  # This is the main application. It may or may not also start up the app.
45
- phrender.add_javascript_file '/assets/application.js'
44
+ javascript_files = [ '/assets/application.js' ]
46
45
 
47
46
  # This is just raw javascript. Typically the app boot code.
48
- phrender.add_javascript "MyApp.boot()"
47
+ javascript = [ "MyApp.boot()" ]
48
+
49
+ # Javascript files and raw javascript get concatenated. Files first, then raw
50
+ # code in array order. This code is then run against the index file using
51
+ # PhantomJS
49
52
 
50
53
  # Rackup!
51
- run phrender.rack_app
54
+ run Phrender::RackStatic.new({
55
+ :asset_root => asset_root,
56
+ :index_file => index_file,
57
+ :javascript_files => javascript_files,
58
+ :javascript => javascript
59
+ })
60
+ # Additionally, you map pass the option :timeout, which gets passed on to
61
+ # PhantomJS.
52
62
  ```
53
63
 
54
64
  ### For partially dynamic javascript sites:
@@ -63,23 +73,27 @@ In your rackup file:
63
73
  require 'phrender'
64
74
  require 'my_rack_app'
65
75
 
66
- # This is what you provide
67
- app = MyRackApp.new
68
-
69
- # Available options are timeout and ssl, if, for some reason, your rack app is
76
+ # These options are the same as above, but instead of referencing actual files,
77
+ # the paths are the request paths to send to the upstream application server.
78
+ index_file = 'phrender.html'
79
+ javascript_files = [ '/assets/application.js' ]
80
+ javascript = [ "MyApp.boot()" ]
81
+
82
+ use Phrender::RackMiddleware, {
83
+ :index_file => index_file,
84
+ :javascript_files => javascript_files,
85
+ :javascript => javascript
86
+ }
87
+ # Additional options are timeout and ssl, if, for some reason, your rack app is
70
88
  # serving up SSL encrypted pages. Run `phantomjs --help` to see available
71
89
  # options, or use something falsey to disable. Both options are passed to
72
90
  # phantom.
73
- phrender = Phrender::RackMiddleware.new(app, options)
74
91
 
75
- # These options are the same as above, but instead of referencing actual files,
76
- # the paths are the request paths to send to the upstream application server.
77
- phrender.index_file 'phrender.html'
78
- phrender.add_javascript_file '/assets/application.js'
79
- phrender.add_javascript "MyApp.boot()"
92
+ # Include other middlewarn
93
+ use Rack::Static, :urls => "/assets", :root => "./assets"
80
94
 
81
95
  # Rackup!
82
- run phrender.rack_app
96
+ run MyRackApp.new
83
97
  ```
84
98
 
85
99
  ## Signalling Render Completion
@@ -1,4 +1,4 @@
1
1
  class Phrender
2
2
  EMBER_DRIVER = File.read(
3
- File.expand_path('../phrender/support/ember_driver.js', __FILE__))
3
+ File.expand_path('../support/ember_driver.js', __FILE__))
4
4
  end
@@ -3,6 +3,7 @@ require 'phrender/phantom_js_session'
3
3
 
4
4
  require 'open3'
5
5
  require 'multi_json'
6
+ require 'tempfile'
6
7
 
7
8
  class Phrender::PhantomJSEngine
8
9
 
@@ -28,8 +29,17 @@ class Phrender::PhantomJSEngine
28
29
  end
29
30
 
30
31
  def render(html, javascript, url = nil)
31
- command = app_cmd(html, javascript, url)
32
- session = Phrender::PhantomJSSession.new command, @timeout
32
+ javascript_file = make_temp_file(javascript, 'file.js')
33
+ html_file = make_temp_file(html, 'file.html')
34
+ program_options = { :html => html_file.path,
35
+ :javascript => javascript_file.path,
36
+ :url => url,
37
+ :timeout => @timeout * 1000.0 }
38
+
39
+ session = Phrender::PhantomJSSession.new @boot_cmd.join(' '), @timeout
40
+
41
+ session.stdin.puts MultiJson.dump(program_options)
42
+ session.stdin.close
33
43
 
34
44
  begin
35
45
  sleep @poll_interval
@@ -39,6 +49,10 @@ class Phrender::PhantomJSEngine
39
49
  # Clean up phantom
40
50
  session.shutdown
41
51
 
52
+ # Clean up temp files
53
+ javascript_file.unlink
54
+ html_file.unlink
55
+
42
56
  # Feed something out the chain
43
57
  if session.rendered
44
58
  session.page
@@ -51,17 +65,15 @@ class Phrender::PhantomJSEngine
51
65
  end
52
66
  end
53
67
 
54
- def app_cmd(html, javascript, url)
55
- program_options = { :html => html,
56
- :javascript => javascript,
57
- :url => url,
58
- :timeout => @timeout }
59
- encoded_options = MultiJson.dump(MultiJson.dump(program_options))
60
- "%s %s" % [ @boot_cmd.join(' '), encoded_options ]
61
- end
62
-
63
68
  protected
64
69
 
70
+ def make_temp_file(data, name)
71
+ file = Tempfile.new(name)
72
+ file.write(data)
73
+ file.close
74
+ file
75
+ end
76
+
65
77
  def parse_output(session)
66
78
  output = session.stdout.gets
67
79
  begin
@@ -18,9 +18,12 @@ class Phrender::PhantomJSSession
18
18
  end
19
19
 
20
20
  def shutdown
21
- @stdin.close
22
- @stdout.close
23
- @stderr.close
21
+ [ @stdin, @stdout, @stderr ].each do |pipe|
22
+ begin
23
+ pipe.close
24
+ rescue IOError
25
+ end
26
+ end
24
27
  begin
25
28
  Process.kill("TERM", @wait_thr.pid)
26
29
  rescue Errno::ESRCH
@@ -1,41 +1,49 @@
1
1
  require 'phrender/phantom_js_engine'
2
- require 'phrender/rack_base'
3
2
 
4
3
  require 'rack'
5
4
 
6
- class Phrender::RackMiddleware < Phrender::RackBase
7
- def initialize(backend, opts = {})
5
+ class Phrender::RackMiddleware
6
+ def initialize(app, opts = {})
7
+ @app = app
8
+ @index_file = opts[:index_file]
9
+ @javascript_paths = opts[:javascript_files]
10
+ @raw_javascript = opts[:javascript].join(';')
8
11
  @phantom = Phrender::PhantomJSEngine.new(opts)
9
- @backend = backend
10
- super
11
12
  end
12
13
 
13
- def rack_app
14
- backend = @backend
15
- @app ||= Rack::Builder.new do
16
- use Proxy
17
- run backend
14
+ def call(env)
15
+ status, headers, body = @app.call(env)
16
+ if (status == 404 || headers['Content-Type'] == 'text/html')
17
+ if (env['HTTP_USER_AGENT'].match(/PhantomJS/))
18
+ [ 500, { 'Content-Type' => 'text/html' }, [
19
+ 'Server Error: HTML file contains recursive lookup' ] ]
20
+ else
21
+ body = render(env['REQUEST_URI'])
22
+ [ 200, { 'Content-Type' => 'text/html' }, [ body ] ]
23
+ end
24
+ else
25
+ [ status, headers, body ]
18
26
  end
19
27
  end
20
28
 
21
- def render(path, app)
22
- program = load_js(app)
23
- html = load_html(app)
24
- @phantom.render(html, program)
25
- end
26
-
27
29
  protected
28
30
 
29
- def load_html(app)
31
+ def render(request_uri)
32
+ program = load_js
33
+ html = load_html
34
+ @phantom.render(html, program, request_uri)
35
+ end
36
+
37
+ def load_html
30
38
  req = Rack::MockRequest.env_for('',
31
39
  'PATH_INFO' => @index_file,
32
40
  'REQUEST_METHOD' => 'GET'
33
41
  )
34
- status, headers, body = app.call(req)
35
- body
42
+ status, headers, body = @app.call(req)
43
+ parse_body body
36
44
  end
37
45
 
38
- def load_js(app)
46
+ def load_js
39
47
  js_from_files = @javascript_paths.map do |path|
40
48
  if path == :ember_driver
41
49
  Phrender::EMBER_DRIVER
@@ -44,12 +52,22 @@ class Phrender::RackMiddleware < Phrender::RackBase
44
52
  'PATH_INFO' => path,
45
53
  'REQUEST_METHOD' => 'GET'
46
54
  )
47
- status, headers, body = app.call(req)
48
- body
55
+ status, headers, body = @app.call(req)
56
+ parse_body body
49
57
  end
50
58
  end.join(';')
51
59
  program = js_from_files + @raw_javascript
52
- program
60
+ program.to_s
61
+ end
62
+
63
+ def parse_body(body)
64
+ if body.respond_to? :each
65
+ data = ''
66
+ body.each{ |part| data << part }
67
+ data
68
+ else
69
+ body.to_s
70
+ end
53
71
  end
54
72
 
55
73
  end
@@ -1,45 +1,12 @@
1
1
  require 'phrender/phantom_js_engine'
2
- require 'phrender/rack_base'
2
+ require 'phrender/rack_middleware'
3
3
 
4
4
  require 'rack'
5
5
 
6
- class Phrender::RackStatic < Phrender::RackBase
7
- def initialize(root_directory, opts = {})
8
- @phantom = Phrender::PhantomJSEngine.new(opts)
9
- @root_directory = root_directory
10
- super
6
+ class Phrender::RackStatic < Phrender::RackMiddleware
7
+ def initialize(opts = {})
8
+ asset_root = opts.delete :asset_root
9
+ app = Rack::File.new(asset_root)
10
+ super(app, opts)
11
11
  end
12
-
13
- def rack_app
14
- static_directory = @root_directory
15
- @app ||= Rack::Builder.new do
16
- use Proxy
17
- run Rack::File.new(static_directory)
18
- end
19
- end
20
-
21
- def render(path, app)
22
- program = load_js(app)
23
- html = load_html(app)
24
- @phantom.render(html, program)
25
- end
26
-
27
- protected
28
-
29
- def load_html(app)
30
- File.read File.join(@root_directory, @index_file)
31
- end
32
-
33
- def load_js(app)
34
- js_from_files = @javascript_paths.map do |path|
35
- if path == :ember_driver
36
- Phrender::EMBER_DRIVER
37
- else
38
- File.read File.join(@root_directory, path)
39
- end
40
- end.join(';')
41
- program = js_from_files + @raw_javascript
42
- program
43
- end
44
-
45
12
  end
@@ -13,4 +13,3 @@ Ember.Route = Ember.Route.extend({
13
13
  this._super.apply(this, arguments);
14
14
  }
15
15
  });
16
-
@@ -6,13 +6,13 @@ var system = require('system'),
6
6
  var stdout = system.stdout;
7
7
 
8
8
  // global opts
9
- var options = JSON.parse(system.args[system.args.length - 1]),
9
+ var options = JSON.parse(fs.read("/dev/stdin")),
10
10
  globals = {
11
11
  "page": null,
12
12
  "timer": null,
13
13
  "expired": false,
14
14
  "rendered": false,
15
- "html": options.html
15
+ "html": fs.read(options.html)
16
16
  };
17
17
 
18
18
  // functions
@@ -61,8 +61,9 @@ printPage = function(url) {
61
61
  // Log javascript console messages
62
62
  globals.page.onConsoleMessage = function(msg) {
63
63
  if (msg.trim() === "-- PHRENDER COMPLETE --"){
64
+ logMessage('phrender complete');
64
65
  globals.rendered = true;
65
- } else {
66
+ } else if (!msg.match(/^\[✓\].+/)) {
66
67
  logMessage(msg);
67
68
  }
68
69
  };
@@ -70,9 +71,7 @@ printPage = function(url) {
70
71
  // capture errors
71
72
  globals.page.onError = logError;
72
73
 
73
- globals.page.evaluate(function(code) {
74
- eval(code);
75
- }, options.javascript);
74
+ globals.page.injectJs(options.javascript);
76
75
 
77
76
  // Catch something
78
77
  globals.timer = setTimeout(writeHtml, options.timeout);
@@ -1,3 +1,3 @@
1
1
  class Phrender
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/phrender.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require "phrender/version"
2
2
  require "phrender/logger"
3
+ require "phrender/ember_driver"
3
4
  require "phrender/phantom_js_engine"
4
5
  require "phrender/phantom_js_session"
5
- require "phrender/rack_base"
6
6
  require "phrender/rack_middleware"
7
7
  require "phrender/rack_static"
8
8
 
@@ -14,16 +14,6 @@ describe 'Phrender::PhantomJSEngine' do
14
14
  File.read(File.expand_path('../phantom_js_engine/app.js', __FILE__))
15
15
  }
16
16
 
17
- it 'generates a startup command with escaped json' do
18
- command = phantom.app_cmd(index, app, 'http://localhost')
19
- expect(command).to match(
20
- /phantomjs (.+?)phrender\/lib\/phrender\/support\/phantom_bridge.js/
21
- )
22
- expect(command).to include("--ignore-ssl-errors=true")
23
- expect(command).to include("<html>")
24
- expect(command).to include("use strict")
25
- end
26
-
27
17
  it 'renders a simple page' do
28
18
  whitespace_regex = /(\n|^ +)/
29
19
  html = <<-HTML.strip_heredoc.gsub(whitespace_regex, '')
@@ -10,11 +10,19 @@ describe 'Phrender::RackMiddleware' do
10
10
  b
11
11
  }
12
12
  let(:app) {
13
- p = Phrender::RackMiddleware.new(backend)
14
- p.index_file = 'phrender.html'
15
- p.add_javascript_file 'app.js'
16
- p.add_javascript 'App.run'
17
- p.rack_app
13
+ _backend = backend # Needed because builder changes the block's context
14
+ Rack::Builder.new do
15
+ use Phrender::RackMiddleware, {
16
+ :index_file => 'phrender.html',
17
+ :javascript_files => [
18
+ 'app.js'
19
+ ],
20
+ :javascript => [
21
+ "App.run()"
22
+ ]
23
+ }
24
+ run _backend
25
+ end
18
26
  }
19
27
 
20
28
  it 'runs the app contained in the referenced assets' do
@@ -4,11 +4,16 @@ require 'phrender/rack_static'
4
4
  describe 'Phrender::RackStatic' do
5
5
  let(:root) { File.expand_path '../rack_static', __FILE__ }
6
6
  let(:app) {
7
- p = Phrender::RackStatic.new(root)
8
- p.index_file = 'phrender.html'
9
- p.add_javascript_file 'app.js'
10
- p.add_javascript 'App.run'
11
- p.rack_app
7
+ Phrender::RackStatic.new({
8
+ :asset_root => root,
9
+ :index_file => 'phrender.html',
10
+ :javascript_files => [
11
+ 'app.js'
12
+ ],
13
+ :javascript => [
14
+ "App.run()"
15
+ ]
16
+ })
12
17
  }
13
18
 
14
19
  it 'runs the app contained in the referenced assets' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phrender
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - M Smart, theScore Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-23 00:00:00.000000000 Z
11
+ date: 2014-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -153,7 +153,6 @@ files:
153
153
  - lib/phrender/logger.rb
154
154
  - lib/phrender/phantom_js_engine.rb
155
155
  - lib/phrender/phantom_js_session.rb
156
- - lib/phrender/rack_base.rb
157
156
  - lib/phrender/rack_middleware.rb
158
157
  - lib/phrender/rack_static.rb
159
158
  - lib/phrender/support/ember_driver.js
@@ -1,50 +0,0 @@
1
- class Phrender::RackBase
2
- class Proxy
3
- class << self
4
- attr_accessor :host
5
- end
6
-
7
- def initialize(app)
8
- @app = app
9
- end
10
-
11
- def call(env)
12
- self.class.host.call(env, @app)
13
- end
14
- end
15
-
16
- attr_accessor :index_file
17
-
18
- def initialize(*args)
19
- @javascript_paths = []
20
- @raw_javascript = ''
21
- Proxy.host = self
22
- end
23
-
24
- def rack_app
25
- raise NotImplementedError
26
- end
27
-
28
- def render(path, app)
29
- raise NotImplementedError
30
- end
31
-
32
- def call(env, app)
33
- status, headers, body = app.call(env)
34
- if status == 404
35
- body = render(env['PATH_INFO'], app)
36
- [ 200, { 'Content-Type' => 'text/html' }, body ]
37
- else
38
- [ status, headers, body ]
39
- end
40
- end
41
-
42
- def add_javascript_file(path)
43
- @javascript_paths.push path
44
- end
45
-
46
- def add_javascript(code)
47
- @raw_javascript << ';' + code
48
- end
49
-
50
- end