react_on_rails 0.1.8 → 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.jscsrc +3 -1
- data/.rubocop.yml +7 -2
- data/.travis.yml +24 -2
- data/README.md +105 -85
- data/Rakefile +14 -4
- data/app/assets/javascripts/react_on_rails.js +67 -33
- data/app/helpers/react_on_rails_helper.rb +14 -4
- data/docs/Contributing.md +66 -0
- data/docs/README.md +1 -0
- data/docs/sample_generated_js/client-generated.js +12 -0
- data/docs/sample_generated_js/server-generated.js +11 -0
- data/lib/react_on_rails/server_rendering_pool.rb +64 -58
- data/lib/react_on_rails/version.rb +1 -1
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b275f388735a62982a5056840c44bf0779da6636
|
4
|
+
data.tar.gz: 27d0bfbe15a24476c55c9ba6fa8973213e875f1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 168fd64398f5d3e015401652ce81e60fca5a083500cee3bf4645898476fdbc7161f912fe59362e73f633f889f3976de8ff332809a375e9260526b568dd7f4b94
|
7
|
+
data.tar.gz: bccaeff6f9225a65e246c9eeef5a48d97dcb1e8d96acba82afcd8719690eb095d4d1f8a1a577cf896b4ef540150519adc2fe895e8c0cf71e07f95046b846c795
|
data/.gitignore
CHANGED
@@ -11,8 +11,11 @@
|
|
11
11
|
|
12
12
|
/spec/dummy/client/node_modules
|
13
13
|
/spec/dummy/app/assets/javascripts/generated/
|
14
|
+
/spec/dummy-react-013/client/node_modules
|
15
|
+
/spec/dummy-react-013/app/assets/javascripts/generated/
|
14
16
|
|
15
17
|
# RVM
|
16
18
|
.ruby-version
|
17
19
|
.ruby-gemset
|
18
20
|
|
21
|
+
node_modules
|
data/.jscsrc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"preset": "airbnb",
|
3
3
|
"fileExtensions": [".js", ".jsx"],
|
4
|
-
"excludeFiles": ["build/**", "node_modules/**"]
|
4
|
+
"excludeFiles": ["**/build/**", "**/node_modules/**", "**/generated/**", "**/docs/**", "**/tmp/**", "**/sample_generated/**"],
|
5
|
+
"requireTrailingComma": { ignoreSingleValue: true, ignoreSingleLine: true },
|
6
|
+
"validateQuoteMarks": false
|
5
7
|
}
|
data/.rubocop.yml
CHANGED
@@ -37,13 +37,17 @@ Lint/HandleExceptions:
|
|
37
37
|
|
38
38
|
# Offense count: 1
|
39
39
|
Metrics/AbcSize:
|
40
|
-
Max:
|
40
|
+
Max: 23
|
41
41
|
|
42
42
|
# Offense count: 1
|
43
43
|
# Configuration parameters: CountComments.
|
44
44
|
Metrics/ClassLength:
|
45
45
|
Max: 114
|
46
46
|
|
47
|
+
Metrics/ParameterLists:
|
48
|
+
Max: 5
|
49
|
+
CountKeywordArgs: false
|
50
|
+
|
47
51
|
# Offense count: 9
|
48
52
|
# Configuration parameters: CountComments.
|
49
53
|
Metrics/MethodLength:
|
@@ -52,11 +56,12 @@ Metrics/MethodLength:
|
|
52
56
|
# Offense count: 1
|
53
57
|
# Configuration parameters: CountComments.
|
54
58
|
Metrics/ModuleLength:
|
55
|
-
Max:
|
59
|
+
Max: 110
|
56
60
|
|
57
61
|
# Offense count: 3
|
58
62
|
# Configuration parameters: AllowedVariables.
|
59
63
|
Style/GlobalVars:
|
60
64
|
Exclude:
|
61
65
|
- 'spec/dummy/config/environments/development.rb'
|
66
|
+
- 'spec/dummy-react-013/config/environments/development.rb'
|
62
67
|
|
data/.travis.yml
CHANGED
@@ -1,12 +1,34 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- 2.2.2
|
4
|
+
|
4
5
|
gemfile:
|
5
6
|
- spec/dummy/Gemfile
|
6
|
-
|
7
|
+
|
8
|
+
env:
|
9
|
+
- export RAILS_ENV=test
|
10
|
+
|
11
|
+
install:
|
12
|
+
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install 4.2.0
|
13
|
+
- npm install -g npm
|
14
|
+
- bundle install
|
15
|
+
- cd spec/dummy/client && npm install
|
16
|
+
- $(npm bin)/webpack --config webpack.server.js
|
17
|
+
- $(npm bin)/webpack --config webpack.client.js
|
18
|
+
- cd ../../dummy-react-013/client && npm install
|
19
|
+
- $(npm bin)/webpack --config webpack.server.js
|
20
|
+
- $(npm bin)/webpack --config webpack.client.js
|
21
|
+
|
22
|
+
before_script:
|
23
|
+
- cd ../../
|
24
|
+
- export DISPLAY=:99.0
|
25
|
+
- sh -e /etc/init.d/xvfb start
|
26
|
+
|
7
27
|
script:
|
8
28
|
- rake run_rspec:gem
|
9
|
-
- rake run_rspec:dummy
|
29
|
+
- DRIVER=selenium_firefox rake run_rspec:dummy
|
30
|
+
- DRIVER=selenium_firefox rake run_rspec:dummy_react_013
|
31
|
+
|
10
32
|
notifications:
|
11
33
|
slack:
|
12
34
|
secure: LfcUk4AJ4vAxWwRIyw4tFh8QNbYefMwfG/oLfsN3CdRMWMOtCOHR1GGsRhAOlfVVJ/FvHqVqWj5gK7z7CaO5Uvl7rD3/zJ8QzExKx/iH9yWj55iIPuKLzwFNnBwRpFW/cqyU2lFPPRxGD50BUn3c+qybkuSqtKZ6qtTowwqlxLa5iyM3N95aZp7MEIKCP7cPcnHfLbJyP8wBpotp/rtw62eXM2HIRJJwgjcp+n+My7VFR9DnBXNFf6R91aZHM4U4cHHDbu15HFtH8honVrzK1JQdyqMNHga+j04dFuaS7z9Q369/hsELMOBp/227+Pz7ZRfWZFK4UASguOvyeX7RmGTRpTuWLm1XJeUzfsPZVROecaSVQBve+U7F12yKqilt97QlvRXn2EGyBILqvxtFNNR4S9kgAf72/6EFgiM1TKq7i9zy6lVOnagU2+7amq7UeopX1uoFsUfNKMR7YbgV1WjF0IK95UP0b0/7ZOJlPYgi5zzkQi129qAFWSMmxGk+ZpsttHh/tjJtvAh0A3mHq/zb5w4ub/MbSyZqeDUNgGj72QArOWUFSAStQT1ybsVLeDoKPgOvVq7OV1D64rpcHjBXcqOCit8tDZ+TqkFhcYJo2cITSaqE4zJXn+4F5s7So5O8CyfKYQq+kFJCooYGmfgTUckJpGl7eIvKmL4TN9Q=
|
data/README.md
CHANGED
@@ -5,56 +5,129 @@
|
|
5
5
|
|
6
6
|
Gem Published: https://rubygems.org/gems/react_on_rails
|
7
7
|
|
8
|
-
|
8
|
+
Live example, including server rendering + redux: http://www.reactrails.com/
|
9
|
+
Sponsored by [ShakaCode.com](http://www.shakacode.com/)
|
9
10
|
|
10
|
-
|
11
|
+
See [Action Plan for v1.0](https://github.com/shakacode/react_on_rails/issues/1). We're ready v1.0.
|
12
|
+
|
13
|
+
Feedback and pull-requests encouraged! Thanks in advance! We've got a private slack channel to discuss react + webpack + rails. [Email us for an invite contact@shakacode.com](mailto: contact@shakacode.com).
|
11
14
|
|
12
15
|
Supports:
|
13
16
|
|
14
17
|
1. Rails
|
15
18
|
2. Webpack
|
16
|
-
3. React
|
19
|
+
3. React, both v0.14 and v0.13.
|
17
20
|
4. Redux
|
18
21
|
5. Turbolinks
|
19
22
|
6. Server side rendering with fragment caching
|
20
|
-
7. react-router for client side rendering (and
|
23
|
+
7. react-router for client side rendering (and server side very soon)
|
21
24
|
|
22
25
|
## OPEN ISSUES
|
23
|
-
1.
|
24
|
-
2.
|
25
|
-
3.
|
26
|
-
4. Longer term, we hope to put in many conveniences into this gem, in terms of Webpack + Rails integration.
|
26
|
+
1. Almost all the open issues are nice to haves like more tests.
|
27
|
+
2. If you want to work on any of the open issues, please comment on the issue. My team is mentoring anybody that's trying to help with the issues.
|
28
|
+
3. Longer term, we hope to put in many conveniences into this gem, in terms of Webpack + Rails integration. We're open to suggestions.
|
27
29
|
|
28
30
|
## Links
|
29
|
-
1.
|
31
|
+
1. See https://github.com/shakacode/react-webpack-rails-tutorial/ for how to integrate it!
|
30
32
|
2. http://www.railsonmaui.com/blog/2014/10/03/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
|
31
|
-
3. http://forum.
|
32
|
-
4.
|
33
|
-
5.
|
34
|
-
|
35
|
-
products, client work, and open source.
|
33
|
+
3. http://forum.shakacode.com
|
34
|
+
4. If you're looking for consulting on a project using React and Rails, [email us! contact@shakacode.com](mailto: contact@shakacode.com)? You can first join our slack room for some free advice.
|
35
|
+
5. We're looking for great developers that want to work with Rails + React with a distributed, worldwide team, for our own
|
36
|
+
products, client work, and open source. [More info here](http://www.shakacode.com/about/index.html#work-with-us).
|
36
37
|
|
37
38
|
## How is different than the [react-rails gem](https://github.com/reactjs/react-rails)?
|
38
39
|
1. `react_on_rails` depends on [webpack](http://webpack.github.io/). `react-rails` integrates closely with sprockets and
|
39
40
|
helps you integrate JSX and the react code into a Rails project.
|
40
|
-
2. Likewise, using Webpack as
|
41
|
+
2. Likewise, using Webpack as shown in the [react-webpack-rails-tutorial](https://github.com/justin808/react-webpack-rails-tutorial/)
|
41
42
|
does involve some extra setup. However, we feel that tight and simple integration with the node ecosystem is more than
|
42
43
|
worth any minor setup costs.
|
43
44
|
3. `react-rails` depends on `jquery-ujs` for client side rendering. `react_on_rails` has it's own JS code that does not
|
44
45
|
depend on jquery.
|
45
46
|
|
46
|
-
##
|
47
|
+
## Installation Checklist
|
48
|
+
1. Include the gems `react_on_rails` and `therubyracer` like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/361f4338ebb39a5d3934b00cb6d6fcf494773000/Gemfile#L42) and run `bundle`. Note, you can sustitute your preferable JavaScript engine.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
gem "react_on_rails"
|
52
|
+
gem "therubyracer"
|
53
|
+
```
|
54
|
+
1. Globally expose React in your webpack config like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.client.base.config.js#L31):
|
55
|
+
|
56
|
+
```javascript
|
57
|
+
module: {
|
58
|
+
loaders: [
|
59
|
+
// React is necessary for the client rendering:
|
60
|
+
{test: require.resolve('react'), loader: 'expose?React'},
|
61
|
+
```
|
62
|
+
1. Require `react_on_rails` in your `application.js` like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/361f4338ebb39a5d3934b00cb6d6fcf494773000/app/assets/javascripts/application.js#L15). It possibly should come after you require `turbolinks`:
|
63
|
+
|
64
|
+
```
|
65
|
+
//= require react_on_rails
|
66
|
+
```
|
67
|
+
1. Expose your client globals like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/app/startup/clientGlobals.jsx#L3):
|
68
|
+
|
69
|
+
```javascript
|
70
|
+
import App from './ClientApp';
|
71
|
+
window.App = App;
|
72
|
+
```
|
73
|
+
1. Put your client globals file as webpack entry points like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.client.rails.config.js#L22). Similar pattern for server rendering.
|
74
|
+
|
75
|
+
```javascript
|
76
|
+
config.entry.app.push('./app/startup/clientGlobals');
|
77
|
+
```
|
78
|
+
1. See customization of configuration options below.
|
47
79
|
|
48
|
-
|
80
|
+
### Additional Steps For Server Rendering (option `prerender` shown below)
|
81
|
+
See the next section for a sample webpack.server.rails.config.js.
|
82
|
+
1. Expose your server globals like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/app/startup/serverGlobals.jsx#L7)
|
83
|
+
|
84
|
+
```javascript
|
85
|
+
import App from './ServerApp';
|
86
|
+
global.App = App;
|
87
|
+
```
|
88
|
+
2. Make the server globals file an entry point in your webpack config, like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.server.rails.config.js#L7)
|
49
89
|
|
50
|
-
```
|
51
|
-
|
52
|
-
|
53
|
-
|
90
|
+
```javascript
|
91
|
+
entry: ['./app/startup/serverGlobals'],
|
92
|
+
```
|
93
|
+
3. Ensure the name of your ouput file (shown [here](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.server.rails.config.js#L9)) of your server bundle corresponds to the configuration of the gem. The default path is `app/assets/javascripts/generated`. See below for customization of configuration variables.
|
94
|
+
4. Expose `React` in your webpack config, like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/client/webpack.server.rails.config.js#L23)
|
54
95
|
|
55
|
-
|
96
|
+
#### Sample webpack.server.rails.config.js (ONLY for server rendering)
|
97
|
+
Be sure to check out the latest example version of [client/webpack.server.rails.config.js](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/client/webpack.server.rails.config.js).
|
56
98
|
|
57
|
-
|
99
|
+
```javascript
|
100
|
+
// Common webpack configuration for server bundle
|
101
|
+
|
102
|
+
module.exports = {
|
103
|
+
|
104
|
+
// the project dir
|
105
|
+
context: __dirname,
|
106
|
+
entry: ['./app/startup/serverGlobals'],
|
107
|
+
output: {
|
108
|
+
filename: 'server-bundle.js',
|
109
|
+
path: '../app/assets/javascripts/generated',
|
110
|
+
|
111
|
+
// CRITICAL to set libraryTarget: 'this' for enabling Rails to find the exposed modules IF you
|
112
|
+
// use the "expose" webpackfunctionality. See startup/serverGlobals.jsx.
|
113
|
+
// NOTE: This is NOT necessary if you use the syntax of global.MyComponent = MyComponent syntax.
|
114
|
+
// See http://webpack.github.io/docs/configuration.html#externals for documentation of this option
|
115
|
+
//libraryTarget: 'this',
|
116
|
+
},
|
117
|
+
resolve: {
|
118
|
+
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', 'config.js'],
|
119
|
+
},
|
120
|
+
module: {
|
121
|
+
loaders: [
|
122
|
+
{test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/},
|
123
|
+
|
124
|
+
// React is necessary for the client rendering:
|
125
|
+
{ test: require.resolve('react'), loader: 'expose?React' },
|
126
|
+
{ test: require.resolve('react-dom/server'), loader: 'expose?ReactDOMServer' },
|
127
|
+
],
|
128
|
+
},
|
129
|
+
};
|
130
|
+
```
|
58
131
|
|
59
132
|
## What Happens?
|
60
133
|
|
@@ -100,8 +173,12 @@ Params are:
|
|
100
173
|
If you're curious as to what the gem generates for the server and client rendering, see [`spec/dummy/client/app/startup/serverGlobals.jsx`](https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/spec/sample_generated_js/server-generated.js)
|
101
174
|
and [`spec/dummy/client/app/startup/ClientReduxApp.jsx`](https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/spec/sample_generated_js/client-generated.js) for examples of this. Note, this is not the code that you are providing. You can see the client code by viewing the page source.
|
102
175
|
|
103
|
-
* **props**: [hash] Properties to pass to the react object
|
176
|
+
* **props**: [hash | string of json] Properties to pass to the react object. See this example if you're using Jbuilder: [react-webpack-rails-tutorial view rendering props using jBuilder](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/app/views/pages/index.html.erb#L20)
|
104
177
|
|
178
|
+
```erb
|
179
|
+
<%= react_component('App', render(template: "/comments/index.json.jbuilder"),
|
180
|
+
generator_function: true, prerender: true) %>
|
181
|
+
```
|
105
182
|
* **options:** [hash]
|
106
183
|
* **generator_function**: <true/false> default is false, set to true if you want to use a generator function rather than a React Component.
|
107
184
|
* **prerender**: <true/false> set to false when debugging!
|
@@ -238,81 +315,24 @@ gem "therubyracer"
|
|
238
315
|
* [Charlie Marsh's article "Rendering React Components on the Server"](http://www.crmarsh.com/react-ssr/)
|
239
316
|
* [Node globals](https://nodejs.org/api/globals.html#globals_global)
|
240
317
|
|
241
|
-
|
242
|
-
## Development Setup for Gem Contributors
|
243
|
-
|
244
|
-
### Initial Setup
|
245
|
-
After checking out the repo, making sure you have rvm and nvm setup (setup ruby and node),
|
246
|
-
cd to `spec/dummy` and run `bin/setup` to install dependencies.
|
247
|
-
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
248
|
-
|
249
|
-
### Starting the Dummy App
|
250
|
-
To run the test app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start`.
|
251
|
-
If you don't do this, then `webpack` will not generate a new bundle,
|
252
|
-
and you will be seriously confused when you change JavaScript and the app does not change.
|
253
|
-
|
254
|
-
### Install and Release
|
255
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
|
256
|
-
update the version number in `version.rb`, and then run `bundle exec rake release`,
|
257
|
-
which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
258
|
-
|
259
|
-
### RSpec Testing
|
260
|
-
Run `rake` for testing the gem and `spec/dummy`. Otherwise, the `rspec` command only works for testing within `spec/dummy`.
|
261
|
-
|
262
|
-
If you run `rspec` at the top level, you'll see this message: `require': cannot load such file -- rails_helper (LoadError)`
|
263
|
-
|
264
|
-
### Debugging
|
265
|
-
Start the sample app like this for some debug printing:
|
266
|
-
```bash
|
267
|
-
TRACE_REACT_ON_RAILS=true && foreman start
|
268
|
-
```
|
269
|
-
|
270
318
|
### Generated JavaScript
|
271
319
|
|
272
320
|
1. See spec/dummy/spec/sample_generated_js/server-generated.js to see the JavaScript for typical server rendering.
|
273
321
|
2. See spec/dummy/spec/sample_generated_js/client-generated.js to see the JavaScript for typical client rendering.
|
274
322
|
|
275
|
-
### Linting
|
276
|
-
All linting is performed from the docker container. You will need docker and docker-compose installed
|
277
|
-
locally to lint code changes via the lint container.
|
278
|
-
|
279
|
-
* [Install Docker Toolbox for Mac](https://www.docker.com/toolbox)
|
280
|
-
* [Install Docker Compose for Linux](https://docs.docker.com/compose/install/)
|
281
|
-
|
282
|
-
Once you have docker and docker-compose running locally, run `docker-compose build lint`. This will build
|
283
|
-
the `reactonrails_lint` docker image and docker-compose `lint` container. The inital build is slow,
|
284
|
-
but after the install, startup is very quick.
|
285
|
-
|
286
|
-
### Linting Commands
|
287
|
-
Run `rake -D docker` to see all docker linting commands for rake. `rake docker` will run all linters.
|
288
|
-
For individual rake linting commands please refer to `rake -D docker` for the list.
|
289
|
-
You can run specfic linting for directories or files by using `docker-compose run lint rubocop (file path or directory)`, etc.
|
290
|
-
`docker-compose run lint /bin/bash` sets you up to run from the container command line.
|
291
|
-
|
292
323
|
## Contributing
|
293
324
|
|
294
325
|
Bug reports and pull requests are welcome on GitHub at https://github.com/shakacode/react_on_rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
295
326
|
|
327
|
+
More [tips on contributing here](docs/Contributing.md)
|
328
|
+
|
296
329
|
## License
|
297
330
|
|
298
331
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
299
332
|
|
300
|
-
## Updating New Versions of the Gem
|
301
|
-
|
302
|
-
See https://github.com/svenfuchs/gem-release
|
303
|
-
|
304
|
-
```bash
|
305
|
-
gem bump
|
306
|
-
cd spec/dummy
|
307
|
-
bundle
|
308
|
-
git commit -am "Updated Gemfile.lock"
|
309
|
-
cd ../..
|
310
|
-
gem tag
|
311
|
-
gem release
|
312
|
-
```
|
313
|
-
|
314
333
|
# Authors
|
315
|
-
|
334
|
+
|
335
|
+
[The Shaka Code team!](http://www.shakacode.com/about/)
|
316
336
|
|
317
337
|
1. [Justin Gordon](https://github.com/justin808/)
|
318
338
|
2. [Samnang Chhun](https://github.com/samnang)
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require "fileutils"
|
|
3
3
|
namespace :run_rspec do
|
4
4
|
desc "Run RSpec for top level only"
|
5
5
|
task :gem do
|
6
|
-
sh %( rspec
|
6
|
+
sh %( rspec spec/react_on_rails_spec.rb )
|
7
7
|
end
|
8
8
|
|
9
9
|
desc "Run RSpec for spec/dummy only"
|
@@ -11,7 +11,12 @@ namespace :run_rspec do
|
|
11
11
|
sh %( cd spec/dummy && rspec )
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
desc "Run RSpec for spec/dummy only"
|
15
|
+
task :dummy_react_013 do
|
16
|
+
sh %( cd spec/dummy-react-013 && rspec )
|
17
|
+
end
|
18
|
+
|
19
|
+
task run_rspec: [:gem, :dummy, :dummy_react_013] do
|
15
20
|
puts "Completed all RSpec tests"
|
16
21
|
end
|
17
22
|
end
|
@@ -43,13 +48,15 @@ namespace :lint do
|
|
43
48
|
|
44
49
|
desc "Run jscs from shell"
|
45
50
|
task :jscs do
|
46
|
-
sh "jscs -e ."
|
51
|
+
sh "jscs -e -v ."
|
47
52
|
end
|
48
53
|
|
49
|
-
|
54
|
+
desc "Run all eslint, jscs, rubocop linters. Skip ruby-lint and scss"
|
55
|
+
task lint: [:eslint, :jscs, :rubocop] do
|
50
56
|
puts "Completed all linting"
|
51
57
|
end
|
52
58
|
end
|
59
|
+
|
53
60
|
desc "Runs all linters. Run `rake -D lint` to see all available lint options"
|
54
61
|
task lint: ["lint:lint"]
|
55
62
|
|
@@ -86,3 +93,6 @@ end
|
|
86
93
|
|
87
94
|
desc "Runs all linters from docker. Run `rake -D docker` to see all available lint options"
|
88
95
|
task docker: ["docker:lint"]
|
96
|
+
|
97
|
+
desc "Run all tests and linting"
|
98
|
+
task ci: %w(docker run_rspec)
|
@@ -18,36 +18,42 @@
|
|
18
18
|
if (domNode) {
|
19
19
|
var reactElement = createReactElement(componentName, propsVarName, props,
|
20
20
|
domId, trace, generatorFunction);
|
21
|
-
|
21
|
+
provideClientReact().render(reactElement, domNode);
|
22
22
|
}
|
23
23
|
}
|
24
24
|
catch (e) {
|
25
|
-
handleError(
|
25
|
+
ReactOnRails.handleError({
|
26
|
+
e: e,
|
27
|
+
componentName: componentName,
|
28
|
+
serverSide: false,
|
29
|
+
});
|
26
30
|
}
|
27
31
|
};
|
28
32
|
|
29
|
-
var turbolinksInstalled = typeof
|
33
|
+
var turbolinksInstalled = (typeof Turbolinks !== 'undefined');
|
30
34
|
if (!expectTurboLinks || (!turbolinksInstalled && expectTurboLinks)) {
|
31
35
|
if (expectTurboLinks) {
|
32
|
-
console.warn(
|
36
|
+
console.warn('WARNING: NO TurboLinks detected in JS, but it is in your Gemfile');
|
33
37
|
}
|
34
|
-
|
38
|
+
|
39
|
+
document.addEventListener('DOMContentLoaded', function(event) {
|
35
40
|
renderIfDomNodePresent();
|
36
41
|
});
|
37
42
|
} else {
|
38
43
|
function onPageChange(event) {
|
39
44
|
var removePageChangeListener = function() {
|
40
|
-
document.removeEventListener(
|
41
|
-
document.removeEventListener(
|
45
|
+
document.removeEventListener('page:change', onPageChange);
|
46
|
+
document.removeEventListener('page:before-unload', removePageChangeListener);
|
42
47
|
var domNode = document.getElementById(domId);
|
43
|
-
|
48
|
+
provideClientReact().unmountComponentAtNode(domNode);
|
44
49
|
};
|
45
|
-
|
50
|
+
|
51
|
+
document.addEventListener('page:before-unload', removePageChangeListener);
|
46
52
|
|
47
53
|
renderIfDomNodePresent();
|
48
54
|
}
|
49
55
|
|
50
|
-
document.addEventListener(
|
56
|
+
document.addEventListener('page:change', onPageChange);
|
51
57
|
}
|
52
58
|
};
|
53
59
|
|
@@ -65,31 +71,27 @@
|
|
65
71
|
try {
|
66
72
|
var reactElement = createReactElement(componentName, propsVarName, props,
|
67
73
|
domId, trace, generatorFunction);
|
68
|
-
htmlResult =
|
74
|
+
htmlResult = provideServerReact().renderToString(reactElement);
|
69
75
|
}
|
70
76
|
catch (e) {
|
71
|
-
htmlResult = handleError(
|
77
|
+
htmlResult = ReactOnRails.handleError({
|
78
|
+
e: e,
|
79
|
+
componentName: componentName,
|
80
|
+
serverSide: true,
|
81
|
+
});
|
72
82
|
}
|
73
83
|
|
74
84
|
consoleReplay = ReactOnRails.buildConsoleReplay();
|
75
85
|
return JSON.stringify([htmlResult, consoleReplay]);
|
76
86
|
};
|
77
87
|
|
78
|
-
function createReactElement(componentName, propsVarName, props, domId, trace, generatorFunction) {
|
79
|
-
if (trace) {
|
80
|
-
console.log('RENDERED ' + componentName + ' with data_variable ' +
|
81
|
-
propsVarName + ' to dom node with id: ' + domId);
|
82
|
-
}
|
83
|
-
|
84
|
-
if (generatorFunction) {
|
85
|
-
return this[componentName](props);
|
86
|
-
} else {
|
87
|
-
return React.createElement(this[componentName], props);
|
88
|
-
}
|
89
|
-
}
|
90
|
-
|
91
88
|
// Passing either componentName or jsCode
|
92
|
-
|
89
|
+
ReactOnRails.handleError = function(options) {
|
90
|
+
var e = options.e;
|
91
|
+
var componentName = options.componentName;
|
92
|
+
var jsCode = options.jsCode;
|
93
|
+
var serverSide = options.serverSide;
|
94
|
+
|
93
95
|
var lineOne =
|
94
96
|
'ERROR: You specified the option generator_function (could be in your defaults) to be\n';
|
95
97
|
var lastLine =
|
@@ -125,15 +127,17 @@
|
|
125
127
|
if (e.fileName) {
|
126
128
|
console.error('location: ' + e.fileName + ':' + e.lineNumber);
|
127
129
|
}
|
130
|
+
|
128
131
|
console.error('message: ' + e.message);
|
129
132
|
console.error('stack: ' + e.stack);
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
133
|
+
if (serverSide) {
|
134
|
+
msg += 'Exception in rendering!\n' +
|
135
|
+
(e.fileName ? '\nlocation: ' + e.fileName + ':' + e.lineNumber : '') +
|
136
|
+
'\nMessage: ' + e.message + '\n\n' + e.stack;
|
137
|
+
var reactElement = React.createElement('pre', null, msg);
|
138
|
+
return provideServerReact().renderToString(reactElement);
|
139
|
+
}
|
140
|
+
};
|
137
141
|
|
138
142
|
ReactOnRails.buildConsoleReplay = function() {
|
139
143
|
var consoleReplay = '';
|
@@ -145,9 +149,39 @@
|
|
145
149
|
consoleReplay += '\nconsole.' + msg.level + '.apply(console, ' +
|
146
150
|
JSON.stringify(msg.arguments) + ');';
|
147
151
|
});
|
152
|
+
|
148
153
|
consoleReplay += '\n</script>';
|
149
154
|
}
|
150
155
|
|
151
156
|
return consoleReplay;
|
157
|
+
};
|
158
|
+
|
159
|
+
function createReactElement(componentName, propsVarName, props, domId, trace, generatorFunction) {
|
160
|
+
if (trace) {
|
161
|
+
console.log('RENDERED ' + componentName + ' with data_variable ' +
|
162
|
+
propsVarName + ' to dom node with id: ' + domId);
|
163
|
+
}
|
164
|
+
|
165
|
+
if (generatorFunction) {
|
166
|
+
return this[componentName](props);
|
167
|
+
} else {
|
168
|
+
return React.createElement(this[componentName], props);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
function provideClientReact() {
|
173
|
+
if (typeof ReactDOM === 'undefined') {
|
174
|
+
return React;
|
175
|
+
}
|
176
|
+
|
177
|
+
return ReactDOM;
|
178
|
+
}
|
179
|
+
|
180
|
+
function provideServerReact() {
|
181
|
+
if (typeof ReactDOMServer === 'undefined') {
|
182
|
+
return React;
|
183
|
+
}
|
184
|
+
|
185
|
+
return ReactDOMServer;
|
152
186
|
}
|
153
187
|
}.call(this));
|
@@ -53,7 +53,7 @@ module ReactOnRailsHelper
|
|
53
53
|
data_variable_name = "__#{component_name.camelize(:lower)}Data#{react_component_index}__"
|
54
54
|
turbolinks_loaded = Object.const_defined?(:Turbolinks)
|
55
55
|
# NOTE: props might include closing script tag that might cause XSS
|
56
|
-
props_string = props
|
56
|
+
props_string = sanitized_props_string(props)
|
57
57
|
page_loaded_js = <<-JS
|
58
58
|
(function() {
|
59
59
|
window.#{data_variable_name} = #{props_string};
|
@@ -89,10 +89,14 @@ module ReactOnRailsHelper
|
|
89
89
|
<<-HTML.html_safe
|
90
90
|
#{data_from_server_script_tag}
|
91
91
|
#{rendered_output}
|
92
|
-
#{replay_console(options) ? console_script :
|
92
|
+
#{replay_console(options) ? console_script : ''}
|
93
93
|
HTML
|
94
94
|
end
|
95
95
|
|
96
|
+
def sanitized_props_string(props)
|
97
|
+
props.is_a?(String) ? json_escape(props) : props.to_json
|
98
|
+
end
|
99
|
+
|
96
100
|
# Helper method to take javascript expression and returns the output from evaluating it.
|
97
101
|
# If you have more than one line that needs to be executed, wrap it in an IIFE.
|
98
102
|
# JS exceptions are caught and console messages are handled properly.
|
@@ -108,7 +112,8 @@ module ReactOnRailsHelper
|
|
108
112
|
return #{js_expression};
|
109
113
|
})();
|
110
114
|
} catch(e) {
|
111
|
-
htmlResult = handleError(e, null,
|
115
|
+
htmlResult = ReactOnRails.handleError({e: e, componentName: null,
|
116
|
+
jsCode: '#{escape_javascript(js_expression)}', serverSide: true});
|
112
117
|
}
|
113
118
|
|
114
119
|
consoleReplay = ReactOnRails.buildConsoleReplay();
|
@@ -117,7 +122,12 @@ module ReactOnRailsHelper
|
|
117
122
|
JS
|
118
123
|
|
119
124
|
result = ReactOnRails::ServerRenderingPool.server_render_js_with_console_logging(wrapper_js)
|
120
|
-
|
125
|
+
|
126
|
+
# IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
|
127
|
+
<<-HTML.html_safe
|
128
|
+
#{result[0]}
|
129
|
+
#{replay_console(options) ? result[1] : ''}
|
130
|
+
HTML
|
121
131
|
end
|
122
132
|
|
123
133
|
private
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Tips for Contributors
|
2
|
+
|
3
|
+
## Development Setup for Gem Contributors
|
4
|
+
|
5
|
+
### Checklist before Committing
|
6
|
+
1. `rake ci`: runs all linters and specs (you need Docker setup, see below)
|
7
|
+
2. Did you need any more tests for your change?
|
8
|
+
3. Did you document your change? Update the README.md?
|
9
|
+
|
10
|
+
### Initial Setup
|
11
|
+
After checking out the repo, making sure you have rvm and nvm setup (setup ruby and node),
|
12
|
+
cd to `spec/dummy` and run `bin/setup` to install dependencies.
|
13
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
14
|
+
|
15
|
+
### Starting the Dummy App
|
16
|
+
To run the test app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start`.
|
17
|
+
If you don't do this, then `webpack` will not generate a new bundle,
|
18
|
+
and you will be seriously confused when you change JavaScript and the app does not change.
|
19
|
+
|
20
|
+
### Install and Release
|
21
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
|
22
|
+
update the version number in `version.rb`, and then run `bundle exec rake release`,
|
23
|
+
which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
24
|
+
|
25
|
+
### RSpec Testing
|
26
|
+
Run `rake` for testing the gem and `spec/dummy` and `spec/dummy-react-013`. Otherwise, the `rspec` command only works for testing within the sample apps, like `spec/dummy`.
|
27
|
+
|
28
|
+
If you run `rspec` at the top level, you'll see this message: `require': cannot load such file -- rails_helper (LoadError)`
|
29
|
+
|
30
|
+
### Debugging
|
31
|
+
Start the sample app like this for some debug printing:
|
32
|
+
```bash
|
33
|
+
TRACE_REACT_ON_RAILS=true && foreman start
|
34
|
+
```
|
35
|
+
|
36
|
+
|
37
|
+
## Updating New Versions of the Gem
|
38
|
+
|
39
|
+
See https://github.com/svenfuchs/gem-release
|
40
|
+
|
41
|
+
```bash
|
42
|
+
gem bump
|
43
|
+
cd spec/dummy
|
44
|
+
bundle
|
45
|
+
git commit -am "Updated Gemfile.lock"
|
46
|
+
cd ../..
|
47
|
+
gem tag
|
48
|
+
gem release
|
49
|
+
```
|
50
|
+
|
51
|
+
### Linting
|
52
|
+
All linting is performed from the docker container. You will need docker and docker-compose installed
|
53
|
+
locally to lint code changes via the lint container.
|
54
|
+
|
55
|
+
* [Install Docker Toolbox for Mac](https://www.docker.com/toolbox)
|
56
|
+
* [Install Docker Compose for Linux](https://docs.docker.com/compose/install/)
|
57
|
+
|
58
|
+
Once you have docker and docker-compose running locally, run `docker-compose build lint`. This will build
|
59
|
+
the `reactonrails_lint` docker image and docker-compose `lint` container. The inital build is slow,
|
60
|
+
but after the install, startup is very quick.
|
61
|
+
|
62
|
+
### Linting Commands
|
63
|
+
Run `rake -D docker` to see all docker linting commands for rake. `rake docker` will run all linters.
|
64
|
+
For individual rake linting commands please refer to `rake -D docker` for the list.
|
65
|
+
You can run specfic linting for directories or files by using `docker-compose run lint rubocop (file path or directory)`, etc.
|
66
|
+
`docker-compose run lint /bin/bash` sets you up to run from the container command line.
|
data/docs/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
## PENDING: ADD DOCS HERE
|
@@ -0,0 +1,12 @@
|
|
1
|
+
(function() {
|
2
|
+
window.__helloWorldData0__ = {"helloWorldData":{"name":"Mr. Server Side Rendering"}};
|
3
|
+
ReactOnRails.clientRenderReactComponent({
|
4
|
+
componentName: 'HelloWorld',
|
5
|
+
domId: 'HelloWorld-react-component-0',
|
6
|
+
propsVarName: '__helloWorldData0__',
|
7
|
+
props: window.__helloWorldData0__,
|
8
|
+
trace: true,
|
9
|
+
generatorFunction: false,
|
10
|
+
expectTurboLinks: true
|
11
|
+
});
|
12
|
+
})();
|
@@ -0,0 +1,11 @@
|
|
1
|
+
(function() {
|
2
|
+
var props = {"helloWorldData":{"name":"Mr. Server Side Rendering"}};
|
3
|
+
return ReactOnRails.serverRenderReactComponent({
|
4
|
+
componentName: 'HelloWorld',
|
5
|
+
domId: 'HelloWorld-react-component-0',
|
6
|
+
propsVarName: '__helloWorldData0__',
|
7
|
+
props: props,
|
8
|
+
trace: true,
|
9
|
+
generatorFunction: false
|
10
|
+
});
|
11
|
+
})();
|
@@ -1,62 +1,20 @@
|
|
1
|
-
require
|
1
|
+
require "connection_pool"
|
2
2
|
|
3
|
-
# Based on the react-rails gem
|
3
|
+
# Based on the react-rails gem.
|
4
|
+
# None of these methods should be called directly.
|
5
|
+
# See app/helpers/react_on_rails_helper.rb
|
4
6
|
module ReactOnRails
|
5
7
|
class ServerRenderingPool
|
6
8
|
def self.reset_pool
|
7
9
|
options = { size: ReactOnRails.configuration.server_renderer_pool_size,
|
8
10
|
timeout: ReactOnRails.configuration.server_renderer_pool_size }
|
9
|
-
|
11
|
+
@js_context_pool = ConnectionPool.new(options) { create_js_context }
|
10
12
|
end
|
11
13
|
|
12
|
-
def self.eval_js(js_code)
|
13
|
-
@@js_context_pool.with do |js_context|
|
14
|
-
result = js_context.eval(js_code)
|
15
|
-
js_context.eval(CLEAR_CONSOLE)
|
16
|
-
result
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.create_js_context
|
21
|
-
server_js_file = ReactOnRails.configuration.server_bundle_js_file
|
22
|
-
if server_js_file.present? && File.exist?(server_js_file)
|
23
|
-
bundle_js_code = File.read(server_js_file)
|
24
|
-
base_js_code = <<-JS
|
25
|
-
#{CONSOLE_POLYFILL}
|
26
|
-
#{bundle_js_code};
|
27
|
-
#{::Rails.application.assets['react_on_rails.js'].to_s};
|
28
|
-
JS
|
29
|
-
ExecJS.compile(base_js_code)
|
30
|
-
else
|
31
|
-
if server_js_file.present?
|
32
|
-
Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
|
33
|
-
end
|
34
|
-
ExecJS.compile("")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
CLEAR_CONSOLE = <<-JS
|
39
|
-
console.history = []
|
40
|
-
JS
|
41
|
-
|
42
|
-
# Reimplement console methods for replaying on the client
|
43
|
-
CONSOLE_POLYFILL = <<-JS
|
44
|
-
var console = { history: [] };
|
45
|
-
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
46
|
-
console[level] = function () {
|
47
|
-
var argArray = Array.prototype.slice.call(arguments);
|
48
|
-
if (argArray.length > 0) {
|
49
|
-
argArray[0] = '[SERVER] ' + argArray[0];
|
50
|
-
}
|
51
|
-
console.history.push({level: level, arguments: argArray});
|
52
|
-
};
|
53
|
-
});
|
54
|
-
JS
|
55
|
-
|
56
14
|
class PrerenderError < RuntimeError
|
57
15
|
def initialize(component_name, props, js_message)
|
58
16
|
message = ["Encountered error \"#{js_message}\" when prerendering #{component_name} with #{props}",
|
59
|
-
|
17
|
+
js_message.backtrace.join("\n")].join("\n")
|
60
18
|
super(message)
|
61
19
|
end
|
62
20
|
end
|
@@ -69,13 +27,7 @@ var console = { history: [] };
|
|
69
27
|
# js_code MUST RETURN json stringify array of two elements
|
70
28
|
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
71
29
|
def self.server_render_js_with_console_logging(js_code)
|
72
|
-
|
73
|
-
puts "Z" * 80
|
74
|
-
puts "react_renderer.rb: 92"
|
75
|
-
puts "wrote file tmp/server-generated.js"
|
76
|
-
File.write("tmp/server-generated.js", js_code)
|
77
|
-
puts "Z" * 80
|
78
|
-
end
|
30
|
+
trace_messsage(js_code)
|
79
31
|
|
80
32
|
json_string = eval_js(js_code)
|
81
33
|
# element 0 is the html, element 1 is the script tag for the server console output
|
@@ -89,13 +41,67 @@ var console = { history: [] };
|
|
89
41
|
if console_script_lines
|
90
42
|
console_script_lines.each do |line|
|
91
43
|
match = re.match(line)
|
92
|
-
if match
|
93
|
-
Rails.logger.info { "[react_on_rails] #{match[:msg]}" }
|
94
|
-
end
|
44
|
+
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
95
45
|
end
|
96
46
|
end
|
97
47
|
end
|
98
48
|
result
|
99
49
|
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
private
|
53
|
+
|
54
|
+
def trace_messsage(js_code)
|
55
|
+
return unless ENV["TRACE_REACT_ON_RAILS"].present?
|
56
|
+
# Set to anything to print generated code.
|
57
|
+
puts "Z" * 80
|
58
|
+
puts "react_renderer.rb: 92"
|
59
|
+
puts "wrote file tmp/server-generated.js"
|
60
|
+
File.write("tmp/server-generated.js", js_code)
|
61
|
+
puts "Z" * 80
|
62
|
+
end
|
63
|
+
|
64
|
+
def eval_js(js_code)
|
65
|
+
@js_context_pool.with do |js_context|
|
66
|
+
result = js_context.eval(js_code)
|
67
|
+
js_context.eval("console.history = []")
|
68
|
+
result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_js_context
|
73
|
+
server_js_file = ReactOnRails.configuration.server_bundle_js_file
|
74
|
+
if server_js_file.present? && File.exist?(server_js_file)
|
75
|
+
bundle_js_code = File.read(server_js_file)
|
76
|
+
base_js_code = <<-JS
|
77
|
+
#{console_polyfill}
|
78
|
+
#{bundle_js_code};
|
79
|
+
#{::Rails.application.assets['react_on_rails.js']};
|
80
|
+
JS
|
81
|
+
ExecJS.compile(base_js_code)
|
82
|
+
else
|
83
|
+
if server_js_file.present?
|
84
|
+
Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
|
85
|
+
end
|
86
|
+
ExecJS.compile("")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Reimplement console methods for replaying on the client
|
91
|
+
def console_polyfill
|
92
|
+
<<-JS
|
93
|
+
var console = { history: [] };
|
94
|
+
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
95
|
+
console[level] = function () {
|
96
|
+
var argArray = Array.prototype.slice.call(arguments);
|
97
|
+
if (argArray.length > 0) {
|
98
|
+
argArray[0] = '[SERVER] ' + argArray[0];
|
99
|
+
}
|
100
|
+
console.history.push({level: level, arguments: argArray});
|
101
|
+
};
|
102
|
+
});
|
103
|
+
JS
|
104
|
+
end
|
105
|
+
end
|
100
106
|
end
|
101
107
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: react_on_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -148,6 +148,10 @@ files:
|
|
148
148
|
- app/assets/javascripts/react_on_rails.js
|
149
149
|
- app/helpers/react_on_rails_helper.rb
|
150
150
|
- docker-compose.yml
|
151
|
+
- docs/Contributing.md
|
152
|
+
- docs/README.md
|
153
|
+
- docs/sample_generated_js/client-generated.js
|
154
|
+
- docs/sample_generated_js/server-generated.js
|
151
155
|
- lib/react_on_rails.rb
|
152
156
|
- lib/react_on_rails/configuration.rb
|
153
157
|
- lib/react_on_rails/server_rendering_pool.rb
|
@@ -169,9 +173,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
169
173
|
version: '0'
|
170
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
175
|
requirements:
|
172
|
-
- - "
|
176
|
+
- - ">"
|
173
177
|
- !ruby/object:Gem::Version
|
174
|
-
version:
|
178
|
+
version: 1.3.1
|
175
179
|
requirements: []
|
176
180
|
rubyforge_project:
|
177
181
|
rubygems_version: 2.4.8
|