module Traitorous # Convert provides a selection of helpers that will build converters for # common situations. module Convert class << self # .skip provides the simplest converter. It does nothing to the value # except pass it through unchanged on both import and export # @return [Traitorous::Converter] def skip Converter.new( StandardProcs.noop, StandardProcs.noop ) end # .default(default_value = nil) creates a StandardProc.default importer # and a StandardProcs.noop exporter # TODO add :export_with for consistency # @param default_value [Object] value to set in cases that data is falsey # @return [Traitorous::Converter] def default(default_value = nil) Converter.new( StandardProcs.default(default_value), StandardProcs.noop ) end # .call_on creates a StandardProc.call_on proc for the importer, and a # StandardProc.call_on_self proc for the exporter. # @param method_name [Symbol, String] method to send data # @param with: [Symbol, String] method to send klass with data as params # @param export_with: [Symbol, String] method to send klass with data as params # @return [Traitorous::Converter] def call_on(klass, with: :new, export_with: :export) Converter.new( StandardProcs.call_on(klass, with_method: with), StandardProcs.call_on_self(export_with) ) end # .call_on_self creates a StandardProc.call_on_self proc for the importer # with the with_method param, and a StandardProc.call_on_self with the # export_with param # @param with_method [Symbol, String] method to send data on import # @param export_with [Symbol, String] method to send data on export # @return [Traitorous::Converter] def call_on_self(with_method, export_with: :export) Converter.new( StandardProcs.call_on_self(with_method), StandardProcs.call_on_self(export_with) ) end # Creates an importer that runs the converter importer or exporter for # each element of an array, return the resulting array # @param converter [Traitorous::Converter] the converter to use for both # import and export. # @return [Traitorous::Converter] def array(converter) Converter.new( proc { |data| Array(data).map { |entry| converter.importer.call(entry) } }, proc { |data| Array(data).map { |entry| converter.exporter.call(entry) } } ) end # TODO better to extract the inject proc into it's own StandardProc? # @param value_converter [Traitorous::Converter] the converter to use for both # import and export. # @return [Traitorous::Converter] def hash(value_converter) Converter.new( proc { |data| data.inject({}) { |h, (k, v)| h[k] = value_converter.importer.call(v); h } }, proc { |data| data.inject({}) { |h, (k, v)| h[k] = value_converter.exporter.call(v); h } }, ) end # TODO better expecting key, value pairs as the output of the converter? # Expects an incoming array, uses the param value_converter for each # element, then uses the key_converter on the resulting value and stores # the key, value pair in the resulting hash. # @note. The value_converter is used before the key_converter, and the # key_converter receives the output of the value_converter as it's data # param. # @param key_converter [Traitorous::Converter] the converter to use for to # generate the hash key for a given value. # @param value_converter [Traitorous::Converter] the converter to use for # converting the value. # @return [Traitorous::Converter] def array_to_hash(key_converter, value_converter) Converter.new( proc do |data_arr| data_arr.inject({}) do |h, d| v = value_converter.importer.call(d) k = key_converter.importer.call(v) h[k] = v h end end, proc { |data_hsh| data_hsh.values.map { |value| value_converter.exporter.call(value) } } ) end end end end