Multiple extensions

You can wrap a route/vertex/edge in multiple extensions. For example, define the following extensions:

module A
    module Vertex
        def display_name
            "I am A"
        end
    end
end

module B
    module Vertex
        def display_name
            "I am B"
        end
    end
end

Now, we can use them as follows:

jruby-1.7.19 :105 > g.v(A)
#<V[3] I am A> #<V[2] I am A> #<V[1] I am A> #<V[0] I am A>
Total: 4

jruby-1.7.19 :106 > g.v(B)
#<V[3] I am B> #<V[2] I am B> #<V[1] I am B> #<V[0] I am B>
Total: 4

jruby-1.7.19 :107 > g.v(A,B)
#<V[3] I am B> #<V[2] I am B> #<V[1] I am B> #<V[0] I am B>
Total: 4

Overriding

In the example above, we extend the route with A,B, and the display_name method from B overrides the one from A.
The question is, if we extend a route with B,A, will A override B?

jruby-1.7.19 :108 > g.v(B,A)
#<V[3] I am B> #<V[2] I am B> #<V[1] I am B> #<V[0] I am B>
Total: 4

That's now what we expected. Why didn't A override B?

This is because Pacer, in order to be efficient, caches sets of extensions that are used together. Once a set of extensions was used to extend a route, the override order for that set is determined.

If you need to change this default behaviour, you can clear the cahce.

Pacer.clear_plugin_cache

# Clear the cache
jruby-1.7.19 :112 > Pacer.clear_plugin_cache

# A overrides B
jruby-1.7.19 :113 > g.v(B,A)
#<V[3] I am A> #<V[2] I am A> #<V[1] I am A> #<V[0] I am A>

# Clear the cache again
jruby-1.7.19 :114 > Pacer.clear_plugin_cache

# This time B overrides A
jruby-1.7.19 :115 > g.v(A,B)
#<V[3] I am B> #<V[2] I am B> #<V[1] I am B> #<V[0] I am B>

Filtering

When extending a route with multiple extensions, only items that satisfy all route_conditions will be included.

For example, consider the following extensions:

module Phone
    def self.route_conditions(graph)
        {type: :phone}
    end
end

module AndroidDevice
    def self.route_conditions(graph)
        {os: :android}
    end
end

With the following data:

g.create_vertex({type: :phone, os: :android})
g.create_vertex({type: :phone, os: :ios})
g.create_vertex({type: :tablet, os: :android})
g.create_vertex({type: :tablet, os: :ios})

In the IRB:

# All phones
jruby-1.7.19 :161 > g.v(Phone).properties
{"os"=>:android, "type"=>:phone} {"os"=>:ios, "type"=>:phone}    
Total: 2

# All Android devices
jruby-1.7.19 :162 > g.v(AndroidDevice).properties
{"os"=>:android, "type"=>:phone}  {"os"=>:android, "type"=>:tablet}
Total: 2

# All Android phones
jruby-1.7.19 :163 > g.v(Phone,AndroidDevice).properties
{"os"=>:android, "type"=>:phone}
Total: 1

The extensions method

Routes, vertices and edges have an extensions method, which returns their extensions as a list of module objects.
For example:

jruby-1.7.19 :188 > g.v(Phone).extensions
 => [Phone] 

jruby-1.7.19 :189 > g.v(Phone,AndroidDevice).extensions
 => [Phone, AndroidDevice]

Common usage:

def some_method(route)
    if route.extensions.include? Ext1
        # Do something ...
    elsif route.extensions.include? Ext2
        # Do something else ...
    else
        # ...
    end
end

Note: An extension that doesn't contain any of the Route, Vertex or Edge sub-modules, is considered irrelevant by Pacer.
When calling extensions on a single items, irrelevant extensions are dropped from the list. On the other hand, when calling it on a route, they are kept.

This is an edge case, as most extensions define useful methods. That being said, there are cases where as extension do not define any methods, and are used for filtering purposes only.