From 686f965c6bb8e3a04e34d3ad4211b84f0e831f12 Mon Sep 17 00:00:00 2001
From: David Chang <zeta11235813@gmail.com>
Date: Wed, 4 Jan 2017 19:06:03 +0800
Subject: [PATCH 1/3] Use React::Server.render_to_static_markup instead

---
 spec/react/dsl_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/spec/react/dsl_spec.rb b/spec/react/dsl_spec.rb
index e948bca..b25a065 100644
--- a/spec/react/dsl_spec.rb
+++ b/spec/react/dsl_spec.rb
@@ -168,7 +168,7 @@ def render
         _undefined_method
       end
     end
-    expect { React.render_to_static_markup(React.create_element(Foo)) }
+    expect { React::Server.render_to_static_markup(React.create_element(Foo)) }
       .to raise_error(NoMethodError)
   end
 

From 94a8a572e7425002468858fd0453587b85f2c37e Mon Sep 17 00:00:00 2001
From: David Chang <zeta11235813@gmail.com>
Date: Wed, 4 Jan 2017 20:52:14 +0800
Subject: [PATCH 2/3] Add React::RenderingContext.create_context

---
 lib/react/component.rb         |   9 +-
 lib/react/rendering_context.rb | 239 +++++++++++++++++++++------------
 spec/spec_helper.rb            |   3 +
 3 files changed, 161 insertions(+), 90 deletions(-)

diff --git a/lib/react/component.rb b/lib/react/component.rb
index 08fdd09..ba94aed 100644
--- a/lib/react/component.rb
+++ b/lib/react/component.rb
@@ -117,9 +117,12 @@ def render
 
     def _render_wrapper
       State.set_state_context_to(self, true) do
-        element = React::RenderingContext.render(nil) { render || '' }
-        @waiting_on_resources =
-          element.waiting_on_resources if element.respond_to? :waiting_on_resources
+        element = nil
+        React::RenderingContext.create_context do
+          element = React::RenderingContext.render(nil) { render || '' }
+          @waiting_on_resources =
+            element.waiting_on_resources if element.respond_to? :waiting_on_resources
+        end
         element
       end
     # rubocop:disable Lint/RescueException # we want to catch all exceptions regardless
diff --git a/lib/react/rendering_context.rb b/lib/react/rendering_context.rb
index 51dbfbe..03a69d2 100644
--- a/lib/react/rendering_context.rb
+++ b/lib/react/rendering_context.rb
@@ -1,117 +1,182 @@
 module React
   class RenderingContext
-    class << self
-      attr_accessor :waiting_on_resources
+    attr_accessor :waiting_on_resources
 
-      def build_only(name, *args, &block)
-        React::Component.deprecation_warning(
-          '..._as_node is deprecated.  Render component and then use the .node method instead'
-        )
-        React::RenderingContext.build { React::RenderingContext.render(name, *args, &block) }.to_n
-      end
+    def build_only(name, *args, &block)
+      React::Component.deprecation_warning(
+        '..._as_node is deprecated.  Render component and then use the .node method instead'
+      )
+      build { render(name, *args, &block) }.to_n
+    end
 
-      def render(name, *args, &block)
-        remove_nodes_from_args(args)
-        @buffer ||= [] unless @buffer
-        if block
-          element = build do
-            saved_waiting_on_resources = waiting_on_resources
-            self.waiting_on_resources = nil
-            run_child_block(name.nil?, &block)
-            if name
-              buffer = @buffer.dup
-              React.create_element(name, *args) { buffer }.tap do |element|
-                element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to?(:waiting_on_resources) }
-              end
-            elsif @buffer.last.is_a? React::Element
-              @buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
-            else
-              @buffer.last.to_s.span.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
+    def render(name, *args, &block)
+      remove_nodes_from_args(args)
+      @buffer ||= [] unless @buffer
+      if block
+        element = build do
+          saved_waiting_on_resources = waiting_on_resources
+          self.waiting_on_resources = nil
+          run_child_block(name.nil?, &block)
+          if name
+            buffer = @buffer.dup
+            React.create_element(name, *args) { buffer }.tap do |element|
+              element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to?(:waiting_on_resources) }
             end
