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.

Parameters:

  • opts (Hash<Symbol,Object>) (defaults to: {})

    a hash containing any number of symbol => value pairs. The symbols should correspond to attributes declared using HappyMapper syntax

See Also:



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).

Parameters:

  • hashes (Array<Hash>)

    The hashes to be compared, with optional name tags

Returns:

  • (Hash)

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

See Also:



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.

Parameters:

  • array (Array)

    The array to be converted to a hash

Returns:

  • (Hash)

    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.

Parameters:

Returns:

  • (Hash)

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

Raises:



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.

Returns:

  • (String)

    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.

Returns:

  • (String)

    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

See Also:



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

Returns Calls to_hash(summary=true).

Returns:

  • (Hash)

    Calls to_hash(summary=true)



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

def summary
  to_hash(summary = true)
end

#to_hash(summary = false) ⇒ Hash

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

Parameters:

  • summary (Boolean) (defaults to: false)

    Controls the depth and detail of recursion

Returns:

  • (Hash)

    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.

Returns:

  • (String)

    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.

Returns:

  • (String)

    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.

Returns:

  • (Array)

    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.

Returns:

  • (Array)

    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