isomorfeus-react 16.13.6 → 16.13.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -10
  3. data/lib/isomorfeus-react-native.rb +5 -0
  4. data/lib/isomorfeus-react-paper.rb +4 -0
  5. data/lib/isomorfeus-react.rb +9 -7
  6. data/lib/isomorfeus/props/validator.rb +2 -2
  7. data/lib/isomorfeus/{react_config.rb → react/config.rb} +1 -1
  8. data/lib/isomorfeus/react/memcached_component_cache.rb +19 -0
  9. data/lib/isomorfeus/react/redis_component_cache.rb +19 -0
  10. data/lib/isomorfeus/{thread_local_component_cache.rb → react/thread_local_component_cache.rb} +0 -0
  11. data/lib/isomorfeus/top_level.rb +0 -7
  12. data/lib/isomorfeus_react/lucid_app/mixin.rb +8 -2
  13. data/lib/isomorfeus_react/lucid_app/native_component_constructor.rb +18 -7
  14. data/lib/isomorfeus_react/lucid_app/native_lucid_component_constructor.rb +1 -2
  15. data/lib/isomorfeus_react/lucid_component/api.rb +0 -27
  16. data/lib/isomorfeus_react/lucid_component/mixin.rb +8 -2
  17. data/lib/isomorfeus_react/lucid_component/native_component_constructor.rb +4 -4
  18. data/lib/isomorfeus_react/lucid_component/native_lucid_component_constructor.rb +4 -28
  19. data/lib/isomorfeus_react/lucid_component/styles_api.rb +34 -0
  20. data/lib/isomorfeus_react/lucid_func/mixin.rb +8 -2
  21. data/lib/isomorfeus_react/lucid_func/native_component_constructor.rb +3 -4
  22. data/lib/isomorfeus_react/react/function_component/api.rb +7 -6
  23. data/lib/isomorfeus_react/react/function_component/mixin.rb +5 -1
  24. data/lib/isomorfeus_react/react/function_component/native_component_constructor.rb +3 -2
  25. data/lib/isomorfeus_react/react/memo_component/mixin.rb +5 -1
  26. data/lib/isomorfeus_react/react/memo_component/native_component_constructor.rb +2 -3
  27. data/lib/isomorfeus_react_material/lucid_material/app/mixin.rb +1 -0
  28. data/lib/isomorfeus_react_material/lucid_material/app/native_component_constructor.rb +17 -6
  29. data/lib/isomorfeus_react_material/lucid_material/component/mixin.rb +1 -0
  30. data/lib/isomorfeus_react_material/lucid_material/component/native_component_constructor.rb +3 -3
  31. data/lib/isomorfeus_react_material/lucid_material/func/mixin.rb +1 -0
  32. data/lib/isomorfeus_react_material/lucid_material/func/native_component_constructor.rb +3 -4
  33. data/lib/isomorfeus_react_paper/lucid_paper/app/base.rb +9 -0
  34. data/lib/isomorfeus_react_paper/lucid_paper/app/mixin.rb +19 -0
  35. data/lib/isomorfeus_react_paper/lucid_paper/app/native_component_constructor.rb +32 -0
  36. data/lib/isomorfeus_react_paper/lucid_paper/component/base.rb +9 -0
  37. data/lib/isomorfeus_react_paper/lucid_paper/component/mixin.rb +18 -0
  38. data/lib/isomorfeus_react_paper/lucid_paper/component/native_component_constructor.rb +25 -0
  39. data/lib/isomorfeus_react_paper/lucid_paper/func/base.rb +9 -0
  40. data/lib/isomorfeus_react_paper/lucid_paper/func/mixin.rb +14 -0
  41. data/lib/isomorfeus_react_paper/lucid_paper/func/native_component_constructor.rb +71 -0
  42. data/lib/react.rb +159 -97
  43. data/lib/react/component/api.rb +5 -4
  44. data/lib/react/component/features.rb +1 -3
  45. data/lib/react/component/mixin.rb +5 -1
  46. data/lib/react/component/native_component_constructor.rb +4 -28
  47. data/lib/react/component/props.rb +4 -3
  48. data/lib/react/component/resolution.rb +47 -63
  49. data/lib/react/component/state.rb +4 -2
  50. data/lib/react/component/styles.rb +2 -23
  51. data/lib/react/context_wrapper.rb +3 -5
  52. data/lib/react/native_constant_wrapper.rb +0 -1
  53. data/lib/react/version.rb +1 -1
  54. data/lib/react_native/component/elements.rb +203 -0
  55. data/lib/react_native/lucid_app/react_native_component_constructor.rb +51 -0
  56. data/lib/react_native/lucid_component/react_native_component_constructor.rb +37 -0
  57. data/lib/react_native/lucid_func/react_native_component_constructor.rb +82 -0
  58. data/lib/react_native/react.rb +120 -0
  59. metadata +69 -23
  60. data/lib/isomorfeus/vivify_module.rb +0 -43
