reactrb 0.7.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +6 -0
- data/.gitignore +33 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +117 -0
- data/Rakefile +28 -0
- data/config.ru +16 -0
- data/example/examples/Gemfile +7 -0
- data/example/examples/app/basics.js.rb +42 -0
- data/example/examples/app/items.rb +11 -0
- data/example/examples/app/jquery.js +5 -0
- data/example/examples/app/nodes.rb +61 -0
- data/example/examples/app/react-router.js +6 -0
- data/example/examples/app/react_api_demo.rb +29 -0
- data/example/examples/app/rerendering.rb +72 -0
- data/example/examples/app/reuse.rb +59 -0
- data/example/examples/app/show.rb +52 -0
- data/example/examples/config.ru +38 -0
- data/example/rails-tutorial/.gitignore +17 -0
- data/example/rails-tutorial/Gemfile +51 -0
- data/example/rails-tutorial/README.rdoc +28 -0
- data/example/rails-tutorial/Rakefile +6 -0
- data/example/rails-tutorial/app/assets/images/.keep +0 -0
- data/example/rails-tutorial/app/assets/javascripts/application.rb +15 -0
- data/example/rails-tutorial/app/assets/stylesheets/application.css +15 -0
- data/example/rails-tutorial/app/controllers/application_controller.rb +6 -0
- data/example/rails-tutorial/app/controllers/concerns/.keep +0 -0
- data/example/rails-tutorial/app/controllers/home_controller.rb +6 -0
- data/example/rails-tutorial/app/helpers/application_helper.rb +2 -0
- data/example/rails-tutorial/app/mailers/.keep +0 -0
- data/example/rails-tutorial/app/models/.keep +0 -0
- data/example/rails-tutorial/app/models/concerns/.keep +0 -0
- data/example/rails-tutorial/app/views/components.rb +3 -0
- data/example/rails-tutorial/app/views/components/home/show.rb +47 -0
- data/example/rails-tutorial/app/views/layouts/application.html.erb +14 -0
- data/example/rails-tutorial/bin/bundle +3 -0
- data/example/rails-tutorial/bin/rails +8 -0
- data/example/rails-tutorial/bin/rake +8 -0
- data/example/rails-tutorial/bin/setup +29 -0
- data/example/rails-tutorial/bin/spring +15 -0
- data/example/rails-tutorial/config.ru +4 -0
- data/example/rails-tutorial/config/application.rb +26 -0
- data/example/rails-tutorial/config/boot.rb +3 -0
- data/example/rails-tutorial/config/database.yml +25 -0
- data/example/rails-tutorial/config/environment.rb +5 -0
- data/example/rails-tutorial/config/environments/development.rb +41 -0
- data/example/rails-tutorial/config/environments/production.rb +79 -0
- data/example/rails-tutorial/config/environments/test.rb +42 -0
- data/example/rails-tutorial/config/initializers/assets.rb +11 -0
- data/example/rails-tutorial/config/initializers/backtrace_silencers.rb +7 -0
- data/example/rails-tutorial/config/initializers/cookies_serializer.rb +3 -0
- data/example/rails-tutorial/config/initializers/filter_parameter_logging.rb +4 -0
- data/example/rails-tutorial/config/initializers/inflections.rb +16 -0
- data/example/rails-tutorial/config/initializers/mime_types.rb +4 -0
- data/example/rails-tutorial/config/initializers/session_store.rb +3 -0
- data/example/rails-tutorial/config/initializers/wrap_parameters.rb +14 -0
- data/example/rails-tutorial/config/locales/en.yml +23 -0
- data/example/rails-tutorial/config/routes.rb +59 -0
- data/example/rails-tutorial/config/secrets.yml +22 -0
- data/example/rails-tutorial/db/seeds.rb +7 -0
- data/example/rails-tutorial/lib/assets/.keep +0 -0
- data/example/rails-tutorial/lib/tasks/.keep +0 -0
- data/example/rails-tutorial/log/.keep +0 -0
- data/example/rails-tutorial/public/404.html +67 -0
- data/example/rails-tutorial/public/422.html +67 -0
- data/example/rails-tutorial/public/500.html +66 -0
- data/example/rails-tutorial/public/favicon.ico +0 -0
- data/example/rails-tutorial/public/robots.txt +5 -0
- data/example/rails-tutorial/test/controllers/.keep +0 -0
- data/example/rails-tutorial/test/fixtures/.keep +0 -0
- data/example/rails-tutorial/test/helpers/.keep +0 -0
- data/example/rails-tutorial/test/integration/.keep +0 -0
- data/example/rails-tutorial/test/mailers/.keep +0 -0
- data/example/rails-tutorial/test/models/.keep +0 -0
- data/example/rails-tutorial/test/test_helper.rb +10 -0
- data/example/rails-tutorial/vendor/assets/javascripts/.keep +0 -0
- data/example/rails-tutorial/vendor/assets/stylesheets/.keep +0 -0
- data/example/sinatra-tutorial/.DS_Store +0 -0
- data/example/sinatra-tutorial/Gemfile +5 -0
- data/example/sinatra-tutorial/README.md +8 -0
- data/example/sinatra-tutorial/_comments.json +42 -0
- data/example/sinatra-tutorial/app/example.rb +290 -0
- data/example/sinatra-tutorial/app/jquery.js +5 -0
- data/example/sinatra-tutorial/config.ru +58 -0
- data/example/sinatra-tutorial/public/base.css +62 -0
- data/example/todos/Gemfile +11 -0
- data/example/todos/README.md +37 -0
- data/example/todos/Rakefile +8 -0
- data/example/todos/app/application.rb +22 -0
- data/example/todos/app/components/app.react.rb +61 -0
- data/example/todos/app/components/footer.react.rb +31 -0
- data/example/todos/app/components/todo_item.react.rb +46 -0
- data/example/todos/app/components/todo_list.react.rb +25 -0
- data/example/todos/app/models/todo.rb +19 -0
- data/example/todos/config.ru +14 -0
- data/example/todos/index.html.haml +16 -0
- data/example/todos/spec/todo_spec.rb +28 -0
- data/example/todos/vendor/base.css +410 -0
- data/example/todos/vendor/bg.png +0 -0
- data/example/todos/vendor/jquery.js +4 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +4 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
- data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
- data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
- data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +105 -0
- data/lib/rails-helpers/top_level_rails_component.rb +54 -0
- data/lib/react/api.rb +127 -0
- data/lib/react/callbacks.rb +42 -0
- data/lib/react/component.rb +269 -0
- data/lib/react/component/api.rb +50 -0
- data/lib/react/component/base.rb +9 -0
- data/lib/react/component/class_methods.rb +190 -0
- data/lib/react/component/props_wrapper.rb +82 -0
- data/lib/react/element.rb +77 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/native_library.rb +53 -0
- data/lib/react/observable.rb +29 -0
- data/lib/react/rendering_context.rb +109 -0
- data/lib/react/state.rb +140 -0
- data/lib/react/top_level.rb +97 -0
- data/lib/react/validator.rb +136 -0
- data/lib/reactive-ruby/component_loader.rb +45 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +196 -0
- data/lib/reactive-ruby/rails.rb +7 -0
- data/lib/reactive-ruby/rails/component_mount.rb +44 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +13 -0
- data/lib/reactive-ruby/rails/railtie.rb +14 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +42 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/lib/reactrb.rb +50 -0
- data/lib/sources/react-latest.js +21167 -0
- data/lib/sources/react-v13.js +21642 -0
- data/lib/sources/react-v14.js +20818 -0
- data/lib/sources/react-v15.js +21167 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- data/reactrb.gemspec +43 -0
- data/spec/controller_helper_spec.rb +22 -0
- data/spec/index.html.erb +12 -0
- data/spec/react/callbacks_spec.rb +106 -0
- data/spec/react/component/base_spec.rb +36 -0
- data/spec/react/component_spec.rb +721 -0
- data/spec/react/dsl_spec.rb +161 -0
- data/spec/react/element_spec.rb +47 -0
- data/spec/react/event_spec.rb +24 -0
- data/spec/react/native_library_spec.rb +10 -0
- data/spec/react/observable_spec.rb +7 -0
- data/spec/react/param_declaration_spec.rb +286 -0
- data/spec/react/react_spec.rb +211 -0
- data/spec/react/state_spec.rb +26 -0
- data/spec/react/top_level_component_spec.rb +68 -0
- data/spec/react/tutorial/tutorial_spec.rb +35 -0
- data/spec/react/validator_spec.rb +128 -0
- data/spec/reactive-ruby/component_loader_spec.rb +68 -0
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +155 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +9 -0
- data/spec/reactive-ruby/rails/component_mount_spec.rb +66 -0
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +35 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/support/react/spec_helpers.rb +57 -0
- data/spec/vendor/es5-shim.min.js +6 -0
- data/spec/vendor/jquery-2.2.4.min.js +4 -0
- metadata +441 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if opal?
|
4
|
+
describe 'the React DSL' do
|
5
|
+
|
6
|
+
it "will turn the last string in a block into a element" do
|
7
|
+
stub_const 'Foo', Class.new
|
8
|
+
Foo.class_eval do
|
9
|
+
include React::Component
|
10
|
+
def render
|
11
|
+
div { "hello" }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>hello</div>')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "has a .span short hand String method" do
|
19
|
+
stub_const 'Foo', Class.new
|
20
|
+
Foo.class_eval do
|
21
|
+
include React::Component
|
22
|
+
def render
|
23
|
+
div { "hello".span; "goodby".span }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div><span>hello</span><span>goodby</span></div>')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "has a .br short hand String method" do
|
31
|
+
stub_const 'Foo', Class.new
|
32
|
+
Foo.class_eval do
|
33
|
+
include React::Component
|
34
|
+
def render
|
35
|
+
div { "hello".br }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(React.render_to_static_markup(React.create_element(Foo)).gsub("<br/>", "<br>")).to eq('<div><span>hello<br></span></div>')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "has a .td short hand String method" do
|
43
|
+
stub_const 'Foo', Class.new
|
44
|
+
Foo.class_eval do
|
45
|
+
include React::Component
|
46
|
+
def render
|
47
|
+
table { tr { "hello".td } }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<table><tr><td>hello</td></tr></table>')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "has a .para short hand String method" do
|
55
|
+
stub_const 'Foo', Class.new
|
56
|
+
Foo.class_eval do
|
57
|
+
include React::Component
|
58
|
+
def render
|
59
|
+
div { "hello".para }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div><p>hello</p></div>')
|
64
|
+
end
|
65
|
+
|
66
|
+
it "will treat the component class name as a first class component name" do
|
67
|
+
stub_const 'Mod::Bar', Class.new
|
68
|
+
Mod::Bar.class_eval do
|
69
|
+
include React::Component
|
70
|
+
def render
|
71
|
+
"a man walks into a bar"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
75
|
+
Foo.class_eval do
|
76
|
+
def render
|
77
|
+
Mod::Bar()
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span>a man walks into a bar</span>')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "can add class names by the haml .class notation" do
|
85
|
+
stub_const 'Mod::Bar', Class.new(React::Component::Base)
|
86
|
+
Mod::Bar.class_eval do
|
87
|
+
collect_other_params_as :attributes
|
88
|
+
def render
|
89
|
+
"a man walks into a bar".span(attributes)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
93
|
+
Foo.class_eval do
|
94
|
+
def render
|
95
|
+
Mod::Bar().the_class
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span class="the-class">a man walks into a bar</span>')
|
100
|
+
end
|
101
|
+
|
102
|
+
it "can use the 'class' keyword for classes" do
|
103
|
+
stub_const 'Foo', Class.new
|
104
|
+
Foo.class_eval do
|
105
|
+
include React::Component
|
106
|
+
def render
|
107
|
+
span(class: "the-class") { "hello" }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span class="the-class">hello</span>')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "can generate a unrendered node using the .as_node method" do # div { "hello" }.as_node
|
115
|
+
stub_const 'Foo', Class.new #(React::Component::Base)
|
116
|
+
Foo.class_eval do
|
117
|
+
include React::Component
|
118
|
+
def render
|
119
|
+
span { "hello".span.as_node.class.name }.as_node.render
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<span>React::Element</span>')
|
124
|
+
end
|
125
|
+
|
126
|
+
it "can use the dangerously_set_inner_HTML param" do
|
127
|
+
stub_const 'Foo', Class.new
|
128
|
+
Foo.class_eval do
|
129
|
+
include React::Component
|
130
|
+
def render
|
131
|
+
div(dangerously_set_inner_HTML: { __html: "Hello Goodby" })
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>Hello Goodby</div>')
|
136
|
+
end
|
137
|
+
|
138
|
+
it "will remove all elements passed as params from the rendering buffer" do
|
139
|
+
stub_const 'X2', Class.new
|
140
|
+
X2.class_eval do
|
141
|
+
include React::Component
|
142
|
+
param :ele
|
143
|
+
def render
|
144
|
+
div do
|
145
|
+
ele.render
|
146
|
+
ele.render
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
stub_const 'Test', Class.new
|
151
|
+
Test.class_eval do
|
152
|
+
include React::Component
|
153
|
+
def render
|
154
|
+
X2(ele: b { "hello" })
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
expect(React.render_to_static_markup(React.create_element(Test))).to eq('<div><b>hello</b><b>hello</b></div>')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
if opal?
|
4
|
+
describe React::Element do
|
5
|
+
it 'bridges `type` of native React.Element attributes' do
|
6
|
+
element = React.create_element('div')
|
7
|
+
expect(element.element_type).to eq("div")
|
8
|
+
end
|
9
|
+
|
10
|
+
async 'is renderable' do
|
11
|
+
element = React.create_element('span')
|
12
|
+
div = `document.createElement("div")`
|
13
|
+
React.render(element, div) do
|
14
|
+
run_async {
|
15
|
+
expect(`div.children[0].tagName`).to eq("SPAN")
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'Event subscription' do
|
21
|
+
it 'is subscribable through `on(:event_name)` method' do
|
22
|
+
expect { |b|
|
23
|
+
element = React.create_element("div").on(:click, &b)
|
24
|
+
instance = renderElementToDocument(element)
|
25
|
+
simulateEvent(:click, instance)
|
26
|
+
}.to yield_with_args(React::Event)
|
27
|
+
|
28
|
+
expect { |b|
|
29
|
+
element = React.create_element("div").on(:key_down, &b)
|
30
|
+
instance = renderElementToDocument(element)
|
31
|
+
simulateEvent(:keyDown, instance, {key: "Enter"})
|
32
|
+
}.to yield_control
|
33
|
+
|
34
|
+
expect { |b|
|
35
|
+
element = React.create_element("form").on(:submit, &b)
|
36
|
+
instance = renderElementToDocument(element)
|
37
|
+
simulateEvent(:submit, instance, {})
|
38
|
+
}.to yield_control
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns self for `on` method' do
|
42
|
+
element = React.create_element("div")
|
43
|
+
expect(element.on(:click){}).to eq(element)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
if opal?
|
4
|
+
describe React::Event do
|
5
|
+
it "should bridge attributes of native SyntheticEvent (see http://facebook.github.io/react/docs/events.html#syntheticevent)" do
|
6
|
+
element = React.create_element('div').on(:click) do |event|
|
7
|
+
expect(event.bubbles).to eq(`#{event.to_n}.bubbles`)
|
8
|
+
expect(event.cancelable).to eq(`#{event.to_n}.cancelable`)
|
9
|
+
expect(event.current_target).to eq(`#{event.to_n}.currentTarget`)
|
10
|
+
expect(event.default_prevented).to eq(`#{event.to_n}.defaultPrevented`)
|
11
|
+
expect(event.event_phase).to eq(`#{event.to_n}.eventPhase`)
|
12
|
+
expect(event.is_trusted?).to eq(`#{event.to_n}.isTrusted`)
|
13
|
+
expect(event.native_event).to eq(`#{event.to_n}.nativeEvent`)
|
14
|
+
expect(event.target).to eq(`#{event.to_n}.target`)
|
15
|
+
expect(event.timestamp).to eq(`#{event.to_n}.timeStamp`)
|
16
|
+
expect(event.event_type).to eq(`#{event.to_n}.type`)
|
17
|
+
expect(event).to respond_to(:prevent_default)
|
18
|
+
expect(event).to respond_to(:stop_propagation)
|
19
|
+
end
|
20
|
+
instance = renderElementToDocument(element)
|
21
|
+
simulateEvent(:click, instance)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if opal?
|
4
|
+
describe React::NativeLibrary do
|
5
|
+
it "will import a React.js library into the Ruby name space" # class BS < NativeLibrary; imports 'ReactBootstrap'; end
|
6
|
+
it "exclude specific components from a library" # exclude "Modal" # can't access BS.Modal
|
7
|
+
it "rename specific components from a library" # rename "Modal" => "FooBar" # BS.FooBar connects to ReactBootstrap.Modal
|
8
|
+
it "can importan multiple libraries into one class"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if opal?
|
4
|
+
describe 'the param macro' do
|
5
|
+
it 'defines collect_other_params_as method on params proxy' do
|
6
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
7
|
+
Foo.class_eval do
|
8
|
+
collect_other_params_as :foo
|
9
|
+
|
10
|
+
def render
|
11
|
+
div { params.foo[:bar] }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
html = React.render_to_static_markup(React.create_element(Foo, { bar: 'biz' }))
|
16
|
+
expect(html).to eq('<div>biz</div>')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'still defines deprecated collect_other_params_as method' do
|
20
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
21
|
+
Foo.class_eval do
|
22
|
+
collect_other_params_as :foo
|
23
|
+
|
24
|
+
def render
|
25
|
+
div { foo[:bar] }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
html = React.render_to_static_markup(React.create_element(Foo, { bar: 'biz' }))
|
30
|
+
expect(html).to eq('<div>biz</div>')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'still defines deprecated param accessor method' do
|
34
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
35
|
+
Foo.class_eval do
|
36
|
+
param :foo
|
37
|
+
|
38
|
+
def render
|
39
|
+
div { foo }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
html = React.render_to_static_markup(React.create_element(Foo, {foo: :bar}))
|
44
|
+
expect(html).to eq('<div>bar</div>')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can create and access a required param" do
|
48
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
49
|
+
Foo.class_eval do
|
50
|
+
param :foo
|
51
|
+
|
52
|
+
def render
|
53
|
+
div { params.foo }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
expect(React.render_to_static_markup(React.create_element(Foo, {foo: :bar}))).to eq('<div>bar</div>')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "can create and access an optional params" do
|
61
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
62
|
+
Foo.class_eval do
|
63
|
+
|
64
|
+
param foo1: :no_bar1
|
65
|
+
param foo2: :no_bar2
|
66
|
+
param :foo3, default: :no_bar3
|
67
|
+
param :foo4, default: :no_bar4
|
68
|
+
|
69
|
+
def render
|
70
|
+
div { "#{params.foo1}-#{params.foo2}-#{params.foo3}-#{params.foo4}" }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
expect(React.render_to_static_markup(React.create_element(Foo, {foo1: :bar1, foo3: :bar3}))).to eq('<div>bar1-no_bar2-bar3-no_bar4</div>')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'can specify validation rules with the type option' do
|
78
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
79
|
+
Foo.class_eval do
|
80
|
+
param :foo, type: String
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(Foo.prop_types).to have_key(:_componentValidator)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can type check params" do
|
87
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
88
|
+
Foo.class_eval do
|
89
|
+
|
90
|
+
param :foo1, type: String
|
91
|
+
param :foo2, type: String
|
92
|
+
|
93
|
+
def render
|
94
|
+
div { "#{params.foo1}-#{params.foo2}" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
expect(React.render_to_static_markup(React.create_element(Foo, {foo1: 12, foo2: "string"}))).to eq('<div>12-string</div>')
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'logs error in warning if validation failed' do
|
102
|
+
stub_const 'Lorem', Class.new
|
103
|
+
stub_const 'Foo2', Class.new(React::Component::Base)
|
104
|
+
Foo2.class_eval do
|
105
|
+
param :foo
|
106
|
+
param :lorem, type: Lorem
|
107
|
+
param :bar, default: nil, type: String
|
108
|
+
def render; div; end
|
109
|
+
end
|
110
|
+
|
111
|
+
%x{
|
112
|
+
var log = [];
|
113
|
+
var org_warn_console = window.console.warn;
|
114
|
+
var org_error_console = window.console.error;
|
115
|
+
window.console.warn = window.console.error = function(str){log.push(str)}
|
116
|
+
}
|
117
|
+
renderToDocument(Foo2, bar: 10, lorem: Lorem.new)
|
118
|
+
`window.console.warn = org_warn_console; window.console.error = org_error_console;`
|
119
|
+
|
120
|
+
expect(`log`).to eq(["Warning: Failed propType: In component `Foo2`\nRequired prop `foo` was not specified\nProvided prop `bar` could not be converted to String"])
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should not log anything if validation passes' do
|
124
|
+
stub_const 'Lorem', Class.new
|
125
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
126
|
+
Foo.class_eval do
|
127
|
+
param :foo
|
128
|
+
param :lorem, type: Lorem
|
129
|
+
param :bar, default: nil, type: String
|
130
|
+
|
131
|
+
def render; div; end
|
132
|
+
end
|
133
|
+
|
134
|
+
%x{
|
135
|
+
var log = [];
|
136
|
+
var org_warn_console = window.console.warn;
|
137
|
+
var org_error_console = window.console.error;
|
138
|
+
window.console.warn = window.console.error = function(str){log.push(str)}
|
139
|
+
}
|
140
|
+
renderToDocument(Foo, foo: 10, bar: '10', lorem: Lorem.new)
|
141
|
+
`window.console.warn = org_warn_console; window.console.error = org_error_console;`
|
142
|
+
expect(`log`).to eq([])
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'advanced type handling' do
|
146
|
+
before(:each) do
|
147
|
+
%x{
|
148
|
+
window.dummy_log = [];
|
149
|
+
window.org_warn_console = window.console.warn;
|
150
|
+
window.org_error_console = window.console.warn
|
151
|
+
window.console.warn = window.console.error = function(str){window.dummy_log.push(str)}
|
152
|
+
}
|
153
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
154
|
+
Foo.class_eval { def render; ""; end }
|
155
|
+
end
|
156
|
+
after(:each) do
|
157
|
+
`window.console.warn = window.org_warn_console; window.console.error = window.org_error_console`
|
158
|
+
end
|
159
|
+
|
160
|
+
it "can use the [] notation for arrays" do
|
161
|
+
Foo.class_eval do
|
162
|
+
param :foo, type: []
|
163
|
+
param :bar, type: []
|
164
|
+
end
|
165
|
+
renderToDocument(Foo, foo: 10, bar: [10])
|
166
|
+
expect(`window.dummy_log`).to eq(["Warning: Failed propType: In component `Foo`\nProvided prop `foo` could not be converted to Array"])
|
167
|
+
end
|
168
|
+
|
169
|
+
it "can use the [xxx] notation for arrays of a specific type" do
|
170
|
+
Foo.class_eval do
|
171
|
+
param :foo, type: [String]
|
172
|
+
param :bar, type: [String]
|
173
|
+
end
|
174
|
+
renderToDocument(Foo, foo: [10], bar: ["10"])
|
175
|
+
expect(`window.dummy_log`).to eq(["Warning: Failed propType: In component `Foo`\nProvided prop `foo`[0] could not be converted to String"])
|
176
|
+
end
|
177
|
+
|
178
|
+
it "can convert a json hash to a type" do
|
179
|
+
stub_const "BazWoggle", Class.new
|
180
|
+
BazWoggle.class_eval do
|
181
|
+
def initialize(kind)
|
182
|
+
@kind = kind
|
183
|
+
end
|
184
|
+
attr_accessor :kind
|
185
|
+
def self._react_param_conversion(json, validate_only)
|
186
|
+
new(json[:bazwoggle]) if json[:bazwoggle]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
Foo.class_eval do
|
190
|
+
param :foo, type: BazWoggle
|
191
|
+
param :bar, type: BazWoggle
|
192
|
+
param :baz, type: [BazWoggle]
|
193
|
+
def render
|
194
|
+
"#{params.bar.kind}, #{params.baz[0].kind}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
expect(React.render_to_static_markup(React.create_element(
|
198
|
+
Foo, foo: "", bar: {bazwoggle: 1}, baz: [{bazwoggle: 2}]))).to eq('<span>1, 2</span>')
|
199
|
+
expect(`window.dummy_log`).to eq(["Warning: Failed propType: In component `Foo`\nProvided prop `foo` could not be converted to BazWoggle"])
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "converts params only once" do
|
203
|
+
|
204
|
+
it "not on every access" do
|
205
|
+
stub_const "BazWoggle", Class.new
|
206
|
+
BazWoggle.class_eval do
|
207
|
+
def initialize(kind)
|
208
|
+
@kind = kind
|
209
|
+
end
|
210
|
+
attr_accessor :kind
|
211
|
+
def self._react_param_conversion(json, validate_only)
|
212
|
+
new(json[:bazwoggle]) if json[:bazwoggle]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
Foo.class_eval do
|
216
|
+
param :foo, type: BazWoggle
|
217
|
+
def render
|
218
|
+
params.foo.kind = params.foo.kind+1
|
219
|
+
"#{params.foo.kind}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
expect(React.render_to_static_markup(React.create_element(Foo, foo: {bazwoggle: 1}))).to eq('<span>2</span>')
|
223
|
+
end
|
224
|
+
|
225
|
+
it "even if contains an embedded native object" do
|
226
|
+
stub_const "Bar", Class.new(React::Component::Base)
|
227
|
+
stub_const "BazWoggle", Class.new
|
228
|
+
BazWoggle.class_eval do
|
229
|
+
def initialize(kind)
|
230
|
+
@kind = kind
|
231
|
+
end
|
232
|
+
attr_accessor :kind
|
233
|
+
def self._react_param_conversion(json, validate_only)
|
234
|
+
new(JSON.from_object(json[0])[:bazwoggle]) if JSON.from_object(json[0])[:bazwoggle]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
Bar.class_eval do
|
238
|
+
param :foo, type: BazWoggle
|
239
|
+
def render
|
240
|
+
params.foo.kind.to_s
|
241
|
+
end
|
242
|
+
end
|
243
|
+
Foo.class_eval do
|
244
|
+
export_state :change_me
|
245
|
+
before_mount do
|
246
|
+
Foo.change_me! "initial"
|
247
|
+
end
|
248
|
+
def render
|
249
|
+
Bar(foo: Native([`{bazwoggle: #{Foo.change_me}}`]))
|
250
|
+
end
|
251
|
+
end
|
252
|
+
div = `document.createElement("div")`
|
253
|
+
React.render(React.create_element(Foo, {}), div)
|
254
|
+
Foo.change_me! "updated"
|
255
|
+
expect(`div.children[0].innerHTML`).to eq("updated")
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it "will alias a Proc type param" do
|
260
|
+
Foo.class_eval do
|
261
|
+
param :foo, type: Proc
|
262
|
+
def render
|
263
|
+
params.foo
|
264
|
+
end
|
265
|
+
end
|
266
|
+
expect(React.render_to_static_markup(React.create_element(Foo, foo: lambda { 'works!' }))).to eq('<span>works!</span>')
|
267
|
+
end
|
268
|
+
|
269
|
+
it "will create a 'bang' (i.e. update) method if the type is React::Observable" do
|
270
|
+
Foo.class_eval do
|
271
|
+
param :foo, type: React::Observable
|
272
|
+
before_mount do
|
273
|
+
params.foo! "ha!"
|
274
|
+
end
|
275
|
+
def render
|
276
|
+
params.foo
|
277
|
+
end
|
278
|
+
end
|
279
|
+
current_state = ""
|
280
|
+
observer = React::Observable.new(current_state) { |new_state| current_state = new_state }
|
281
|
+
expect(React.render_to_static_markup(React.create_element(Foo, foo: observer))).to eq('<span>ha!</span>')
|
282
|
+
expect(current_state).to eq("ha!")
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|