Module: Dynamini::TypeHandler

Included in:
Base
Defined in:
lib/dynamini/type_handler.rb

Constant Summary collapse

GETTER_PROCS =
{
  integer:  proc { |v| v.to_i if v },
  date:     proc do |v|
    if v.is_a?(Date)
      v
    elsif v
      Time.methods.include?(:zone) ? Time.zone.at(v).to_date : Time.at(v).to_date
    end
  end,
  time:     proc do |v|
    if v
      Time.methods.include?(:zone) ? Time.zone.at(v.to_f) : Time.at(v.to_f)
    end
  end,
  float:    proc { |v| v.to_f if v },
  symbol:   proc { |v| v.to_sym if v },
  string:   proc { |v| v.to_s if v },
  boolean:  proc { |v| v },
  array:    proc { |v| (v.is_a?(Enumerable) ? v.to_a : [v]) if v },
  set:      proc { |v| (v.is_a?(Enumerable) ? Set.new(v) : Set.new([v])) if v }
}.freeze
SETTER_PROCS =
{
  integer:  proc { |v| v.to_i if v },
  time:     proc { |v| (v.is_a?(Date) ? v.to_time : v).to_f if v },
  float:    proc { |v| v.to_f if v },
  symbol:   proc { |v| v.to_s if v },
  string:   proc { |v| v.to_s if v },
  boolean:  proc { |v| v },
  date:     proc { |v| v.to_time.to_f if v },
  array:    proc { |v| (v.is_a?(Enumerable) ? v.to_a : [v]) if v },
  set:      proc { |v| (v.is_a?(Enumerable) ? Set.new(v) : Set.new([v])) if v }
}.freeze

Instance Method Summary collapse

Instance Method Details

#attribute_callback(procs, handle, value, validate) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/dynamini/type_handler.rb', line 95

def attribute_callback(procs, handle, value, validate)
  value = handle[:options][:default] if value.nil?
  callback = procs[handle[:format]]
  if should_convert_elements?(handle, value)
    result = convert_elements(value, procs[handle[:options][:of]])
    callback.call(result)
  elsif validate && invalid_enumerable_value?(handle, value)
    raise ArgumentError, "Can't write a non-enumerable value to field handled as #{handle[:format]}"
  else
    callback.call(value)
  end
end

#convert_elements(enumerable, callback) ⇒ Object



116
117
118
# File 'lib/dynamini/type_handler.rb', line 116

def convert_elements(enumerable, callback)
  enumerable.map { |e| callback.call(e) }
end

#define_handled_getter(column, format_class, _options = {}) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/dynamini/type_handler.rb', line 52

def define_handled_getter(column, format_class, _options = {})
  proc = GETTER_PROCS[format_class]
  fail 'Unsupported data type: ' + format_class.to_s if proc.nil?

  define_method(column) do
    read_attribute(column)
  end
end

#define_handled_setter(column, format_class) ⇒ Object



61
62
63
64
65
66
67
68
# File 'lib/dynamini/type_handler.rb', line 61

def define_handled_setter(column, format_class)
  method_name = (column.to_s + '=')
  proc = SETTER_PROCS[format_class]
  fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
  define_method(method_name) do |value|
    write_attribute(column, value)
  end
end

#format_default(format_class) ⇒ Object



70
71
72
73
74
75
76
77
# File 'lib/dynamini/type_handler.rb', line 70

def format_default(format_class)
  case format_class
    when :array
      []
    when :set
      Set.new
  end
end

#handle(column, format_class, options = {}) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/dynamini/type_handler.rb', line 40

def handle(column, format_class, options = {})
  validate_handle(format_class, options)

  options[:default] ||= format_default(format_class)
  options[:default] ||= Set.new if format_class == :set

  self.handles = self.handles.merge(column => { format: format_class, options: options })

  define_handled_getter(column, format_class, options)
  define_handled_setter(column, format_class)
end

#handled_as?(handle, type) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/dynamini/type_handler.rb', line 120

def handled_as?(handle, type)
  type.include? handle[:format]
end

#handled_key(column, value) ⇒ Object



87
88
89
90
91
92
93
# File 'lib/dynamini/type_handler.rb', line 87

def handled_key(column, value)
  if handles[column]
    attribute_callback(GETTER_PROCS, handles[column], value, false)
  else
    value
  end
end

#invalid_enumerable_value?(handle, value) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/dynamini/type_handler.rb', line 112

def invalid_enumerable_value?(handle, value)
  handled_as?(handle, [:array, :set]) && !value.is_a?(Enumerable)
end

#should_convert_elements?(handle, value) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/dynamini/type_handler.rb', line 108

def should_convert_elements?(handle, value)
  handle[:options][:of] && (value.is_a?(Array) || value.is_a?(Set))
end

#validate_handle(format, options) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/dynamini/type_handler.rb', line 79

def validate_handle(format, options)
  if format == :set
    if options[:of] && [:set, :array].include?(options[:of])
      raise ArgumentError, 'Invalid handle: cannot store non-primitive datatypes within a set.'
    end
  end
end