+          elsif @buffer.last.is_a? React::Element
+            @buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
+          else
+            @buffer.last.to_s.span.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
           end
-        elsif name.is_a? React::Element
-          element = name
+        end
+      elsif name.is_a? React::Element
+        element = name
+      else
+        element = React.create_element(name, *args)
+        element.waiting_on_resources = waiting_on_resources
+      end
+      @buffer << element
+      self.waiting_on_resources = nil
+      element
+    end
+
+    def build
+      current = @buffer
+      @buffer = []
+      return_val = yield @buffer
+      @buffer = current
+      return_val
+    end
+
+    def as_node(element)
+      @buffer.delete(element)
+      element
+    end
+
+    alias delete as_node
+
+    def rendered?(element)
+      @buffer.include? element
+    end
+
+    def replace(e1, e2)
+      @buffer[@buffer.index(e1)] = e2
+    end
+
+    def remove_nodes_from_args(args)
+      args[0].each do |key, value|
+        value.as_node if value.is_a?(Element) rescue nil
+      end if args[0] && args[0].is_a?(Hash)
+    end
+
+    # run_child_block gathers the element(s) generated by a child block.
+    # for example when rendering this div: div { "hello".span; "goodby".span }
+    # two child Elements will be generated.
+    #
+    # the final value of the block should either be
+    #   1 an object that responds to :acts_as_string?
+    #   2 a string,
+    #   3 an element that is NOT yet pushed on the rendering buffer
+    #   4 or the last element pushed on the buffer
+    #
+    # in case 1 we change the object to a string, and then it becomes case 2
+    # in case 2 we automatically push the string onto the buffer
+    # in case 3 we also push the Element onto the buffer IF the buffer is empty
+    # case 4 requires no special processing
+    #
+    # Once we have taken care of these special cases we do a check IF we are in an
+    # outer rendering scope.  In this case react only allows us to generate 1 Element
+    # so we insure that is the case, and also check to make sure that element in the buffer
+    # is the element returned
+
+    def run_child_block(is_outer_scope)
+      result = yield
+      result = result.to_s if result.try :acts_as_string?
+      @buffer << result if result.is_a?(String) || (result.is_a?(Element) && @buffer.empty?)
+      raise_render_error(result) if is_outer_scope && @buffer != [result]
+    end
+
+    def raise_render_error(result)
+      improper_render 'A different element was returned than was generated within the DSL.',
+                      'Possibly improper use of Element#delete.' if @buffer.count == 1
+      improper_render "Instead #{@buffer.count} elements were generated.",
+                      'Do you want to wrap your elements in a div?' if @buffer.count > 1
+      improper_render "Instead the component #{result} was returned.",
+                      "Did you mean #{result}()?" if result.try :reactrb_component?
+      improper_render "Instead the #{result.class} #{result} was returned.",
+                      'You may need to convert this to a string.'
+    end
+
+    def improper_render(message, solution)
+      raise "a component's render method must generate and return exactly 1 element or a string.\n"\
+            "    #{message}  #{solution}"
+    end
+
+    class << self
+      attr_accessor :current_context
+
+      def contexts
+        @contexts ||= []
+      end
+
+      def clear
+        @contexts = nil
+        @current_context = nil
+      end
+
+      def create_context(&block)
+        is_root = !self.current_context
+        if is_root
+          self.current_context = self.new
+          result = yield
+          self.current_context = nil
+          result
         else
-          element = React.create_element(name, *args)
-          element.waiting_on_resources = waiting_on_resources
+          contexts << self.current_context
+          self.current_context = self.new
+          result = yield
+          self.current_context = contexts.pop
+          result
         end
-        @buffer << element
-        self.waiting_on_resources = nil
-        element
+      rescue => e
+        contexts.clear
+        self.current_context = nil
+        raise e
       end
 
