From 6f42a7d7567a63e54aeebe2f0b0b090273ce81b4 Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Tue, 30 Jun 2015 15:30:10 -0700 Subject: [PATCH] first pass on #153 allowing configurable serializer --- lib/js_routes.rb | 4 +- lib/routes.js | 21 ++++++---- lib/routes.js.coffee | 17 ++++---- spec/js_routes/generated_javascript_spec.rb | 4 ++ spec/js_routes/options_spec.rb | 27 ++++++++++--- .../rails_routes_compatibility_spec.rb | 39 ------------------- 6 files changed, 51 insertions(+), 61 deletions(-) diff --git a/lib/js_routes.rb b/lib/js_routes.rb index 9bbcd5bc..c044580d 100644 --- a/lib/js_routes.rb +++ b/lib/js_routes.rb @@ -19,7 +19,8 @@ class JsRoutes url_links: nil, camel_case: false, default_url_options: {}, - compact: false + compact: false, + serializer: nil } NODE_TYPES = { @@ -104,6 +105,7 @@ def generate js.gsub!("DEFAULT_URL_OPTIONS", json(@options[:default_url_options].merge(deprecated_default_format))) js.gsub!("PREFIX", @options[:prefix] || "") js.gsub!("NODE_TYPES", json(NODE_TYPES)) + js.gsub!("SERIALIZER", @options[:serializer] || "null") js.gsub!("ROUTES", js_routes) end diff --git a/lib/routes.js b/lib/routes.js index 1c2535a4..03b9d4cc 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -23,8 +23,8 @@ Based on Rails routes of APP_CLASS NodeTypes = NODE_TYPES; Utils = { - serialize: function(object, prefix) { - var element, i, j, key, len, prop, result, s; + default_serializer: function(object, prefix) { + var element, i, j, key, len, prop, s; if (prefix == null) { prefix = null; } @@ -34,16 +34,12 @@ Based on Rails routes of APP_CLASS if (!prefix && !(this.get_object_type(object) === "object")) { throw new Error("Url parameters should be a javascript hash"); } - if (root.jQuery) { - result = root.jQuery.param(object); - return (!result ? "" : result); - } s = []; switch (this.get_object_type(object)) { case "array": for (i = j = 0, len = object.length; j < len; i = ++j) { element = object[i]; - s.push(this.serialize(element, prefix + "[]")); + s.push(this.default_serializer(element, prefix + "[]")); } break; case "object": @@ -56,7 +52,7 @@ Based on Rails routes of APP_CLASS if (prefix != null) { key = prefix + "[" + key + "]"; } - s.push(this.serialize(prop, key)); + s.push(this.default_serializer(prop, key)); } break; default: @@ -69,6 +65,15 @@ Based on Rails routes of APP_CLASS } return s.join("&"); }, + serialize: function(object) { + var custom_serializer; + custom_serializer = SERIALIZER; + if (custom_serializer) { + return custom_serializer(object); + } else { + return this.default_serializer(object); + } + }, clean_path: function(path) { var last_index; path = path.split("://"); diff --git a/lib/routes.js.coffee b/lib/routes.js.coffee index 77ca8b3b..55eb16db 100644 --- a/lib/routes.js.coffee +++ b/lib/routes.js.coffee @@ -15,24 +15,20 @@ NodeTypes = NODE_TYPES Utils = - serialize: (object, prefix = null) -> + default_serializer: (object, prefix = null) -> return "" unless object if !prefix and !(@get_object_type(object) is "object") throw new Error("Url parameters should be a javascript hash") - if root.jQuery - result = root.jQuery.param(object) - return (if not result then "" else result) - s = [] switch @get_object_type(object) when "array" for element, i in object - s.push @serialize(element, prefix + "[]") + s.push @default_serializer(element, prefix + "[]") when "object" for own key, prop of object when prop? key = "#{prefix}[#{key}]" if prefix? - s.push @serialize(prop, key) + s.push @default_serializer(prop, key) else if object s.push "#{encodeURIComponent(prefix.toString())}=#{encodeURIComponent(object.toString())}" @@ -40,6 +36,13 @@ Utils = return "" unless s.length s.join("&") + serialize: (object) -> + custom_serializer = SERIALIZER + if custom_serializer + custom_serializer(object) + else + @default_serializer(object) + clean_path: (path) -> path = path.split("://") last_index = path.length - 1 diff --git a/spec/js_routes/generated_javascript_spec.rb b/spec/js_routes/generated_javascript_spec.rb index 662efcaa..7d9cf247 100644 --- a/spec/js_routes/generated_javascript_spec.rb +++ b/spec/js_routes/generated_javascript_spec.rb @@ -10,6 +10,10 @@ describe "generated js" do subject { JsRoutes.generate } + it "should set the default serializer when none is configured" do + is_expected.to match(%r(serialize: function\(object\) {\s+var custom_serializer;\s+custom_serializer = null;\s+if \(custom_serializer\) {\s+return custom_serializer\(object\);\s+} else {\s+return this.default_serializer\(object\);\s+}\s+},)) + end + it "should include a comment in the header" do app_class = "App" diff --git a/spec/js_routes/options_spec.rb b/spec/js_routes/options_spec.rb index 78f99149..b785924f 100644 --- a/spec/js_routes/options_spec.rb +++ b/spec/js_routes/options_spec.rb @@ -13,6 +13,21 @@ let(:_options) { {} } let(:_warnings) { true } + context "when serializer is specified" do + let(:_options) { {:serializer => "myCustomSerializer"} } + + it "should set configurable serializer" do + # define custom serializer + # this is a nonsense serializer, which always returns foo=bar + # for all inputs + evaljs(%q(function myCustomSerializer(object, prefix) { return "foo=bar"; })) + + # expect the nonsense serializer above to have appened foo=bar + # to the end of the path + expect(evaljs(%q(Routes.inboxes_path()))).to eql("/inboxes?foo=bar") + end + end + context "when exclude is specified" do let(:_options) { {:exclude => /^admin_/} } @@ -292,11 +307,11 @@ context "when only host option is specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } - + it "uses the specified host, defaults protocol to http, defaults port to 80 (leaving it blank)" do expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") end - + it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") end @@ -316,7 +331,7 @@ it "uses the specified protocol and host, defaults port to 80 (leaving it blank)" do expect(evaljs("Routes.inbox_url(1)")).to eq("ftp://example.com#{routes.inbox_path(1)}") end - + it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") end @@ -340,11 +355,11 @@ it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com:3000#{routes.new_session_path}") end - + it "does not override host, protocol, or port when host is specified in route" do expect(evaljs("Routes.sso_url()")).to eq(routes.sso_url) end - + it "does not override port when specified in route" do expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") end @@ -397,7 +412,7 @@ example.run end end - + let(:_options) { { :compact => true, :url_links => "http://localhost" } } it "should not strip urls" do expect(evaljs("Routes.inbox(1)")).to eq(routes.inbox_path(1)) diff --git a/spec/js_routes/rails_routes_compatibility_spec.rb b/spec/js_routes/rails_routes_compatibility_spec.rb index f64dffc3..0cb4518f 100644 --- a/spec/js_routes/rails_routes_compatibility_spec.rb +++ b/spec/js_routes/rails_routes_compatibility_spec.rb @@ -147,45 +147,6 @@ end end - context "when jQuery is present" do - before do - evaljs("window.jQuery = {};") - jscontext[:parameterizeFunc] = lambda {|object| _value.to_param} - evaljs("window.jQuery.param = parameterizeFunc") - end - - shared_examples_for "serialization" do - it "should support serialization of objects" do - expect(evaljs("window.jQuery.param(#{_value.to_json})")).to eq(_value.to_param) - expect(evaljs("Routes.inboxes_path(#{_value.to_json})")).to eq(routes.inboxes_path(_value)) - expect(evaljs("Routes.inbox_path(1, #{_value.to_json})")).to eq(routes.inbox_path(1, _value)) - end - end - context "when parameters is a hash" do - let(:_value) do - {:a => {:b => 'c'}, :q => [1,2]} - end - it_should_behave_like 'serialization' - end - context "when parameters is null" do - let(:_value) do - {:hello => {world: nil}} - end - it_should_behave_like 'serialization' - end - context "when parameters is null" do - let(:_value) do - nil - end - - before do - pending("This test is invalid for nil/null and jruby #{JRUBY_VERSION}") if defined?(JRUBY_VERSION) && '1.7.13' == JRUBY_VERSION - end - - it_should_behave_like 'serialization' - end - end - context "using optional path fragments" do context "including not optional parts" do it "should include everything that is not optional" do