react-rails 0.13.0.0 → 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 +4 -4
- data/README.md +200 -37
- data/lib/assets/javascripts/react_ujs.js.erb +104 -0
- data/lib/generators/react/component_generator.rb +127 -0
- data/lib/generators/react/install_generator.rb +58 -0
- data/lib/generators/templates/component.js.jsx +23 -0
- data/lib/react-rails.rb +2 -0
- data/lib/react/console.rb +30 -0
- data/lib/react/jsx.rb +24 -9
- data/lib/react/jsx/template.rb +2 -2
- data/lib/react/rails.rb +1 -0
- data/lib/react/rails/engine.rb +1 -1
- data/lib/react/rails/railtie.rb +70 -19
- data/lib/react/rails/version.rb +2 -4
- data/lib/react/rails/view_helper.rb +28 -0
- data/lib/react/renderer.rb +83 -0
- metadata +115 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecb96344ad4094e2bb7d7ffe7b45455b807fc7a3
|
4
|
+
data.tar.gz: 8003608ada04a2d20573621278faa29daf6c838c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa90a0d40e3c856840d1b17bc207da5e2bc48f3b1587368eb97c6f4291776253a3b859fca7dbe01da62dd3c1ddd50dc2299bf80c3502bcc513b6e7fb3a9927b7
|
7
|
+
data.tar.gz: b126df93a0c17fba3c78e71433fc77d9688a6d3be7fb3ba45f1e968a24a8caaa151b29a5a9c3cccd29a446ddccf17f8409268c54476b7127ef78319c3ad26dfa
|
data/README.md
CHANGED
@@ -1,90 +1,253 @@
|
|
1
|
-
|
1
|
+
[](http://rubygems.org/gems/react-rails)
|
2
|
+
[](https://travis-ci.org/reactjs/react-rails)
|
3
|
+
[](https://gemnasium.com/reactjs/react-rails)
|
4
|
+
[](https://codeclimate.com/github/reactjs/react-rails)
|
2
5
|
|
3
|
-
|
6
|
+
* * *
|
4
7
|
|
5
|
-
|
8
|
+
# react-rails
|
6
9
|
|
7
|
-
1. making it easy to include `react.js` as part of your dependencies in `application.js`.
|
8
|
-
2. transforming JSX into regular JS on request, or as part of asset precompilation.
|
9
10
|
|
11
|
+
`react-rails` makes it easy to use [React](http://facebook.github.io/react/) and [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) in your Ruby on Rails (3.1+) application. `react-rails` can:
|
10
12
|
|
11
|
-
|
13
|
+
- Provide [various `react` builds](#reactjs-builds) to your asset bundle
|
14
|
+
- Transform [`.jsx` in the asset pipeline](#jsx)
|
15
|
+
- [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
|
16
|
+
- [Render components server-side](#server-rendering) with `prerender: true`.
|
17
|
+
- [Generate components](#component-generator) with a Rails generator
|
12
18
|
|
13
|
-
|
19
|
+
## Installation
|
14
20
|
|
15
|
-
|
21
|
+
Add `react-rails` to your gemfile:
|
16
22
|
|
17
23
|
```ruby
|
18
|
-
|
24
|
+
gem 'react-rails', '~> 1.0'
|
25
|
+
```
|
19
26
|
|
20
|
-
|
27
|
+
Next, run the installation script.
|
28
|
+
|
29
|
+
```bash
|
30
|
+
rails g react:install
|
21
31
|
```
|
22
32
|
|
33
|
+
This will:
|
34
|
+
- create a `components.js` manifest file and a `app/assets/javascripts/components/` directory, where you will put your components
|
35
|
+
- place the following in your `application.js`:
|
36
|
+
|
37
|
+
```js
|
38
|
+
//= require react
|
39
|
+
//= require react_ujs
|
40
|
+
//= require components
|
41
|
+
```
|
23
42
|
|
24
43
|
## Usage
|
25
44
|
|
26
|
-
###
|
45
|
+
### React.js builds
|
27
46
|
|
28
|
-
|
47
|
+
You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html))) to serve in each environment by adding a config. Here are the defaults:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# config/environments/development.rb
|
51
|
+
MyApp::Application.configure do
|
52
|
+
config.react.variant = :development
|
53
|
+
end
|
29
54
|
|
30
|
-
|
55
|
+
# config/environments/production.rb
|
56
|
+
MyApp::Application.configure do
|
57
|
+
config.react.variant = :production
|
58
|
+
end
|
59
|
+
```
|
31
60
|
|
32
|
-
|
33
|
-
// app/assets/application.js
|
61
|
+
To include add-ons, use this config:
|
34
62
|
|
35
|
-
|
63
|
+
```ruby
|
64
|
+
MyApp::Application.configure do
|
65
|
+
config.react.addons = true # defaults to false
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
After restarting your Rails server, `//= require react` will provide the build of React.js which was specified by the configurations.
|
70
|
+
|
71
|
+
`react-rails` offers a few other options for versions & builds of React.js. See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about using the `react-source` gem or dropping in your own copies of React.js.
|
72
|
+
|
73
|
+
### JSX
|
74
|
+
|
75
|
+
After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
|
76
|
+
|
77
|
+
You can use JSX `--harmony` or `--strip-types` options by adding a configuration:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
config.react.jsx_transform_options = {
|
81
|
+
harmony: true,
|
82
|
+
strip_types: true, # for removing Flow type annotations
|
83
|
+
}
|
84
|
+
```
|
85
|
+
|
86
|
+
To use CoffeeScript, create `.js.jsx.coffee` files and embed JSX inside backticks, for example:
|
87
|
+
|
88
|
+
```coffee
|
89
|
+
Component = React.createClass
|
90
|
+
render: ->
|
91
|
+
`<ExampleComponent videos={this.props.videos} />`
|
36
92
|
```
|
37
93
|
|
38
|
-
|
94
|
+
### Rendering & mounting
|
95
|
+
|
96
|
+
`react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`) which work together to put React components on the page. You should require the UJS driver in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks))
|
97
|
+
|
98
|
+
The __view helper__ puts a `div` on the page with the requested component class & props. For example:
|
39
99
|
|
40
100
|
```erb
|
41
|
-
|
101
|
+
<%= react_component('HelloMessage', name: 'John') %>
|
102
|
+
<!-- becomes: -->
|
103
|
+
<div data-react-class="HelloMessage" data-react-props="{"name":"John"}"></div>
|
104
|
+
```
|
105
|
+
|
106
|
+
On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class` and `data-react-props`. Before page unload, it will unmount components (if you want to disable this behavior, remove `data-react-class` attribute in `componentDidMount`).
|
107
|
+
|
108
|
+
`react_ujs` uses Turbolinks events if they're available, otherwise, it uses native events. __Turbolinks >= 2.4.0__ is recommended because it exposes better events.
|
42
109
|
|
43
|
-
|
110
|
+
The view helper's signature is
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
react_component(component_class_name, props={}, html_options={})
|
44
114
|
```
|
45
115
|
|
116
|
+
- `component_class_name` is a string which names a globally-accessible component class. It may have dots (eg, `"MyApp.Header.MenuItem"`).
|
117
|
+
- `props` is either an object that responds to `#to_json` or an already-stringified JSON object (eg, made with Jbuilder, see note below)
|
118
|
+
- `html_options` may include:
|
119
|
+
- `tag:` to use an element other than a `div` to embed `data-react-class` and `-props`.
|
120
|
+
- `prerender: true` to render the component on the server.
|
121
|
+
- `**other` Any other arguments (eg `class:`, `id:`) are passed through to [`content_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag).
|
46
122
|
|
47
|
-
### JSX
|
48
123
|
|
49
|
-
|
124
|
+
### Server rendering
|
125
|
+
|
126
|
+
To render components on the server, pass `prerender: true` to `react_component`:
|
50
127
|
|
128
|
+
```erb
|
129
|
+
<%= react_component('HelloMessage', {name: 'John'}, {prerender: true}) %>
|
130
|
+
<!-- becomes: -->
|
131
|
+
<div data-react-class="HelloMessage" data-react-props="{"name":"John"}">
|
132
|
+
<h1>Hello, John!</h1>
|
133
|
+
</div>
|
134
|
+
```
|
135
|
+
|
136
|
+
_(It will be also be mounted by the UJS on page load.)_
|
51
137
|
|
52
|
-
|
138
|
+
There are some requirements for this to work:
|
53
139
|
|
54
|
-
|
140
|
+
- `react-rails` must load your code. By convention, it uses `components.js`, which was created by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
|
141
|
+
- Your components must be accessible in the global scope. If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
|
55
142
|
|
56
|
-
|
143
|
+
```coffee
|
144
|
+
# @ is `window`:
|
145
|
+
@Component = React.createClass
|
146
|
+
render: ->
|
147
|
+
`<ExampleComponent videos={this.props.videos} />`
|
148
|
+
```
|
149
|
+
- Your code can't reference `document`. Prerender processes don't have access to `document`, so jQuery and some other libs won't work in this environment :(
|
150
|
+
|
151
|
+
You can configure your pool of JS virtual machines and specify where it should load code:
|
57
152
|
|
58
153
|
```ruby
|
59
|
-
# config/environments/
|
154
|
+
# config/environments/application.rb
|
155
|
+
# These are the defaults if you dont specify any yourself
|
60
156
|
MyApp::Application.configure do
|
61
|
-
|
157
|
+
# renderer pool size:
|
158
|
+
config.react.max_renderers = 10
|
159
|
+
# prerender timeout, in seconds:
|
160
|
+
config.react.timeout = 20
|
161
|
+
# where to get React.js source:
|
162
|
+
config.react.react_js = lambda { File.read(::Rails.application.assets.resolve('react.js')) }
|
163
|
+
# array of filenames that will be requested from the asset pipeline
|
164
|
+
# and concatenated:
|
165
|
+
config.react.component_filenames = ['components.js']
|
166
|
+
# server-side console.log, console.warn, and console.error messages will be replayed on the client
|
167
|
+
# (you can set this to `true` in config/enviroments/development.rb to replay in development only)
|
168
|
+
config.react.replay_console = false
|
62
169
|
end
|
170
|
+
```
|
63
171
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
172
|
+
### Component generator
|
173
|
+
|
174
|
+
react-rails ships with a Rails generator to help you get started with a simple component scaffold. You can run it using `rails generate react:component ComponentName`. The generator takes an optional list of arguments for default propTypes, which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html) section of the React documentation.
|
175
|
+
|
176
|
+
For example:
|
177
|
+
|
178
|
+
```shell
|
179
|
+
rails generate react:component Post title:string body:string published:bool published_by:instanceOf{Person}
|
68
180
|
```
|
69
181
|
|
70
|
-
|
182
|
+
would generate the following in `app/assets/javascripts/components/post.js.jsx`:
|
183
|
+
|
184
|
+
```jsx
|
185
|
+
var Post = React.createClass({
|
186
|
+
propTypes: {
|
187
|
+
title: React.PropTypes.string,
|
188
|
+
body: React.PropTypes.string,
|
189
|
+
published: React.PropTypes.bool,
|
190
|
+
publishedBy: React.PropTypes.instanceOf(Person)
|
191
|
+
},
|
192
|
+
|
193
|
+
render: function() {
|
194
|
+
return (
|
195
|
+
<div>
|
196
|
+
<div>Title: {this.props.title}</div>
|
197
|
+
<div>Body: {this.props.body}</div>
|
198
|
+
<div>Published: {this.props.published}</div>
|
199
|
+
<div>Published By: {this.props.published_by}</div>
|
200
|
+
</div>
|
201
|
+
);
|
202
|
+
}
|
203
|
+
});
|
204
|
+
```
|
205
|
+
|
206
|
+
The generator can use the following arguments to create basic propTypes:
|
207
|
+
|
208
|
+
* any
|
209
|
+
* array
|
210
|
+
* bool
|
211
|
+
* element
|
212
|
+
* func
|
213
|
+
* number
|
214
|
+
* object
|
215
|
+
* node
|
216
|
+
* shape
|
217
|
+
* string
|
218
|
+
|
219
|
+
The following additional arguments have special behavior:
|
71
220
|
|
72
|
-
|
221
|
+
* `instanceOf` takes an optional class name in the form of {className}
|
222
|
+
* `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
|
223
|
+
* `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`
|
224
|
+
|
225
|
+
Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes to prevent your terminal from expanding them into an argument list.
|
226
|
+
|
227
|
+
### Jbuilder & react-rails
|
228
|
+
|
229
|
+
If you use Jbuilder to pass JSON string to `react_component`, make sure your JSON is a stringified hash, not an array. This is not the Rails default -- you should add the root node yourself. For example:
|
73
230
|
|
74
231
|
```ruby
|
75
|
-
|
76
|
-
|
232
|
+
# BAD: returns a stringified array
|
233
|
+
json.array!(@messages) do |message|
|
234
|
+
json.extract! message, :id, :name
|
235
|
+
json.url message_url(message, format: :json)
|
77
236
|
end
|
78
|
-
```
|
79
237
|
|
238
|
+
# GOOD: returns a stringified hash
|
239
|
+
json.messages(@messages) do |message|
|
240
|
+
json.extract! message, :id, :name
|
241
|
+
json.url message_url(message, format: :json)
|
242
|
+
end
|
243
|
+
```
|
80
244
|
|
81
245
|
## CoffeeScript
|
82
246
|
|
83
|
-
It is possible to use JSX with CoffeeScript. We need to embed JSX inside backticks so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
|
247
|
+
It is possible to use JSX with CoffeeScript. The caveat is that you will still need to include the docblock. Since CoffeeScript doesn't allow `/* */` style comments, we need to do something a little different. We also need to embed JSX inside backticks so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
|
84
248
|
|
85
249
|
```coffee
|
86
250
|
Component = React.createClass
|
87
251
|
render: ->
|
88
252
|
`<ExampleComponent videos={this.props.videos} />`
|
89
253
|
```
|
90
|
-
|
@@ -0,0 +1,104 @@
|
|
1
|
+
/*globals React, Turbolinks*/
|
2
|
+
|
3
|
+
// Unobtrusive scripting adapter for React
|
4
|
+
;(function(document, window) {
|
5
|
+
// jQuery is optional. Use it to support legacy browsers.
|
6
|
+
var $ = (typeof window.jQuery !== 'undefined') && window.jQuery;
|
7
|
+
|
8
|
+
// create the namespace
|
9
|
+
window.ReactRailsUJS = {
|
10
|
+
CLASS_NAME_ATTR: 'data-react-class',
|
11
|
+
PROPS_ATTR: 'data-react-props',
|
12
|
+
RAILS_ENV_DEVELOPMENT: <%= Rails.env == "development" %>,
|
13
|
+
// helper method for the mount and unmount methods to find the
|
14
|
+
// `data-react-class` DOM elements
|
15
|
+
findDOMNodes: function(searchSelector) {
|
16
|
+
// we will use fully qualified paths as we do not bind the callbacks
|
17
|
+
var selector;
|
18
|
+
if (typeof searchSelector === 'undefined') {
|
19
|
+
var selector = '[' + window.ReactRailsUJS.CLASS_NAME_ATTR + ']';
|
20
|
+
} else {
|
21
|
+
var selector = searchSelector + ' [' + window.ReactRailsUJS.CLASS_NAME_ATTR + ']';
|
22
|
+
}
|
23
|
+
|
24
|
+
if ($) {
|
25
|
+
return $(selector);
|
26
|
+
} else {
|
27
|
+
return document.querySelectorAll(selector);
|
28
|
+
}
|
29
|
+
},
|
30
|
+
|
31
|
+
mountComponents: function(searchSelector) {
|
32
|
+
var nodes = window.ReactRailsUJS.findDOMNodes(searchSelector);
|
33
|
+
|
34
|
+
for (var i = 0; i < nodes.length; ++i) {
|
35
|
+
var node = nodes[i];
|
36
|
+
var className = node.getAttribute(window.ReactRailsUJS.CLASS_NAME_ATTR);
|
37
|
+
|
38
|
+
// Assume className is simple and can be found at top-level (window).
|
39
|
+
// Fallback to eval to handle cases like 'My.React.ComponentName'.
|
40
|
+
var constructor = window[className] || eval.call(window, className);
|
41
|
+
var propsJson = node.getAttribute(window.ReactRailsUJS.PROPS_ATTR);
|
42
|
+
var props = propsJson && JSON.parse(propsJson);
|
43
|
+
|
44
|
+
React.render(React.createElement(constructor, props), node);
|
45
|
+
}
|
46
|
+
},
|
47
|
+
|
48
|
+
unmountComponents: function(searchSelector) {
|
49
|
+
var nodes = window.ReactRailsUJS.findDOMNodes(searchSelector);
|
50
|
+
|
51
|
+
for (var i = 0; i < nodes.length; ++i) {
|
52
|
+
var node = nodes[i];
|
53
|
+
|
54
|
+
React.unmountComponentAtNode(node);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
};
|
58
|
+
|
59
|
+
// functions not exposed publicly
|
60
|
+
function handleTurbolinksEvents () {
|
61
|
+
var handleEvent;
|
62
|
+
var unmountEvent;
|
63
|
+
|
64
|
+
if ($) {
|
65
|
+
handleEvent = function(eventName, callback) {
|
66
|
+
$(document).on(eventName, callback);
|
67
|
+
};
|
68
|
+
|
69
|
+
} else {
|
70
|
+
handleEvent = function(eventName, callback) {
|
71
|
+
document.addEventListener(eventName, callback);
|
72
|
+
};
|
73
|
+
}
|
74
|
+
|
75
|
+
if (Turbolinks.EVENTS) {
|
76
|
+
unmountEvent = Turbolinks.EVENTS.BEFORE_UNLOAD;
|
77
|
+
} else {
|
78
|
+
unmountEvent = 'page:receive';
|
79
|
+
Turbolinks.pagesCached(0);
|
80
|
+
|
81
|
+
if (window.ReactRailsUJS.RAILS_ENV_DEVELOPMENT) {
|
82
|
+
console.warn('The Turbolinks cache has been disabled (Turbolinks >= 2.4.0 is recommended). See https://github.com/reactjs/react-rails/issues/87 for more information.');
|
83
|
+
}
|
84
|
+
}
|
85
|
+
handleEvent('page:change', function() {window.ReactRailsUJS.mountComponents()});
|
86
|
+
handleEvent(unmountEvent, function() {window.ReactRailsUJS.unmountComponents()});
|
87
|
+
}
|
88
|
+
|
89
|
+
function handleNativeEvents() {
|
90
|
+
if ($) {
|
91
|
+
$(function() {window.ReactRailsUJS.mountComponents()});
|
92
|
+
$(window).unload(function() {window.ReactRailsUJS.unmountComponents()});
|
93
|
+
} else {
|
94
|
+
document.addEventListener('DOMContentLoaded', function() {window.ReactRailsUJS.mountComponents()});
|
95
|
+
window.addEventListener('unload', function() {window.ReactRailsUJS.unmountComponents()});
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
|
100
|
+
handleTurbolinksEvents();
|
101
|
+
} else {
|
102
|
+
handleNativeEvents();
|
103
|
+
}
|
104
|
+
})(document, window);
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module React
|
2
|
+
module Generators
|
3
|
+
class ComponentGenerator < ::Rails::Generators::NamedBase
|
4
|
+
source_root File.expand_path '../../templates', __FILE__
|
5
|
+
desc <<-DESC.strip_heredoc
|
6
|
+
Description:
|
7
|
+
Scaffold a react component into app/assets/javascripts/components.
|
8
|
+
The generated component will include a basic render function and a PropTypes
|
9
|
+
hash to help with development.
|
10
|
+
|
11
|
+
Available field types:
|
12
|
+
|
13
|
+
Basic prop types do not take any additional arguments. If you do not specify
|
14
|
+
a prop type, the generic node will be used. The basic types available are:
|
15
|
+
|
16
|
+
any
|
17
|
+
array
|
18
|
+
bool
|
19
|
+
element
|
20
|
+
func
|
21
|
+
number
|
22
|
+
object
|
23
|
+
node
|
24
|
+
shape
|
25
|
+
string
|
26
|
+
|
27
|
+
Special PropTypes take additional arguments in {}, and must be enclosed in
|
28
|
+
single quotes to keep bash from expanding the arguments in {}.
|
29
|
+
|
30
|
+
instanceOf
|
31
|
+
takes an optional class name in the form of {className}
|
32
|
+
|
33
|
+
oneOf
|
34
|
+
behaves like an enum, and takes an optional list of strings that will
|
35
|
+
be allowed in the form of 'name:oneOf{one,two,three}'.
|
36
|
+
|
37
|
+
oneOfType.
|
38
|
+
oneOfType takes an optional list of react and custom types in the form of
|
39
|
+
'model:oneOfType{string,number,OtherType}'
|
40
|
+
|
41
|
+
Examples:
|
42
|
+
rails g react:component person name
|
43
|
+
rails g react:component restaurant name:string rating:number owner:instanceOf{Person}
|
44
|
+
rails g react:component food 'kind:oneOf{meat,cheese,vegetable}'
|
45
|
+
rails g react:component events 'location:oneOfType{string,Restaurant}'
|
46
|
+
DESC
|
47
|
+
|
48
|
+
argument :attributes,
|
49
|
+
:type => :array,
|
50
|
+
:default => [],
|
51
|
+
:banner => "field[:type] field[:type] ..."
|
52
|
+
|
53
|
+
REACT_PROP_TYPES = {
|
54
|
+
"node" => 'React.PropTypes.node',
|
55
|
+
"bool" => 'React.PropTypes.bool',
|
56
|
+
"boolean" => 'React.PropTypes.bool',
|
57
|
+
"string" => 'React.PropTypes.string',
|
58
|
+
"number" => 'React.PropTypes.number',
|
59
|
+
"object" => 'React.PropTypes.object',
|
60
|
+
"array" => 'React.PropTypes.array',
|
61
|
+
"shape" => 'React.PropTypes.shape({})',
|
62
|
+
"element" => 'React.PropTypes.element',
|
63
|
+
"func" => 'React.PropTypes.func',
|
64
|
+
"function" => 'React.PropTypes.func',
|
65
|
+
"any" => 'React.PropTypes.any',
|
66
|
+
|
67
|
+
"instanceOf" => ->(type) {
|
68
|
+
'React.PropTypes.instanceOf(%s)' % type.to_s.camelize
|
69
|
+
},
|
70
|
+
|
71
|
+
"oneOf" => ->(*options) {
|
72
|
+
enums = options.map{|k| "'#{k.to_s}'"}.join(',')
|
73
|
+
'React.PropTypes.oneOf([%s])' % enums
|
74
|
+
},
|
75
|
+
|
76
|
+
"oneOfType" => ->(*options) {
|
77
|
+
types = options.map{|k| "#{lookup(k.to_s, k.to_s)}" }.join(',')
|
78
|
+
'React.PropTypes.oneOfType([%s])' % types
|
79
|
+
},
|
80
|
+
}
|
81
|
+
|
82
|
+
def create_component_file
|
83
|
+
extension = "js.jsx"
|
84
|
+
file_path = File.join('app/assets/javascripts/components', "#{file_name}.#{extension}")
|
85
|
+
template("component.#{extension}", file_path)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def parse_attributes!
|
91
|
+
self.attributes = (attributes || []).map do |attr|
|
92
|
+
name, type, options = "", "", ""
|
93
|
+
options_regex = /(?<options>{.*})/
|
94
|
+
|
95
|
+
name, type = attr.split(':')
|
96
|
+
|
97
|
+
if matchdata = options_regex.match(type)
|
98
|
+
options = matchdata[:options]
|
99
|
+
type = type.gsub(options_regex, '')
|
100
|
+
end
|
101
|
+
|
102
|
+
{ :name => name, :type => lookup(type, options) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.lookup(type = "node", options = "")
|
107
|
+
react_prop_type = REACT_PROP_TYPES[type]
|
108
|
+
if react_prop_type.blank?
|
109
|
+
if type =~ /^[[:upper:]]/
|
110
|
+
react_prop_type = REACT_PROP_TYPES['instanceOf']
|
111
|
+
else
|
112
|
+
react_prop_type = REACT_PROP_TYPES['node']
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
options = options.to_s.gsub(/[{}]/, '').split(',')
|
117
|
+
|
118
|
+
react_prop_type = react_prop_type.call(*options) if react_prop_type.respond_to? :call
|
119
|
+
react_prop_type
|
120
|
+
end
|
121
|
+
|
122
|
+
def lookup(type = "node", options = "")
|
123
|
+
self.class.lookup(type, options)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module React
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < ::Rails::Generators::Base
|
4
|
+
source_root File.expand_path '../../templates', __FILE__
|
5
|
+
|
6
|
+
desc 'Create default react.js folder layout and prep application.js'
|
7
|
+
|
8
|
+
class_option :skip_git,
|
9
|
+
type: :boolean,
|
10
|
+
aliases: '-g',
|
11
|
+
default: false,
|
12
|
+
desc: 'Skip Git keeps'
|
13
|
+
|
14
|
+
def create_directory
|
15
|
+
empty_directory 'app/assets/javascripts/components'
|
16
|
+
create_file 'app/assets/javascripts/components/.gitkeep' unless options[:skip_git]
|
17
|
+
end
|
18
|
+
|
19
|
+
def inject_react
|
20
|
+
require_react = "//= require react\n"
|
21
|
+
|
22
|
+
if manifest.exist?
|
23
|
+
manifest_contents = File.read(manifest)
|
24
|
+
|
25
|
+
if manifest_contents.include? 'require turbolinks'
|
26
|
+
inject_into_file manifest, require_react, {after: "//= require turbolinks\n"}
|
27
|
+
elsif manifest_contents.include? 'require_tree'
|
28
|
+
inject_into_file manifest, require_react, {before: '//= require_tree'}
|
29
|
+
else
|
30
|
+
append_file manifest, require_react
|
31
|
+
end
|
32
|
+
else
|
33
|
+
create_file manifest, require_react
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def inject_components
|
38
|
+
inject_into_file manifest, "//= require components\n", {after: "//= require react\n"}
|
39
|
+
end
|
40
|
+
|
41
|
+
def inject_react_ujs
|
42
|
+
inject_into_file manifest, "//= require react_ujs\n", {after: "//= require react\n"}
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_components
|
46
|
+
components_js = "//= require_tree ./components\n"
|
47
|
+
components_file = File.join(*%w(app assets javascripts components.js))
|
48
|
+
create_file components_file, components_js
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def manifest
|
54
|
+
Pathname.new(destination_root).join('app/assets/javascripts', 'application.js')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
var <%= file_name.camelize %> = React.createClass({
|
2
|
+
<% if attributes.size > 0 -%>
|
3
|
+
propTypes: {
|
4
|
+
<% attributes.each_with_index do |attribute, idx| -%>
|
5
|
+
<%= attribute[:name].camelize(:lower) %>: <%= attribute[:type] %><% if (idx < attributes.length-1) %>,<% end %>
|
6
|
+
<% end -%>
|
7
|
+
},
|
8
|
+
<% end -%>
|
9
|
+
|
10
|
+
render: function() {
|
11
|
+
<% if attributes.size > 0 -%>
|
12
|
+
return (
|
13
|
+
<div>
|
14
|
+
<% attributes.each do |attribute| -%>
|
15
|
+
<div><%= attribute[:name].titleize %>: {this.props.<%= attribute[:name] %>}</div>
|
16
|
+
<% end -%>
|
17
|
+
</div>
|
18
|
+
);
|
19
|
+
<% else -%>
|
20
|
+
return <div />;
|
21
|
+
<% end -%>
|
22
|
+
}
|
23
|
+
});
|
data/lib/react-rails.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
module React
|
2
|
+
class Console
|
3
|
+
def self.polyfill_js
|
4
|
+
# Overwrite global `console` object with something that can capture messages
|
5
|
+
# to return to client later for debugging
|
6
|
+
<<-JS
|
7
|
+
var console = { history: [] };
|
8
|
+
['error', 'log', 'info', 'warn'].forEach(function (fn) {
|
9
|
+
console[fn] = function () {
|
10
|
+
console.history.push({level: fn, arguments: Array.prototype.slice.call(arguments)});
|
11
|
+
};
|
12
|
+
});
|
13
|
+
JS
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.replay_as_script_js
|
17
|
+
<<-JS
|
18
|
+
(function (history) {
|
19
|
+
if (history && history.length > 0) {
|
20
|
+
result += '\\n<scr'+'ipt>';
|
21
|
+
history.forEach(function (msg) {
|
22
|
+
result += '\\nconsole.' + msg.level + '.apply(console, ' + JSON.stringify(msg.arguments) + ');';
|
23
|
+
});
|
24
|
+
result += '\\n</scr'+'ipt>';
|
25
|
+
}
|
26
|
+
})(console.history);
|
27
|
+
JS
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/react/jsx.rb
CHANGED
@@ -1,21 +1,36 @@
|
|
1
1
|
require 'execjs'
|
2
2
|
require 'react/source'
|
3
3
|
require 'react/jsx/template'
|
4
|
+
require 'rails'
|
4
5
|
|
5
6
|
module React
|
6
7
|
module JSX
|
8
|
+
mattr_accessor :transform_options
|
9
|
+
|
7
10
|
def self.context
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# lazily loaded during first request and reloaded every time when in dev or test
|
12
|
+
unless @context && ::Rails.env.production?
|
13
|
+
contents =
|
14
|
+
# If execjs uses therubyracer, there is no 'global'. Make sure
|
15
|
+
# we have it so JSX script can work properly.
|
16
|
+
'var global = global || this;' +
|
17
|
+
|
18
|
+
# search for transformer file using sprockets - allows user to override
|
19
|
+
# this file in his own application
|
20
|
+
File.read(::Rails.application.assets.resolve('JSXTransformer.js'))
|
21
|
+
|
22
|
+
@context = ExecJS.compile(contents)
|
23
|
+
end
|
24
|
+
|
25
|
+
@context
|
15
26
|
end
|
16
27
|
|
17
|
-
def self.transform(code)
|
18
|
-
|
28
|
+
def self.transform(code, options={})
|
29
|
+
js_options = {
|
30
|
+
stripTypes: options[:strip_types],
|
31
|
+
harmony: options[:harmony],
|
32
|
+
}
|
33
|
+
result = context.call('JSXTransformer.transform', code, js_options)
|
19
34
|
return result['code']
|
20
35
|
end
|
21
36
|
end
|
data/lib/react/jsx/template.rb
CHANGED
data/lib/react/rails.rb
CHANGED
data/lib/react/rails/engine.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module React
|
2
2
|
module Rails
|
3
3
|
class Engine < ::Rails::Engine
|
4
|
-
initializer "react_rails.setup_engine", :
|
4
|
+
initializer "react_rails.setup_engine", :group => :all do |app|
|
5
5
|
app.assets.register_engine '.jsx', React::JSX::Template
|
6
6
|
end
|
7
7
|
end
|
data/lib/react/rails/railtie.rb
CHANGED
@@ -5,32 +5,83 @@ module React
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
config.react = ActiveSupport::OrderedOptions.new
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
# Sensible defaults. Can be overridden in application.rb
|
9
|
+
config.react.variant = (::Rails.env.production? ? :production : :development)
|
10
|
+
config.react.addons = false
|
11
|
+
config.react.jsx_transform_options = {}
|
12
|
+
# Server-side rendering
|
13
|
+
config.react.max_renderers = 10
|
14
|
+
config.react.timeout = 20 #seconds
|
15
|
+
config.react.react_js = lambda {File.read(::Rails.application.assets.resolve('react.js'))}
|
16
|
+
config.react.component_filenames = ['components.js']
|
10
17
|
|
18
|
+
# Watch .jsx files for changes in dev, so we can reload the JS VMs with the new JS code.
|
19
|
+
initializer "react_rails.add_watchable_files", group: :all do |app|
|
20
|
+
app.config.watchable_files.concat Dir["#{app.root}/app/assets/javascripts/**/*.jsx*"]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Include the react-rails view helper lazily
|
24
|
+
initializer "react_rails.setup_view_helpers", group: :all do |app|
|
25
|
+
React::JSX.transform_options = app.config.react.jsx_transform_options
|
26
|
+
ActiveSupport.on_load(:action_view) do
|
27
|
+
include ::React::Rails::ViewHelper
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
initializer "react_rails.setup_vendor", group: :all do |app|
|
11
32
|
# Mimic behavior of ember-rails...
|
12
33
|
# We want to include different files in dev/prod. The unminified builds
|
13
34
|
# contain console logging for invariants and logging to help catch
|
14
35
|
# common mistakes. These are all stripped out in the minified build.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
|
37
|
+
# Copy over the variant into a path that sprockets will pick up.
|
38
|
+
# We'll always copy to 'react.js' so that no includes need to change.
|
39
|
+
# We'll also always copy of JSXTransformer.js
|
40
|
+
tmp_path = app.root.join('tmp/react-rails')
|
41
|
+
filename = 'react' +
|
42
|
+
(app.config.react.addons ? '-with-addons' : '') +
|
43
|
+
(app.config.react.variant == :production ? '.min.js' : '.js')
|
44
|
+
FileUtils.mkdir_p(tmp_path)
|
45
|
+
FileUtils.cp(::React::Source.bundled_path_for(filename),
|
46
|
+
tmp_path.join('react.js'))
|
47
|
+
FileUtils.cp(::React::Source.bundled_path_for('JSXTransformer.js'),
|
48
|
+
tmp_path.join('JSXTransformer.js'))
|
49
|
+
app.assets.prepend_path tmp_path
|
50
|
+
|
51
|
+
# Allow overriding react files that are not based on environment
|
52
|
+
# e.g. /vendor/assets/react/JSXTransformer.js
|
53
|
+
dropin_path = app.root.join("vendor/assets/react")
|
54
|
+
app.assets.prepend_path dropin_path if dropin_path.exist?
|
55
|
+
|
56
|
+
# Allow overriding react files that are based on environment
|
57
|
+
# e.g. /vendor/assets/react/development/react.js
|
58
|
+
dropin_path_env = app.root.join("vendor/assets/react/#{app.config.react.variant}")
|
59
|
+
app.assets.prepend_path dropin_path_env if dropin_path_env.exist?
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
config.after_initialize do |app|
|
64
|
+
# Server Rendering
|
65
|
+
# Concat component_filenames together for server rendering
|
66
|
+
app.config.react.components_js = lambda {
|
67
|
+
app.config.react.component_filenames.map do |filename|
|
68
|
+
app.assets[filename].to_s
|
69
|
+
end.join(";")
|
70
|
+
}
|
71
|
+
|
72
|
+
do_setup = lambda do
|
73
|
+
cfg = app.config.react
|
74
|
+
React::Renderer.setup!( cfg.react_js, cfg.components_js, cfg.replay_console,
|
75
|
+
{:size => cfg.max_renderers, :timeout => cfg.timeout})
|
32
76
|
end
|
77
|
+
|
78
|
+
do_setup.call
|
79
|
+
|
80
|
+
# Reload the JS VMs in dev when files change
|
81
|
+
ActionDispatch::Reloader.to_prepare(&do_setup)
|
33
82
|
end
|
83
|
+
|
84
|
+
|
34
85
|
end
|
35
86
|
end
|
36
87
|
end
|
data/lib/react/rails/version.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module React
|
2
2
|
module Rails
|
3
|
-
#
|
4
|
-
|
5
|
-
VERSION = '0.13.0.0'
|
3
|
+
# If you change this, make sure to update VERSIONS.md
|
4
|
+
VERSION = '1.0.0'
|
6
5
|
end
|
7
6
|
end
|
8
|
-
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module React
|
2
|
+
module Rails
|
3
|
+
module ViewHelper
|
4
|
+
|
5
|
+
# Render a UJS-type HTML tag annotated with data attributes, which
|
6
|
+
# are used by react_ujs to actually instantiate the React component
|
7
|
+
# on the client.
|
8
|
+
#
|
9
|
+
def react_component(name, args = {}, options = {}, &block)
|
10
|
+
options = {:tag => options} if options.is_a?(Symbol)
|
11
|
+
block = Proc.new{concat React::Renderer.render(name, args)} if options[:prerender]
|
12
|
+
|
13
|
+
html_options = options.reverse_merge(:data => {})
|
14
|
+
html_options[:data].tap do |data|
|
15
|
+
data[:react_class] = name
|
16
|
+
data[:react_props] = React::Renderer.react_props(args) unless args.empty?
|
17
|
+
end
|
18
|
+
html_tag = html_options[:tag] || :div
|
19
|
+
|
20
|
+
# remove internally used properties so they aren't rendered to DOM
|
21
|
+
html_options.except!(:tag, :prerender)
|
22
|
+
|
23
|
+
content_tag(html_tag, '', html_options, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
|
3
|
+
module React
|
4
|
+
class Renderer
|
5
|
+
|
6
|
+
class PrerenderError < RuntimeError
|
7
|
+
def initialize(component_name, props, js_message)
|
8
|
+
message = ["Encountered error \"#{js_message}\" when prerendering #{component_name} with #{props}",
|
9
|
+
js_message.backtrace.join("\n")].join("\n")
|
10
|
+
super(message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
cattr_accessor :pool
|
15
|
+
|
16
|
+
def self.setup!(react_js, components_js, replay_console, args={})
|
17
|
+
args.assert_valid_keys(:size, :timeout)
|
18
|
+
@@react_js = react_js
|
19
|
+
@@components_js = components_js
|
20
|
+
@@replay_console = replay_console
|
21
|
+
@@pool.shutdown{} if @@pool
|
22
|
+
reset_combined_js!
|
23
|
+
default_pool_options = {:size =>10, :timeout => 20}
|
24
|
+
@@pool = ConnectionPool.new(default_pool_options.merge(args)) { self.new }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.render(component, args={})
|
28
|
+
@@pool.with do |renderer|
|
29
|
+
renderer.render(component, args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.react_props(args={})
|
34
|
+
if args.is_a? String
|
35
|
+
args
|
36
|
+
else
|
37
|
+
args.to_json
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def context
|
42
|
+
@context ||= ExecJS.compile(self.class.combined_js)
|
43
|
+
end
|
44
|
+
|
45
|
+
def render(component, args={})
|
46
|
+
react_props = React::Renderer.react_props(args)
|
47
|
+
jscode = <<-JS
|
48
|
+
(function () {
|
49
|
+
var result = React.renderToString(React.createElement(#{component}, #{react_props}));
|
50
|
+
#{@@replay_console ? React::Console.replay_as_script_js : ''}
|
51
|
+
return result;
|
52
|
+
})()
|
53
|
+
JS
|
54
|
+
context.eval(jscode).html_safe
|
55
|
+
rescue ExecJS::ProgramError => e
|
56
|
+
raise PrerenderError.new(component, react_props, e)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.setup_combined_js
|
63
|
+
<<-JS
|
64
|
+
var global = global || this;
|
65
|
+
var self = self || this;
|
66
|
+
var window = window || this;
|
67
|
+
#{React::Console.polyfill_js}
|
68
|
+
#{@@react_js.call};
|
69
|
+
React = global.React;
|
70
|
+
#{@@components_js.call};
|
71
|
+
JS
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.reset_combined_js!
|
75
|
+
@@combined_js = setup_combined_js
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.combined_js
|
79
|
+
@@combined_js
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: react-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul O’Shannessy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: appraisal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,7 +39,7 @@ dependencies:
|
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: 1.2.2
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: coffee-rails
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
@@ -39,14 +53,98 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: es5-shim-rails
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.5
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.5
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jbuilder
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
79
|
requirements:
|
45
80
|
- - ">="
|
46
81
|
- !ruby/object:Gem::Version
|
47
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: poltergeist
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.3.3
|
48
90
|
type: :development
|
49
91
|
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.3.3
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: test-unit
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.5'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.5'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: turbolinks
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.0.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 2.0.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: coffee-script-source
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.8'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.8'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: connection_pool
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
50
148
|
version_requirements: !ruby/object:Gem::Requirement
|
51
149
|
requirements:
|
52
150
|
- - ">="
|
@@ -84,16 +182,16 @@ dependencies:
|
|
84
182
|
name: react-source
|
85
183
|
requirement: !ruby/object:Gem::Requirement
|
86
184
|
requirements:
|
87
|
-
- -
|
185
|
+
- - "~>"
|
88
186
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.13
|
187
|
+
version: '0.13'
|
90
188
|
type: :runtime
|
91
189
|
prerelease: false
|
92
190
|
version_requirements: !ruby/object:Gem::Requirement
|
93
191
|
requirements:
|
94
|
-
- -
|
192
|
+
- - "~>"
|
95
193
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.13
|
194
|
+
version: '0.13'
|
97
195
|
description: Compile your JSX on demand or precompile for production.
|
98
196
|
email:
|
99
197
|
- paul@oshannessy.com
|
@@ -103,14 +201,21 @@ extra_rdoc_files: []
|
|
103
201
|
files:
|
104
202
|
- LICENSE
|
105
203
|
- README.md
|
204
|
+
- lib/assets/javascripts/react_ujs.js.erb
|
205
|
+
- lib/generators/react/component_generator.rb
|
206
|
+
- lib/generators/react/install_generator.rb
|
207
|
+
- lib/generators/templates/component.js.jsx
|
106
208
|
- lib/react-rails.rb
|
209
|
+
- lib/react/console.rb
|
107
210
|
- lib/react/jsx.rb
|
108
211
|
- lib/react/jsx/template.rb
|
109
212
|
- lib/react/rails.rb
|
110
213
|
- lib/react/rails/engine.rb
|
111
214
|
- lib/react/rails/railtie.rb
|
112
215
|
- lib/react/rails/version.rb
|
113
|
-
|
216
|
+
- lib/react/rails/view_helper.rb
|
217
|
+
- lib/react/renderer.rb
|
218
|
+
homepage: https://github.com/reactjs/react-rails
|
114
219
|
licenses:
|
115
220
|
- APL 2.0
|
116
221
|
metadata: {}
|
@@ -130,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
235
|
version: '0'
|
131
236
|
requirements: []
|
132
237
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.
|
238
|
+
rubygems_version: 2.4.5
|
134
239
|
signing_key:
|
135
240
|
specification_version: 4
|
136
241
|
summary: React/JSX adapter for the Ruby on Rails asset pipeline.
|