Skip to content

Instantly share code, notes, and snippets.

@sikachu
Created July 22, 2015 17:54
Show Gist options
  • Save sikachu/2ab126c4c9a61d94387d to your computer and use it in GitHub Desktop.
Save sikachu/2ab126c4c9a61d94387d to your computer and use it in GitHub Desktop.
YAML Serializer with Syck Fallback
# Usage
class User
serialize :data, YAMLColumnWithSyckFallback.new
end
# lib/yaml_column_with_syck_fallback.rb
class YAMLColumnWithSyckFallback
def initialize
@serializer = ActiveRecord::Coders::YAMLColumn.new
end
def dump(object)
@serializer.dump(object)
end
def load(yaml)
result = @serializer.load(yaml)
if result.is_a?(String)
result = Syck.load(result)
end
if yaml =~ /!binary/
Hash[
result.map do |attribute_name, values|
[force_encoding(attribute_name.dup), force_encoding(values.dup)]
end
]
else
result
end
end
private
def force_encoding(string_or_array)
if string_or_array.is_a?(Array)
string_or_array.map { |value| force_encoding(value) }
else
if string_or_array.respond_to?(:force_encoding)
string_or_array.force_encoding("UTF-8")
end
end
end
end
# spec/lib/yaml_column_with_syck_fallback_spec.rb
require 'spec_helper'
describe YAMLColumnWithSyckFallback do
let(:serializer) { YAMLColumnWithSyckFallback.new }
describe '#dump' do
it 'converts data to YAML using serializer' do
data = { 'name' => ['John', 'Joe'] }
expected_yaml = ActiveRecord::Coders::YAMLColumn.new.dump(data)
expect(serializer.dump(data)).to eq expected_yaml
end
end
describe '#load' do
context 'when default serializer is able to deserialize the YAML' do
it 'does not use Syck to parse the YAML' do
allow(Syck).to receive(:load).never
yaml = YAML.dump('name' => ['John', 'Joe'])
expect(serializer.load(yaml)).to eq('name' => ['John', 'Joe'])
end
it 'parses change with single value' do
yaml = "--- \nname: John"
expect(serializer.load(yaml)).to eq('name' => 'John')
end
it 'parses data into UTF-8 encoding' do
yaml = <<-YAML.strip_heredoc
---
? !binary "6Kit6KiI5aOr44OR44Oz44OB44Oq44K544OI\n"
:
- "1"
- "0"
description:
- <no description>
- !binary |
VGhlIGNhYmxlIGxhZGRlcnMgYXJlIG5vdCBwYWludGVkLCB0aGVpciBzaGFy
cCBlZGdlcyBhcmUgbm90IGZpbGVkIHRvIGJlIGZsYXQu55S157yG5qGl5p62
5rKh5pyJ5Za35ryG77yM6ZSL5Yip6L6557yY5Lmf5rKh5pyJ5aSE55CG44CC
YAML
result = serializer.load(yaml)
expect(result.keys[0].encoding).to eq(Encoding::UTF_8)
expect(result.keys[1].encoding).to eq(Encoding::UTF_8)
expect(result['description'][0].encoding).to eq(Encoding::UTF_8)
expect(result['description'][1].encoding).to eq(Encoding::UTF_8)
end
end
context 'when default serializer is unable to deserialize the YAML' do
it 'tries to use Syck to parse the YAML' do
allow(Syck).to receive(:load).and_call_original
yaml = "--- \nNational Grid Ref: \n- \"\"\n- ,jkjhkjhlk\n"
expect(serializer.load(yaml)).
to eq('National Grid Ref' => ['', ',jkjhkjhlk'])
expect(Syck).to have_received(:load)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment