def parse(value, name: nil)
      case type
      when :boolean
        [true, 'true', 't', '1'].include?(value)
      when :date, :datetime
        if (digits = value.to_s.scan(/(\d+)/).flatten).present?
          date = if digits.first.length == 4  # 2017-01-10
            Time.zone.local(*digits)
          else # 01/10/2016
            year = digits.find { |d| d.length == 4}
            digits = [year] + (digits - [year])
            Time.zone.local(*digits)
          end

          name.to_s.start_with?('end_') ? date.end_of_day : date
        end
      when :time
        if (digits = value.to_s.scan(/(\d+)/).flatten).present?
          now = Time.zone.now
          Time.zone.local(now.year, now.month, now.day, *digits)
        end
      when :decimal, :currency
        (value.kind_of?(String) ? value.gsub(/[^0-9|\-|\.]/, '') : value).to_f
      when :duration
        if value.to_s.include?('h')
          (hours, minutes) = (value.to_s.gsub(/[^0-9|\-|h]/, '').split('h'))
          (hours.to_i * 60) + ((hours.to_i < 0) ? -(minutes.to_i) : minutes.to_i)
        else
          value.to_s.gsub(/[^0-9|\-|h]/, '').to_i
        end
      when :effective_obfuscation
        klass.respond_to?(:deobfuscate) ? klass.deobfuscate(value) : value.to_s
      when :effective_roles
        EffectiveRoles.roles.include?(value.to_sym) ? value : EffectiveRoles.roles_for(value)
      when :integer
        (value.kind_of?(String) ? value.gsub(/\D/, '') : value).to_i
      when :percent # Integer * 1000. Percentage to 3 digits.
        value.kind_of?(Integer) ? value : (value.to_s.gsub(/[^0-9|\-|\.]/, '').to_f * 1000.0).round
      when :phone
        digits = value.to_s.gsub(/\D/, '').chars
        digits = (digits.first == '1' ? digits[1..10] : digits[0..9]) # Throw away a leading 1

        return nil unless digits.length == 10

        "(#{digits[0..2].join}) #{digits[3..5].join}-#{digits[6..10].join}"
      when :integer
        (value.kind_of?(String) ? value.gsub(/\D/, '') : value).to_i
      when :nil
        value.presence
      when :price # Integer * 100. Number of cents.
        value.kind_of?(Integer) ? value : (value.to_s.gsub(/[^0-9|\-|\.]/, '').to_f * 100.0).round
      when :string, :text, :email
        value.to_s
      when :belongs_to_polymorphic
        value.to_s
      when :belongs_to, :has_many, :has_and_belongs_to_many, :has_one, :resource, :effective_addresses  # Returns an Array of ints, an Int or String
        if value.kind_of?(Integer) || value.kind_of?(Array)
          value
        else
          digits = value.to_s.gsub(/[^0-9|,]/, '') # '87' or '87,254,300' or 'something'

          if digits == value || digits.length == 10
            if klass.respond_to?(:deobfuscate)
              digits.split(',').map { |str| klass.deobfuscate(str).to_i }
            else
              digits.split(',').map { |str| str.to_i }
            end
          else
            value.to_s
          end
        end
      else
        raise "unsupported type #{type}"
      end
    end
def parse(value, name: nil)
      case type
      when :boolean
        [true, 'true', 't', '1'].include?(value)
      when :date, :datetime
        if (digits = value.to_s.scan(/(\d+)/).flatten).present?
          date = if digits.first.length == 4  # 2017-01-10
            Time.zone.local(*digits)
          else # 01/10/2016
            year = digits.find { |d| d.length == 4}
            digits = [year] + (digits - [year])
            Time.zone.local(*digits)
          end

          name.to_s.start_with?('end_') ? date.end_of_day : date
        end
      when :time
        if (digits = value.to_s.scan(/(\d+)/).flatten).present?
          now = Time.zone.now
          Time.zone.local(now.year, now.month, now.day, *digits)
        end
      when :decimal, :currency
        (value.kind_of?(String) ? value.gsub(/[^0-9|\-|\.]/, '') : value).to_f
      when :duration
        if value.to_s.include?('h')
          (hours, minutes) = (value.to_s.gsub(/[^0-9|\-|h]/, '').split('h'))
          (hours.to_i * 60) + ((hours.to_i < 0) ? -(minutes.to_i) : minutes.to_i)
        else
          value.to_s.gsub(/[^0-9|\-|h]/, '').to_i
        end
      when :effective_obfuscation
        klass.respond_to?(:deobfuscate) ? klass.deobfuscate(value) : value.to_s
      when :effective_roles
        EffectiveRoles.roles.include?(value.to_sym) ? value : EffectiveRoles.roles_for(value)
      when :integer
        (value.kind_of?(String) ? value.gsub(/\D/, '') : value).to_i
      when :percent # Integer * 1000. Percentage to 3 digits.
        value.kind_of?(Integer) ? value : (value.to_s.gsub(/[^0-9|\-|\.]/, '').to_f * 1000.0).round
      when :phone
        digits = value.to_s.gsub(/\D/, '').chars
        digits = (digits.first == '1' ? digits[1..10] : digits[0..9]) # Throw away a leading 1

        return nil unless digits.length == 10

        "(#{digits[0..2].join}) #{digits[3..5].join}-#{digits[6..10].join}"
      when :integer
        (value.kind_of?(String) ? value.gsub(/\D/, '') : value).to_i
      when :nil
        value.presence
      when :price # Integer * 100. Number of cents.
        value.kind_of?(Integer) ? value : (value.to_s.gsub(/[^0-9|\-|\.]/, '').to_f * 100.0).round
      when :string, :text, :email
        value.to_s
      when :belongs_to_polymorphic
        value.to_s
      when :belongs_to, :has_many, :has_and_belongs_to_many, :has_one, :resource, :effective_addresses  # Returns an Array of ints, an Int or String
        if value.kind_of?(Integer) || value.kind_of?(Array)
          value
        else
          digits = value.to_s.gsub(/[^0-9|,]/, '') # '87' or '87,254,300' or 'something'

          if digits == value || digits.length == 10
            if klass.respond_to?(:deobfuscate)
              digits.split(',').map { |str| klass.deobfuscate(str).to_i }
            else
              digits.split(',').map { |str| str.to_i }
            end
          else
            value.to_s
          end
        end
      else
        raise "unsupported type #{type}"
      end
    end
This kind of follows the rails GeneratedAttribute method.
 In that case it will be initialized with a name and a type.
 We also use this class to do value parsing in Datatables.
 In that case it will be initialized with just a 'name'