isomorfeus-react 16.13.6 → 16.13.11

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