data/lib/react.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module React
2
- # language=JS
3
2
  %x{
4
3
  self.render_buffer = [];
5
4
 
@@ -13,12 +12,47 @@ module React
13
12
  core.propTypes[prop_name] = core.prototype.validateProp;
14
13
  };
15
14
 
15
+ self.props_are_equal = function(this_props, next_props) {
16
+ let counter = 0;
17
+ for (var property in next_props) {
18
+ counter++;
19
+ if (next_props.hasOwnProperty(property)) {
20
+ if (!this_props.hasOwnProperty(property)) { return false; };
21
+ if (property === "children") { if (next_props.children !== this_props.children) { return false; }}
22
+ else if (typeof next_props[property] === "object" && next_props[property] !== null && typeof next_props[property]['$!='] === "function" &&
23
+ typeof this_props[property] !== "undefined" && this_props[property] !== null ) {
24
+ if (#{ !! (`next_props[property]` != `this_props[property]`) }) { return false; }
25
+ } else if (next_props[property] !== this_props[property]) { return false; }
26
+ }
27
+ }
28
+ if (counter !== Object.keys(this_props).length) { return false; }
29
+ return true;
30
+ };
31
+
32
+ self.state_is_not_equal = function(this_state, next_state) {
33
+ let counter = 0;
34
+ for (var property in next_state) {
35
+ counter++;
36
+ if (next_state.hasOwnProperty(property)) {
37
+ if (!this_state.hasOwnProperty(property)) { return true; };
38
+ if (typeof next_state[property] === "object" && next_state[property] !== null && typeof next_state[property]['$!='] === "function" &&
39
+ typeof this_state[property] !== "undefined" && this_state[property] !== null) {
40
+ if (#{ !! (`next_state[property]` != `this_state[property]`) }) { return true }
41
+ } else if (next_state[property] !== this_state[property]) { return true }
42
+ }
43
+ }
44
+ if (counter !== Object.keys(this_state).length) { return true; }
45
+ return false;
46
+ };
47
+
16
48
  self.lower_camelize = function(snake_cased_word) {
49
+ if (self.prop_dictionary[snake_cased_word]) { return self.prop_dictionary[snake_cased_word]; }
17
50
  let parts = snake_cased_word.split('_');
18
51
  let res = parts[0];
19
52
  for (let i = 1; i < parts.length; i++) {
20
53
  res += parts[i][0].toUpperCase() + parts[i].slice(1);
21
54
  }
55
+ self.prop_dictionary[snake_cased_word] = res;
22
56
  return res;
23
57
  };
24
58
 
@@ -34,79 +68,6 @@ module React
34
68
  else { return Opal.Hash.$new(event); }
35
69
  };
36
70
 
37
- self.to_native_react_props = function(ruby_style_props) {
38
- let result = {};
39
- let keys = ruby_style_props.$keys();
40
- let keys_length = keys.length;
41
- let key = '';
42
- for (let i = 0; i < keys_length; i++) {
43
- key = keys[i];
44
- if (key[0] === 'o' && key[1] === 'n' && key[2] === '_') {
45
- let handler = ruby_style_props['$[]'](key);
46
- let type = typeof handler;
47
- if (type === "function") {
48
- let active_c = self.active_component();
49
- result[self.lower_camelize(key)] = function(event, info) {
50
- let ruby_event = self.native_to_ruby_event(event);
51
- #{`active_c.__ruby_instance`.instance_exec(`ruby_event`, `info`, &`handler`)};
52
- }
53
- } else if (type === "object" && typeof handler.$call === "function" ) {
54
- if (!handler.react_event_handler_function) {
55
- handler.react_event_handler_function = function(event, info) {
56
- let ruby_event = self.native_to_ruby_event(event);
57
- handler.$call(ruby_event, info)
58
- };
59
- }
60
- result[self.lower_camelize(key)] = handler.react_event_handler_function;
61
- } else if (type === "string" ) {
62
- let active_component = self.active_component();
63
- let method_ref;
64
- let method_name = '$' + handler;
65
- if (typeof active_component[method_name] === "function") {
66
- // got a ruby instance
67
- if (active_component.native && active_component.native.method_refs && active_component.native.method_refs[handler]) { method_ref = active_component.native.method_refs[handler]; } // ruby instance with native
68
- else if (active_component.method_refs && active_component.method_refs[handler]) { method_ref = active_component.method_refs[handler]; } // ruby function component
69
- else { method_ref = active_component.$method_ref(handler); } // create the ref
70
- } else if (typeof active_component.__ruby_instance[method_name] === "function") {
71
- // got a native instance
72
- if (active_component.method_refs && active_component.method_refs[handler]) { method_ref = active_component.method_refs[handler]; }
73
- else { method_ref = active_component.__ruby_instance.$method_ref(handler); } // create ref for native
74
- }
75
- if (method_ref) {
76
- if (!method_ref.react_event_handler_function) {
77
- method_ref.react_event_handler_function = function(event, info) {
78
- let ruby_event = self.native_to_ruby_event(event);
79
- method_ref.$call(ruby_event, info)
80
- };
81
- }
82
- result[self.lower_camelize(key)] = method_ref.react_event_handler_function;
83
- } else {
84
- let component_name;
85
- if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
86
- else { component_name = active_component.$to_s(); }
87
- #{Isomorfeus.raise_error(message: "Is #{`handler`} a valid method of #{`component_name`}? If so then please use: #{`key`}: method_ref(:#{`handler`}) within component: #{`component_name`}")}
88
- }
89
- } else {
90
- let active_component = self.active_component();
91
- let component_name;
92
- if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
93
- else { component_name = active_component.$to_s(); }
94
- #{Isomorfeus.raise_error(message: "Received invalid value for #{`key`} with #{`handler`} within component: #{`component_name`}")}
95
- console.error( + key + " event handler:", handler, " within component:", self.active_component());
96
- }
97
- } else if (key[0] === 'a' && key.startsWith("aria_")) {
98
- result[key.replace("_", "-")] = ruby_style_props['$[]'](key);
99
- } else if (key === "style") {
100
- let val = ruby_style_props['$[]'](key);
101
- if (typeof val.$to_n === "function") { val = val.$to_n() }
102
- result["style"] = val;
103
- } else {
104
- result[key.indexOf('_') > 0 ? self.lower_camelize(key) : key] = ruby_style_props['$[]'](key);
105
- }
106
- }
107
- return result;
108
- };
109
-
110
71
  self.internal_prepare_args_and_render = function(component, args, block) {
111
72
  const operain = self.internal_render;
112
73
  if (args.length > 0) {
@@ -118,26 +79,6 @@ module React
118
79
  } else { operain(component, null, null, block); }
119
80
  };
120
81
 
121
- self.internal_render = function(component, props, string_child, block) {
122
- const operabu = self.render_buffer;
123
- let children;
124
- let native_props = null;
125
- if (string_child) {
126
- children = [string_child];
127
- } else if (block && block !== nil) {
128
- operabu.push([]);
129
- // console.log("internal_render pushed", Opal.React.render_buffer, Opal.React.render_buffer.toString());
130
- let block_result = block.$call();
131
- if (block_result && (block_result.constructor === String || block_result.constructor === Number)) {
132
- operabu[operabu.length - 1].push(block_result);
133
- }
134
- // console.log("internal_render popping", Opal.React.render_buffer, Opal.React.render_buffer.toString());
135
- children = operabu.pop();
136
- }
137
- if (props && props !== nil) { native_props = self.to_native_react_props(props); }
138
- operabu[operabu.length - 1].push(Opal.global.React.createElement.apply(this, [component, native_props].concat(children)));
139
- };
140
-
141
82
  self.active_components = [];
142
83
 
143
84
  self.active_component = function() {
@@ -153,8 +94,131 @@ module React
153
94
  if (length === 0) { return null; };
154
95
  return self.active_redux_components[length-1];
155
96
  };
97
+
98
+ function isObject(obj) { return (obj && typeof obj === 'object'); }
99
+
100
+ self.merge_deep = function(one, two) {
101
+ return [one, two].reduce(function(pre, obj) {
102
+ Object.keys(obj).forEach(function(key){
103
+ let pVal = pre[key];
104
+ let oVal = obj[key];
105
+ if (Array.isArray(pVal) && Array.isArray(oVal)) {
106
+ pre[key] = pVal.concat.apply(this, oVal);
107
+ } else if (isObject(pVal) && isObject(oVal)) {
108
+ pre[key] = self.merge_deep(pVal, oVal);
109
+ } else {
110
+ pre[key] = oVal;
111
+ }
112
+ });
113
+ return pre;
114
+ }, {});
115
+ };
156
116
  }
157
117
 
118
+ if on_browser? || on_ssr?
119
+ %x{
120
+ self.prop_dictionary = {};
121
+
122
+ self.to_native_react_props = function(ruby_style_props) {
123
+ let result = {};
124
+ let keys = ruby_style_props.$$keys;
125
+ let keys_length = keys.length;
126
+ let key = '';
127
+ for (let i = 0; i < keys_length; i++) {
128
+ key = keys[i];
129
+ let value = ruby_style_props.$$smap[key];
130
+ if (key[0] === 'o' && key[1] === 'n' && key[2] === '_') {
131
+ let type = typeof value;
132
+ if (type === "function") {
133
+ let active_c = self.active_component();
134
+ result[self.lower_camelize(key)] = function(event, info) {
135
+ let ruby_event = self.native_to_ruby_event(event);
136
+ #{`active_c.__ruby_instance`.instance_exec(`ruby_event`, `info`, &`value`)};
137
+ }
138
+ } else if (type === "object" && typeof value.m === "object" && typeof value.m.$call === "function" ) {
139
+ if (!value.react_event_handler_function) {
140
+ value.react_event_handler_function = function(event, info) {
141
+ let ruby_event = self.native_to_ruby_event(event);
142
+ if (value.a.length > 0) { value.m.$call.apply(value.m, [ruby_event, info].concat(value.a)); }
143
+ else { value.m.$call(ruby_event, info); }
144
+ };
145
+ }
146
+ result[self.lower_camelize(key)] = value.react_event_handler_function;
147
+ } else if (type === "string" ) {
148
+ let active_component = self.active_component();
149
+ let method_ref;
150
+ let method_name = '$' + value;
151
+ if (typeof active_component[method_name] === "function") {
152
+ // got a ruby instance
153
+ if (active_component.native && active_component.native.method_refs && active_component.native.method_refs[value]) { method_ref = active_component.native.method_refs[value]; } // ruby instance with native
154
+ else if (active_component.method_refs && active_component.method_refs[value]) { method_ref = active_component.method_refs[value]; } // ruby function component
155
+ else { method_ref = active_component.$method_ref(value); } // create the ref
156
+ } else if (typeof active_component.__ruby_instance[method_name] === "function") {
157
+ // got a native instance
158
+ if (active_component.method_refs && active_component.method_refs[value]) { method_ref = active_component.method_refs[value]; }
159
+ else { method_ref = active_component.__ruby_instance.$method_ref(value); } // create ref for native
160
+ }
161
+ if (method_ref) {
162
+ if (!method_ref.react_event_handler_function) {
163
+ method_ref.react_event_handler_function = function(event, info) {
164
+ let ruby_event = self.native_to_ruby_event(event);
165
+ method_ref.m.$call(ruby_event, info)
166
+ };
167
+ }
168
+ result[self.lower_camelize(key)] = method_ref.react_event_handler_function;
169
+ } else {
170
+ let component_name;
171
+ if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
172
+ else { component_name = active_component.$to_s(); }
173
+ #{Isomorfeus.raise_error(message: "Is #{`value`} a valid method of #{`component_name`}? If so then please use: #{`key`}: method_ref(:#{`value`}) within component: #{`component_name`}")}
174
+ }
175
+ } else {
176
+ let active_component = self.active_component();
177
+ let component_name;
178
+ if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
179
+ else { component_name = active_component.$to_s(); }
180
+ #{Isomorfeus.raise_error(message: "Received invalid value for #{`key`} with #{`value`} within component: #{`component_name`}")}
181
+ console.error( + key + " event handler:", value, " within component:", self.active_component());
182
+ }
183
+ } else if (key[0] === 'a' && key.startsWith("aria_")) {
184
+ result[key.replace("_", "-")] = value;
185
+ } else if (key === "style" || key === "theme") {
186
+ if (typeof value.$to_n === "function") { value = value.$to_n() }
187
+ result[key] = value;
188
+ } else {
189
+ result[self.lower_camelize(key)] = value;
190
+ }
191
+ }
192
+ return result;
193
+ };
194
+
195
+ self.render_block_result = function(block_result) {
196
+ if (block_result.constructor === String || block_result.constructor === Number) {
197
+ Opal.React.render_buffer[Opal.React.render_buffer.length - 1].push(block_result);
198
+ }
199
+ };
200
+
201
+ self.internal_render = function(component, props, string_child, block) {
202
+ const operabu = self.render_buffer;
203
+ let native_props;
204
+ if (props && props !== nil) { native_props = self.to_native_react_props(props); }
205
+ if (string_child) {
206
+ operabu[operabu.length - 1].push(Opal.global.React.createElement(component, native_props, string_child));
207
+ } else if (block && block !== nil) {
208
+ operabu.push([]);
209
+ // console.log("internal_render pushed", Opal.React.render_buffer, Opal.React.render_buffer.toString());
210
+ let block_result = block.$call();
211
+ if (block_result && block_result !== nil) { Opal.React.render_block_result(block_result); }
212
+ // console.log("internal_render popping", Opal.React.render_buffer, Opal.React.render_buffer.toString());
213
+ let children = operabu.pop();
214
+ operabu[operabu.length - 1].push(Opal.global.React.createElement.apply(this, [component, native_props].concat(children)));
215
+ } else {
216
+ operabu[operabu.length - 1].push(Opal.global.React.createElement(component, native_props));
217
+ }
218
+ };
219
+ }
220
+ end
221
+
158
222
  def self.clone_element(ruby_react_element, props = nil, children = nil, &block)
