hypernova 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +38 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +211 -0
- data/Rakefile +7 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/hypernova.gemspec +42 -0
- data/lib/hypernova/batch.rb +49 -0
- data/lib/hypernova/batch_renderer.rb +65 -0
- data/lib/hypernova/batch_url_builder.rb +13 -0
- data/lib/hypernova/blank_renderer.rb +34 -0
- data/lib/hypernova/configuration.rb +34 -0
- data/lib/hypernova/controller_helpers.rb +106 -0
- data/lib/hypernova/faraday_connection.rb +17 -0
- data/lib/hypernova/faraday_request.rb +11 -0
- data/lib/hypernova/http_client_request.rb +21 -0
- data/lib/hypernova/parsed_response.rb +24 -0
- data/lib/hypernova/plugin_helper.rb +59 -0
- data/lib/hypernova/plugins/development_mode_plugin.rb +27 -0
- data/lib/hypernova/rails/action_controller.rb +9 -0
- data/lib/hypernova/request.rb +33 -0
- data/lib/hypernova/request_service.rb +34 -0
- data/lib/hypernova/response.rb +64 -0
- data/lib/hypernova/version.rb +3 -0
- data/lib/hypernova.rb +66 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6154064fe73279cdc77345298bdf5739bd92acd9
|
4
|
+
data.tar.gz: 7cd5efc03841f7897c80ef0eb297a24e45d3e758
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1c2f2306577a3f8542c77995c962a8ea713d54cb17ef06110b2bce04d9a465f8aa2eb9e037dcb2f50b21d6ab26c1838cd483c51bd78fe389425477b2ce39bef5
|
7
|
+
data.tar.gz: 8b6f89f50c0597b6f552ab575054836f513c8717effa6ec5370555900a431a9a94edd1b5f86251ef2d49f120e2972d972875ce334ee872fa4eb265a3dac43600
|
data/.gitignore
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalization:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
37
|
+
|
38
|
+
mystique-ruby-*.gem
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Airbnb
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
# hypernova-ruby [](https://travis-ci.org/airbnb/hypernova-ruby)
|
2
|
+
|
3
|
+
> A Ruby client for the Hypernova service
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
Add this line to your application’s Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'hypernova'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install hypernova
|
20
|
+
|
21
|
+
|
22
|
+
In Rails, create an initializer in `config/initializers/hypernova.rb`.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
# Really basic configuration only consists of the host and the port
|
26
|
+
Hypernova.configure do |config|
|
27
|
+
config.host = "localhost"
|
28
|
+
config.port = 80
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
Add an `:around_filter` to your controller so you can opt into Hypernova rendering of view partials.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# In my_controller.rb
|
36
|
+
require 'hypernova'
|
37
|
+
|
38
|
+
class MyController < ApplicationController
|
39
|
+
around_filter :hypernova_render_support
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
Use the following methods to render React components in your view/templates.
|
44
|
+
|
45
|
+
```erb
|
46
|
+
<%=
|
47
|
+
render_react_component(
|
48
|
+
'MyComponent.js',
|
49
|
+
:name => 'Person',
|
50
|
+
:color => 'Blue',
|
51
|
+
:shape => 'Triangle'
|
52
|
+
)
|
53
|
+
%>
|
54
|
+
```
|
55
|
+
|
56
|
+
## Configuration
|
57
|
+
|
58
|
+
You can pass more configuration options to Hypernova.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
Hypernova.configure do |config|
|
62
|
+
config.http_adapter = :patron # Use any adapter supported by Faraday
|
63
|
+
config.host = "localhost"
|
64
|
+
config.port = 80
|
65
|
+
config.open_timeout = 0.1
|
66
|
+
config.scheme = :https # Valid schemes include :http and :https
|
67
|
+
config.timeout = 0.6
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
If you do not want to use `Faraday`, you can configure Hypernova Ruby to use an HTTP client that
|
72
|
+
responds to `post` and accepts a hash argument.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Hypernova.configure do |config|
|
76
|
+
# Use your own HTTP client!
|
77
|
+
config.http_client = SampleHTTPClient.new
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
You can access a lower-level interface to exactly specify the parameters that are sent to the
|
82
|
+
Hypernova service.
|
83
|
+
|
84
|
+
```erb
|
85
|
+
<% things.each |thing| %>
|
86
|
+
<li>
|
87
|
+
<%=
|
88
|
+
hypernova_batch_render(
|
89
|
+
:name => 'your/component/thing.bundle.js',
|
90
|
+
:data => thing
|
91
|
+
)
|
92
|
+
%>
|
93
|
+
</li>
|
94
|
+
<% end %>
|
95
|
+
```
|
96
|
+
|
97
|
+
You can also use the batch interface if you want to create and submit batches yourself:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
batch = Hypernova::Batch.new(service)
|
101
|
+
|
102
|
+
# each job in a hypernova render batch is identified by a token
|
103
|
+
# this allows retrieval of unordered jobs
|
104
|
+
token = batch.render(
|
105
|
+
:name => 'some_bundle.bundle.js',
|
106
|
+
:data => {foo: 1, bar: 2}
|
107
|
+
)
|
108
|
+
token2 = batch.render(
|
109
|
+
:name => 'some_bundle.bundle.js',
|
110
|
+
:data => {foo: 2, bar: 1}
|
111
|
+
)
|
112
|
+
# now we can submit the batch job and await its results
|
113
|
+
# this blocks, and takes a significant time in round trips, so try to only
|
114
|
+
# use it once per request!
|
115
|
+
result = batch.submit!
|
116
|
+
|
117
|
+
# ok now we can access our rendered strings.
|
118
|
+
foo1 = result[token].html_safe
|
119
|
+
foo2 = result[token2].html_safe
|
120
|
+
```
|
121
|
+
|
122
|
+
## Plugins
|
123
|
+
|
124
|
+
Hypernova enables you to control and alter requests at different stages of
|
125
|
+
the render lifecycle via a plugin system.
|
126
|
+
|
127
|
+
### Example
|
128
|
+
|
129
|
+
All methods on a plugin are optional, and they are listed in the order that
|
130
|
+
they are called.
|
131
|
+
|
132
|
+
**initializers/hypernova.rb:**
|
133
|
+
```ruby
|
134
|
+
# initializers/hypernova.rb
|
135
|
+
require 'hypernova'
|
136
|
+
|
137
|
+
class HypernovaPlugin
|
138
|
+
# get_view_data allows you to alter the data given to any individual
|
139
|
+
# component being rendered.
|
140
|
+
# component is the name of the component being rendered.
|
141
|
+
# data is the data being given to the component.
|
142
|
+
def get_view_data(component_name, data)
|
143
|
+
phrase_hash = data[:phrases]
|
144
|
+
data[:phrases].keys.each do |phrase_key|
|
145
|
+
phrase_hash[phrase_key] = "test phrase"
|
146
|
+
end
|
147
|
+
data
|
148
|
+
end
|
149
|
+
|
150
|
+
# prepare_request allows you to alter the request object in any way that you
|
151
|
+
# need.
|
152
|
+
# Unless manipulated by another plugin, request takes the shape:
|
153
|
+
# { 'component_name.js': { :name => 'component_name.js', :data => {} } }
|
154
|
+
def prepare_request(current_request, original_request)
|
155
|
+
current_request.keys.each do |key|
|
156
|
+
phrase_hash = req[key][:data][:phrases]
|
157
|
+
if phrase_hash.present?
|
158
|
+
phrase_hash.keys.each do |phrase_key|
|
159
|
+
phrase_hash[phrase_key] = phrase_hash[phrase_key].upcase
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
current_request
|
164
|
+
end
|
165
|
+
|
166
|
+
# send_request? allows you to determine whether a request should continue
|
167
|
+
# on to the hypernova server. Returning false prevents the request from
|
168
|
+
# occurring, and results in the fallback html.
|
169
|
+
def send_request?(request)
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
173
|
+
# after_response gives you a chance to alter the response from hypernova.
|
174
|
+
# This will be most useful for altering the resulting html field, and special
|
175
|
+
# handling of any potential errors.
|
176
|
+
# res is a Hash like { 'component_name.js': { html: String, err: Error? } }
|
177
|
+
def after_response(current_response, original_response)
|
178
|
+
current_response.keys.each do |key|
|
179
|
+
hash = current_response[key]
|
180
|
+
hash['html'] = '<div>hello</div>'
|
181
|
+
end
|
182
|
+
current_response
|
183
|
+
end
|
184
|
+
|
185
|
+
# NOTE: If an error happens in here, it won’t be caught.
|
186
|
+
def on_error(error, jobs)
|
187
|
+
puts "Oh no, error - #{error}, jobs - #{jobs}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
Hypernova.add_plugin!(HypernovaPlugin.new)
|
192
|
+
```
|
193
|
+
|
194
|
+
## Development
|
195
|
+
|
196
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
197
|
+
`bin/console` for an interactive prompt that will allow you to experiment.
|
198
|
+
|
199
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
200
|
+
release a new version, update the version number in `version.rb`, and then run
|
201
|
+
`bundle exec rake release` to create a git tag for the version, push git
|
202
|
+
commits and tags, and push the `.gem` file to
|
203
|
+
[rubygems.org](https://rubygems.org).
|
204
|
+
|
205
|
+
## Contributing
|
206
|
+
|
207
|
+
1. Fork it ( https://github.com/[my-github-username]/hypernova/fork )
|
208
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
209
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
210
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
211
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "hypernova"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/hypernova.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "hypernova/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.authors = %w(
|
8
|
+
Jake Teton-Landis
|
9
|
+
Jordan Harband
|
10
|
+
Ian Christian Myers
|
11
|
+
Tommy Dang
|
12
|
+
)
|
13
|
+
spec.bindir = "exe"
|
14
|
+
spec.description = "A Ruby client for the Hypernova service"
|
15
|
+
spec.email = %w(
|
16
|
+
jake.tl@airbnb.com
|
17
|
+
ljharb@gmail.com
|
18
|
+
ian.myers@airbnb.com
|
19
|
+
tommy.dang@airbnb.com
|
20
|
+
)
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
spec.homepage = 'https://github.com/airbnb/hypernova-ruby'
|
24
|
+
spec.license = 'MIT'
|
25
|
+
spec.name = 'hypernova'
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
spec.summary = %q{Batch interface for Hypernova, the React render service.}
|
28
|
+
spec.version = Hypernova::VERSION
|
29
|
+
|
30
|
+
if spec.respond_to?(:metadata)
|
31
|
+
spec.metadata["allowed_push_host"] = 'https://rubygems.org'
|
32
|
+
end
|
33
|
+
|
34
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
35
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
+
spec.add_development_dependency "rspec", "~> 3.4"
|
37
|
+
spec.add_development_dependency "simplecov", "~> 0.11"
|
38
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
39
|
+
spec.add_development_dependency "webmock", "~> 2.0"
|
40
|
+
|
41
|
+
spec.add_runtime_dependency "faraday", "~> 0.8"
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Hypernova
|
4
|
+
class Batch
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_accessor :service
|
8
|
+
attr_reader :jobs
|
9
|
+
|
10
|
+
def_delegators :jobs, :empty?
|
11
|
+
|
12
|
+
##
|
13
|
+
# @param service the Hypernova backend service to use for render_react_batch
|
14
|
+
# The only requirement for the `service` object is the method render_react_batch
|
15
|
+
# which should accept a Hash of { job_token :: Scalar => job_data :: Hash }
|
16
|
+
# the subscript operator, to access result via tokens
|
17
|
+
def initialize(service)
|
18
|
+
# TODO: make hashmap instead????
|
19
|
+
@jobs = []
|
20
|
+
@service = service
|
21
|
+
end
|
22
|
+
|
23
|
+
def render(job)
|
24
|
+
Hypernova.verify_job_shape(job)
|
25
|
+
token = jobs.length
|
26
|
+
jobs << job
|
27
|
+
token.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def submit!
|
31
|
+
service.render_batch(jobs_hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
def submit_fallback!
|
35
|
+
service.render_batch_blank(jobs_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :service
|
41
|
+
|
42
|
+
# creates a hash with each index mapped to the value at that index
|
43
|
+
def jobs_hash
|
44
|
+
hash = {}
|
45
|
+
jobs.each_with_index { |job, idx| hash[idx.to_s] = job }
|
46
|
+
hash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "hypernova/blank_renderer"
|
2
|
+
|
3
|
+
class Hypernova::BatchRenderer
|
4
|
+
def initialize(jobs)
|
5
|
+
@jobs = jobs
|
6
|
+
end
|
7
|
+
|
8
|
+
# Sample response argument:
|
9
|
+
# {
|
10
|
+
# "DeathStarLaserComponent.js" => {
|
11
|
+
# "duration" => 17,
|
12
|
+
# "error" => nil,
|
13
|
+
# "html" => "<h1>Hello World</h1>",
|
14
|
+
# "statusCode" => 200,
|
15
|
+
# "success" => true,
|
16
|
+
# },
|
17
|
+
# "IonCannon.js" => {
|
18
|
+
# "duration" => 7,
|
19
|
+
# "error" => {
|
20
|
+
# "stack" => [
|
21
|
+
# "no_plans",
|
22
|
+
# "not_enough_resources",
|
23
|
+
# ],
|
24
|
+
# },
|
25
|
+
# "html" => blank_html_rendered_by_blank_renderer,
|
26
|
+
# "statusCode" => 500,
|
27
|
+
# "success" => false,
|
28
|
+
# },
|
29
|
+
# }
|
30
|
+
|
31
|
+
# Example of what is returned by this method:
|
32
|
+
# {
|
33
|
+
# "DeathStarLaserComponent.js" => "<h1>Hello World</h1>",
|
34
|
+
# "IonCannon.js" => <p>Feel my power!</p>,
|
35
|
+
# }
|
36
|
+
def render(response)
|
37
|
+
response.each_with_object({}) do |array, hash|
|
38
|
+
name_of_component = array[0]
|
39
|
+
hash[name_of_component] = extract_html_from_result(name_of_component, array[1])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Example of what is returned by this method:
|
44
|
+
# {
|
45
|
+
# "DeathStarLaserComponent.js" => <div>I am blank</div>,
|
46
|
+
# "IonCannon.js" => <div>I am blank</div>,
|
47
|
+
# }
|
48
|
+
def render_blank
|
49
|
+
hash = {}
|
50
|
+
jobs.each { |name_of_component, job| hash[name_of_component] = render_blank_html(job) }
|
51
|
+
hash
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
attr_reader :jobs
|
57
|
+
|
58
|
+
def extract_html_from_result(name_of_component, result)
|
59
|
+
result["html"].nil? ? render_blank_html(jobs[name_of_component]) : result["html"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def render_blank_html(job)
|
63
|
+
Hypernova::BlankRenderer.new(job).render
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "uri"
|
2
|
+
|
3
|
+
class Hypernova::BatchUrlBuilder
|
4
|
+
def self.base_url
|
5
|
+
configuration = Hypernova.configuration
|
6
|
+
builder = configuration.scheme == :https ? URI::HTTPS : URI::HTTP
|
7
|
+
builder.build(host: configuration.host, port: configuration.port).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.path
|
11
|
+
"/batch"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
class Hypernova::BlankRenderer
|
4
|
+
def initialize(job)
|
5
|
+
@job = job
|
6
|
+
end
|
7
|
+
|
8
|
+
def render
|
9
|
+
<<-HTML
|
10
|
+
<div data-hypernova-key="#{key}"></div>
|
11
|
+
<script type="application/json" data-hypernova-key="#{key}"><!--#{encode}--></script>
|
12
|
+
HTML
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :job
|
18
|
+
|
19
|
+
def data
|
20
|
+
job[:data]
|
21
|
+
end
|
22
|
+
|
23
|
+
def encode
|
24
|
+
JSON.generate(data).gsub(/&/, '&').gsub(/>/, '>')
|
25
|
+
end
|
26
|
+
|
27
|
+
def key
|
28
|
+
name.gsub(/\W/, "")
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
job[:name]
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "faraday"
|
2
|
+
|
3
|
+
class Hypernova::Configuration
|
4
|
+
VALID_SCHEMES = [:http, :https].freeze
|
5
|
+
|
6
|
+
attr_accessor :http_adapter,
|
7
|
+
:http_client,
|
8
|
+
:host,
|
9
|
+
:open_timeout,
|
10
|
+
:port,
|
11
|
+
:scheme,
|
12
|
+
:timeout
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@open_timeout = 0.1
|
16
|
+
@scheme = :http
|
17
|
+
@timeout = 0.6
|
18
|
+
end
|
19
|
+
|
20
|
+
def http_adapter
|
21
|
+
@http_adapter || Faraday.default_adapter
|
22
|
+
end
|
23
|
+
|
24
|
+
def scheme=(value)
|
25
|
+
validate_scheme!(value)
|
26
|
+
@scheme = value
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_scheme!(value)
|
32
|
+
raise TypeError.new("Unknown scheme #{value}") unless VALID_SCHEMES.include?(value)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "hypernova/plugin_helper"
|
2
|
+
require "hypernova/request_service"
|
3
|
+
|
4
|
+
module Hypernova
|
5
|
+
##
|
6
|
+
# Mixin.
|
7
|
+
# Implements the high-level rails helper interface.
|
8
|
+
# Currently untested.
|
9
|
+
module ControllerHelpers
|
10
|
+
include Hypernova::PluginHelper
|
11
|
+
|
12
|
+
##
|
13
|
+
# a Rails around_filter to support hypernova batch rendering.
|
14
|
+
def hypernova_render_support
|
15
|
+
hypernova_batch_before
|
16
|
+
yield
|
17
|
+
hypernova_batch_after
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# enqueue a render into the current request's hypernova batch
|
22
|
+
def hypernova_batch_render(job)
|
23
|
+
if @hypernova_batch.nil?
|
24
|
+
raise NilBatchError.new('called hypernova_batch_render without calling '\
|
25
|
+
'hypernova_batch_before. Check your around_filter for :hypernova_render_support')
|
26
|
+
end
|
27
|
+
batch_token = @hypernova_batch.render(job)
|
28
|
+
template_safe_token = Hypernova.render_token(batch_token)
|
29
|
+
@hypernova_batch_mapping[template_safe_token] = batch_token
|
30
|
+
template_safe_token
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# shortcut method to render a react component
|
35
|
+
# @param [String] name the hypernova bundle name, like 'packages/p3/foo.bundle.js' (for now)
|
36
|
+
# @param [Hash] props the props to be passed to the component
|
37
|
+
# :^)k|8 <-- this is a chill peep riding a skateboard
|
38
|
+
def render_react_component(component, data = {})
|
39
|
+
begin
|
40
|
+
new_data = get_view_data(component, data)
|
41
|
+
rescue StandardError => e
|
42
|
+
on_error(e)
|
43
|
+
new_data = data
|
44
|
+
end
|
45
|
+
job = {
|
46
|
+
:data => new_data,
|
47
|
+
:name => component,
|
48
|
+
}
|
49
|
+
|
50
|
+
hypernova_batch_render(job)
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Retrieve a handle to a hypernova service
|
55
|
+
# OVERRIDE IN YOUR IMPLEMENTATION CLASS TO GET A DIFFERENT SERVICE
|
56
|
+
def hypernova_service
|
57
|
+
@_hypernova_service ||= Hypernova::RequestService.new
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
##
|
63
|
+
# set up a new hypernova batch for this request.
|
64
|
+
# The batch's service is provided by instance method #hypernova_service
|
65
|
+
# which you should override after including this mixin.
|
66
|
+
def hypernova_batch_before
|
67
|
+
@hypernova_batch = Hypernova::Batch.new(hypernova_service)
|
68
|
+
@hypernova_batch_mapping = {}
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Modifies response.body to have all batched hypernova render results
|
73
|
+
def hypernova_batch_after
|
74
|
+
if @hypernova_batch.nil?
|
75
|
+
raise NilBatchError.new('called hypernova_batch_after without calling '\
|
76
|
+
'hypernova_batch_before. Check your around_filter for :hypernova_render_support')
|
77
|
+
end
|
78
|
+
return if @hypernova_batch.empty?
|
79
|
+
|
80
|
+
jobs = @hypernova_batch.jobs
|
81
|
+
hash = jobs.each_with_object({}) do |job, h|
|
82
|
+
h[job[:name]] = job
|
83
|
+
end
|
84
|
+
hash = prepare_request(hash, hash)
|
85
|
+
if send_request?(hash)
|
86
|
+
begin
|
87
|
+
will_send_request(hash)
|
88
|
+
result = @hypernova_batch.submit!
|
89
|
+
on_success(result, hash)
|
90
|
+
rescue StandardError => e
|
91
|
+
on_error(e)
|
92
|
+
result = @hypernova_batch.submit_fallback!
|
93
|
+
end
|
94
|
+
else
|
95
|
+
result = @hypernova_batch.submit_fallback!
|
96
|
+
end
|
97
|
+
|
98
|
+
new_body = Hypernova.replace_tokens_with_result(
|
99
|
+
response.body,
|
100
|
+
@hypernova_batch_mapping,
|
101
|
+
result
|
102
|
+
)
|
103
|
+
response.body = new_body
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "hypernova/batch_url_builder"
|
3
|
+
|
4
|
+
class Hypernova::FaradayConnection
|
5
|
+
def self.build
|
6
|
+
configuration = Hypernova.configuration
|
7
|
+
Faraday.new(
|
8
|
+
request: {
|
9
|
+
open_timeout: configuration.open_timeout,
|
10
|
+
timeout: configuration.timeout,
|
11
|
+
},
|
12
|
+
url: Hypernova::BatchUrlBuilder.base_url,
|
13
|
+
) do |builder|
|
14
|
+
builder.adapter(configuration.http_adapter) if configuration.http_adapter
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "hypernova/faraday_connection"
|
2
|
+
|
3
|
+
class Hypernova::FaradayRequest
|
4
|
+
def self.post(payload)
|
5
|
+
Hypernova::FaradayConnection.build.post do |request|
|
6
|
+
request.url(Hypernova::BatchUrlBuilder.path)
|
7
|
+
request.headers["Content-Type"] = "application/json"
|
8
|
+
request.body = payload[:body].to_json
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "hypernova/batch_url_builder"
|
2
|
+
|
3
|
+
class Hypernova::HttpClientRequest
|
4
|
+
def self.post(payload)
|
5
|
+
if is_client_requiring_1_argument?
|
6
|
+
client.post(Hypernova::BatchUrlBuilder.path, payload)
|
7
|
+
else
|
8
|
+
client.post(payload)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.client
|
13
|
+
Hypernova.configuration.http_client
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.is_client_requiring_1_argument?
|
17
|
+
client.method(:post).arity == -2
|
18
|
+
end
|
19
|
+
|
20
|
+
private_class_method :client, :is_client_requiring_1_argument?
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "hypernova/request"
|
2
|
+
require "hypernova/response"
|
3
|
+
|
4
|
+
class Hypernova::ParsedResponse
|
5
|
+
def initialize(jobs)
|
6
|
+
@jobs = jobs
|
7
|
+
end
|
8
|
+
|
9
|
+
def body
|
10
|
+
response.parsed_body
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :jobs
|
16
|
+
|
17
|
+
def request
|
18
|
+
Hypernova::Request.new(jobs)
|
19
|
+
end
|
20
|
+
|
21
|
+
def response
|
22
|
+
Hypernova::Response.new(request)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Hypernova::PluginHelper
|
2
|
+
def get_view_data(name, data)
|
3
|
+
Hypernova.plugins.reduce(data) do |data, plugin|
|
4
|
+
if plugin.respond_to?(:get_view_data)
|
5
|
+
plugin.get_view_data(name, data)
|
6
|
+
else
|
7
|
+
data
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare_request(current_request, original_request)
|
13
|
+
Hypernova.plugins.reduce(current_request) do |req, plugin|
|
14
|
+
if plugin.respond_to?(:prepare_request)
|
15
|
+
plugin.prepare_request(req, original_request)
|
16
|
+
else
|
17
|
+
req
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_request?(jobs_hash)
|
23
|
+
Hypernova.plugins.all? do |plugin|
|
24
|
+
if plugin.respond_to?(:send_request?)
|
25
|
+
plugin.send_request?(jobs_hash)
|
26
|
+
else
|
27
|
+
true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def will_send_request(jobs_hash)
|
33
|
+
Hypernova.plugins.each do |plugin|
|
34
|
+
if plugin.respond_to?(:will_send_request)
|
35
|
+
plugin.will_send_request(jobs_hash)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def after_response(current_response, original_response)
|
41
|
+
Hypernova.plugins.reduce(current_response) do |response, plugin|
|
42
|
+
if plugin.methods.include?(:after_response)
|
43
|
+
plugin.after_response(response, original_response)
|
44
|
+
else
|
45
|
+
response
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_error(error, job = {})
|
51
|
+
Hypernova.plugins.each { |plugin| plugin.on_error(error, job) if plugin.respond_to?(:on_error) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_success(res, jobs_hash)
|
55
|
+
Hypernova.plugins.each do |plugin|
|
56
|
+
plugin.on_success(res, jobs_hash) if plugin.respond_to?(:on_success)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class DevelopmentModePlugin
|
2
|
+
def after_response(current_response, _)
|
3
|
+
current_response.each do |name, result|
|
4
|
+
current_response[name] = result.merge({ "html" => render(name, result) }) if result["error"]
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def render(name, result)
|
11
|
+
<<-HTML
|
12
|
+
<div style="background-color: #ff5a5f; color: #fff; padding: 12px;">
|
13
|
+
<p style="margin: 0">
|
14
|
+
<strong>Development Warning!</strong>
|
15
|
+
The <code>#{name}</code> component failed to render with Hypernova. Error stack:
|
16
|
+
</p>
|
17
|
+
<ul style="padding: 0 20px">
|
18
|
+
<li>#{stack_trace(result).join("</li><li>")}</li>
|
19
|
+
</ul>
|
20
|
+
</div>
|
21
|
+
HTML
|
22
|
+
end
|
23
|
+
|
24
|
+
def stack_trace(result)
|
25
|
+
result["error"]["stack"] || []
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "hypernova/faraday_request"
|
2
|
+
require "hypernova/http_client_request"
|
3
|
+
|
4
|
+
class Hypernova::Request
|
5
|
+
def initialize(jobs)
|
6
|
+
@jobs = jobs
|
7
|
+
end
|
8
|
+
|
9
|
+
def body
|
10
|
+
post.body
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :jobs
|
16
|
+
|
17
|
+
def payload
|
18
|
+
{
|
19
|
+
:body => jobs,
|
20
|
+
:idempotent => true,
|
21
|
+
:request_format => :json,
|
22
|
+
:response_format => :json,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def post
|
27
|
+
if Hypernova.configuration.http_client
|
28
|
+
Hypernova::HttpClientRequest.post(payload)
|
29
|
+
else
|
30
|
+
Hypernova::FaradayRequest.post(payload)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "hypernova/batch_renderer"
|
2
|
+
require "hypernova/parsed_response"
|
3
|
+
require "hypernova/plugin_helper"
|
4
|
+
|
5
|
+
class Hypernova::RequestService
|
6
|
+
include Hypernova::PluginHelper
|
7
|
+
|
8
|
+
def render_batch(jobs)
|
9
|
+
return render_batch_blank(jobs) if jobs.empty?
|
10
|
+
response_body = Hypernova::ParsedResponse.new(jobs).body
|
11
|
+
response_body.each do |index_string, resp|
|
12
|
+
error(resp["error"], jobs[index_string.to_i]) if resp["error"]
|
13
|
+
end
|
14
|
+
build_renderer(jobs).render(response_body)
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_batch_blank(jobs)
|
18
|
+
build_renderer(jobs).render_blank
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_error(name, message)
|
24
|
+
Module.const_get(name).new(message)
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_renderer(jobs)
|
28
|
+
Hypernova::BatchRenderer.new(jobs)
|
29
|
+
end
|
30
|
+
|
31
|
+
def error(error_data, job)
|
32
|
+
on_error(build_error(error_data["name"], error_data["message"]), job)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "json"
|
2
|
+
require "hypernova/plugin_helper"
|
3
|
+
|
4
|
+
class Hypernova::Response
|
5
|
+
include Hypernova::PluginHelper
|
6
|
+
|
7
|
+
def initialize(request)
|
8
|
+
@request = request
|
9
|
+
end
|
10
|
+
|
11
|
+
# Example parsed body with no error:
|
12
|
+
# {
|
13
|
+
# "0" => {
|
14
|
+
# "name" => "hello_world.js",
|
15
|
+
# "html" => "<div>Hello World</div>",
|
16
|
+
# "meta" => {},
|
17
|
+
# "duration" => 100,
|
18
|
+
# "statusCode" => 200,
|
19
|
+
# "success" => true,
|
20
|
+
# "error" => nil,
|
21
|
+
# }
|
22
|
+
# }
|
23
|
+
|
24
|
+
# Example parsed body with error:
|
25
|
+
# {
|
26
|
+
# "0" => {
|
27
|
+
# "html" => "<p>Error!</p>",
|
28
|
+
# "name" => "goodbye_galaxy.js",
|
29
|
+
# "meta" => {},
|
30
|
+
# "duration" => 100,
|
31
|
+
# "statusCode" => 500,
|
32
|
+
# "success" => false,
|
33
|
+
# "error" => {
|
34
|
+
# "name" => "TypeError",
|
35
|
+
# "message" => "Cannot read property 'forEach' of undefined",
|
36
|
+
# "stack" => [
|
37
|
+
# "TypeError: Cannot read property 'forEach' of undefined",
|
38
|
+
# "at TravelerLanding.componentWillMount",
|
39
|
+
# "at ReactCompositeComponentMixin.mountComponent",
|
40
|
+
# ],
|
41
|
+
# },
|
42
|
+
# }
|
43
|
+
# }
|
44
|
+
def parsed_body
|
45
|
+
response = parse_body
|
46
|
+
# This enables backward compatibility with the old server response format.
|
47
|
+
# In the new format, the response results are contained within a "results" key. The top level
|
48
|
+
# hash contains a "success" and "error" which relates to the whole batch.
|
49
|
+
response = response["results"] || response
|
50
|
+
after_response(response, response)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :request
|
56
|
+
|
57
|
+
def body
|
58
|
+
request.body
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_body
|
62
|
+
JSON.parse(body)
|
63
|
+
end
|
64
|
+
end
|
data/lib/hypernova.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "hypernova/batch"
|
2
|
+
require "hypernova/configuration"
|
3
|
+
require "hypernova/rails/action_controller"
|
4
|
+
require "hypernova/version"
|
5
|
+
|
6
|
+
module Hypernova
|
7
|
+
# thrown by ControllerHelper methods if you don't call hypernova_batch_before first
|
8
|
+
class NilBatchError < StandardError; end
|
9
|
+
|
10
|
+
# thrown by Batch#render if your job doesn't have the right keys and stuff.
|
11
|
+
class BadJobError < StandardError; end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure
|
18
|
+
self.configuration ||= Hypernova::Configuration.new
|
19
|
+
yield(configuration)
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: more interesting token format?
|
23
|
+
RENDER_TOKEN_REGEX = /__hypernova_render_token\[\w+\]__/
|
24
|
+
|
25
|
+
def self.render_token(batch_token)
|
26
|
+
"__hypernova_render_token[#{batch_token}]__"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.plugins
|
30
|
+
@plugins ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.add_plugin!(plugin)
|
34
|
+
plugins << plugin
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# replace all hypernova tokens in `body` with the render results given by batch_result,
|
39
|
+
# using render_token_to_batch_token to map render tokens into batch tokens
|
40
|
+
# @param [String] body
|
41
|
+
# @param [Hash] render_token_to_batch_token
|
42
|
+
# @param respond_to(:[]) batch_result
|
43
|
+
def self.replace_tokens_with_result(body, render_token_to_batch_token, batch_result)
|
44
|
+
# replace all render tokens in the current response body with the
|
45
|
+
# hypernova result for that render.
|
46
|
+
return body.gsub(RENDER_TOKEN_REGEX) do |render_token|
|
47
|
+
batch_token = render_token_to_batch_token[render_token]
|
48
|
+
if batch_token.nil?
|
49
|
+
next render_token
|
50
|
+
end
|
51
|
+
render_result = batch_result[batch_token]
|
52
|
+
# replace with that render result.
|
53
|
+
next render_result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# raises a BadJobError if the job hash is not of the right shape.
|
59
|
+
def self.verify_job_shape(job)
|
60
|
+
[:name, :data].each do |key|
|
61
|
+
if job[key].nil?
|
62
|
+
raise BadJobError.new("Hypernova render jobs must have key #{key}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hypernova
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jake
|
8
|
+
- Teton-Landis
|
9
|
+
- Jordan
|
10
|
+
- Harband
|
11
|
+
- Ian
|
12
|
+
- Christian
|
13
|
+
- Myers
|
14
|
+
- Tommy
|
15
|
+
- Dang
|
16
|
+
autorequire:
|
17
|
+
bindir: exe
|
18
|
+
cert_chain: []
|
19
|
+
|
20
|
+
date: 2016-06-08 00:00:00 Z
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: bundler
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: "1.9"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: "10.0"
|
40
|
+
type: :development
|
41
|
+
version_requirements: *id002
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
prerelease: false
|
45
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ~>
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "3.4"
|
50
|
+
type: :development
|
51
|
+
version_requirements: *id003
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: simplecov
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0.11"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id004
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0.10"
|
70
|
+
type: :development
|
71
|
+
version_requirements: *id005
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: webmock
|
74
|
+
prerelease: false
|
75
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "2.0"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: faraday
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0.8"
|
90
|
+
type: :runtime
|
91
|
+
version_requirements: *id007
|
92
|
+
description: A Ruby client for the Hypernova service
|
93
|
+
email:
|
94
|
+
- jake.tl@airbnb.com
|
95
|
+
- ljharb@gmail.com
|
96
|
+
- ian.myers@airbnb.com
|
97
|
+
- tommy.dang@airbnb.com
|
98
|
+
executables: []
|
99
|
+
|
100
|
+
extensions: []
|
101
|
+
|
102
|
+
extra_rdoc_files: []
|
103
|
+
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- .travis.yml
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/console
|
112
|
+
- bin/setup
|
113
|
+
- hypernova.gemspec
|
114
|
+
- lib/hypernova.rb
|
115
|
+
- lib/hypernova/batch.rb
|
116
|
+
- lib/hypernova/batch_renderer.rb
|
117
|
+
- lib/hypernova/batch_url_builder.rb
|
118
|
+
- lib/hypernova/blank_renderer.rb
|
119
|
+
- lib/hypernova/configuration.rb
|
120
|
+
- lib/hypernova/controller_helpers.rb
|
121
|
+
- lib/hypernova/faraday_connection.rb
|
122
|
+
- lib/hypernova/faraday_request.rb
|
123
|
+
- lib/hypernova/http_client_request.rb
|
124
|
+
- lib/hypernova/parsed_response.rb
|
125
|
+
- lib/hypernova/plugin_helper.rb
|
126
|
+
- lib/hypernova/plugins/development_mode_plugin.rb
|
127
|
+
- lib/hypernova/rails/action_controller.rb
|
128
|
+
- lib/hypernova/request.rb
|
129
|
+
- lib/hypernova/request_service.rb
|
130
|
+
- lib/hypernova/response.rb
|
131
|
+
- lib/hypernova/version.rb
|
132
|
+
homepage: https://github.com/airbnb/hypernova-ruby
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata:
|
136
|
+
allowed_push_host: https://rubygems.org
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- &id008
|
145
|
+
- ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: "0"
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- *id008
|
151
|
+
requirements: []
|
152
|
+
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 2.4.7
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: Batch interface for Hypernova, the React render service.
|
158
|
+
test_files: []
|
159
|
+
|
160
|
+
has_rdoc:
|