Class: ARMS::MultiCoder
- Inherits:
-
Object
- Object
- ARMS::MultiCoder
- Defined in:
- lib/arms/multi_coder.rb
Instance Method Summary collapse
-
#dump(object) ⇒ Object
Dumped (serialized) data.
-
#initialize(coders, model: nil, attr_name: nil) ⇒ MultiCoder
constructor
loads and dumps between database column and model attribute, using any number of coders.
-
#load(column_data) ⇒ Object
Loaded (deserialized) data.
Constructor Details
#initialize(coders, model: nil, attr_name: nil) ⇒ MultiCoder
loads and dumps between database column and model attribute, using any number of coders.
the first coder is closest to the loaded model attribute. the last coder is closest to the dumped database column.
each coder must respond to #load and #dump. such a coder can be passed directly, or as a shortcut consisting of a key registered with ARMS.register_coder_shortcut and optional arguments (using an array). each of the following is a valid coder (an element of the coders array):
# direct reference to the coder
::ActiveRecord::Coders::YAMLColumn.new('foo')
# shortcut, equivalent to the above
:yaml
# shortcut passing optional `object_class` argument to yaml coder.
# the first element of this array is the shortcut key, and the remainder
# is arguments passed to instantiate the coder.
[:yaml, Array]
here are a few example invocations that instantiate a MultiCoder:
# two coders: indifferent hashes, YAML with argument Hash (the object_class)
MultiCoder.new([:indifferent_hashes, [YAML, Hash]], attr_name: 'preferences', model: Foo)
# two coders: struct coder with argument Preference (the struct class), JSON coder
MultiCoder.new([[:struct, Preference], :json], attr_name: 'preferences', model: Foo)
load goes like:
database column -> coderN.load -> ... -> coder1.load -> model attribute
dump goes like:
model attribute -> coder1.dump -> ... -> coderN.dump -> database column
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/arms/multi_coder.rb', line 43 def initialize(coders, model: nil, attr_name: nil) @coders = coders.each_with_index.map do |coder, i| shortcut_invocation = ShortcutInvocation.new shortcut_invocation.model = model shortcut_invocation.attr_name = attr_name if coder.respond_to?(:to_ary) shortcut_invocation.args = coder[1..-1] coder = coder[0] end if ARMS.instance_exec { @coder_shortcuts }.key?(coder) ARMS.instance_exec { @coder_shortcuts }[coder].(shortcut_invocation) elsif coder.respond_to?(:load) && coder.respond_to?(:dump) if shortcut_invocation.args.nil? || shortcut_invocation.args.empty? coder else raise(InvalidCoder.new("given shortcut arguments are not passed to the coder at index #{i} which responds to #load and #dump. coder: #{coder.inspect}; shortcut args: #{shortcut_invocation.args.inspect}").tap { |e| e.coder = coder }) end else raise(InvalidCoder.new("given coder at index #{i} is not a recognized shortcut and does not respond to #load and #dump. coder: #{coder.inspect}; shortcut args: #{shortcut_invocation.args.inspect}").tap { |e| e.coder = coder }) end end end |
Instance Method Details
#dump(object) ⇒ Object
Returns dumped (serialized) data.
78 79 80 81 82 |
# File 'lib/arms/multi_coder.rb', line 78 def dump(object) @coders.inject(object) do |data, coder| coder.dump(data) end end |
#load(column_data) ⇒ Object
Returns loaded (deserialized) data.
70 71 72 73 74 |
# File 'lib/arms/multi_coder.rb', line 70 def load(column_data) @coders.reverse.inject(column_data) do |data, coder| coder.load(data) end end |