From ba3ae62a775182c663c6797e21618bb37de3aaba Mon Sep 17 00:00:00 2001
From: Cristian Bica <cristian.bica@gmail.com>
Date: Sat, 31 May 2014 17:31:20 +0300
Subject: Deep serialization

---
 lib/active_job/arguments.rb   | 32 ++++++++++++++++++++++++++++----
 test/cases/parameters_test.rb | 27 ++++++++++++++++++++++++++-
 2 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/lib/active_job/arguments.rb b/lib/active_job/arguments.rb
index d1cc6d3177..6fe52397da 100644
--- a/lib/active_job/arguments.rb
+++ b/lib/active_job/arguments.rb
@@ -3,14 +3,19 @@ require 'active_support/core_ext/object/try'
 
 module ActiveJob
   class Arguments
-    TYPE_WHITELIST = [ NilClass, Fixnum, Float, String, TrueClass, FalseClass, Hash, Array, Bignum ]
+    TYPE_WHITELIST = [ NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
 
     def self.serialize(arguments)
       arguments.collect do |argument|
-        if argument.respond_to?(:global_id)
+        case argument
+        when ActiveModel::GlobalIdentification
           argument.global_id
-        elsif TYPE_WHITELIST.include?(argument.class)
+        when *TYPE_WHITELIST
           argument
+        when Hash
+          Hash[ argument.map{ |key, value| [ serialize_hash_key(key), serialize([value]).first ] } ]
+        when Array
+          serialize(argument)
         else
           raise "Unsupported argument type: #{argument.class.name}"
         end
@@ -18,7 +23,26 @@ module ActiveJob
     end
 
     def self.deserialize(arguments)
-      arguments.collect { |argument| ActiveModel::GlobalLocator.locate(argument) || argument }
+      arguments.collect do |argument|
+        case argument
+        when Array
+          deserialize(argument)
+        when Hash
+          argument.with_indifferent_access
+        else
+          ActiveModel::GlobalLocator.locate(argument) || argument
+        end
+      end
     end
+
+    private
+      def self.serialize_hash_key(key)
+        case key
+        when String, Symbol
+          key.to_s
+        else
+          raise "Unsupported hash key type: #{key.class.name}"
+        end
+      end
   end
 end
diff --git a/test/cases/parameters_test.rb b/test/cases/parameters_test.rb
index 625c59c404..93b34278a5 100644
--- a/test/cases/parameters_test.rb
+++ b/test/cases/parameters_test.rb
@@ -1,6 +1,7 @@
 require 'helper'
 require 'active_job/arguments'
 require 'models/person'
+require 'active_support/core_ext/hash/indifferent_access'
 
 class ParameterSerializationTest < ActiveSupport::TestCase
   test 'should make no change to regular values' do
@@ -14,7 +15,7 @@ class ParameterSerializationTest < ActiveSupport::TestCase
     assert_equal [ 'a' ], ActiveJob::Arguments.serialize([ 'a' ])
     assert_equal [ true ], ActiveJob::Arguments.serialize([ true ])
     assert_equal [ false ], ActiveJob::Arguments.serialize([ false ])
-    assert_equal [ { a: 1 } ], ActiveJob::Arguments.serialize([ { a: 1 } ])
+    assert_equal [ { "a" => 1, "b" => 2 } ], ActiveJob::Arguments.serialize([ { a: 1, "b" => 2 } ])
     assert_equal [ [ 1 ] ], ActiveJob::Arguments.serialize([ [ 1 ] ])
     assert_equal [ 1_000_000_000_000_000_000_000 ], ActiveJob::Arguments.serialize([ 1_000_000_000_000_000_000_000 ])
 
@@ -24,6 +25,25 @@ class ParameterSerializationTest < ActiveSupport::TestCase
     assert_equal "Unsupported argument type: #{self.class.name}", err.message
   end
 
+  test 'should dive deep into arrays or hashes' do
+    assert_equal [ { "a" => Person.find(5).gid }.with_indifferent_access ], ActiveJob::Arguments.serialize([ { a: Person.find(5) } ])
+    assert_equal [ [ Person.find(5).gid ] ], ActiveJob::Arguments.serialize([ [ Person.find(5) ] ])
+  end
+
+  test 'should dive deep into arrays or hashes and raise exception on complex objects' do
+    err = assert_raises RuntimeError do
+      ActiveJob::Arguments.serialize([ 1, [self] ])
+    end
+    assert_equal "Unsupported argument type: #{self.class.name}", err.message
+  end
+
+  test 'shoud dive deep into hashes and allow raise exception on not string/symbol keys' do
+    err = assert_raises RuntimeError do
+      ActiveJob::Arguments.serialize([ [ { 1 => 2 } ] ])
+    end
+    assert_equal "Unsupported hash key type: Fixnum", err.message
+  end
+
   test 'should serialize records with global id' do
     assert_equal [ Person.find(5).gid ], ActiveJob::Arguments.serialize([ Person.find(5) ])
   end
@@ -45,4 +65,9 @@ class ParameterDeserializationTest < ActiveSupport::TestCase
   test 'should serialize values and records together' do
     assert_equal [ 3, Person.find(5) ], ActiveJob::Arguments.deserialize([ 3, Person.find(5).gid ])
   end
+
+  test 'should dive deep when desierializing' do
+    assert_equal [ [ 3, Person.find(5) ] ], ActiveJob::Arguments.deserialize([ [ 3, Person.find(5).gid ] ])
+  end
+
 end
-- 
cgit v1.2.3


From a4a7f0279af91307a8b36a8c437c4734721741d6 Mon Sep 17 00:00:00 2001
From: Cristian Bica <cristian.bica@gmail.com>
Date: Tue, 3 Jun 2014 00:54:07 +0300
Subject: Fixed Hash deserialisation

---
 lib/active_job/arguments.rb   | 2 +-
 test/cases/parameters_test.rb | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/active_job/arguments.rb b/lib/active_job/arguments.rb
index 6fe52397da..553ab20f65 100644
--- a/lib/active_job/arguments.rb
+++ b/lib/active_job/arguments.rb
@@ -28,7 +28,7 @@ module ActiveJob
         when Array
           deserialize(argument)
         when Hash
-          argument.with_indifferent_access
+          Hash[argument.map{ |key, value| [ key, deserialize([value]).first ] }].with_indifferent_access
         else
           ActiveModel::GlobalLocator.locate(argument) || argument
         end
diff --git a/test/cases/parameters_test.rb b/test/cases/parameters_test.rb
index 93b34278a5..737f3c26b7 100644
--- a/test/cases/parameters_test.rb
+++ b/test/cases/parameters_test.rb
@@ -66,8 +66,12 @@ class ParameterDeserializationTest < ActiveSupport::TestCase
     assert_equal [ 3, Person.find(5) ], ActiveJob::Arguments.deserialize([ 3, Person.find(5).gid ])
   end
 
-  test 'should dive deep when desierializing' do
+  test 'should dive deep when deserialising arrays' do
     assert_equal [ [ 3, Person.find(5) ] ], ActiveJob::Arguments.deserialize([ [ 3, Person.find(5).gid ] ])
   end
 
+  test 'should dive deep when deserialising hashes' do
+    assert_equal [ { "5" => Person.find(5) } ], ActiveJob::Arguments.deserialize([ { "5" => Person.find(5).gid } ])
+  end
+
 end
-- 
cgit v1.2.3