reactrb 0.8.3 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/component-name-lookup.md +145 -0
- data/config.ru +0 -1
- data/lib/react/api.rb +31 -2
- data/lib/react/component.rb +15 -126
- data/lib/react/component/class_methods.rb +45 -22
- data/lib/react/component/dsl_instance_methods.rb +57 -0
- data/lib/react/component/props_wrapper.rb +6 -0
- data/lib/react/component/tags.rb +96 -0
- data/lib/react/native_library.rb +76 -39
- data/lib/react/rendering_context.rb +19 -21
- data/lib/react/top_level.rb +19 -29
- data/lib/reactive-ruby/rails/component_mount.rb +3 -1
- data/lib/reactive-ruby/rails/controller_helper.rb +10 -10
- data/lib/reactive-ruby/version.rb +1 -1
- data/lib/reactrb.rb +16 -15
- data/lib/reactrb/auto-import.rb +32 -0
- data/lib/sources/react-v14.js +84 -0
- data/spec/react/component_spec.rb +0 -41
- data/spec/react/dsl_spec.rb +114 -4
- data/spec/react/native_library_spec.rb +293 -5
- data/spec/react/opal_jquery_extensions_spec.rb +4 -2
- data/spec/spec_helper.rb +3 -1
- metadata +7 -2
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'action_controller'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
module ActionController
|
4
|
+
# adds render_component helper to ActionControllers
|
5
|
+
class Base
|
6
|
+
def render_component(*args)
|
7
|
+
@component_name = (args[0].is_a? Hash) || args.empty? ? params[:action].camelize : args.shift
|
8
|
+
@render_params = args.shift || {}
|
9
|
+
options = args[0] || {}
|
10
|
+
render inline: '<%= react_component @component_name, @render_params, '\
|
11
|
+
'{ prerender: !params[:no_prerender] } %>',
|
12
|
+
layout: options.key?(:layout) ? options[:layout].to_s : :default
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
data/lib/reactrb.rb
CHANGED
@@ -2,26 +2,25 @@
|
|
2
2
|
|
3
3
|
if RUBY_ENGINE == 'opal'
|
4
4
|
if `window.React === undefined || window.React.version === undefined`
|
5
|
-
raise
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
"OR TO USE A SPECIFIC VERSION",
|
18
|
-
" add 'require \"react-v1x\"' immediately before the require of 'reactrb'."
|
19
|
-
].join("\n")
|
5
|
+
raise "No React.js Available\n\n"\
|
6
|
+
"React.js must be defined before requiring 'reactrb'\n"\
|
7
|
+
"'reactrb' has been tested with react v13, v14, and v15.\n\n"\
|
8
|
+
"IF USING 'react-rails':\n"\
|
9
|
+
" add 'require \"react\"' immediately before the 'require \"reactive-ruby\" "\
|
10
|
+
"directive in 'views/components.rb'.\n"\
|
11
|
+
"IF USING WEBPACK:\n"\
|
12
|
+
" add 'react' to your webpack manifest.\n"\
|
13
|
+
"OTHERWISE TO GET THE LATEST TESTED VERSION\n"\
|
14
|
+
" add 'require \"react-latest\"' immediately before the require of 'reactrb',\n"\
|
15
|
+
"OR TO USE A SPECIFIC VERSION\n"\
|
16
|
+
" add 'require \"react-v1x\"' immediately before the require of 'reactrb'."
|
20
17
|
end
|
21
18
|
require 'react/hash'
|
22
19
|
require 'react/top_level'
|
23
20
|
require 'react/observable'
|
24
21
|
require 'react/component'
|
22
|
+
require 'react/component/dsl_instance_methods'
|
23
|
+
require 'react/component/tags'
|
25
24
|
require 'react/component/base'
|
26
25
|
require 'react/element'
|
27
26
|
require 'react/event'
|
@@ -36,10 +35,12 @@ if RUBY_ENGINE == 'opal'
|
|
36
35
|
else
|
37
36
|
require 'opal'
|
38
37
|
require 'opal-browser'
|
38
|
+
# rubocop:disable Lint/HandleExceptions
|
39
39
|
begin
|
40
40
|
require 'opal-jquery'
|
41
41
|
rescue LoadError
|
42
42
|
end
|
43
|
+
# rubocop:enable Lint/HandleExceptions
|
43
44
|
require 'opal-activesupport'
|
44
45
|
require 'reactive-ruby/version'
|
45
46
|
require 'reactive-ruby/rails' if defined?(Rails)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# rubocop:disable Style/FileName
|
2
|
+
# require 'reactrb/auto-import' to automatically
|
3
|
+
# import JS libraries and components when they are detected
|
4
|
+
if RUBY_ENGINE == 'opal'
|
5
|
+
# modifies const and method_missing so that they will attempt
|
6
|
+
# to auto import native libraries and components using React::NativeLibrary
|
7
|
+
class Object
|
8
|
+
class << self
|
9
|
+
alias _reactrb_original_const_missing const_missing
|
10
|
+
alias _reactrb_original_method_missing method_missing
|
11
|
+
|
12
|
+
def const_missing(const_name)
|
13
|
+
# Opal uses const_missing to initially define things,
|
14
|
+
# so we always call the original, and respond to the exception
|
15
|
+
_reactrb_original_const_missing(const_name)
|
16
|
+
rescue StandardError => e
|
17
|
+
React::NativeLibrary.import_const_from_native(Object, const_name, true) || raise(e)
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method_name, *args, &block)
|
21
|
+
method = method_name.gsub(/_as_node/, '') # remove once _as_node is deprecated.
|
22
|
+
component_class = React::NativeLibrary.import_const_from_native(self, method, false)
|
23
|
+
_reactrb_original_method_missing(method, *args, &block) unless component_class
|
24
|
+
if method == method_name
|
25
|
+
React::RenderingContext.render(component_class, *args, &block)
|
26
|
+
else # remove once _as_node is deprecated.
|
27
|
+
React::RenderingContext.build_only(component_class, *args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/sources/react-v14.js
CHANGED
@@ -20816,3 +20816,87 @@ module.exports = warning;
|
|
20816
20816
|
})(function(React) {
|
20817
20817
|
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
20818
20818
|
});
|
20819
|
+
/**
|
20820
|
+
* ReactDOM v0.14.8
|
20821
|
+
*
|
20822
|
+
* Copyright 2013-2015, Facebook, Inc.
|
20823
|
+
* All rights reserved.
|
20824
|
+
*
|
20825
|
+
* This source code is licensed under the BSD-style license found in the
|
20826
|
+
* LICENSE file in the root directory of this source tree. An additional grant
|
20827
|
+
* of patent rights can be found in the PATENTS file in the same directory.
|
20828
|
+
*
|
20829
|
+
*/
|
20830
|
+
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
|
20831
|
+
;(function(f) {
|
20832
|
+
// CommonJS
|
20833
|
+
if (typeof exports === "object" && typeof module !== "undefined") {
|
20834
|
+
module.exports = f(require('react'));
|
20835
|
+
|
20836
|
+
// RequireJS
|
20837
|
+
} else if (typeof define === "function" && define.amd) {
|
20838
|
+
define(['react'], f);
|
20839
|
+
|
20840
|
+
// <script>
|
20841
|
+
} else {
|
20842
|
+
var g;
|
20843
|
+
if (typeof window !== "undefined") {
|
20844
|
+
g = window;
|
20845
|
+
} else if (typeof global !== "undefined") {
|
20846
|
+
g = global;
|
20847
|
+
} else if (typeof self !== "undefined") {
|
20848
|
+
g = self;
|
20849
|
+
} else {
|
20850
|
+
// works providing we're not in "use strict";
|
20851
|
+
// needed for Java 8 Nashorn
|
20852
|
+
// see https://github.com/facebook/react/issues/3037
|
20853
|
+
g = this;
|
20854
|
+
}
|
20855
|
+
g.ReactDOM = f(g.React);
|
20856
|
+
}
|
20857
|
+
|
20858
|
+
})(function(React) {
|
20859
|
+
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
20860
|
+
});
|
20861
|
+
/**
|
20862
|
+
* ReactDOMServer v0.14.8
|
20863
|
+
*
|
20864
|
+
* Copyright 2013-2015, Facebook, Inc.
|
20865
|
+
* All rights reserved.
|
20866
|
+
*
|
20867
|
+
* This source code is licensed under the BSD-style license found in the
|
20868
|
+
* LICENSE file in the root directory of this source tree. An additional grant
|
20869
|
+
* of patent rights can be found in the PATENTS file in the same directory.
|
20870
|
+
*
|
20871
|
+
*/
|
20872
|
+
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
|
20873
|
+
;(function(f) {
|
20874
|
+
// CommonJS
|
20875
|
+
if (typeof exports === "object" && typeof module !== "undefined") {
|
20876
|
+
module.exports = f(require('react'));
|
20877
|
+
|
20878
|
+
// RequireJS
|
20879
|
+
} else if (typeof define === "function" && define.amd) {
|
20880
|
+
define(['react'], f);
|
20881
|
+
|
20882
|
+
// <script>
|
20883
|
+
} else {
|
20884
|
+
var g;
|
20885
|
+
if (typeof window !== "undefined") {
|
20886
|
+
g = window;
|
20887
|
+
} else if (typeof global !== "undefined") {
|
20888
|
+
g = global;
|
20889
|
+
} else if (typeof self !== "undefined") {
|
20890
|
+
g = self;
|
20891
|
+
} else {
|
20892
|
+
// works providing we're not in "use strict";
|
20893
|
+
// needed for Java 8 Nashorn
|
20894
|
+
// see https://github.com/facebook/react/issues/3037
|
20895
|
+
g = this;
|
20896
|
+
}
|
20897
|
+
g.ReactDOMServer = f(g.React);
|
20898
|
+
}
|
20899
|
+
|
20900
|
+
})(function(React) {
|
20901
|
+
return React.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
20902
|
+
});
|
@@ -616,47 +616,6 @@ describe React::Component do
|
|
616
616
|
expect(React.render_to_static_markup(element)).to eq('<div></div>')
|
617
617
|
end
|
618
618
|
|
619
|
-
it 'redefines `p` to make method missing work' do
|
620
|
-
stub_const 'Foo', Class.new
|
621
|
-
Foo.class_eval do
|
622
|
-
include React::Component
|
623
|
-
|
624
|
-
def render
|
625
|
-
p(class_name: 'foo') do
|
626
|
-
p
|
627
|
-
div { 'lorem ipsum' }
|
628
|
-
p(id: '10')
|
629
|
-
end
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
element = React.create_element(Foo)
|
634
|
-
markup = '<p class="foo"><p></p><div>lorem ipsum</div><p id="10"></p></p>'
|
635
|
-
expect(React.render_to_static_markup(element)).to eq(markup)
|
636
|
-
end
|
637
|
-
|
638
|
-
it 'only overrides `p` in render context' do
|
639
|
-
stub_const 'Foo', Class.new
|
640
|
-
Foo.class_eval do
|
641
|
-
include React::Component
|
642
|
-
|
643
|
-
before_mount do
|
644
|
-
p 'first'
|
645
|
-
end
|
646
|
-
|
647
|
-
after_mount do
|
648
|
-
p 'second'
|
649
|
-
end
|
650
|
-
|
651
|
-
def render
|
652
|
-
div
|
653
|
-
end
|
654
|
-
end
|
655
|
-
|
656
|
-
expect(Kernel).to receive(:p).with('first')
|
657
|
-
expect(Kernel).to receive(:p).with('second')
|
658
|
-
renderToDocument(Foo)
|
659
|
-
end
|
660
619
|
end
|
661
620
|
|
662
621
|
describe 'isMounted()' do
|
data/spec/react/dsl_spec.rb
CHANGED
@@ -2,13 +2,66 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
if opal?
|
4
4
|
|
5
|
-
module TestMod123
|
6
|
-
|
5
|
+
module TestMod123
|
6
|
+
class Bar < React::Component::Base
|
7
|
+
end
|
7
8
|
end
|
8
|
-
end
|
9
9
|
|
10
10
|
describe 'the React DSL' do
|
11
11
|
|
12
|
+
context "render macro" do
|
13
|
+
|
14
|
+
it "can define the render method with the render macro with a html tag container" do
|
15
|
+
stub_const 'Foo', Class.new
|
16
|
+
Foo.class_eval do
|
17
|
+
include React::Component
|
18
|
+
render(:div, class: :foo) do
|
19
|
+
"hello"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div class="foo">hello</div>')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can define the render method with the render macro without a container" do
|
27
|
+
stub_const 'Foo', Class.new
|
28
|
+
Foo.class_eval do
|
29
|
+
include React::Component
|
30
|
+
render do
|
31
|
+
"hello"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span>hello</span>')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can define the render method with the render macro with a application defined container" do
|
39
|
+
stub_const 'Bar', Class.new(React::Component::Base)
|
40
|
+
Bar.class_eval do
|
41
|
+
param :p1
|
42
|
+
render { "hello #{params.p1}" }
|
43
|
+
end
|
44
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
45
|
+
Foo.class_eval do
|
46
|
+
render Bar, p1: "fred"
|
47
|
+
end
|
48
|
+
|
49
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span>hello fred</span>')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "can use the upcase version of builtin tags" do
|
54
|
+
stub_const 'Foo', Class.new
|
55
|
+
Foo.class_eval do
|
56
|
+
include React::Component
|
57
|
+
def render
|
58
|
+
DIV { "hello" }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>hello</div>')
|
63
|
+
end
|
64
|
+
|
12
65
|
it "will turn the last string in a block into a element" do
|
13
66
|
stub_const 'Foo', Class.new
|
14
67
|
Foo.class_eval do
|
@@ -17,7 +70,6 @@ describe 'the React DSL' do
|
|
17
70
|
div { "hello" }
|
18
71
|
end
|
19
72
|
end
|
20
|
-
|
21
73
|
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>hello</div>')
|
22
74
|
end
|
23
75
|
|
@@ -69,6 +121,38 @@ describe 'the React DSL' do
|
|
69
121
|
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div><p>hello</p></div>')
|
70
122
|
end
|
71
123
|
|
124
|
+
it 'can do a method call on a class name that is not a direct sibling' do
|
125
|
+
stub_const 'Mod', Module.new
|
126
|
+
stub_const 'Mod::NestedMod', Module.new
|
127
|
+
stub_const 'Mod::Comp', Class.new(React::Component::Base)
|
128
|
+
Mod::Comp.class_eval do
|
129
|
+
render { 'Mod::Comp' }
|
130
|
+
end
|
131
|
+
stub_const 'Mod::NestedMod::NestedComp', Class.new(React::Component::Base)
|
132
|
+
Mod::NestedMod::NestedComp.class_eval do
|
133
|
+
render do
|
134
|
+
Comp()
|
135
|
+
end
|
136
|
+
end
|
137
|
+
expect(React.render_to_static_markup(React.create_element(Mod::NestedMod::NestedComp)))
|
138
|
+
.to eq('<span>Mod::Comp</span>')
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'raises a meaningful error if a Constant Name is not actually a component' do
|
142
|
+
stub_const 'Mod', Module.new
|
143
|
+
stub_const 'Mod::NestedMod', Module.new
|
144
|
+
stub_const 'Mod::Comp', Class.new
|
145
|
+
stub_const 'Mod::NestedMod::NestedComp', Class.new(React::Component::Base)
|
146
|
+
Mod::NestedMod::NestedComp.class_eval do
|
147
|
+
backtrace :none
|
148
|
+
render do
|
149
|
+
Comp()
|
150
|
+
end
|
151
|
+
end
|
152
|
+
expect { React.render_to_static_markup(React.create_element(Mod::NestedMod::NestedComp)) }
|
153
|
+
.to raise_error('Comp does not appear to be a react component.')
|
154
|
+
end
|
155
|
+
|
72
156
|
it "will treat the component class name as a first class component name" do
|
73
157
|
stub_const 'Mod::Bar', Class.new
|
74
158
|
Mod::Bar.class_eval do
|
@@ -141,6 +225,32 @@ describe 'the React DSL' do
|
|
141
225
|
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>Hello Goodby</div>')
|
142
226
|
end
|
143
227
|
|
228
|
+
it 'should convert a hash param to hyphenated html attributes if in React::HASH_ATTRIBUTES' do
|
229
|
+
stub_const 'Foo', Class.new
|
230
|
+
Foo.class_eval do
|
231
|
+
include React::Component
|
232
|
+
def render
|
233
|
+
div(data: { foo: :bar }, aria: { foo_bar: :foo })
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
expect(React.render_to_static_markup(React.create_element(Foo)))
|
238
|
+
.to eq('<div data-foo="bar" aria-foo-bar="foo"></div>')
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'should not convert a hash param to hyphenated html attributes if not in React::HASH_ATTRIBUTES' do
|
242
|
+
stub_const 'Foo', Class.new
|
243
|
+
Foo.class_eval do
|
244
|
+
include React::Component
|
245
|
+
def render
|
246
|
+
div(title: { bar: :foo })
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
expect(React.render_to_static_markup(React.create_element(Foo)))
|
251
|
+
.to eq('<div title="{"bar"=>"foo"}"></div>')
|
252
|
+
end
|
253
|
+
|
144
254
|
it "will remove all elements passed as params from the rendering buffer" do
|
145
255
|
stub_const 'X2', Class.new
|
146
256
|
X2.class_eval do
|
@@ -1,10 +1,298 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'reactrb/auto-import'
|
2
3
|
|
3
4
|
if opal?
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
|
6
|
+
module NativeLibraryTestModule
|
7
|
+
class Component < React::Component::Base
|
8
|
+
param :time_stamp
|
9
|
+
backtrace :none
|
10
|
+
render { NativeComponent(name: "There - #{params.time_stamp}") }
|
11
|
+
end
|
12
|
+
|
13
|
+
class NestedComponent < React::Component::Base
|
14
|
+
param :time_stamp
|
15
|
+
backtrace :none
|
16
|
+
render { NativeLibrary::NativeNestedLibrary::NativeComponent(name: "There - #{params.time_stamp}") }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "React::NativeLibrary" do
|
21
|
+
|
22
|
+
after(:each) do
|
23
|
+
%x{
|
24
|
+
delete window.NativeLibrary;
|
25
|
+
delete window.NativeComponent;
|
26
|
+
delete window.nativeLibrary;
|
27
|
+
delete window.nativeComponent;
|
28
|
+
delete window.NativeObject;
|
29
|
+
}
|
30
|
+
Object.send :remove_const, :NativeLibrary
|
31
|
+
Object.send :remove_const, :NativeComponent
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can use native_react_component? to detect a native React.js component" do
|
35
|
+
%x{
|
36
|
+
window.NativeComponent = React.createClass({
|
37
|
+
displayName: "HelloMessage",
|
38
|
+
render: function render() {
|
39
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
40
|
+
}
|
41
|
+
})
|
42
|
+
}
|
43
|
+
expect(React::API.native_react_component?(`window.NativeComponent`)).to be_truthy
|
44
|
+
expect(React::API.native_react_component?(`{render: function render() {}}`)).to be_falsy
|
45
|
+
expect(React::API.native_react_component?(`window.DoesntExist`)).to be_falsy
|
46
|
+
expect(React::API.native_react_component?(``)).to be_falsy
|
47
|
+
end
|
48
|
+
|
49
|
+
it "will import a React.js library into the Ruby name space" do
|
50
|
+
%x{
|
51
|
+
window.NativeLibrary = {
|
52
|
+
NativeComponent: React.createClass({
|
53
|
+
displayName: "HelloMessage",
|
54
|
+
render: function render() {
|
55
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
56
|
+
}
|
57
|
+
})
|
58
|
+
}
|
59
|
+
}
|
60
|
+
stub_const 'Foo', Class.new(React::NativeLibrary)
|
61
|
+
Foo.class_eval do
|
62
|
+
imports "NativeLibrary"
|
63
|
+
end
|
64
|
+
expect(React.render_to_static_markup(
|
65
|
+
React.create_element(Foo::NativeComponent, name: "There"))).to eq('<div>Hello There</div>')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "will rename an imported a React.js component" do
|
69
|
+
%x{
|
70
|
+
window.NativeLibrary = {
|
71
|
+
NativeComponent: React.createClass({
|
72
|
+
displayName: "HelloMessage",
|
73
|
+
render: function render() {
|
74
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
75
|
+
}
|
76
|
+
})
|
77
|
+
}
|
78
|
+
}
|
79
|
+
stub_const 'Foo', Class.new(React::NativeLibrary)
|
80
|
+
Foo.class_eval do
|
81
|
+
imports "NativeLibrary"
|
82
|
+
rename "NativeComponent" => "Bar"
|
83
|
+
end
|
84
|
+
expect(React.render_to_static_markup(
|
85
|
+
React.create_element(Foo::Bar, name: "There"))).to eq('<div>Hello There</div>')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "will give a reasonable error when failing to import a renamed component" do
|
89
|
+
%x{
|
90
|
+
window.NativeLibrary = {
|
91
|
+
NativeComponent: React.createClass({
|
92
|
+
displayName: "HelloMessage",
|
93
|
+
render: function render() {
|
94
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
95
|
+
}
|
96
|
+
})
|
97
|
+
}
|
98
|
+
}
|
99
|
+
stub_const 'Foo', Class.new(React::NativeLibrary)
|
100
|
+
expect do
|
101
|
+
Foo.class_eval do
|
102
|
+
imports "NativeLibrary"
|
103
|
+
rename "MispelledComponent" => "Bar"
|
104
|
+
end
|
105
|
+
end.to raise_error(/could not import MispelledComponent/)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "will import a single React.js component into the ruby name space" do
|
109
|
+
%x{
|
110
|
+
window.NativeComponent = React.createClass({
|
111
|
+
displayName: "HelloMessage",
|
112
|
+
render: function render() {
|
113
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
114
|
+
}
|
115
|
+
})
|
116
|
+
}
|
117
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
118
|
+
Foo.class_eval do
|
119
|
+
imports "NativeComponent"
|
120
|
+
end
|
121
|
+
expect(React.render_to_static_markup(
|
122
|
+
React.create_element(Foo, name: "There"))).to eq('<div>Hello There</div>')
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
it "will import a name scoped React.js component into the ruby name space" do
|
127
|
+
%x{
|
128
|
+
window.NativeLibrary = {
|
129
|
+
NativeComponent: React.createClass({
|
130
|
+
displayName: "HelloMessage",
|
131
|
+
render: function render() {
|
132
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
133
|
+
}
|
134
|
+
})
|
135
|
+
}
|
136
|
+
}
|
137
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
138
|
+
Foo.class_eval do
|
139
|
+
imports "NativeLibrary.NativeComponent"
|
140
|
+
end
|
141
|
+
expect(React.render_to_static_markup(
|
142
|
+
React.create_element(Foo, name: "There"))).to eq('<div>Hello There</div>')
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
it "will give a meaningful error if the React.js component is invalid" do
|
147
|
+
%x{
|
148
|
+
window.NativeObject = {}
|
149
|
+
}
|
150
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
151
|
+
expect do
|
152
|
+
Foo.class_eval do
|
153
|
+
imports "NativeObject"
|
154
|
+
end
|
155
|
+
end.to raise_error("Foo cannot import 'NativeObject': does not appear to be a native react component.")
|
156
|
+
expect do
|
157
|
+
Foo.class_eval do
|
158
|
+
imports "window.Baz"
|
159
|
+
end
|
160
|
+
end.to raise_error(/^Foo cannot import \'window\.Baz\'\: (?!does not appear to be a native react component)..*$/)
|
161
|
+
end
|
162
|
+
|
163
|
+
context "automatic importing" do
|
164
|
+
|
165
|
+
it "will automatically import a React.js component when referenced in another component" do
|
166
|
+
%x{
|
167
|
+
window.NativeComponent = React.createClass({
|
168
|
+
displayName: "HelloMessage",
|
169
|
+
render: function render() {
|
170
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
171
|
+
}
|
172
|
+
})
|
173
|
+
}
|
174
|
+
expect(React.render_to_static_markup(
|
175
|
+
React.create_element(NativeLibraryTestModule::Component, time_stamp: Time.now))).to match(/<div>Hello There.*<\/div>/)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "will automatically import a React.js component when referenced in another component" do
|
179
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
180
|
+
Foo.class_eval do
|
181
|
+
render { NativeComponent(name: "There") }
|
182
|
+
end
|
183
|
+
%x{
|
184
|
+
window.NativeComponent = React.createClass({
|
185
|
+
displayName: "HelloMessage",
|
186
|
+
render: function render() {
|
187
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
188
|
+
}
|
189
|
+
})
|
190
|
+
}
|
191
|
+
expect(React.render_to_static_markup(
|
192
|
+
React.create_element(Foo))).to eq('<div>Hello There</div>')
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'will automatically import a React.js component when referenced in another component with the _as_node suffix' do
|
196
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
197
|
+
Foo.class_eval do
|
198
|
+
render(:div) do
|
199
|
+
e = React::Element.new(NativeComponent_as_node(name: 'There'))
|
200
|
+
2.times { e.render }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
%x{
|
204
|
+
window.NativeComponent = React.createClass({
|
205
|
+
displayName: "HelloMessage",
|
206
|
+
render: function render() {
|
207
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
208
|
+
}
|
209
|
+
})
|
210
|
+
}
|
211
|
+
expect(React.render_to_static_markup(
|
212
|
+
React.create_element(Foo))).to eq('<div><div>Hello There</div><div>Hello There</div></div>')
|
213
|
+
end
|
214
|
+
|
215
|
+
it "will automatically import a React.js component in a library when referenced in another component with the _as_node suffix" do
|
216
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
217
|
+
Foo.class_eval do
|
218
|
+
render(:div) do
|
219
|
+
e = React::Element.new(NativeLibrary::NativeComponent_as_node(name: 'There'))
|
220
|
+
2.times { e.render }
|
221
|
+
end
|
222
|
+
end
|
223
|
+
%x{
|
224
|
+
window.NativeLibrary = {
|
225
|
+
NativeComponent: React.createClass({
|
226
|
+
displayName: "HelloMessage",
|
227
|
+
render: function render() {
|
228
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
229
|
+
}
|
230
|
+
})
|
231
|
+
}
|
232
|
+
}
|
233
|
+
expect(React.render_to_static_markup(
|
234
|
+
React.create_element(Foo))).to eq('<div><div>Hello There</div><div>Hello There</div></div>')
|
235
|
+
end
|
236
|
+
|
237
|
+
it "will automatically import a React.js component when referenced as a constant" do
|
238
|
+
%x{
|
239
|
+
window.NativeComponent = React.createClass({
|
240
|
+
displayName: "HelloMessage",
|
241
|
+
render: function render() {
|
242
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
243
|
+
}
|
244
|
+
})
|
245
|
+
}
|
246
|
+
expect(React.render_to_static_markup(
|
247
|
+
React.create_element(NativeComponent, name: "There"))).to eq('<div>Hello There</div>')
|
248
|
+
end
|
249
|
+
|
250
|
+
it "will automatically import a native library containing a React.js component" do
|
251
|
+
%x{
|
252
|
+
window.NativeLibrary = {
|
253
|
+
NativeNestedLibrary: {
|
254
|
+
NativeComponent: React.createClass({
|
255
|
+
displayName: "HelloMessage",
|
256
|
+
render: function render() {
|
257
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
258
|
+
}
|
259
|
+
})
|
260
|
+
}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
expect(React.render_to_static_markup(
|
265
|
+
React.create_element(NativeLibraryTestModule::NestedComponent, time_stamp: Time.now))).to match(/<div>Hello There.*<\/div>/)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "the library and components can begin with lower case letters" do
|
269
|
+
%x{
|
270
|
+
window.nativeLibrary = {
|
271
|
+
nativeComponent: React.createClass({
|
272
|
+
displayName: "HelloMessage",
|
273
|
+
render: function render() {
|
274
|
+
return React.createElement("div", null, "Hello ", this.props.name);
|
275
|
+
}
|
276
|
+
})
|
277
|
+
}
|
278
|
+
}
|
279
|
+
expect(React.render_to_static_markup(
|
280
|
+
React.create_element(NativeLibrary::NativeComponent, name: "There"))).to eq('<div>Hello There</div>')
|
281
|
+
end
|
282
|
+
|
283
|
+
it "will produce a sensible error if the component is not in the library" do
|
284
|
+
%x{
|
285
|
+
window.NativeLibrary = {
|
286
|
+
NativeNestedLibrary: {
|
287
|
+
}
|
288
|
+
}
|
289
|
+
}
|
290
|
+
expect do
|
291
|
+
React.render_to_static_markup(React.create_element(NativeLibraryTestModule::NestedComponent, time_stamp: Time.now))
|
292
|
+
end.to raise_error("could not import a react component named: NativeLibrary.NativeNestedLibrary.NativeComponent")
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
9
297
|
end
|
10
298
|
end
|