Class: Kanade::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/kanade/engine.rb

Constant Summary collapse

@@converters =
{}
@@name_resolvers =
{}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration = nil) ⇒ Engine

Returns a new instance of Engine.



8
9
10
# File 'lib/kanade/engine.rb', line 8

def initialize(configuration=nil)
  @config = configuration || Kanade::Config.default
end

Class Method Details

.converter(sym) ⇒ Object



145
146
147
# File 'lib/kanade/engine.rb', line 145

def self.converter(sym)
  @@converters[sym]
end

.register_converter!(klass) ⇒ Object

Raises:



113
114
115
116
117
118
119
120
121
122
# File 'lib/kanade/engine.rb', line 113

def self.register_converter!(klass)
  key = klass.name.split('::').last.underscore.to_sym

  return if key === :base

  # We don't support multiple converter for now
  raise NotSupportedError.new("#{key} registered twice") if not @@converters[key].nil?

  @@converters[key] = klass.new
end

.register_name_resolver!(klass) ⇒ Object

Raises:



124
125
126
127
128
129
130
131
132
133
# File 'lib/kanade/engine.rb', line 124

def self.register_name_resolver!(klass)
  key = klass.name.split('::').last.underscore.to_sym

  return if key === :base

  # We don't support multiple converter for now
  raise NotSupportedError.new("#{key} registered twice") if not @@name_resolvers[key].nil?

  @@name_resolvers[key] = klass.new
end

Instance Method Details

#configure {|@config| ... } ⇒ Object

Yields:

  • (@config)


12
13
14
# File 'lib/kanade/engine.rb', line 12

def configure
  yield @config
end

#deserialize(definition, json) ⇒ Object

Raises:



59
60
61
62
63
64
65
# File 'lib/kanade/engine.rb', line 59

def deserialize(definition, json)
  raise NotSupportedError.new("Can not process non-class!") unless definition.is_a?(Class)
  raise NotSupportedError.new("Can not process other than DTO!") unless definition < Dto

  hash = JSON.parse(json)
  deserialize_object(definition, hash)
end

#deserialize_list(value, field_info) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/kanade/engine.rb', line 91

def deserialize_list(value, field_info)
  return nil if value.nil?

  # Catatan pribadi: Jadi "of" itu harusnya mengandung field definition?
  # bukan of: Product, tapi of: {as: :dto, of: Product}
  # dengan field definition ini, kita bisa membuat hal yang lebih konfleks, misal:
  # of: {as: :symbol, mapping: {success: 'RES_SUCCESS'}}
  value.map do |v|
    if field_info.options[:of].is_a?(Class) and field_info.options[:of] < Dto
      deserialize_object(field_info.options[:of], v)
    else
      conversion_method = field_info.options[:of]
      # TODO how to refer to static field?
      converter = Engine.converter(conversion_method)

      raise NotSupportedError.new("Can not process unknown converter! #{conversion_method}") if converter.nil?

      converter.deserialize(v, field_info)
    end
  end
end

#deserialize_object(definition, hash) ⇒ Object

IF engine contains deserialization logic, we can no more unit test the converters. Seems like, the conversion logic must be outsourced to its respective converter



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/kanade/engine.rb', line 70

def deserialize_object(definition, hash)
  return nil if hash.nil?
  result = definition.new
  result.__fields.each do |field|
    name = field.key_json || name_to_json(field.sym)

    if field.options[:as] == :list
      value = deserialize_list(hash[name], field)
    elsif field.options[:as] == :dto
      value = deserialize_object(field.options[:of], hash[name])
    else
      value = hash[name]
    end

    next if value.nil?

    result.send("#{field.key_ruby}=", value)
  end
  result
end

#name_to_json(sym) ⇒ Object



140
141
142
143
# File 'lib/kanade/engine.rb', line 140

def name_to_json(sym)
  strategy = @config.contract
  @@name_resolvers[strategy].serialize(sym)
end

#name_to_ruby(string) ⇒ Object



135
136
137
138
# File 'lib/kanade/engine.rb', line 135

def name_to_ruby(string)
  strategy = @config.contract
  @@name_resolvers[strategy].deserialize(string)
end

#serialize(object) ⇒ Object



16
17
18
# File 'lib/kanade/engine.rb', line 16

def serialize(object)
  traverse_field(object).to_json
end

#serialize_list(list, field_info) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/kanade/engine.rb', line 42

def serialize_list(list, field_info)
  return nil if list.nil?
  list.map do |entry|
    if field_info.options[:of].is_a?(Class) and field_info.options[:of] < Dto
      traverse_field(entry)
    else
      conversion_method = field_info.options[:of]
      # TODO how to refer to static field?
      converter = Engine.converter(conversion_method)

      raise NotSupportedError.new("Can not process unknown converter! #{conversion_method}") if converter.nil?

      converter.serialize(entry, field_info)
    end
  end
end

#traverse_field(object) ⇒ Object

Raises:



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/kanade/engine.rb', line 20

def traverse_field(object)
  return nil if object.nil?
  raise NotSupportedError.new("Serializer only works for Kanade::Dto, and #{object.class.name} does not extend Kanade::Dto") unless object.class < Kanade::Dto

  result = {}

  object.__fields.each do |field|
    name = field.key_json || name_to_json(field.sym)

    if field.options[:as] == :list
      value = serialize_list(object.send(field.sym), field)
    elsif field.options[:as] == :dto
      value = traverse_field(object.send(field.sym))
    else
      value = field.converter.serialize(object.send(field.sym), field)
    end
    result[name] = value
  end

  result
end