Class: Serializer::Serializable

Inherits:
Object
  • Object
show all
Includes:
HappyMapper
Defined in:
lib/serializer/serializable.rb

Overview

Note:

Copyright © 2012 by The Board of Trustees of the Leland Stanford Junior University. All rights reserved. See LICENSE for details.

Some utility methods to faciliate serialization of data fields to Hash, JSON, or YAML shared by all subclasses. This class assumes that HappyMapper is used for declaration of fields to be serialized.

Data Model

  • Serializable = utility methods to faciliate serialization to Hash, JSON, or YAML

    • Manifest = adds methods for marshalling/unmarshalling data to a persistent XML file format

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Serializable

A flexible initializer based on the DataMapper “create factory” design pattern.



22
23
24
25
26
27
28
29
# File 'lib/serializer/serializable.rb', line 22

def initialize(opts = {})
  opts.each do |key, value|
    errmsg = "#{key} is not a variable name in #{self.class.name}"
    raise(Moab::MoabRuntimeError, errmsg) unless variable_names.include?(key.to_s) || key == :test

    instance_variable_set("@#{key}", value)
  end
end

Class Method Details

.deep_diff(*hashes) ⇒ Hash

Returns Generate a hash containing the differences between two hashes (recursively descend parallel trees of hashes).



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/serializer/serializable.rb', line 142

def self.deep_diff(*hashes)
  diff = {}
  case hashes.length
  when 4
    ltag, left, rtag, right = hashes
  when 2
    ltag = :left
    left = hashes[0]
    rtag = :right
    right = hashes[1]
  else
    raise ArgumentError, "wrong number of arguments (#{hashes.length} for 2 or 4)"
  end
  (left.keys | right.keys).each do |k|
    if left[k] != right[k]
      diff[k] = if left[k].is_a?(Hash) && right[k].is_a?(Hash)
                  deep_diff(ltag, left[k], rtag, right[k])
                else
                  Hash.[](ltag, left[k], rtag, right[k])
                end
    end
  end
  diff
end

Instance Method Details

#array_to_hash(array, summary = false) ⇒ Hash

Returns Generate a hash from an array of objects. If the array member has a field tagged as a key, that field will be used as the hash.key. Otherwise the index position of the array member will be used as the key.



83
84
85
86
87
88
89
90
91
# File 'lib/serializer/serializable.rb', line 83

def array_to_hash(array, summary = false)
  item_hash = {}
  array.each_index do |index|
    item = array[index]
    ikey = item.respond_to?(:key) && item.key ? item.key : index
    item_hash[ikey] = item.respond_to?(:to_hash) ? item.to_hash(summary) : item
  end
  item_hash
end

#diff(other) ⇒ Hash

Returns Generate a hash containing the differences between two objects of the same type.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/serializer/serializable.rb', line 122

def diff(other)
  raise(Moab::MoabRuntimeError, "Cannot compare different classes") if self.class != other.class

  left = other.to_hash
  right = to_hash
  if key.nil? || other.key.nil?
    ltag = :old
    rtag = :new
  else
    ltag = other.key
    rtag = key
  end
  Serializable.deep_diff(ltag, left, rtag, right)
end

#keyString

Returns For the current object instance, return the string to use as a hash key.



72
73
74
75
76
# File 'lib/serializer/serializable.rb', line 72

def key
  return send(key_name) if key_name

  nil
end

#key_nameString

Returns Determine which attribute was marked as an object instance key. Keys are indicated by option :key=true when declaring the object’s variables. This follows the same convention as used by DataMapper.



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/serializer/serializable.rb', line 57

def key_name
  unless defined?(@key_name)
    @key_name = nil
    self.class.attributes.each do |attribute|
      if attribute.options[:key]
        @key_name = attribute.name
        break
      end
    end
  end
  @key_name
end

#summaryHash



115
116
117
# File 'lib/serializer/serializable.rb', line 115

def summary
  to_hash(true)
end

#to_hash(summary = false) ⇒ Hash

Returns Recursively generate an Hash containing the object’s properties.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/serializer/serializable.rb', line 96

def to_hash(summary = false)
  oh = {}
  vars = summary ? variables.select { |v| summary_fields.include?(v.name) } : variables
  vars.each do |variable|
    key = variable.name.to_s
    value = send(variable.name)
    oh[key] = case value
              when Array
                array_to_hash(value, summary)
              when Serializable
                value.to_hash
              else
                value
              end
  end
  oh
end

#to_json(summary = false) ⇒ String

Returns Generate JSON output from a hash of the object’s variables.



169
170
171
172
# File 'lib/serializer/serializable.rb', line 169

def to_json(summary = false)
  hash = to_hash(summary)
  JSON.pretty_generate(hash)
end

#to_yaml(summary = false) ⇒ String

Returns Generate YAML output from a hash of the object’s variables.



176
177
178
# File 'lib/serializer/serializable.rb', line 176

def to_yaml(summary = false)
  to_hash(summary).to_yaml
end

#variable_namesArray

Returns Extract the names of the variables.



48
49
50
# File 'lib/serializer/serializable.rb', line 48

def variable_names
  variables.collect(&:name)
end

#variablesArray

Returns A list of HappyMapper xml attribute, element and text nodes declared for the class.



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/serializer/serializable.rb', line 33

def variables
  attributes = self.class.attributes
  elements   = self.class.elements
  attributes + elements
  # text_node enhancement added by unhappymapper, which is not being used
  # It enables elements having both attributes and a text value
  #text_node = []
  #if self.class.instance_variable_defined?("@text_node")
  #  text_node << self.class.instance_variable_get("@text_node")
  #end
  #attributes + elements + text_node
end