-      def build
-        current = @buffer
-        @buffer = []
-        return_val = yield @buffer
-        @buffer = current
-        return_val
+      def build_only(name, *args, &block)
+        current_context.build_only(name, *args, &block)
+      end
+
+      def render(name, *args, &block)
+        current_context.render(name, *args, &block)
+      end
+
+      def build(&block)
+        create_context {
+          current_context.build(&block)
+        }
       end
 
       def as_node(element)
-        @buffer.delete(element)
-        element
+        current_context.as_node(element)
       end
 
       alias delete as_node
 
       def rendered?(element)
-        @buffer.include? element
+        current_context.rendered?(element)
       end
 
       def replace(e1, e2)
-        @buffer[@buffer.index(e1)] = e2
+        current_context.replace(e1, e2)
       end
 
       def remove_nodes_from_args(args)
-        args[0].each do |key, value|
-          value.as_node if value.is_a?(Element) rescue nil
-        end if args[0] && args[0].is_a?(Hash)
+        current_context.remove_nodes_from_args(args)
       end
 
-      # run_child_block gathers the element(s) generated by a child block.
-      # for example when rendering this div: div { "hello".span; "goodby".span }
-      # two child Elements will be generated.
-      #
-      # the final value of the block should either be
-      #   1 an object that responds to :acts_as_string?
-      #   2 a string,
-      #   3 an element that is NOT yet pushed on the rendering buffer
-      #   4 or the last element pushed on the buffer
-      #
-      # in case 1 we change the object to a string, and then it becomes case 2
-      # in case 2 we automatically push the string onto the buffer
-      # in case 3 we also push the Element onto the buffer IF the buffer is empty
-      # case 4 requires no special processing
-      #
-      # Once we have taken care of these special cases we do a check IF we are in an
-      # outer rendering scope.  In this case react only allows us to generate 1 Element
-      # so we insure that is the case, and also check to make sure that element in the buffer
-      # is the element returned
-
       def run_child_block(is_outer_scope)
-        result = yield
-        result = result.to_s if result.try :acts_as_string?
-        @buffer << result if result.is_a?(String) || (result.is_a?(Element) && @buffer.empty?)
-        raise_render_error(result) if is_outer_scope && @buffer != [result]
-      end
-
-      # heurestically raise a meaningful error based on the situation
-
-      def raise_render_error(result)
-        improper_render 'A different element was returned than was generated within the DSL.',
-                        'Possibly improper use of Element#delete.' if @buffer.count == 1
-        improper_render "Instead #{@buffer.count} elements were generated.",
-                        'Do you want to wrap your elements in a div?' if @buffer.count > 1
-        improper_render "Instead the component #{result} was returned.",
-                        "Did you mean #{result}()?" if result.try :reactrb_component?
-        improper_render "Instead the #{result.class} #{result} was returned.",
-                        'You may need to convert this to a string.'
-      end
-
-      def improper_render(message, solution)
-        raise "a component's render method must generate and return exactly 1 element or a string.\n"\
-              "    #{message}  #{solution}"
+        current_context.run_child_block(is_outer_scope)
       end
     end
   end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d90e90c..3a4378c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -76,6 +76,9 @@ def self.should_immediately_generate(opts={}, &block)
   RSpec.configure do |config|
     config.include React::SpecHelpers
     config.filter_run_excluding :ruby
+    config.after :all do
+      React::RenderingContext.clear
+    end
     if `(React.version.search(/^0\.13/) === -1)`
       config.filter_run_excluding :v13_only
     else

From bc15679a64f3c5312b741aee7d39e6bbf8e128ba Mon Sep 17 00:00:00 2001
From: David Chang <zeta11235813@gmail.com>
Date: Wed, 4 Jan 2017 20:55:01 +0800
Subject: [PATCH 3/3] =?UTF-8?q?Don=E2=80=99t=20build=20on=20branch=20other?=
 =?UTF-8?q?=20than=20master?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .travis.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 3b67e7f..a96093a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,9 @@ rvm:
   - 2.0.0
   - 2.1
   - jruby-19mode
+branches:
+  only:
+    - master
 before_script:
   - phantomjs --version
 env: