reactrb 0.8.3 → 0.8.4
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/.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
|