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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2958d070204fb5e6864522685980645766fe0c7c
|
4
|
+
data.tar.gz: a6a28802f1b4711703ee21fce59648ab020d4b68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9b615808c1a56ea6ce344c902387dc2d27d21e971fbea47e2191439bf7e46ae5efd0f523a5f09a282c863247005f9071d6337a4e521567b1d06cdd95a515620
|
7
|
+
data.tar.gz: 6b17254733aaa175a56bfc8ec4a22601af4579758363a941c79bc514fd6276e911e3d89191dd6f48f6d0de4d543639bfe373350dec0ad4e1adc9339abf8e01cf
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#### Notes on how component names are looked up
|
2
|
+
|
3
|
+
Given:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
|
7
|
+
class Blat < React::Component::Base
|
8
|
+
|
9
|
+
render do
|
10
|
+
Bar()
|
11
|
+
Foo::Bar()
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class Bar < React::Component::Base
|
17
|
+
end
|
18
|
+
|
19
|
+
module Foo
|
20
|
+
|
21
|
+
class Bar < React::Component::Base
|
22
|
+
|
23
|
+
render do
|
24
|
+
Blat()
|
25
|
+
Baz()
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Baz < React::Component::Base
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
The problem is that method lookup is different than constant lookup. We can prove it by running this code:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
def try_it(test, &block)
|
39
|
+
puts "trying #{test}"
|
40
|
+
result = yield
|
41
|
+
puts "success#{': '+result.to_s if result}"
|
42
|
+
rescue Exception => e
|
43
|
+
puts "failed: #{e}"
|
44
|
+
ensure
|
45
|
+
puts "---------------------------------"
|
46
|
+
end
|
47
|
+
|
48
|
+
module Boom
|
49
|
+
|
50
|
+
Bar = 12
|
51
|
+
|
52
|
+
def self.Bar
|
53
|
+
puts " Boom::Bar says hi"
|
54
|
+
end
|
55
|
+
|
56
|
+
class Baz
|
57
|
+
def doit
|
58
|
+
try_it("Bar()") { Bar() }
|
59
|
+
try_it("Boom::Bar()") {Boom::Bar()}
|
60
|
+
try_it("Bar") { Bar }
|
61
|
+
try_it("Boom::Bar") { Boom::Bar }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
Boom::Baz.new.doit
|
69
|
+
```
|
70
|
+
|
71
|
+
which prints:
|
72
|
+
|
73
|
+
```text
|
74
|
+
trying Bar()
|
75
|
+
failed: Bar: undefined method `Bar' for #<Boom::Baz:0x774>
|
76
|
+
---------------------------------
|
77
|
+
trying Boom::Bar()
|
78
|
+
Boom::Bar says hi
|
79
|
+
success
|
80
|
+
---------------------------------
|
81
|
+
trying Bar
|
82
|
+
success: 12
|
83
|
+
---------------------------------
|
84
|
+
trying Boom::Bar
|
85
|
+
success: 12
|
86
|
+
---------------------------------
|
87
|
+
```
|
88
|
+
|
89
|
+
[try-it](http://opalrb.org/try/?code:def%20try_it(test%2C%20%26block)%0A%20%20puts%20%22trying%20%23%7Btest%7D%22%0A%20%20result%20%3D%20yield%0A%20%20puts%20%22success%23%7B%27%3A%20%27%2Bresult.to_s%20if%20result%7D%22%0Arescue%20Exception%20%3D%3E%20e%0A%20%20puts%20%22failed%3A%20%23%7Be%7D%22%0Aensure%0A%20%20puts%20%22---------------------------------%22%0Aend%0A%0Amodule%20Boom%0A%20%20%0A%20%20Bar%20%3D%2012%0A%20%20%0A%20%20def%20self.Bar%0A%20%20%20%20puts%20%22%20%20%20Boom%3A%3ABar%20says%20hi%22%0A%20%20end%0A%0A%20%20class%20Baz%0A%20%20%20%20def%20doit%0A%20%20%20%20%20%20try_it(%22Bar()%22)%20%7B%20Bar()%20%7D%0A%20%20%20%20%20%20try_it(%22Boom%3A%3ABar()%22)%20%7BBoom%3A%3ABar()%7D%0A%20%20%20%20%20%20try_it(%22Bar%22)%20%7B%20Bar%20%7D%0A%20%20%20%20%20%20try_it(%22Boom%3A%3ABar%22)%20%7B%20Boom%3A%3ABar%20%7D%0A%20%20%20%20end%0A%20%20end%0Aend%0A%20%20%0A%0A%0ABoom%3A%3ABaz.new.doit)
|
90
|
+
|
91
|
+
|
92
|
+
What we need to do is:
|
93
|
+
|
94
|
+
1. when defining a component class `Foo`, also define in the same scope that Foo is being defined a method `self.Foo` that will accept Foo's params and child block, and render it.
|
95
|
+
|
96
|
+
2. As long as a name is qualified with at least one scope (i.e. `ModName::Foo()`) everything will work out, but if we say just `Foo()` then the only way I believe out of this is to handle it via method_missing, and let method_missing do a const_get on the method_name (which will return the class) and then render that component.
|
97
|
+
|
98
|
+
#### details
|
99
|
+
|
100
|
+
To define `self.Foo` in the same scope level as the class `Foo`, we need code like this:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
def register_component_dsl_method(component)
|
104
|
+
split_name = component.name && component.name.split('::')
|
105
|
+
return unless split_name && split_name.length > 2
|
106
|
+
component_name = split_name.last
|
107
|
+
parent = split_name.inject([Module]) { |nesting, next_const| nesting + [nesting.last.const_get(next_const)] }[-2]
|
108
|
+
class << parent
|
109
|
+
define_method component_name do |*args, &block|
|
110
|
+
React::RenderingContext.render(name, *args, &block)
|
111
|
+
end
|
112
|
+
define_method "#{component_name}_as_node" do |*args, &block|
|
113
|
+
React::Component.deprecation_warning("..._as_node is deprecated. Render component and then use the .node method instead")
|
114
|
+
send(component_name, *args, &block).node
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
module React
|
120
|
+
module Component
|
121
|
+
def self.included(base)
|
122
|
+
...
|
123
|
+
register_component_dsl_method(base.name)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
The component's method_missing function will look like this:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
def method_missing(name, *args, &block)
|
133
|
+
if name =~ /_as_node$/
|
134
|
+
React::Component.deprecation_warning("..._as_node is deprecated. Render component and then use the .node method instead")
|
135
|
+
method_missing(name.gsub(/_as_node$/,""), *args, &block).node
|
136
|
+
else
|
137
|
+
component = const_get name if defined? name
|
138
|
+
React::RenderingContext.render(nil, component, *args, &block)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
### other related issues
|
144
|
+
|
145
|
+
The Kernel#p method conflicts with the <p> tag. However the p method can be invoked on any object so we are going to go ahead and use it, and deprecate the para method.
|
data/config.ru
CHANGED
data/lib/react/api.rb
CHANGED
@@ -1,11 +1,38 @@
|
|
1
1
|
require 'react/native_library'
|
2
2
|
|
3
3
|
module React
|
4
|
+
# Provides the internal mechanisms to interface between reactrb and native components
|
5
|
+
# the code will attempt to create a js component wrapper on any rb class that has a
|
6
|
+
# render (or possibly _render_wrapper) method. The mapping between rb and js components
|
7
|
+
# is kept in the @@component_classes hash.
|
8
|
+
|
9
|
+
# Also provides the mechanism to build react elements
|
10
|
+
|
11
|
+
# TOOO - the code to deal with components should be moved to a module that will be included
|
12
|
+
# in a class which will then create the JS component for that class. That module will then
|
13
|
+
# be included in React::Component, but can be used by any class wanting to become a react
|
14
|
+
# component (but without other DSL characteristics.)
|
4
15
|
class API
|
5
16
|
@@component_classes = {}
|
6
17
|
|
7
18
|
def self.import_native_component(opal_class, native_class)
|
8
|
-
@@component_classes[opal_class
|
19
|
+
@@component_classes[opal_class] = native_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.eval_native_react_component(name)
|
23
|
+
component = `eval(name)`
|
24
|
+
raise "#{name} is not defined" if `#{component} === undefined`
|
25
|
+
unless `#{component}.prototype !== undefined` &&
|
26
|
+
(`!!#{component}.prototype.isReactComponent` || `!!#{component}.prototype.render`)
|
27
|
+
raise 'does not appear to be a native react component'
|
28
|
+
end
|
29
|
+
component
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.native_react_component?(name)
|
33
|
+
eval_native_react_component(name)
|
34
|
+
rescue
|
35
|
+
nil
|
9
36
|
end
|
10
37
|
|
11
38
|
def self.create_native_react_class(type)
|
@@ -74,7 +101,7 @@ module React
|
|
74
101
|
params << @@component_classes[type]
|
75
102
|
elsif type.kind_of?(Class)
|
76
103
|
params << create_native_react_class(type)
|
77
|
-
elsif HTML_TAGS.include?(type)
|
104
|
+
elsif React::Component::Tags::HTML_TAGS.include?(type)
|
78
105
|
params << type
|
79
106
|
elsif type.is_a? String
|
80
107
|
return React::Element.new(type)
|
@@ -108,6 +135,8 @@ module React
|
|
108
135
|
props["className"] = value
|
109
136
|
elsif ["style", "dangerously_set_inner_HTML"].include? key
|
110
137
|
props[lower_camelize(key)] = value.to_n
|
138
|
+
elsif React::HASH_ATTRIBUTES.include?(key) && value.is_a?(Hash)
|
139
|
+
value.each { |k, v| props["#{key}-#{k.tr('_', '-')}"] = v.to_n }
|
111
140
|
else
|
112
141
|
props[React::ATTRIBUTES.include?(lower_camelize(key)) ? lower_camelize(key) : key] = value
|
113
142
|
end
|
data/lib/react/component.rb
CHANGED
@@ -15,6 +15,8 @@ module React
|
|
15
15
|
def self.included(base)
|
16
16
|
base.include(API)
|
17
17
|
base.include(Callbacks)
|
18
|
+
base.include(Tags)
|
19
|
+
base.include(DslInstanceMethods)
|
18
20
|
base.class_eval do
|
19
21
|
class_attribute :initial_state
|
20
22
|
define_callback :before_mount
|
@@ -25,28 +27,14 @@ module React
|
|
25
27
|
define_callback :before_unmount
|
26
28
|
end
|
27
29
|
base.extend(ClassMethods)
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if name =~ /_as_node$/
|
36
|
-
node_only = true
|
37
|
-
name = name.gsub(/_as_node$/, "")
|
38
|
-
end
|
39
|
-
begin
|
40
|
-
name = const_get(name)
|
41
|
-
rescue Exception
|
42
|
-
name = nil
|
43
|
-
end
|
44
|
-
unless name && name.method_defined?(:render)
|
45
|
-
return super
|
46
|
-
end
|
47
|
-
React::RenderingContext.build_or_render(node_only, name, *args, &block)
|
48
|
-
end
|
49
|
-
end
|
32
|
+
def self.deprecation_warning(message)
|
33
|
+
@deprecation_messages ||= []
|
34
|
+
message = "Warning: Deprecated feature used in #{name}. #{message}"
|
35
|
+
unless @deprecation_messages.include? message
|
36
|
+
@deprecation_messages << message
|
37
|
+
IsomorphicHelpers.log message, :warning
|
50
38
|
end
|
51
39
|
end
|
52
40
|
|
@@ -58,64 +46,6 @@ module React
|
|
58
46
|
raise "no render defined"
|
59
47
|
end unless method_defined?(:render)
|
60
48
|
|
61
|
-
def deprecated_params_method(name, *args, &block)
|
62
|
-
self.class.deprecation_warning "Direct access to param `#{name}`. Use `params.#{name}` instead."
|
63
|
-
params.send(name, *args, &block)
|
64
|
-
end
|
65
|
-
|
66
|
-
def children
|
67
|
-
nodes = if `#{@native}.props.children==undefined`
|
68
|
-
[]
|
69
|
-
else
|
70
|
-
[`#{@native}.props.children`].flatten
|
71
|
-
end
|
72
|
-
class << nodes
|
73
|
-
include Enumerable
|
74
|
-
|
75
|
-
def to_n
|
76
|
-
self
|
77
|
-
end
|
78
|
-
|
79
|
-
def each(&block)
|
80
|
-
if block_given?
|
81
|
-
%x{
|
82
|
-
React.Children.forEach(#{self.to_n}, function(context){
|
83
|
-
#{block.call(React::Element.new(`context`))}
|
84
|
-
})
|
85
|
-
}
|
86
|
-
nil
|
87
|
-
else
|
88
|
-
Enumerator.new(`React.Children.count(#{self.to_n})`) do |y|
|
89
|
-
%x{
|
90
|
-
React.Children.forEach(#{self.to_n}, function(context){
|
91
|
-
#{y << React::Element.new(`context`)}
|
92
|
-
})
|
93
|
-
}
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
nodes
|
100
|
-
end
|
101
|
-
|
102
|
-
def params
|
103
|
-
@props_wrapper
|
104
|
-
end
|
105
|
-
|
106
|
-
def props
|
107
|
-
Hash.new(`#{@native}.props`)
|
108
|
-
end
|
109
|
-
|
110
|
-
def refs
|
111
|
-
Hash.new(`#{@native}.refs`)
|
112
|
-
end
|
113
|
-
|
114
|
-
def state
|
115
|
-
#raise "No native ReactComponent associated" unless @native
|
116
|
-
@state_wrapper ||= StateWrapper.new(@native, self)
|
117
|
-
end
|
118
|
-
|
119
49
|
def update_react_js_state(object, name, value)
|
120
50
|
if object
|
121
51
|
set_state({"***_state_updated_at-***" => Time.now.to_f, "#{object.class.to_s+'.' unless object == self}#{name}" => value})
|
@@ -206,46 +136,14 @@ module React
|
|
206
136
|
self.class.process_exception(e, self)
|
207
137
|
end
|
208
138
|
|
209
|
-
|
210
|
-
if block || args.count == 0 || (args.count == 1 && args.first.is_a?(Hash))
|
211
|
-
_p_tag(*args, &block)
|
212
|
-
else
|
213
|
-
Kernel.p(*args)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def component?(name)
|
218
|
-
name_list = name.split("::")
|
219
|
-
scope_list = self.class.name.split("::").inject([Module]) { |nesting, next_const| nesting + [nesting.last.const_get(next_const)] }.reverse
|
220
|
-
scope_list.each do |scope|
|
221
|
-
component = name_list.inject(scope) do |scope, class_name|
|
222
|
-
scope.const_get(class_name)
|
223
|
-
end rescue nil
|
224
|
-
return component if component && component.method_defined?(:render)
|
225
|
-
end
|
226
|
-
nil
|
227
|
-
end
|
228
|
-
|
229
|
-
def method_missing(n, *args, &block)
|
230
|
-
return props[n] if props.key? n # TODO deprecate and remove - done so that params shadow tags, no longer needed
|
231
|
-
name = n
|
232
|
-
if name =~ /_as_node$/
|
233
|
-
node_only = true
|
234
|
-
name = name.gsub(/_as_node$/, "")
|
235
|
-
end
|
236
|
-
unless (HTML_TAGS.include?(name) || name == 'present' || name == '_p_tag' || (name = component?(name, self)))
|
237
|
-
return super
|
238
|
-
end
|
239
|
-
|
240
|
-
if name == "present"
|
241
|
-
name = args.shift
|
242
|
-
end
|
139
|
+
attr_reader :waiting_on_resources
|
243
140
|
|
244
|
-
|
245
|
-
|
141
|
+
def _render_wrapper
|
142
|
+
State.set_state_context_to(self) do
|
143
|
+
React::RenderingContext.render(nil) {render || ""}.tap { |element| @waiting_on_resources = element.waiting_on_resources if element.respond_to? :waiting_on_resources }
|
246
144
|
end
|
247
|
-
|
248
|
-
|
145
|
+
rescue Exception => e
|
146
|
+
self.class.process_exception(e, self)
|
249
147
|
end
|
250
148
|
|
251
149
|
def watch(value, &on_change)
|
@@ -256,14 +154,5 @@ module React
|
|
256
154
|
State.initialize_states(self, self.class.define_state(*args, &block))
|
257
155
|
end
|
258
156
|
|
259
|
-
attr_reader :waiting_on_resources
|
260
|
-
|
261
|
-
def _render_wrapper
|
262
|
-
State.set_state_context_to(self) do
|
263
|
-
React::RenderingContext.render(nil) {render || ""}.tap { |element| @waiting_on_resources = element.waiting_on_resources if element.respond_to? :waiting_on_resources }
|
264
|
-
end
|
265
|
-
rescue Exception => e
|
266
|
-
self.class.process_exception(e, self)
|
267
|
-
end
|
268
157
|
end
|
269
158
|
end
|
@@ -1,29 +1,35 @@
|
|
1
1
|
module React
|
2
2
|
module Component
|
3
|
+
# class level methods (macros) for components
|
3
4
|
module ClassMethods
|
4
5
|
def backtrace(*args)
|
5
|
-
@
|
6
|
+
@dont_catch_exceptions = (args[0] == :none)
|
7
|
+
@backtrace_off = @dont_catch_exceptions || (args[0] == :off)
|
6
8
|
end
|
7
9
|
|
8
10
|
def process_exception(e, component, reraise = nil)
|
9
11
|
message = ["Exception raised while rendering #{component}"]
|
10
|
-
if e.backtrace && e.backtrace.length > 1 && !@backtrace_off
|
11
|
-
message
|
12
|
-
message += e.backtrace[1..-1].collect { |line| line }
|
12
|
+
if e.backtrace && e.backtrace.length > 1 && !@backtrace_off
|
13
|
+
append_backtrace(message, e.backtrace)
|
13
14
|
else
|
14
15
|
message[0] += ": #{e.message}"
|
15
16
|
end
|
16
|
-
message
|
17
|
-
|
18
|
-
raise e if reraise
|
17
|
+
`console.error(#{message.join("\n")})`
|
18
|
+
raise e if reraise || @dont_catch_exceptions
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def append_backtrace(message_array, backtrace)
|
22
|
+
message_array << " #{backtrace[0]}"
|
23
|
+
backtrace[1..-1].each { |line| message_array << line }
|
24
|
+
end
|
25
|
+
|
26
|
+
def render(container = nil, params = {}, &block)
|
27
|
+
define_method :render do
|
28
|
+
if container
|
29
|
+
React::RenderingContext.render(container, params) { instance_eval(&block) if block }
|
30
|
+
else
|
31
|
+
instance_eval(&block)
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
@@ -82,14 +88,14 @@ module React
|
|
82
88
|
end
|
83
89
|
|
84
90
|
def required_param(name, options = {})
|
85
|
-
deprecation_warning "`required_param` is deprecated, use `param` instead."
|
91
|
+
React::Component.deprecation_warning "`required_param` is deprecated, use `param` instead."
|
86
92
|
validator.requires(name, options)
|
87
93
|
end
|
88
94
|
|
89
95
|
alias_method :require_param, :required_param
|
90
96
|
|
91
97
|
def optional_param(name, options = {})
|
92
|
-
deprecation_warning "`optional_param` is deprecated, use `param param_name: default_value` instead."
|
98
|
+
React::Component.deprecation_warning "`optional_param` is deprecated, use `param param_name: default_value` instead."
|
93
99
|
validator.optional(name, options)
|
94
100
|
end
|
95
101
|
|
@@ -128,16 +134,16 @@ module React
|
|
128
134
|
|
129
135
|
def define_state_methods(this, name, from = nil, &block)
|
130
136
|
this.define_method("#{name}") do
|
131
|
-
|
137
|
+
React::Component.deprecation_warning "Direct access to state `#{name}`. Use `state.#{name}` instead." if from.nil? || from == this
|
132
138
|
State.get_state(from || self, name)
|
133
139
|
end
|
134
140
|
this.define_method("#{name}=") do |new_state|
|
135
|
-
|
141
|
+
React::Component.deprecation_warning "Direct assignment to state `#{name}`. Use `#{(from && from != this) ? from : 'state'}.#{name}!` instead."
|
136
142
|
yield name, State.get_state(from || self, name), new_state if block && block.arity > 0
|
137
143
|
State.set_state(from || self, name, new_state)
|
138
144
|
end
|
139
145
|
this.define_method("#{name}!") do |*args|
|
140
|
-
|
146
|
+
React::Component.deprecation_warning "Direct access to state `#{name}`. Use `state.#{name}` instead." if from.nil? or from == this
|
141
147
|
if args.count > 0
|
142
148
|
yield name, State.get_state(from || self, name), args[0] if block && block.arity > 0
|
143
149
|
current_value = State.get_state(from || self, name)
|
@@ -172,16 +178,33 @@ module React
|
|
172
178
|
end
|
173
179
|
|
174
180
|
def export_component(opts = {})
|
175
|
-
export_name = (opts[:as] || name).split(
|
181
|
+
export_name = (opts[:as] || name).split('::')
|
176
182
|
first_name = export_name.first
|
177
|
-
Native(`window`)[first_name] = add_item_to_tree(
|
183
|
+
Native(`window`)[first_name] = add_item_to_tree(
|
184
|
+
Native(`window`)[first_name],
|
185
|
+
[React::API.create_native_react_class(self)] + export_name[1..-1].reverse
|
186
|
+
).to_n
|
187
|
+
end
|
188
|
+
|
189
|
+
def imports(component_name)
|
190
|
+
React::API.import_native_component(
|
191
|
+
self, React::API.eval_native_react_component(component_name)
|
192
|
+
)
|
193
|
+
define_method(:render) {} # define a dummy render method - will never be called...
|
194
|
+
rescue Exception => e # rubocop:disable Lint/RescueException : we need to catch everything!
|
195
|
+
raise "#{self} cannot import '#{component_name}': #{e.message}."
|
196
|
+
# rubocop:enable Lint/RescueException
|
197
|
+
ensure
|
198
|
+
self
|
178
199
|
end
|
179
200
|
|
180
201
|
def add_item_to_tree(current_tree, new_item)
|
181
202
|
if Native(current_tree).class != Native::Object || new_item.length == 1
|
182
|
-
new_item.inject { |
|
203
|
+
new_item.inject { |a, e| { e => a } }
|
183
204
|
else
|
184
|
-
Native(current_tree)[new_item.last] = add_item_to_tree(
|
205
|
+
Native(current_tree)[new_item.last] = add_item_to_tree(
|
206
|
+
Native(current_tree)[new_item.last], new_item[0..-2]
|
207
|
+
)
|
185
208
|
current_tree
|
186
209
|
end
|
187
210
|
end
|