From ce6ff380789eb0ae9f8d1ed5867645c33a9245a3 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 24 Jun 2016 20:20:49 -0400 Subject: [PATCH] feat(React) expose camelize_props function --- lib/react-rails.rb | 2 +- lib/react.rb | 19 ++++++++ lib/react/rails/component_mount.rb | 21 ++------- test/react_asset_test.rb | 47 +++++++++++++++++++ test/react_test.rb | 73 ++++++++++++------------------ 5 files changed, 99 insertions(+), 63 deletions(-) create mode 100644 lib/react.rb create mode 100644 test/react_asset_test.rb diff --git a/lib/react-rails.rb b/lib/react-rails.rb index fdb8abf93..582309dcf 100644 --- a/lib/react-rails.rb +++ b/lib/react-rails.rb @@ -1,4 +1,4 @@ +require 'react' require 'react/jsx' require 'react/rails' require 'react/server_rendering' - diff --git a/lib/react.rb b/lib/react.rb new file mode 100644 index 000000000..5e6b0f754 --- /dev/null +++ b/lib/react.rb @@ -0,0 +1,19 @@ +module React + # Recursively camelize `props`, returning a new Hash + # @param props [Object] If it's a Hash or Array, it will be recursed. Otherwise it will be returned. + # @return [Hash] a new hash whose keys are camelized strings + def self.camelize_props(props) + case props + when Hash + props.each_with_object({}) do |(key, value), new_props| + new_key = key.to_s.camelize(:lower) + new_value = camelize_props(value) + new_props[new_key] = new_value + end + when Array + props.map { |item| camelize_props(item) } + else + props + end + end +end diff --git a/lib/react/rails/component_mount.rb b/lib/react/rails/component_mount.rb index 3f098f400..7864773b3 100644 --- a/lib/react/rails/component_mount.rb +++ b/lib/react/rails/component_mount.rb @@ -24,7 +24,9 @@ def teardown(env) # on the client. def react_component(name, props = {}, options = {}, &block) options = {:tag => options} if options.is_a?(Symbol) - props = camelize_props_key(props) if camelize_props_switch + if camelize_props_switch + props = React.camelize_props(props) + end prerender_options = options[:prerender] if prerender_options @@ -45,23 +47,6 @@ def react_component(name, props = {}, options = {}, &block) content_tag(html_tag, '', html_options, &block) end - - private - - def camelize_props_key(props) - return props unless props.is_a?(Hash) - props.inject({}) do |h, (k,v)| - h[k.to_s.camelize(:lower)] = case v - when Hash - camelize_props_key(v) - when Array - v.map {|i| camelize_props_key(i) } - else - v - end - h - end - end end end end diff --git a/test/react_asset_test.rb b/test/react_asset_test.rb new file mode 100644 index 000000000..6cb525e0f --- /dev/null +++ b/test/react_asset_test.rb @@ -0,0 +1,47 @@ +require 'test_helper' + +class ReactAssetTest < ActionDispatch::IntegrationTest + setup do + clear_sprockets_cache + end + + teardown do + clear_sprockets_cache + end + + test 'asset pipeline should deliver drop-in react file replacement' do + app_react_file_path = File.expand_path("../dummy/vendor/assets/javascripts/react.js", __FILE__) + react_file_token = "'test_confirmation_token_react_content_non_production';\n" + File.write(app_react_file_path, react_file_token) + manually_expire_asset("react.js") + react_asset = Rails.application.assets['react.js'] + + get '/assets/react.js' + + File.unlink(app_react_file_path) + + assert_response :success + assert_equal react_file_token.length, react_asset.to_s.length, "The asset pipeline serves the drop-in file" + assert_equal react_file_token.length, @response.body.length, "The asset route serves the drop-in file" + end + + test 'precompiling assets works' do + begin + precompile_assets + ensure + clear_precompiled_assets + end + end + + test "the development version with addons is loaded" do + asset = Rails.application.assets.find_asset('react') + assert asset.pathname.to_s.end_with?('development-with-addons/react.js') + end + + test "the production build is optimized for production" do + production_path = File.expand_path("../../lib/assets/react-source/production/react.js", __FILE__) + production_js = File.read(production_path) + env_checks = production_js.scan("NODE_ENV") + assert_equal(0, env_checks.length, "Dead code is removed for production") + end +end diff --git a/test/react_test.rb b/test/react_test.rb index f63ba6797..329224bd5 100644 --- a/test/react_test.rb +++ b/test/react_test.rb @@ -1,46 +1,31 @@ -require 'test_helper' -class ReactTest < ActionDispatch::IntegrationTest - setup do - clear_sprockets_cache - end - - teardown do - clear_sprockets_cache - end - - test 'asset pipeline should deliver drop-in react file replacement' do - app_react_file_path = File.expand_path("../dummy/vendor/assets/javascripts/react.js", __FILE__) - react_file_token = "'test_confirmation_token_react_content_non_production';\n" - File.write(app_react_file_path, react_file_token) - manually_expire_asset("react.js") - react_asset = Rails.application.assets['react.js'] - - get '/assets/react.js' - - File.unlink(app_react_file_path) - - assert_response :success - assert_equal react_file_token.length, react_asset.to_s.length, "The asset pipeline serves the drop-in file" - assert_equal react_file_token.length, @response.body.length, "The asset route serves the drop-in file" - end - - test 'precompiling assets works' do - begin - precompile_assets - ensure - clear_precompiled_assets - end - end - - test "the development version with addons is loaded" do - asset = Rails.application.assets.find_asset('react') - assert asset.pathname.to_s.end_with?('development-with-addons/react.js') - end - - test "the production build is optimized for production" do - production_path = File.expand_path("../../lib/assets/react-source/production/react.js", __FILE__) - production_js = File.read(production_path) - env_checks = production_js.scan("NODE_ENV") - assert_equal(0, env_checks.length, "Dead code is removed for production") +require "test_helper" + +class ReactTest < ActiveSupport::TestCase + def test_it_camelizes_props + raw_props = { + multi_word_sym: { + nested_key: [ + {double_nested: true}, + 1, + "string item", + [ { nested_array: {} }], + ] + }, + "alreadyCamelized" => :ok, + } + + expected_props = { + "multiWordSym" => { + "nestedKey" => [ + { "doubleNested" => true }, + 1, + "string item", + [ { "nestedArray" => {} }], + ] + }, + "alreadyCamelized" => :ok + } + + assert_equal expected_props, React.camelize_props(raw_props) end end