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
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
|