hyper-react 0.99.6 → 1.0.0.lap21

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 (187) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +27 -0
  3. data/.gitignore +30 -37
  4. data/.rubocop.yml +1159 -0
  5. data/.travis.yml +32 -0
  6. data/Appraisals +31 -0
  7. data/CHANGELOG.md +143 -0
  8. data/DOCS.md +1515 -0
  9. data/Gemfile +2 -5
  10. data/LICENSE +19 -0
  11. data/README.md +5 -33
  12. data/Rakefile +25 -6
  13. data/UPGRADING.md +24 -0
  14. data/component-name-lookup.md +145 -0
  15. data/dciy.toml +3 -0
  16. data/dciy_prepare.sh +8 -0
  17. data/dciy_run.sh +10 -0
  18. data/hyper-react.gemspec +24 -18
  19. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
  20. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +5 -0
  21. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
  22. data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
  23. data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
  24. data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
  25. data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
  26. data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
  27. data/lib/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
  28. data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +117 -0
  29. data/lib/hyper-react.rb +66 -4
  30. data/lib/rails-helpers/top_level_rails_component.rb +75 -0
  31. data/lib/react/api.rb +203 -0
  32. data/lib/react/callbacks.rb +41 -0
  33. data/lib/react/children.rb +30 -0
  34. data/lib/react/component.rb +177 -0
  35. data/lib/react/component/api.rb +69 -0
  36. data/lib/react/component/base.rb +13 -0
  37. data/lib/react/component/class_methods.rb +181 -0
  38. data/lib/react/component/dsl_instance_methods.rb +23 -0
  39. data/lib/react/component/params.rb +6 -0
  40. data/lib/react/component/props_wrapper.rb +78 -0
  41. data/lib/react/component/should_component_update.rb +99 -0
  42. data/lib/react/component/tags.rb +108 -0
  43. data/lib/react/config.rb +5 -0
  44. data/lib/react/config/client.rb.erb +19 -0
  45. data/lib/react/config/server.rb +23 -0
  46. data/lib/react/element.rb +150 -0
  47. data/lib/react/event.rb +76 -0
  48. data/lib/react/ext/hash.rb +9 -0
  49. data/lib/react/ext/opal-jquery/element.rb +26 -0
  50. data/lib/react/ext/string.rb +8 -0
  51. data/lib/react/hash.rb +13 -0
  52. data/lib/react/native_library.rb +87 -0
  53. data/lib/react/object.rb +15 -0
  54. data/lib/react/react-source-browser.rb +3 -0
  55. data/lib/react/react-source-server.rb +3 -0
  56. data/lib/react/react-source.rb +16 -0
  57. data/lib/react/ref_callback.rb +31 -0
  58. data/lib/react/rendering_context.rb +146 -0
  59. data/lib/react/server.rb +19 -0
  60. data/lib/react/state_wrapper.rb +23 -0
  61. data/lib/react/test.rb +16 -0
  62. data/lib/react/test/dsl.rb +17 -0
  63. data/lib/react/test/matchers/render_html_matcher.rb +56 -0
  64. data/lib/react/test/rspec.rb +15 -0
  65. data/lib/react/test/session.rb +37 -0
  66. data/lib/react/test/utils.rb +71 -0
  67. data/lib/react/top_level.rb +110 -0
  68. data/lib/react/top_level_render.rb +28 -0
  69. data/lib/react/validator.rb +136 -0
  70. data/lib/reactive-ruby/component_loader.rb +43 -0
  71. data/lib/reactive-ruby/isomorphic_helpers.rb +235 -0
  72. data/lib/reactive-ruby/rails.rb +8 -0
  73. data/lib/reactive-ruby/rails/component_mount.rb +48 -0
  74. data/lib/reactive-ruby/rails/controller_helper.rb +14 -0
  75. data/lib/reactive-ruby/rails/railtie.rb +20 -0
  76. data/lib/reactive-ruby/serializers.rb +15 -0
  77. data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +41 -0
  78. data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +46 -0
  79. data/lib/reactive-ruby/version.rb +3 -0
  80. data/lib/reactrb/auto-import.rb +27 -0
  81. data/logo1.png +0 -0
  82. data/logo2.png +0 -0
  83. data/logo3.png +0 -0
  84. data/path_release_steps.md +9 -0
  85. data/spec/controller_helper_spec.rb +35 -0
  86. data/spec/index.html.erb +11 -0
  87. data/spec/react/callbacks_spec.rb +142 -0
  88. data/spec/react/children_spec.rb +132 -0
  89. data/spec/react/component/base_spec.rb +36 -0
  90. data/spec/react/component_spec.rb +1073 -0
  91. data/spec/react/dsl_spec.rb +323 -0
  92. data/spec/react/element_spec.rb +132 -0
  93. data/spec/react/event_spec.rb +39 -0
  94. data/spec/react/native_library_spec.rb +387 -0
  95. data/spec/react/observable_spec.rb +31 -0
  96. data/spec/react/opal_jquery_extensions_spec.rb +68 -0
  97. data/spec/react/param_declaration_spec.rb +253 -0
  98. data/spec/react/react_spec.rb +278 -0
  99. data/spec/react/refs_callback_spec.rb +65 -0
  100. data/spec/react/server_spec.rb +25 -0
  101. data/spec/react/state_spec.rb +52 -0
  102. data/spec/react/test/dsl_spec.rb +43 -0
  103. data/spec/react/test/matchers/render_html_matcher_spec.rb +83 -0
  104. data/spec/react/test/rspec_spec.rb +62 -0
  105. data/spec/react/test/session_spec.rb +88 -0
  106. data/spec/react/test/utils_spec.rb +28 -0
  107. data/spec/react/top_level_component_spec.rb +103 -0
  108. data/spec/react/tutorial/tutorial_spec.rb +42 -0
  109. data/spec/react/validator_spec.rb +134 -0
  110. data/spec/reactive-ruby/component_loader_spec.rb +74 -0
  111. data/spec/reactive-ruby/isomorphic_helpers_spec.rb +157 -0
  112. data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +17 -0
  113. data/spec/reactive-ruby/rails/component_mount_spec.rb +64 -0
  114. data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +39 -0
  115. data/spec/spec_helper.rb +55 -0
  116. data/spec/test_app/README.md +24 -0
  117. data/spec/test_app/Rakefile +6 -0
  118. data/spec/test_app/app/assets/config/manifest.js +3 -0
  119. data/spec/test_app/app/assets/images/.keep +0 -0
  120. data/spec/test_app/app/assets/javascripts/application.rb +7 -0
  121. data/spec/test_app/app/assets/javascripts/cable.js +13 -0
  122. data/spec/test_app/app/assets/javascripts/channels/.keep +0 -0
  123. data/spec/test_app/app/assets/javascripts/server_rendering.js +5 -0
  124. data/spec/test_app/app/assets/stylesheets/application.css +15 -0
  125. data/spec/test_app/app/channels/application_cable/channel.rb +4 -0
  126. data/spec/test_app/app/channels/application_cable/connection.rb +4 -0
  127. data/spec/test_app/app/controllers/application_controller.rb +3 -0
  128. data/spec/test_app/app/controllers/concerns/.keep +0 -0
  129. data/spec/test_app/app/helpers/application_helper.rb +2 -0
  130. data/spec/test_app/app/jobs/application_job.rb +2 -0
  131. data/spec/test_app/app/mailers/application_mailer.rb +4 -0
  132. data/spec/test_app/app/models/application_record.rb +3 -0
  133. data/spec/test_app/app/models/concerns/.keep +0 -0
  134. data/spec/test_app/app/views/components.rb +11 -0
  135. data/spec/test_app/app/views/components/hello_world.rb +11 -0
  136. data/spec/test_app/app/views/components/todo.rb +14 -0
  137. data/spec/test_app/app/views/layouts/application.html.erb +14 -0
  138. data/spec/test_app/app/views/layouts/explicit_layout.html.erb +0 -0
  139. data/spec/test_app/app/views/layouts/mailer.html.erb +13 -0
  140. data/spec/test_app/app/views/layouts/mailer.text.erb +1 -0
  141. data/spec/test_app/app/views/layouts/test_layout.html.erb +0 -0
  142. data/spec/test_app/bin/bundle +3 -0
  143. data/spec/test_app/bin/rails +4 -0
  144. data/spec/test_app/bin/rake +4 -0
  145. data/spec/test_app/bin/setup +38 -0
  146. data/spec/test_app/bin/update +29 -0
  147. data/spec/test_app/bin/yarn +11 -0
  148. data/spec/test_app/config.ru +5 -0
  149. data/spec/test_app/config/application.rb +45 -0
  150. data/spec/test_app/config/boot.rb +6 -0
  151. data/spec/test_app/config/cable.yml +10 -0
  152. data/spec/test_app/config/database.yml +25 -0
  153. data/spec/test_app/config/environment.rb +5 -0
  154. data/spec/test_app/config/environments/development.rb +54 -0
  155. data/spec/test_app/config/environments/production.rb +91 -0
  156. data/spec/test_app/config/environments/test.rb +42 -0
  157. data/spec/test_app/config/initializers/application_controller_renderer.rb +8 -0
  158. data/spec/test_app/config/initializers/assets.rb +14 -0
  159. data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
  160. data/spec/test_app/config/initializers/cookies_serializer.rb +5 -0
  161. data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
  162. data/spec/test_app/config/initializers/inflections.rb +16 -0
  163. data/spec/test_app/config/initializers/mime_types.rb +4 -0
  164. data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
  165. data/spec/test_app/config/locales/en.yml +33 -0
  166. data/spec/test_app/config/puma.rb +56 -0
  167. data/spec/test_app/config/routes.rb +3 -0
  168. data/spec/test_app/config/secrets.yml +32 -0
  169. data/spec/test_app/config/spring.rb +6 -0
  170. data/spec/test_app/db/development.sqlite3 +0 -0
  171. data/spec/test_app/db/schema.rb +15 -0
  172. data/spec/test_app/db/seeds.rb +7 -0
  173. data/spec/test_app/db/test.sqlite3 +0 -0
  174. data/spec/test_app/lib/assets/.keep +0 -0
  175. data/spec/test_app/log/.keep +0 -0
  176. data/spec/test_app/package.json +5 -0
  177. data/spec/test_app/public/404.html +67 -0
  178. data/spec/test_app/public/422.html +67 -0
  179. data/spec/test_app/public/500.html +66 -0
  180. data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
  181. data/spec/test_app/public/apple-touch-icon.png +0 -0
  182. data/spec/test_app/public/favicon.ico +0 -0
  183. data/spec/vendor/es5-shim.min.js +7 -0
  184. data/spec/vendor/jquery-2.2.4.min.js +4 -0
  185. metadata +401 -61
  186. data/CODE_OF_CONDUCT.md +0 -49
  187. data/lib/react/version.rb +0 -3