159
223
  block_result = `null`
160
224
  if block_given?
@@ -185,9 +249,7 @@ module React
185
249
  operabu.push([]);
186
250
  // console.log("create_element pushed", Opal.React.render_buffer, Opal.React.render_buffer.toString());
187
251
  let block_result = block.$call();
188
- if (block_result && (block_result.constructor === String || block_result.constructor === Number)) {
189
- operabu[operabu.length - 1].push(block_result);
190
- }
252
+ if (block_result && block_result !== nil) { Opal.React.render_block_result(block_result); }
191
253
  // console.log("create_element popping", Opal.React.render_buffer, Opal.React.render_buffer.toString());
192
254
  children = operabu.pop();
193
255
  } else if (children === nil) { children = []; }
@@ -98,12 +98,13 @@ module React
98
98
  end
99
99
  alias gre get_react_element
100
100
 
101
- def method_ref(method_symbol)
101
+ def method_ref(method_symbol, *args)
102
+ method_key = "#{method_symbol}#{args}"
102
103
  %x{
103
- if (#@native.method_refs && #@native.method_refs[#{method_symbol}]) { return #@native.method_refs[#{method_symbol}]; }
104
+ if (#@native.method_refs && #@native.method_refs[#{method_key}]) { return #@native.method_refs[#{method_key}]; }
104
105
  if (!#@native.method_refs) { #@native.method_refs = {}; }
105
- #@native.method_refs[#{method_symbol}] = #{method(method_symbol)};
106
- return #@native.method_refs[#{method_symbol}];
106
+ #@native.method_refs[#{method_key}] = { m: #{method(method_symbol)}, a: args };
107
+ return #@native.method_refs[#{method_key}];
107
108
  }
108
109
  end
109
110
  alias m_ref method_ref
@@ -21,9 +21,7 @@ module React
21
21
  let block_result = block.$call()
22
22
  let last_buffer_length = operabu[operabu.length - 1].length;
23
23
  let last_buffer_element = operabu[operabu.length - 1][last_buffer_length - 1];
24
- if (block_result && (block_result.constructor === String || block_result.constructor === Number)) {
25
- operabu[operabu.length - 1].push(block_result);
26
- }
24
+ if (block_result && block_result !== nil) { Opal.React.render_block_result(block_result); }
27
25
  }
28
26
  // console.log("portal popping", operabu, operabu.toString());
29
27
  let result = operabu.pop();
@@ -5,7 +5,11 @@ module React
5
5
  base.include(::Native::Wrapper)
6
6
  base.extend(::React::Component::NativeComponentConstructor)
7
7
  base.extend(::LucidPropDeclaration::Mixin)
8
- base.include(::React::Component::Elements)
8
+ if on_browser? || on_ssr?
9
+ base.include(::React::Component::Elements)
10
+ elsif on_mobile?
11
+ base.include(::ReactNative::Component::Elements)
12
+ end
9
13
  base.include(::React::Component::Api)
10
14
  base.include(::React::Component::Callbacks)
11
15
  base.include(::React::Component::Initializer)
@@ -43,42 +43,18 @@ module React
43
43
  // console.log("react component pushed", oper.render_buffer, oper.render_buffer.toString());
44
44
  oper.active_components.push(this);
45
45
  let block_result = #{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
46
- if (block_result && (block_result.constructor === String || block_result.constructor === Number)) { oper.render_buffer[oper.render_buffer.length - 1].push(block_result); }
46
+ if (block_result && block_result !== nil) { oper.render_block_result(block_result); }
47
47
  // console.log("react component popping", oper.render_buffer, oper.render_buffer.toString());
48
48
  oper.active_components.pop();
49
49
  let result = oper.render_buffer.pop();
50
- if (result.length === 1) { return result[0]; }
51
- return result;
50
+ return (result.length === 1) ? result[0] : result;
52
51
  }
53
52
  shouldComponentUpdate(next_props, next_state) {
54
53
  if (base.should_component_update_block) {
55
54
  return #{!!`this.__ruby_instance`.instance_exec(React::Component::Props.new(`{props: next_props}`), React::Component::State.new(`{state: next_state }`), &`base.should_component_update_block`)};
56
55
  }
57
- let counter = 0;
58
- for (var property in next_props) {
59
- counter++;
60
- if (next_props.hasOwnProperty(property)) {
61
- if (!this.props.hasOwnProperty(property)) { return true; };
62
- if (property === "children") { if (next_props.children !== this.props.children) { return true; }}
63
- else if (typeof next_props[property] !== "undefined" && next_props[property] !== null && typeof next_props[property]['$!='] === "function" &&
64
- typeof this.props[property] !== "undefined" && this.props[property] !== null ) {
65
- if (#{ !! (`next_props[property]` != `this.props[property]`) }) { return true; }
66
- } else if (next_props[property] !== this.props[property]) { return true; }
67
- }
68
- }
69
- if (counter !== Object.keys(this.props).length) { return true; }
70
- counter = 0;
71
- for (var property in next_state) {
72
- counter++;
73
- if (next_state.hasOwnProperty(property)) {
74
- if (!this.state.hasOwnProperty(property)) { return true; };
75
- if (typeof next_state[property] !== "undefined" && next_state[property] !== null && typeof next_state[property]['$!='] === "function" &&
76
- typeof this.state[property] !== "undefined" && this.state[property] !== null) {
77
- if (#{ !! (`next_state[property]` != `this.state[property]`) }) { return true }
78
- } else if (next_state[property] !== this.state[property]) { return true }
79
- }
80
- }
81
- if (counter !== Object.keys(this.state).length) { return true; }
56
+ if (!Opal.React.props_are_equal(this.props, next_props)) { return true; }
57
+ if (Opal.React.state_is_not_equal(this.state, next_state)) { return true; }
82
58
  return false;
83
59
  }
84
60
  validateProp(props, propName, componentName) {
@@ -7,11 +7,12 @@ module React
7
7
 
8
8
  def method_missing(prop, *args, &block)
9
9
  %x{
10
- if (typeof #@native.props[prop] === 'undefined') {
10
+ const p = #@native.props;
11
+ if (typeof p[prop] === 'undefined') {
11
12
  prop = Opal.React.lower_camelize(prop);
12
- if (typeof #@native.props[prop] === 'undefined') { return #{nil}; }
13
+ if (typeof p[prop] === 'undefined') { return nil; }
13
14
  }
14
- return #@native.props[prop];
15
+ return p[prop];
15
16
  }
16
17
  end
17
18
 
@@ -3,13 +3,15 @@ module React
3
3
  module Resolution
4
4
  def self.included(base)
5
5
  base.instance_exec do
6
- alias _react_component_class_resolution_original_const_missing const_missing
6
+ unless method_defined?(:_react_component_class_resolution_original_const_missing)
7
+ alias _react_component_class_resolution_original_const_missing const_missing
8
+ end
7
9
 
8
10
  def const_missing(const_name)
9
- # language=JS
10
11
  %x{
11
12
  if (typeof Opal.global[const_name] !== "undefined" && (const_name[0] === const_name[0].toUpperCase())) {
12
13
  var new_const = #{React::NativeConstantWrapper.new(`Opal.global[const_name]`, const_name)};
14
+ new_const.react_component = Opal.global[const_name];
13
15
  #{Object.const_set(const_name, `new_const`)};
14
16
  return new_const;
15
17
  } else {
@@ -20,7 +22,6 @@ module React
20
22
 
21
23
  # this is required for autoloading support, as the component may not be loaded and so its method is not registered.
22
24
  # must load it first, done by const_get, and next time the method will be there.
23
-
24
25
  unless method_defined?(:_react_component_class_resolution_original_method_missing)
25
26
  alias _react_component_class_resolution_original_method_missing method_missing
26
27
  end
@@ -28,36 +29,21 @@ module React
28
29
  def method_missing(component_name, *args, &block)
29
30
  # check for ruby component and render it
30
31
  # otherwise pass on method missing
31
- # language=JS
32
32
  %x{
33
- var modules = self.$to_s().split("::");
34
- var modules_length = modules.length;
35
- var module;
36
33
  var constant;
37
- var component;
38
- for (var i = modules_length; i > 0; i--) {
39
- try {
40
- module = modules.slice(0, i).join('::');
41
- constant = self.$const_get(module).$const_get(component_name, false);
42
- if (typeof constant.react_component !== 'undefined') {
43
- component = constant.react_component;
44
- break;
45
- }
46
- } catch(err) { component = null; }
47
- }
48
- if (!component) {
49
- try {
50
- constant = Opal.Object.$const_get(component_name);
51
- if (typeof constant.react_component !== 'undefined') {
52
- component = constant.react_component;
53
- }
54
- } catch(err) { component = null; }
55
- }
56
- if (component) {
57
- return Opal.React.internal_prepare_args_and_render(component, args, block);
58
- } else {
59
- return #{_react_component_class_resolution_original_method_missing(component_name, *args, block)};
60
- }
34
+ if (typeof self.iso_react_const_cache === 'undefined') { self.iso_react_const_cache = {}; }
35
+ try {
36
+ if (typeof self.iso_react_const_cache[component_name] !== 'undefined') {
37
+ constant = self.iso_react_const_cache[component_name]
38
+ } else {
39
+ constant = self.$const_get(component_name);
40
+ self.iso_react_const_cache[component_name] = constant;
41
+ }
42
+ if (typeof constant.react_component !== 'undefined') {
43
+ return Opal.React.internal_prepare_args_and_render(constant.react_component, args, block);
44
+ }
45
+ } catch(err) { }
46
+ return #{_react_component_class_resolution_original_method_missing(component_name, *args, block)};
61
47
  }
62
48
  end
63
49
  end
@@ -68,44 +54,42 @@ module React
68
54
  end
69
55
 
70
56
  def method_missing(component_name, *args, &block)
71
- # html tags are defined as methods, so they will not end up here.
72
- # first check for native component and render it, we want to be fast for native components
73
- # second check for ruby component and render it, they are a bit slower anyway
74
- # third pass on method missing
75
- # language=JS
57
+ # Further on it must check for modules, because $const_get does not take
58
+ # the full nesting into account, as usually its called via $$ with the
59
+ # nesting provided by the compiler.
76
60
  %x{
77
- var component = null;
78
- if (typeof Opal.global[component_name] !== "undefined" && (component_name[0] === component_name[0].toUpperCase())) {
79
- component = Opal.global[component_name];
61
+ var constant;
62
+ if (typeof self.iso_react_const_cache === 'undefined') { self.iso_react_const_cache = {}; }
63
+
64
+ if (typeof self.iso_react_const_cache[component_name] !== 'undefined') {
65
+ constant = self.iso_react_const_cache[component_name]
66
+ } else if (typeof self.$$is_a_module !== 'undefined') {
67
+ try {
68
+ constant = self.$const_get(component_name);
69
+ self.iso_react_const_cache[component_name] = constant;
70
+ } catch(err) { }
80
71
  } else {
81
- var modules = self.$to_s().split("::");
82
- var modules_length = modules.length;
83
- var module;
84
- var constant;
85
- for (var i = modules_length; i > 0; i--) {
86
- try {
87
- module = modules.slice(0, i).join('::');
88
- constant = self.$class().$const_get(module).$const_get(component_name, false);
89
- if (typeof constant.react_component !== 'undefined') {
90
- component = constant.react_component;
72
+ let sc = self.$class();
73
+ try {
74
+ constant = sc.$const_get(component_name);
75
+ self.iso_react_const_cache[component_name] = constant;
76
+ } catch(err) {
77
+ var module_names = sc.$to_s().split("::");
78
+ var module_name;
79
+ for (var i = module_names.length - 1; i > 0; i--) {
80
+ module_name = module_names.slice(0, i).join('::');
81
+ try {
82
+ constant = sc.$const_get(module_name).$const_get(component_name, false);
83
+ self.iso_react_const_cache[component_name] = constant;
91
84
  break;
92
- }
93
- } catch(err) { component = null; }
94
- }
95
- if (!component) {
96
- try {
97
- constant = Opal.Object.$const_get(component_name);
98
- if (typeof constant.react_component !== 'undefined') {
99
- component = constant.react_component;
100
- }
101
- } catch(err) { component = null; }
85
+ } catch(err) { }
86
+ }
102
87
  }
103
88
  }
104
- if (component) {
105
- return Opal.React.internal_prepare_args_and_render(component, args, block);
106
- } else {
107
- return #{_react_component_resolution_original_method_missing(component_name, *args, block)};
89
+ if (constant && typeof constant.react_component !== 'undefined') {
90
+ return Opal.React.internal_prepare_args_and_render(constant.react_component, args, block);
108
91
  }
92
+ return #{_react_component_resolution_original_method_missing(component_name, *args, block)};
109
93
  }
110
94
  end
111
95
  end