Module: Serialisable

Defined in:
lib/serialisable.rb,
lib/serialisable/version.rb,
lib/serialisable/selector.rb

Overview

Serialisable allows you to easily define an object that can deserialise xml into instances of itself. It provides a simple but powerful DSL for defining elements and attributes.

require 'serialisable'
require 'time'

class Play
  extend Serialisable

  root 'play'
  element :artist, 'artist'
  element :name, 'name'
  element :played_at, 'playedat', Time
end

class User
  extend Serialisable

  root 'user'
  attribute :id, 'id', :to_i
  element   :name, 'name'
  elements  :plays, 'plays', Play

  def inspect
    "#<User:#{id} #{name}>"
  end
end

user = User.deserialise <<XML
<?xml version="1.0" encoding="utf-8"?>
<user id="12452">
  <name>John Doe</name>
  <plays>
    <play>
      <artist>Arctic Monkeys</artist>
      <name>505</name>
      <playedat>2014-02-03T12:23:55Z</playedat>
    </play>
    <play>
      <artist>Aphex Twin</artist>
      <name>Windowlicker</name>
      <playedat>2014-02-03T12:26:13Z</playedat>
    </play>
  </plays>
</user>
XML

p user
#=> #<User:12452 John Doe>
p user.plays.map(&:name)
#=> ["505", "Windowlicker"]

Examples:

Type as Symbol


class Count
  extend Serialisable

  root 'count'
  attribute :value, 'value', :to_i
end

count = Count.deserialise <<XML
<?xml version="1.0" encoding="utf-8"?>
<count value="500" />
XML

p count.value #=> 500

Type as object responding to #parse


class IntParser
  def parse(str); str.to_i; end
end

class Count
  extend Serialisable

  root 'count'
  attribute :value, 'value', IntParser
end

count = Count.deserialise <<XML
<?xml version="1.0" encoding="utf-8"?>
<count value="500" />
XML

p count.value #=> 500

Defined Under Namespace

Classes: Selector

Constant Summary collapse

VERSION =
'0.0.1'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(obj) ⇒ Object


97
98
99
# File 'lib/serialisable.rb', line 97

def self.extended(obj)
  obj.instance_variable_set(:@__selectors, [])
end

Instance Method Details

#attribute(name, selector, type = nil) ⇒ Object

Define an attribute selector. This will match an attribute in the defined root element that has the name given by selector.

Parameters:

  • name (Symbol)

    Name of the method to be defined on the class that returns the value matched.

  • selector (String)

    Name of xml attribute to match against.

  • type (Symbol, #parse) (defaults to: nil)

    If a symbol is given the matched string will have the method named by it called on it. If an object responding to #parse is given then the string value will be passed to that method.


117
118
119
# File 'lib/serialisable.rb', line 117

def attribute(name, selector, type = nil)
  @__selectors << Selector::Attribute.new(name, selector, type)
end

#deserialise(xml) ⇒ Object

Deserialises the given xml into an instance of the class.

Parameters:

  • xml (String)

Returns:

  • An instance of the class that the method was called on.


216
217
218
# File 'lib/serialisable.rb', line 216

def deserialise(xml)
  __deserialise Nokogiri::XML(xml)
end

#element(name, serialisable) ⇒ Object #element(name, root, serialisable) ⇒ Object #element(name, selector, type = nil) ⇒ Object

Define an element selector. This will match a node in the defined root element that has the name given by selector.

Overloads:

  • #element(name, serialisable) ⇒ Object

    Use this when the node being matched contains nested xml.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • serialisable (Serialisable)
  • #element(name, root, serialisable) ⇒ Object

    Use this when the node being matched contains nested xml and the root needs to be set.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • root (String)

      Name of the root of the nested element, this overrides any root set on the serialisable passed.

    • serialisable (Serialisable)

      Serialisable object that represents the nested element.

  • #element(name, selector, type = nil) ⇒ Object

    Use this when the node only contains text.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • selector (String)

      Name of xml attribute to match against.

    • type (Symbol, #parse) (defaults to: nil)

      If a symbol is given the matched string will have the method named by it called on it. If an object responding to #parse is given then the string value will be passed to that method.


152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/serialisable.rb', line 152

def element(name, selector, type = nil)
  if selector.respond_to?(:__deserialise, true)
    @__selectors << Selector::Nested.new(name, selector)

  elsif type.respond_to?(:__deserialise, true)
    cloned_type = type.clone
    cloned_type.instance_variable_set(:@__root, selector)
    @__selectors << Selector::Nested.new(name, cloned_type)

  else
    @__selectors << Selector::Node.new(name, selector, type)
  end
end

#elements(name, serialisable) ⇒ Object #elements(name, root, serialisable) ⇒ Object #elements(name, selector, type = nil) ⇒ Object

Define an elements selector. This will match all nodes in the defined root element that has the name given by selector. The method created by this will return an array of matching values.

Overloads:

  • #elements(name, serialisable) ⇒ Object

    Use this when the nodes being matched contains nested xml.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • serialisable (Serialisable)
  • #elements(name, root, serialisable) ⇒ Object

    Use this when the nodes being matched contains nested xml and the root needs to be set.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • root (String)

      Name of the root of the nested element, this overrides any root set on the serialisable passed.

    • serialisable (Serialisable)

      Serialisable object that represents the nested element.

  • #elements(name, selector, type = nil) ⇒ Object

    Use this when the nodes only contain text.

    Parameters:

    • name (Symbol)

      Name of the method to be defined on the class that returns the value matched.

    • selector (String)

      Name of xml attribute to match against.

    • type (Symbol, #parse) (defaults to: nil)

      If a symbol is given the matched string will have the method named by it called on it. If an object responding to #parse is given then the string value will be passed to that method.


198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/serialisable.rb', line 198

def elements(name, selector, type = nil)
  if selector.respond_to?(:__deserialise_all, true)
    @__selectors << Selector::NestedMultiple.new(name, selector, type)

  elsif type.respond_to?(:__deserialise_all, true)
    cloned_type = type.clone
    cloned_type.instance_variable_set(:@__root, selector)
    @__selectors << Selector::NestedMultiple.new(name, cloned_type)

  else
    @__selectors << Selector::Nodes.new(name, selector, type)
  end
end

#root(selector) ⇒ Object

Define the element that makes up the root for the class.

Parameters:

  • selector (String)

    Name of xml element to mark as the root.


104
105
106
# File 'lib/serialisable.rb', line 104

def root(selector)
  @__root = selector
end