@@ -0,0 +1,76 @@
1
+ module React
2
+ class Event
3
+ include Native
4
+ alias_native :bubbles, :bubbles
5
+ alias_native :cancelable, :cancelable
6
+ alias_native :current_target, :currentTarget
7
+ alias_native :default_prevented, :defaultPrevented
8
+ alias_native :event_phase, :eventPhase
9
+ alias_native :is_trusted?, :isTrusted
10
+ alias_native :native_event, :nativeEvent
11
+ alias_native :target, :target
12
+ alias_native :timestamp, :timeStamp
13
+ alias_native :event_type, :type
14
+ alias_native :prevent_default, :preventDefault
15
+ alias_native :stop_propagation, :stopPropagation
16
+ # Clipboard
17
+ alias_native :clipboard_data, :clipboardData
18
+ # Keyboard
19
+ alias_native :alt_key, :altKey
20
+ alias_native :char_code, :charCode
21
+ alias_native :ctrl_key, :ctrlKey
22
+ alias_native :get_modifier_state, :getModifierState
23
+ alias_native :key, :key
24
+ alias_native :key_code, :keyCode
25
+ alias_native :locale, :locale
26
+ alias_native :location, :location
27
+ alias_native :meta_key, :metaKey
28
+ alias_native :repeat, :repeat
29
+ alias_native :shift_key, :shiftKey
30
+ alias_native :which, :which
31
+ # Focus
32
+ alias_native :related_target, :relatedTarget
33
+ # Mouse
34
+ alias_native :alt_key, :altKey
35
+ alias_native :button, :button
36
+ alias_native :buttons, :buttons
37
+ alias_native :client_x, :clientX
38
+ alias_native :client_y, :clientY
39
+ alias_native :ctrl_key, :ctrlKey
40
+ alias_native :get_modifier_state, :getModifierState
41
+ alias_native :meta_key, :metaKey
42
+ alias_native :page_x, :pageX
43
+ alias_native :page_y, :pageY
44
+ alias_native :related_target, :relatedTarget
45
+ alias_native :screen_x, :screen_x
46
+ alias_native :screen_y, :screen_y
47
+ alias_native :shift_key, :shift_key
48
+ # Touch
49
+ alias_native :alt_key, :altKey
50
+ alias_native :changed_touches, :changedTouches
51
+ alias_native :ctrl_key, :ctrlKey
52
+ alias_native :get_modifier_state, :getModifierState
53
+ alias_native :meta_key, :metaKey
54
+ alias_native :shift_key, :shiftKey
55
+ alias_native :target_touches, :targetTouches
56
+ alias_native :touches, :touches
57
+ # UI
58
+ alias_native :detail, :detail
59
+ alias_native :view, :view
60
+ # Wheel
61
+ alias_native :delta_mode, :deltaMode
62
+ alias_native :delta_x, :deltaX
63
+ alias_native :delta_y, :deltaY
64
+ alias_native :delta_z, :deltaZ
65
+
66
+ BUILT_IN_EVENTS = %w{onCopy onCut onPaste onKeyDown onKeyPress onKeyUp
67
+ onFocus onBlur onChange onInput onSubmit onClick onDoubleClick onDrag
68
+ onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop
69
+ onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver
70
+ onMouseUp onTouchCancel onTouchEnd onTouchMove onTouchStart onScroll}
71
+
72
+ def initialize(native_element)
73
+ @native = native_element
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def shallow_to_n
3
+ hash = `{}`
4
+ self.each do |key, value|
5
+ `hash[#{key}] = #{value}`
6
+ end
7
+ hash
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ Element.instance_eval do
2
+ def self.find(selector)
3
+ selector = begin
4
+ selector.dom_node
5
+ rescue
6
+ selector
7
+ end if `#{selector}.$dom_node !== undefined`
8
+ `$(#{selector})`
9
+ end
10
+
11
+ def self.[](selector)
12
+ find(selector)
13
+ end
14
+
15
+ define_method :render do |container = nil, params = {}, &block|
16
+ if `#{self.to_n}._reactrb_component_class === undefined`
17
+ `#{self.to_n}._reactrb_component_class = #{Class.new(Hyperloop::Component)}`
18
+ end
19
+ klass = `#{self.to_n}._reactrb_component_class`
20
+ klass.class_eval do
21
+ render(container, params, &block)
22
+ end
23
+
24
+ React.render(React.create_element(`#{self.to_n}._reactrb_component_class`), self)
25
+ end
26
+ end if Object.const_defined?('Element')
@@ -0,0 +1,8 @@
1
+ class String
2
+ def event_camelize
3
+ `return #{self}.replace(/(^|_)([^_]+)/g, function(match, pre, word, index) {
4
+ var capitalize = true;
5
+ return capitalize ? word.substr(0,1).toUpperCase()+word.substr(1) : word;
6
+ })`
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ class Hash
2
+
3
+ alias_method :_pre_react_patch_initialize, :initialize
4
+
5
+ def initialize(defaults = undefined, &block)
6
+ if (`defaults===null`)
7
+ _pre_react_patch_initialize(&block)
8
+ else
9
+ _pre_react_patch_initialize(defaults, &block)
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,87 @@
1
+ module React
2
+ # NativeLibrary handles importing JS libraries. Importing native components is handled
3
+ # by the React::Base. It also provides several methods used by auto-import.rb
4
+
5
+ # A NativeLibrary is simply a wrapper that holds the name of the native js library.
6
+ # It responds to const_missing and method_missing by looking up objects within the js library.
7
+ # If the object is a react component it is wrapped by a reactrb component class, otherwise
8
+ # a nested NativeLibrary is returned.
9
+
10
+ # Two macros are provided: imports (for naming the native library) and renames which allows
11
+ # the members of a library to be given different names within the ruby name space.
12
+
13
+ # Public methods used by auto-import.rb are import_const_from_native and find_and_render_component
14
+ class NativeLibrary
15
+ class << self
16
+ def imports(native_name)
17
+ @native_prefix = "#{native_name}."
18
+ self
19
+ end
20
+
21
+ def rename(rename_list)
22
+ # rename_list is a hash in the form: native_name => ruby_name, native_name => ruby_name
23
+ rename_list.each do |js_name, ruby_name|
24
+ native_name = lookup_native_name(js_name)
25
+ if lookup_native_name(js_name)
26
+ create_component_wrapper(self, native_name, ruby_name) ||
27
+ create_library_wrapper(self, native_name, ruby_name)
28
+ else
29
+ raise "class #{name} < React::NativeLibrary could not import #{js_name}. "\
30
+ "Native value #{scope_native_name(js_name)} is undefined."
31
+ end
32
+ end
33
+ end
34
+
35
+ def import_const_from_native(klass, const_name, create_library)
36
+ native_name = lookup_native_name(const_name) ||
37
+ lookup_native_name(const_name[0].downcase + const_name[1..-1])
38
+ native_name && (
39
+ create_component_wrapper(klass, native_name, const_name) || (
40
+ create_library &&
41
+ create_library_wrapper(klass, native_name, const_name)))
42
+ end
43
+
44
+ def const_missing(const_name)
45
+ import_const_from_native(self, const_name, true) || super
46
+ end
47
+
48
+ def method_missing(method, *args, &block)
49
+ component_class = const_get(method) if const_defined?(method, false)
50
+ component_class ||= import_const_from_native(self, method, false)
51
+ raise 'could not import a react component named: '\
52
+ "#{scope_native_name method}" unless component_class
53
+ React::RenderingContext.render(component_class, *args, &block)
54
+ end
55
+
56
+ private
57
+
58
+ def lookup_native_name(js_name)
59
+ native_name = scope_native_name(js_name)
60
+ `eval(#{native_name}) !== undefined && native_name`
61
+ # rubocop:disable Lint/RescueException # that is what eval raises in Opal >= 0.10.
62
+ rescue Exception
63
+ nil
64
+ # rubocop:enable Lint/RescueException
65
+ end
66
+
67
+ def scope_native_name(js_name)
68
+ "#{@native_prefix}#{js_name}"
69
+ end
70
+
71
+ def create_component_wrapper(klass, native_name, ruby_name)
72
+ if React::API.native_react_component?(native_name)
73
+ new_klass = klass.const_set ruby_name, Class.new
74
+ new_klass.class_eval do
75
+ include Hyperloop::Component::Mixin
76
+ imports native_name
77
+ end
78
+ new_klass
79
+ end
80
+ end
81
+
82
+ def create_library_wrapper(klass, native_name, ruby_name)
83
+ klass.const_set ruby_name, Class.new(React::NativeLibrary).imports(native_name)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,15 @@
1
+ # Lazy load HTML tag constants in the form DIV or A
2
+ # This is needed to allow for a HAML expression like this DIV.my_class
3
+ class Object
4
+ class << self
5
+ alias _reactrb_tag_original_const_missing const_missing
6
+
7
+ def const_missing(const_name)
8
+ # Opal uses const_missing to initially define things,
9
+ # so we always call the original, and respond to the exception
10
+ _reactrb_tag_original_const_missing(const_name)
11
+ rescue StandardError => e
12
+ React::Component::Tags.html_tag_class_for(const_name) || raise(e)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ if RUBY_ENGINE == 'opal'
2
+ require 'react.js'
3
+ end
@@ -0,0 +1,3 @@
1
+ if RUBY_ENGINE == 'opal'
2
+ require 'react-server.js'
3
+ end
@@ -0,0 +1,16 @@
1
+ if RUBY_ENGINE == 'opal'
2
+ %x{
3
+ var ms = [
4
+ "Warning: `react/react-source` is deprecated, ",
5
+ "use `react/react-source-browser` or `react/react-source-server` instead."
6
+ ]
7
+ console.error(ms.join(""));
8
+ }
9
+ require 'react.js'
10
+ require "react-server.js"
11
+ else
12
+ require "react/config"
13
+ require "react/rails/asset_variant"
14
+ react_directory = React::Rails::AssetVariant.new(React::Config.config).react_directory
15
+ Opal.append_path react_directory.untaint
16
+ end
@@ -0,0 +1,31 @@
1
+ require 'react/native_library'
2
+
3
+ module React
4
+ module RefsCallbackExtension
5
+ end
6
+
7
+ class API
8
+ class << self
9
+ alias :orig_convert_props :convert_props
10
+ end
11
+
12
+ def self.convert_props(properties)
13
+ props = self.orig_convert_props(properties)
14
+ props.map do |key, value|
15
+ if key == "ref" && value.is_a?(Proc)
16
+ new_proc = Proc.new do |native_inst|
17
+ if `#{native_inst}.__opalInstance !== undefined && #{native_inst}.__opalInstance !== null`
18
+ value.call(`#{native_inst}.__opalInstance`)
19
+ elsif `ReactDOM.findDOMNode !== undefined && #{native_inst}.nodeType === undefined`
20
+ value.call(`ReactDOM.findDOMNode(#{native_inst})`) # react >= v0.15.`)
21
+ else
22
+ value.call(native_inst)
23
+ end
24
+ end
25
+ props[key] = new_proc
26
+ end
27
+ end
28
+ props
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,146 @@
1
+ module React
2
+ class RenderingContext
3
+ class << self
4
+ attr_accessor :waiting_on_resources
5
+
6
+ def render(name, *args, &block)
7
+ was_outer_most = !@not_outer_most
8
+ @not_outer_most = true
9
+ remove_nodes_from_args(args)
10
+ @buffer ||= [] unless @buffer
11
+ if block
12
+ element = build do
13
+ saved_waiting_on_resources = waiting_on_resources
14
+ self.waiting_on_resources = nil
15
+ run_child_block(name.nil?, &block)
16
+ if name
17
+ buffer = @buffer.dup
18
+ React::API.create_element(name, *args) { buffer }.tap do |element|
19
+ element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to?(:waiting_on_resources) }
20
+ element.waiting_on_resources ||= waiting_on_resources if buffer.last.is_a?(String)
21
+ end
22
+ elsif @buffer.last.is_a? React::Element
23
+ @buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
24
+ else
25
+ buffer_s = @buffer.last.to_s
26
+ React::RenderingContext.render(:span) { buffer_s }.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
27
+ end
28
+ end
29
+ elsif name.is_a? React::Element
30
+ element = name
31
+ else
32
+ element = React::API.create_element(name, *args)
33
+ element.waiting_on_resources = waiting_on_resources
34
+ end
35
+ @buffer << element
36
+ self.waiting_on_resources = nil
37
+ element
38
+ ensure
39
+ @not_outer_most = @buffer = nil if was_outer_most
40
+ end
41
+
42
+ def build
43
+ current = @buffer
44
+ @buffer = []
45
+ return_val = yield @buffer
46
+ @buffer = current
47
+ return_val
48
+ end
49
+
50
+ def delete(element)
51
+ @buffer.delete(element)
52
+ element
53
+ end
54
+ alias as_node delete
55
+
56
+ def rendered?(element)
57
+ @buffer.include? element
58
+ end
59
+
60
+ def replace(e1, e2)
61
+ @buffer[@buffer.index(e1)] = e2
62
+ end
63
+
64
+ def remove_nodes_from_args(args)
65
+ args[0].each do |key, value|
66
+ begin
67
+ value.delete if value.is_a?(Element) # deletes Element from buffer
68
+ rescue Exception
69
+ end
70
+ end if args[0] && args[0].is_a?(Hash)
71
+ end
72
+
73
+ # run_child_block gathers the element(s) generated by a child block.
74
+ # for example when rendering this div: div { "hello".span; "goodby".span }
75
+ # two child Elements will be generated.
76
+ #
77
+ # the final value of the block should either be
78
+ # 1 an object that responds to :acts_as_string?
79
+ # 2 a string,
80
+ # 3 an element that is NOT yet pushed on the rendering buffer
81
+ # 4 or the last element pushed on the buffer
82
+ #
83
+ # in case 1 we change the object to a string, and then it becomes case 2
84
+ # in case 2 we automatically push the string onto the buffer
85
+ # in case 3 we also push the Element onto the buffer IF the buffer is empty
86
+ # case 4 requires no special processing
87
+ #
88
+ # Once we have taken care of these special cases we do a check IF we are in an
89
+ # outer rendering scope. In this case react only allows us to generate 1 Element
90
+ # so we insure that is the case, and also check to make sure that element in the buffer
91
+ # is the element returned
92
+
93
+ def run_child_block(is_outer_scope)
94
+ result = yield
95
+ if result.respond_to?(:acts_as_string?) && result.acts_as_string?
96
+ @buffer << result.to_s
97
+ elsif result.is_a?(String) || (result.is_a?(React::Element) && @buffer.empty?)
98
+ @buffer << result
99
+ end
100
+ raise_render_error(result) if is_outer_scope && @buffer != [result]
101
+ end
102
+
103
+ # heurestically raise a meaningful error based on the situation
104
+
105
+ def raise_render_error(result)
106
+ improper_render 'A different element was returned than was generated within the DSL.',
107
+ 'Possibly improper use of Element#delete.' if @buffer.count == 1
108
+ improper_render "Instead #{@buffer.count} elements were generated.",
109
+ 'Do you want to wrap your elements in a div?' if @buffer.count > 1
110
+ improper_render "Instead the component #{result} was returned.",
111
+ "Did you mean #{result}()?" if result.try :reactrb_component?
112
+ improper_render "Instead the #{result.class} #{result} was returned.",
113
+ 'You may need to convert this to a string.'
114
+ end
115
+
116
+ def improper_render(message, solution)
117
+ raise "a component's render method must generate and return exactly 1 element or a string.\n"\
118
+ " #{message} #{solution}"
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ class Object
125
+ [:span, :td, :th, :while_loading].each do |tag|
126
+ define_method(tag) do |*args, &block|
127
+ args.unshift(tag)
128
+ return send(*args, &block) if is_a? React::Component
129
+ React::RenderingContext.render(*args) { to_s }
130
+ end
131
+ end
132
+
133
+ def para(*args, &block)
134
+ args.unshift(:p)
135
+ return send(*args, &block) if is_a? React::Component
136
+ React::RenderingContext.render(*args) { to_s }
137
+ end
138
+
139
+ def br
140
+ return send(:br) if is_a? React::Component
141
+ React::RenderingContext.render(:span) do
142
+ React::RenderingContext.render(to_s)
143
+ React::RenderingContext.render(:br)
144
+ end
145
+ end
146
+ end