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,43 @@
1
+ module ReactiveRuby
2
+ class ComponentLoader
3
+ attr_reader :v8_context
4
+ private :v8_context
5
+
6
+ def initialize(v8_context)
7
+ unless v8_context
8
+ raise ArgumentError.new('Could not obtain ExecJS runtime context')
9
+ end
10
+ @v8_context = v8_context
11
+ end
12
+
13
+ def load(file = components)
14
+ return true if loaded?
15
+ !!v8_context.eval(opal(file))
16
+ end
17
+
18
+ def load!(file = components)
19
+ return true if loaded?
20
+ self.load(file)
21
+ ensure
22
+ raise "No HyperReact components found in #{components}" unless loaded?
23
+ end
24
+
25
+ def loaded?
26
+ !!v8_context.eval('Opal.React !== undefined')
27
+ rescue ::ExecJS::Error
28
+ false
29
+ end
30
+
31
+ private
32
+
33
+ def components
34
+ opts = ::Rails.configuration.react.server_renderer_options
35
+ return opts[:files].first.gsub(/.js$/,'') if opts && opts[:files]
36
+ 'components'
37
+ end
38
+
39
+ def opal(file)
40
+ Opal::Sprockets.load_asset(file)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,235 @@
1
+ require "react/config"
2
+
3
+ module React
4
+ module IsomorphicHelpers
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ if RUBY_ENGINE != 'opal'
10
+ def self.load_context(ctx, controller, name = nil)
11
+ @context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller, name)
12
+ @context.load_opal_context
13
+ ::Rails.logger.debug "************************** React Server Context Initialized #{name} #{Time.now.to_f} *********************************************"
14
+ @context
15
+ end
16
+ else
17
+ def self.load_context(unique_id = nil, name = nil)
18
+ # can be called on the client to force re-initialization for testing purposes
19
+ if !unique_id || !@context || @context.unique_id != unique_id
20
+ if on_opal_server?
21
+ `console.history = []` rescue nil
22
+ message = "************************ React Prerendering Context Initialized #{name} ***********************"
23
+ else
24
+ message = "************************ React Browser Context Initialized ****************************"
25
+ end
26
+ log(message)
27
+ @context = Context.new(unique_id)
28
+ end
29
+ @context
30
+ end
31
+ end
32
+
33
+ def self.context
34
+ @context
35
+ end
36
+
37
+ def self.log(message, message_type = :info)
38
+ message = [message] unless message.is_a? Array
39
+
40
+ is_production = React::Config.config[:environment] == 'production'
41
+
42
+ if (message_type == :info || message_type == :warning) && is_production
43
+ return
44
+ end
45
+
46
+ if message_type == :info
47
+ if on_opal_server?
48
+ style = 'background: #00FFFF; color: red'
49
+ else
50
+ style = 'background: #222; color: #bada55'
51
+ end
52
+ message = ["%c" + message[0], style]+message[1..-1]
53
+ `console.log.apply(console, message)`
54
+ elsif message_type == :warning
55
+ `console.warn.apply(console, message)`
56
+ else
57
+ `console.error.apply(console, message)`
58
+ end
59
+ end
60
+
61
+ if RUBY_ENGINE != 'opal'
62
+ def self.on_opal_server?
63
+ false
64
+ end
65
+
66
+ def self.on_opal_client?
67
+ false
68
+ end
69
+ else
70
+ def self.on_opal_server?
71
+ `typeof Opal.global.document === 'undefined'`
72
+ end
73
+
74
+ def self.on_opal_client?
75
+ !on_opal_server?
76
+ end
77
+ end
78
+
79
+ def log(*args)
80
+ IsomorphicHelpers.log(*args)
81
+ end
82
+
83
+ def on_opal_server?
84
+ self.class.on_opal_server?
85
+ end
86
+
87
+ def on_opal_client?
88
+ self.class.on_opal_client?
89
+ end
90
+
91
+ def self.prerender_footers(controller = nil)
92
+ footer = Context.prerender_footer_blocks.collect { |block| block.call controller }.join("\n")
93
+ if RUBY_ENGINE != 'opal'
94
+ footer = (footer + @context.send_to_opal(:prerender_footers).to_s) if @context
95
+ footer = footer.html_safe
96
+ end
97
+ footer
98
+ end
99
+
100
+ class Context
101
+ attr_reader :controller
102
+ attr_reader :unique_id
103
+
104
+ def self.define_isomorphic_method(method_name, &block)
105
+ @@ctx_methods ||= {}
106
+ @@ctx_methods[method_name] = block
107
+ end
108
+
109
+ def self.before_first_mount_blocks
110
+ @before_first_mount_blocks ||= []
111
+ end
112
+
113
+ def self.prerender_footer_blocks
114
+ @prerender_footer_blocks ||= []
115
+ end
116
+
117
+ def initialize(unique_id, ctx = nil, controller = nil, cname = nil)
118
+ @unique_id = unique_id
119
+ @cname = cname
120
+ if RUBY_ENGINE != 'opal'
121
+ @controller = controller
122
+ @ctx = ctx
123
+ if defined? @@ctx_methods
124
+ @@ctx_methods.each do |method_name, block|
125
+ @ctx.attach("ServerSideIsomorphicMethod.#{method_name}", proc{|args| block.call(args.to_json)})
126
+ end
127
+ end
128
+ end
129
+ Hyperloop::Application::Boot.run(context: self)
130
+ self.class.before_first_mount_blocks.each { |block| block.call(self) }
131
+ end
132
+
133
+ def load_opal_context
134
+ send_to_opal(:load_context, @unique_id, @cname)
135
+ end
136
+
137
+ def eval(js)
138
+ @ctx.eval(js) if @ctx
139
+ end
140
+
141
+ def send_to_opal(method_name, *args)
142
+ return unless @ctx
143
+ args = [1] if args.length == 0
144
+ ::ReactiveRuby::ComponentLoader.new(@ctx).load!
145
+ method_args = args.collect do |arg|
146
+ quarg = "#{arg}".tr('"', "'")
147
+ "\"#{quarg}\""
148
+ end.join(', ')
149
+ @ctx.eval("Opal.React.$const_get('IsomorphicHelpers').$#{method_name}(#{method_args})")
150
+ end
151
+
152
+ def self.register_before_first_mount_block(&block)
153
+ before_first_mount_blocks << block
154
+ end
155
+
156
+ def self.register_prerender_footer_block(&block)
157
+ prerender_footer_blocks << block
158
+ end
159
+ end
160
+
161
+ class IsomorphicProcCall
162
+
163
+ attr_reader :context
164
+
165
+ def result
166
+ @result.first if @result
167
+ end
168
+
169
+ def initialize(name, block, context, *args)
170
+ @name = name
171
+ @context = context
172
+ block.call(self, *args)
173
+ @result ||= send_to_server(*args)
174
+ end
175
+
176
+ def when_on_client(&block)
177
+ @result = [block.call] if IsomorphicHelpers.on_opal_client?
178
+ end
179
+
180
+ def send_to_server(*args)
181
+ if IsomorphicHelpers.on_opal_server?
182
+ method_string = "ServerSideIsomorphicMethod." + @name + "(" + args.to_json + ")"
183
+ @result = [JSON.parse(`eval(method_string)`)]
184
+ end
185
+ end
186
+
187
+ def when_on_server(&block)
188
+ @result = [block.call.to_json] unless IsomorphicHelpers.on_opal_client? || IsomorphicHelpers.on_opal_server?
189
+ end
190
+ end
191
+
192
+ module ClassMethods
193
+ def on_opal_server?
194
+ IsomorphicHelpers.on_opal_server?
195
+ end
196
+
197
+ def on_opal_client?
198
+ IsomorphicHelpers.on_opal_client?
199
+ end
200
+
201
+ def log(*args)
202
+ IsomorphicHelpers.log(*args)
203
+ end
204
+
205
+ def controller
206
+ IsomorphicHelpers.context.controller
207
+ end
208
+
209
+ def before_first_mount(&block)
210
+ React::IsomorphicHelpers::Context.register_before_first_mount_block(&block)
211
+ end
212
+
213
+ def prerender_footer(&block)
214
+ React::IsomorphicHelpers::Context.register_prerender_footer_block(&block)
215
+ end
216
+
217
+ if RUBY_ENGINE != 'opal'
218
+ def isomorphic_method(name, &block)
219
+ React::IsomorphicHelpers::Context.send(:define_isomorphic_method, name) do |args_as_json|
220
+ React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *JSON.parse(args_as_json)).result
221
+ end
222
+ end
223
+ else
224
+ require 'json'
225
+
226
+ def isomorphic_method(name, &block)
227
+ self.class.send(:define_method, name) do | *args |
228
+ React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *args).result
229
+ end
230
+ end
231
+ end
232
+
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,8 @@
1
+ require 'action_view'
2
+ require 'react-rails'
3
+ require 'reactive-ruby/server_rendering/hyper_asset_container'
4
+ require 'reactive-ruby/server_rendering/contextual_renderer'
5
+ require 'reactive-ruby/rails/component_mount'
6
+ require 'reactive-ruby/rails/railtie'
7
+ require 'reactive-ruby/rails/controller_helper'
8
+ require 'reactive-ruby/component_loader'
@@ -0,0 +1,48 @@
1
+ module ReactiveRuby
2
+ module Rails
3
+ class ComponentMount < React::Rails::ComponentMount
4
+ attr_accessor :controller
5
+
6
+ def setup(controller)
7
+ self.controller = controller
8
+ end
9
+
10
+ def react_component(name, props = {}, options = {}, &block)
11
+ if options[:prerender] || [:on, 'on', true].include?(Hyperloop.prerendering)
12
+ options = context_initializer_options(options, name)
13
+ end
14
+ props = serialized_props(props, name, controller)
15
+ super(top_level_name, props, options, &block).gsub("\n","")
16
+ .gsub(/(<script>.*<\/script>)<\/div>$/,'</div>\1').html_safe +
17
+ footers
18
+ end
19
+
20
+ private
21
+
22
+ def context_initializer_options(options, name)
23
+ options[:prerender] = {options[:prerender] => true} unless options[:prerender].is_a? Hash
24
+ existing_context_initializer = options[:prerender][:context_initializer]
25
+
26
+ options[:prerender][:context_initializer] = lambda do |ctx|
27
+ React::IsomorphicHelpers.load_context(ctx, controller, name)
28
+ existing_context_initializer.call(ctx) if existing_context_initializer
29
+ end
30
+
31
+ options
32
+ end
33
+
34
+ def serialized_props(props, name, controller)
35
+ { render_params: props, component_name: name,
36
+ controller: controller.class.name.gsub(/Controller$/,"") }.react_serializer
37
+ end
38
+
39
+ def top_level_name
40
+ 'React.TopLevelRailsComponent'
41
+ end
42
+
43
+ def footers
44
+ React::IsomorphicHelpers.prerender_footers(controller)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,14 @@
1
+ require 'action_controller'
2
+
3
+ module ActionController
4
+ # adds render_component helper to ActionControllers
5
+ class Base
6
+ def render_component(*args)
7
+ @component_name = (args[0].is_a? Hash) || args.empty? ? params[:action].camelize : args.shift
8
+ @render_params = args.shift || {}
9
+ options = args[0] || {}
10
+ render inline: '<%= react_component @component_name, @render_params %>',
11
+ layout: options.key?(:layout) ? options[:layout].to_s : :default
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module ReactiveRuby
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ config.before_configuration do |app|
5
+ app.config.assets.enabled = true
6
+ app.config.assets.paths << ::Rails.root.join('app', 'views').to_s
7
+ app.config.react.server_renderer = ReactiveRuby::ServerRendering::ContextualRenderer
8
+ app.config.react.view_helper_implementation = ReactiveRuby::Rails::ComponentMount
9
+ ReactiveRuby::ServerRendering::ContextualRenderer.asset_container_class = ReactiveRuby::ServerRendering::HyperAssetContainer
10
+ end
11
+ config.after_initialize do
12
+ class ::HyperloopController < ::ApplicationController
13
+ def action_missing(name)
14
+ render_component
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ [Bignum, FalseClass, Fixnum, Float, Integer, NilClass, String, Symbol, Time, TrueClass].each do |klass|
2
+ klass.send(:define_method, :react_serializer) do
3
+ as_json
4
+ end
5
+ end
6
+
7
+ BigDecimal.send(:define_method, :react_serializer) { as_json } rescue nil
8
+
9
+ Array.send(:define_method, :react_serializer) do
10
+ self.collect { |e| e.react_serializer }.as_json
11
+ end
12
+
13
+ Hash.send(:define_method, :react_serializer) do
14
+ Hash[*self.collect { |key, value| [key, value.react_serializer] }.flatten(1)].as_json
15
+ end
@@ -0,0 +1,41 @@
1
+ module ReactiveRuby
2
+ module ServerRendering
3
+ def self.context_instance_name
4
+ '@context'
5
+ end
6
+
7
+ def self.context_instance_for(context)
8
+ context.instance_variable_get(context_instance_name)
9
+ end
10
+
11
+ class ContextualRenderer < React::ServerRendering::BundleRenderer
12
+ def initialize(options = {})
13
+ super(options)
14
+ ComponentLoader.new(v8_context).load
15
+ end
16
+
17
+ def render(component_name, props, prerender_options)
18
+ if prerender_options.is_a?(Hash)
19
+ if !v8_runtime? && prerender_options[:context_initializer]
20
+ raise React::ServerRendering::PrerenderError.new(component_name, props, "you must use 'mini_racer' with the prerender[:context] option") unless v8_runtime?
21
+ else
22
+ prerender_options[:context_initializer].call v8_context
23
+ prerender_options = prerender_options[:static] ? :static : true
24
+ end
25
+ end
26
+
27
+ super(component_name, props, prerender_options)
28
+ end
29
+
30
+ private
31
+
32
+ def v8_runtime?
33
+ ExecJS.runtime.name == 'mini_racer (V8)'
34
+ end
35
+
36
+ def v8_context
37
+ @v8_context ||= ReactiveRuby::ServerRendering.context_instance_for(@context)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ require 'react/server_rendering/environment_container'
2
+ require 'react/server_rendering/manifest_container'
3
+ require 'react/server_rendering/webpacker_manifest_container'
4
+
5
+ module ReactiveRuby
6
+ module ServerRendering
7
+ class HyperTestAssetContainer
8
+ def find_asset(logical_path)
9
+ ::Rails.cache.read(logical_path)
10
+ end
11
+ end
12
+
13
+ class HyperAssetContainer
14
+ def initialize
15
+ @ass_containers = []
16
+ if assets_precompiled?
17
+ @ass_containers << React::ServerRendering::ManifestContainer.new if React::ServerRendering::ManifestContainer.compatible?
18
+ else
19
+ @ass_containers << React::ServerRendering::EnvironmentContainer.new if ::Rails.application.assets
20
+ end
21
+ if React::ServerRendering::WebpackerManifestContainer.compatible?
22
+ @ass_containers << React::ServerRendering::WebpackerManifestContainer.new
23
+ end
24
+ @ass_containers << HyperTestAssetContainer.new if ::Rails.env.test?
25
+ end
26
+
27
+ def find_asset(logical_path)
28
+ @ass_containers.each do |ass|
29
+ begin
30
+ asset = ass.find_asset(logical_path)
31
+ return asset if asset && asset != ''
32
+ rescue
33
+ next # no asset found, try the next container
34
+ end
35
+ end
36
+ raise "No asset found for #{logical_path}, tried: #{@ass_containers.map { |c| c.class.name }.join(', ')}"
37
+ end
38
+
39
+ private
40
+
41
+ def assets_precompiled?
42
+ !::Rails.application.config.assets.compile
43
+ end
44
+ end
45
+ end
46
+ end