diff --git a/lib/apex/encoder/aprs_kiss.rb b/lib/apex/encoder/aprs_kiss.rb
index c5f54bc8794a17579e492555bd60ec33918ff19b..1f7f3ff6c5feb795dfd2e992dbbd0e8dfed9cbf3 100644
--- a/lib/apex/encoder/aprs_kiss.rb
+++ b/lib/apex/encoder/aprs_kiss.rb
@@ -34,10 +34,10 @@ module Apex
           frame_map = @data_stream.read
           return nil if frame_map.nil?
 
-          source = Apex::Entity.from_raw(frame_map[:source])
-          destination = Apex::Entity.from_raw(frame_map[:destination])
+          source = Apex::ImmutableEntity.from_raw(frame_map[:source])
+          destination = Apex::ImmutableEntity.from_raw(frame_map[:destination])
 
-          path = Apex::Path.from_raw(frame_map[:path])
+          path = Apex::ImmutablePath.from_raw(frame_map[:path])
 
           return Apex::ImmutableFrame.new(source, destination, path, frame_map[:payload])
         end
diff --git a/lib/apex/encoder/igate_tcp.rb b/lib/apex/encoder/igate_tcp.rb
index d9a24896601497dc5abf2cb47f62730db2359bc4..5621779850c447e2fe918a765b228091b8a3e27b 100644
--- a/lib/apex/encoder/igate_tcp.rb
+++ b/lib/apex/encoder/igate_tcp.rb
@@ -55,9 +55,9 @@ module Apex
 
             path = path.split(',')
 
-            decoded_source = Apex::Entity.from_raw(decoded_source)
-            decoded_destination = Apex::Entity.from_raw(path.shift)
-            decoded_path = Apex::Path.from_raw(path)
+            decoded_source = Apex::ImmutableEntity.from_raw(decoded_source)
+            decoded_destination = Apex::ImmutableEntity.from_raw(path.shift)
+            decoded_path = Apex::ImmutablePath.from_raw(path)
             decoded_payload = frame_so_far
 
             return Apex::ImmutableFrame.new(decoded_source, decoded_destination, decoded_path, decoded_payload)
diff --git a/lib/apex/frame.rb b/lib/apex/frame.rb
index 384b639e4c36c98db00d1d69fc51aa6fe3116fa1..1d729a565578badd1ed510ca63e73f6698ad8747 100644
--- a/lib/apex/frame.rb
+++ b/lib/apex/frame.rb
@@ -1,6 +1,11 @@
 require 'apex/frame/immutable_frame'
 require 'apex/frame/entity'
+require 'apex/frame/immutable_entity'
 require 'apex/frame/hop'
+require 'apex/frame/immutable_hop'
 require 'apex/frame/path'
+require 'apex/frame/immutable_path'
 require 'apex/frame/immutable_message'
 require 'apex/frame/path_agnostic_immutable_frame'
+require 'apex/frame/message'
+require 'apex/frame/frame'
diff --git a/lib/apex/frame/entity.rb b/lib/apex/frame/entity.rb
index 1552f33cd37245c9fdc75dd669e00e11c9923a91..c43114abdaff5d73617deff49339ae2d494b33e2 100644
--- a/lib/apex/frame/entity.rb
+++ b/lib/apex/frame/entity.rb
@@ -1,83 +1,10 @@
 module Apex
   public
-  class Entity
-    attr_reader :callsign, :ssid
-
-    public
-    def initialize(callsign, ssid)
-      raise ArgumentError.new("callsign can not be nil") if callsign.nil?
-
-      raise ArgumentError.new("callsign must be a String") if not callsign.kind_of? String
-      raise ArgumentError.new("ssid must be an Integer.") if (not ssid.nil?) && (not ssid.kind_of? Integer)
-
-      raise ArgumentError.new("ssid must be a value between 0 (inclusive) and 15 (inclusive)") if (not ssid.nil?) && (ssid < 0 || ssid > 15)
-      raise ArgumentError.new("Callsign can not be an empty string") if callsign.empty?
-      raise ArgumentError.new("Callsign must only contain numebers and letters") if callsign.strip.match?(/[^a-zA-Z0-9]/)
-
-      @callsign = callsign.strip.upcase.freeze
-      if (ssid.nil?) || (ssid.eql? 0)
-        @ssid = nil
-      else
-        @ssid = ssid
-      end
-    end
-
-    public
-    def self.from_raw(raw_hop)
-      raise ArgumentError.new("raw_hop can not be nil") if raw_hop.nil?
-
-      callsign = nil
-      ssid = nil
-
-      hop = raw_hop.dup
-
-      raise ArgumentError.new("Hops can only contain letters, numbers and dashes") if hop.strip.match?(/[^a-zA-Z0-9\-]/)
+  module Entity
+    include Abstractify::Abstract
 
-      if not hop.include? "-"
-        ssid = nil
-        callsign = hop.strip
-      else
-        split_hop = hop.strip.split("-")
-        raise ArgumentError.new("More than one hypen seen in a hop, invalid format") if split_hop.length > 2
-        raise ArgumentError.new("Hop format was not valid, hyphen placed at end or beginning of string") if split_hop.length <= 1
-        callsign = split_hop[0]
-        ssid = split_hop[1].to_i
-      end
+    abstract :decrement_ssid, :==, :eql?, :to_s
 
-      return Apex::Entity.new(callsign, ssid)
-    end
-
-    public
-    def decrement_ssid
-      raise RangeError.new("SSID can not be decremented when it is currently 0 or nil") if (self.ssid.nil?) or (self.ssid <= 0)
-
-      return Apex::Entity.new(self.callsign, self.ssid - 1)
-    end
-
-    public
-    def eql?(other)
-      raise ArgumentError.new("The argument must be of type Hop (or a child class).") if not other.kind_of? Apex::Entity
-
-      return self == other
-    end
-
-    public
-    def ==(other)
-      return false if other.nil?
-      return false if not other.respond_to? :callsign
-      return false if not other.respond_to? :ssid
-
-      return false if not self.callsign.eql? other.callsign
-      return false if not self.ssid.eql? other.ssid
-
-      return true
-    end
-
-    public
-    def to_s
-      ret_val = self.callsign.dup
-      ret_val << ("-" + self.ssid.to_s) if not self.ssid.nil?
-      return ret_val
-    end
+    attr_reader :callsign, :ssid
   end
 end
diff --git a/lib/apex/frame/frame.rb b/lib/apex/frame/frame.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6d8e3423a83dd763e2756a832d357d31b349d4f2
--- /dev/null
+++ b/lib/apex/frame/frame.rb
@@ -0,0 +1,22 @@
+require 'abstractify'
+require 'apex/frame/message'
+
+module Apex
+  ##
+  # An APXP compatible APRS frame, excluding the path data entierly. The
+  # UnpathedFrame and all its fields are immutable.
+  #
+  # @example Comparing frames
+  #   orig_frame = Apex.new('WI2ARD-1', 'OMG', ['WIDE2-2' 'WIDE1-1'], 'payload goes here')
+  #   diff_frame = Apex.new('WI2ARD-1', 'OMG', ['WIDE2-2' 'WIDE1-1'], 'different payload')
+  #   assert not orig_frame.eql? diff_frame
+  public
+  module Frame
+    include Apex::Message
+    include Abstractify::Abstract
+
+    abstract :path_agnostic_identity
+
+    attr_accessor :path
+  end
+end
diff --git a/lib/apex/frame/hop.rb b/lib/apex/frame/hop.rb
index b606e53e495534d474afd4e42df3779ced8ed721..ca544118bcd87492e3864126633a56cde19fd76b 100644
--- a/lib/apex/frame/hop.rb
+++ b/lib/apex/frame/hop.rb
@@ -1,85 +1,13 @@
+require 'apex/frame/entity'
+
 module Apex
   public
-  class Hop < Apex::Entity
-    attr_reader :seen
-
-    public
-    def initialize(callsign, ssid, seen)
-
-      raise ArgumentError.new("seen can not be nil") if seen.nil?
-      raise ArgumentError.new("seen must be a Boolean") if not (!!seen == seen)
-
-      super(callsign, ssid)
-
-      @seen = seen
-    end
-
-    public
-    def self.from_raw(raw_hop)
-      raise ArgumentError.new("raw_hop can not be nil") if raw_hop.nil?
-
-      callsign = nil
-      ssid = nil
-      seen = nil
-
-      hop = raw_hop.dup
-      if hop[-1].eql? "*"
-        seen = true
-        hop = hop[0..-2]
-      else
-        seen = false
-      end
-
-      raise ArgumentError.new("Hops can only contain letters, numbers and dashes. Hop: " + hop) if hop.strip.match?(/[^a-zA-Z0-9\-]/)
+  module Hop
+    include Apex::Entity
+    include Abstractify::Abstract
 
-      if not hop.include? "-"
-        ssid = nil
-        callsign = hop.strip
-      else
-        split_hop = hop.strip.split("-")
-        raise ArgumentError.new("More than one hypen seen in a hop, invalid format") if split_hop.length > 2
-        raise ArgumentError.new("Hop format was not valid, hyphen placed at end or beginning of string") if split_hop.length <= 1
-        callsign = split_hop[0]
-        ssid = split_hop[1].to_i
-      end
+    abstract :toggle_seen, :decrement_ssid, :==, :eql?, :to_s
 
-      return Apex::Hop.new(callsign, ssid, seen)
-    end
-
-    public
-    def toggle_seen
-      return Apex::Hop.new(self.callsign, self.ssid, !self.seen)
-    end
-
-    public
-    def decrement_ssid
-      raise RangeError.new("SSID can not be decremented when it is currently 0 or nil") if (self.ssid.nil?) or (self.ssid <= 0)
-
-      return Apex::Hop.new(self.callsign, self.ssid - 1, self.seen)
-    end
-
-    public
-    def eql?(other)
-      raise ArgumentError.new("The argument must be of type Hop (or a child class).") if not other.kind_of? Apex::Hop
-
-      return self == other
-    end
-
-    public
-    def ==(other)
-      return false if !super(other)
-
-      return false if not other.respond_to? :seen
-      return false if not self.seen.eql? other.seen
-
-      return true
-    end
-
-    public
-    def to_s
-      ret_val = super.dup
-      ret_val << "*" if self.seen
-      return ret_val
-    end
+    attr_reader :seen
   end
 end
diff --git a/lib/apex/frame/immutable_entity.rb b/lib/apex/frame/immutable_entity.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e8202386d52dd42fb485281aa95a698318571449
--- /dev/null
+++ b/lib/apex/frame/immutable_entity.rb
@@ -0,0 +1,87 @@
+require 'apex/frame/entity'
+
+module Apex
+  public
+  class ImmutableEntity
+    include Entity
+
+    attr_reader :callsign, :ssid
+
+    public
+    def initialize(callsign, ssid)
+      raise ArgumentError.new("callsign can not be nil") if callsign.nil?
+
+      raise ArgumentError.new("callsign must be a String") if not callsign.kind_of? String
+      raise ArgumentError.new("ssid must be an Integer.") if (not ssid.nil?) && (not ssid.kind_of? Integer)
+
+      raise ArgumentError.new("ssid must be a value between 0 (inclusive) and 15 (inclusive)") if (not ssid.nil?) && (ssid < 0 || ssid > 15)
+      raise ArgumentError.new("Callsign can not be an empty string") if callsign.empty?
+      raise ArgumentError.new("Callsign must only contain numebers and letters") if callsign.strip.match?(/[^a-zA-Z0-9]/)
+
+      @callsign = callsign.strip.upcase.freeze
+      if (ssid.nil?) || (ssid.eql? 0)
+        @ssid = nil
+      else
+        @ssid = ssid
+      end
+    end
+
+    public
+    def self.from_raw(raw_hop)
+      raise ArgumentError.new("raw_hop can not be nil") if raw_hop.nil?
+
+      callsign = nil
+      ssid = nil
+
+      hop = raw_hop.dup
+
+      raise ArgumentError.new("Hops can only contain letters, numbers and dashes") if hop.strip.match?(/[^a-zA-Z0-9\-]/)
+
+      if not hop.include? "-"
+        ssid = nil
+        callsign = hop.strip
+      else
+        split_hop = hop.strip.split("-")
+        raise ArgumentError.new("More than one hypen seen in a hop, invalid format") if split_hop.length > 2
+        raise ArgumentError.new("Hop format was not valid, hyphen placed at end or beginning of string") if split_hop.length <= 1
+        callsign = split_hop[0]
+        ssid = split_hop[1].to_i
+      end
+
+      return Apex::ImmutableEntity.new(callsign, ssid)
+    end
+
+    public
+    def decrement_ssid
+      raise RangeError.new("SSID can not be decremented when it is currently 0 or nil") if (self.ssid.nil?) or (self.ssid <= 0)
+
+      return Apex::ImmutableEntity.new(self.callsign, self.ssid - 1)
+    end
+
+    public
+    def eql?(other)
+      raise ArgumentError.new("The argument must be of type Hop (or a child class).") if not other.kind_of? Apex::Entity
+
+      return self == other
+    end
+
+    public
+    def ==(other)
+      return false if other.nil?
+      return false if not other.respond_to? :callsign
+      return false if not other.respond_to? :ssid
+
+      return false if not self.callsign.eql? other.callsign
+      return false if not self.ssid.eql? other.ssid
+
+      return true
+    end
+
+    public
+    def to_s
+      ret_val = self.callsign.dup
+      ret_val << ("-" + self.ssid.to_s) if not self.ssid.nil?
+      return ret_val
+    end
+  end
+end
diff --git a/lib/apex/frame/immutable_frame.rb b/lib/apex/frame/immutable_frame.rb
index 93ca72dadecab6f03599c12440770d6f9f08f522..44bd4f3808bfcd168ac30f00adaad09e9a88c3b0 100644
--- a/lib/apex/frame/immutable_frame.rb
+++ b/lib/apex/frame/immutable_frame.rb
@@ -1,9 +1,10 @@
 require 'apex/frame/immutable_message'
+require 'apex/frame/frame'
 
 module Apex
   public
   class ImmutableFrame < Apex::ImmutableMessage
-    attr_accessor :path
+    include Frame
 
     protected
     def initialize(source, destination, path, payload)
@@ -18,7 +19,7 @@ module Apex
     public
     def eql?(other)
       raise ArgumentError.new("The argument can not be a UnpathedFrame or a PathAgnosticFrame") if ((other.instance_of? ImmutableMessage) || (other.instance_of? PathAgnosticImmutableFrame))
-      raise ArgumentError.new("The argument must be of type Frame (or a child class).") if not other.kind_of? ImmutableFrame
+      raise ArgumentError.new("The argument must be of type Frame (or a child class).") if not other.kind_of? Frame
 
       return self == other
     end
diff --git a/lib/apex/frame/immutable_hop.rb b/lib/apex/frame/immutable_hop.rb
new file mode 100644
index 0000000000000000000000000000000000000000..79d6b6e5f35fe57eda0ea3c1d4d982c3b0e693e8
--- /dev/null
+++ b/lib/apex/frame/immutable_hop.rb
@@ -0,0 +1,90 @@
+require 'apex/frame/hop'
+require 'apex/frame/immutable_entity'
+
+module Apex
+  public
+  class ImmutableHop < Apex::ImmutableEntity
+    include Hop
+
+    attr_reader :seen
+
+    public
+    def initialize(callsign, ssid, seen)
+
+      raise ArgumentError.new("seen can not be nil") if seen.nil?
+      raise ArgumentError.new("seen must be a Boolean") if not (!!seen == seen)
+
+      super(callsign, ssid)
+
+      @seen = seen
+    end
+
+    public
+    def self.from_raw(raw_hop)
+      raise ArgumentError.new("raw_hop can not be nil") if raw_hop.nil?
+
+      callsign = nil
+      ssid = nil
+      seen = nil
+
+      hop = raw_hop.dup
+      if hop[-1].eql? "*"
+        seen = true
+        hop = hop[0..-2]
+      else
+        seen = false
+      end
+
+      raise ArgumentError.new("Hops can only contain letters, numbers and dashes. Hop: " + hop) if hop.strip.match?(/[^a-zA-Z0-9\-]/)
+
+      if not hop.include? "-"
+        ssid = nil
+        callsign = hop.strip
+      else
+        split_hop = hop.strip.split("-")
+        raise ArgumentError.new("More than one hypen seen in a hop, invalid format") if split_hop.length > 2
+        raise ArgumentError.new("Hop format was not valid, hyphen placed at end or beginning of string") if split_hop.length <= 1
+        callsign = split_hop[0]
+        ssid = split_hop[1].to_i
+      end
+
+      return Apex::ImmutableHop.new(callsign, ssid, seen)
+    end
+
+    public
+    def toggle_seen
+      return Apex::ImmutableHop.new(self.callsign, self.ssid, !self.seen)
+    end
+
+    public
+    def decrement_ssid
+      raise RangeError.new("SSID can not be decremented when it is currently 0 or nil") if (self.ssid.nil?) or (self.ssid <= 0)
+
+      return Apex::ImmutableHop.new(self.callsign, self.ssid - 1, self.seen)
+    end
+
+    public
+    def eql?(other)
+      raise ArgumentError.new("The argument must be of type Hop (or a child class).") if not other.kind_of? Apex::Hop
+
+      return self == other
+    end
+
+    public
+    def ==(other)
+      return false if !super(other)
+
+      return false if not other.respond_to? :seen
+      return false if not self.seen.eql? other.seen
+
+      return true
+    end
+
+    public
+    def to_s
+      ret_val = super.dup
+      ret_val << "*" if self.seen
+      return ret_val
+    end
+  end
+end
diff --git a/lib/apex/frame/immutable_message.rb b/lib/apex/frame/immutable_message.rb
index 7bd8b294f087f499de603c9a55a31914d919ba04..4301ca6a0071ad4819d6c0c978628830dc682c20 100644
--- a/lib/apex/frame/immutable_message.rb
+++ b/lib/apex/frame/immutable_message.rb
@@ -1,3 +1,5 @@
+require 'apex/frame/message'
+
 module Apex
   ##
   # An APXP compatible APRS frame, excluding the path data entierly. The
@@ -9,7 +11,7 @@ module Apex
   #   assert not orig_frame.eql? diff_frame
   public
   class ImmutableMessage
-    attr_accessor :source, :destination, :payload
+    include Message
 
     ##
     # Creates a new frame, all fields are duplicated but and immutable. All
diff --git a/lib/apex/frame/immutable_path.rb b/lib/apex/frame/immutable_path.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c402f7da0dc68136c599ed5c1472c2f2ef90b6a7
--- /dev/null
+++ b/lib/apex/frame/immutable_path.rb
@@ -0,0 +1,116 @@
+require 'apex/frame/hop'
+require 'apex/frame/path'
+
+module Apex
+  public
+  class ImmutablePath
+    include Path
+
+    def initialize(*hops)
+      raise ArgumentError.new("Must be called with atleast one argument") if (hops.nil?) || (hops.length <= 0)
+      @path_array = []
+      last_seen = true
+      hops.each do |hop|
+        raise ArgumentError.new("All arguments must not be nil: #{hops.to_s}") if (hop.nil?)
+        raise ArgumentError.new("All arguments must be of type Hop: #{hops.class.to_s}") if not hop.kind_of? Apex::Hop
+        raise ArgumentError.new("A seen hop can not follow an unseen hop") if (hop.seen) && (!last_seen)
+        last_seen = false if not hop.seen
+        @path_array << hop
+      end
+
+      @path_array.freeze
+      freeze
+    end
+
+    public
+    def self.from_raw(raw_path)
+      raise ArgumentError.new("raw_path can not be nil") if raw_path.nil?
+
+      if raw_path.kind_of? String
+        if raw_path.include? ","
+          raise ArgumentError.new("raw_path is too short") if raw_path.length < 3
+          raw_path = raw_path.split(",")
+        else
+          raise ArgumentError.new("raw_path is too short") if raw_path.length < 1
+          raw_path = [raw_path]
+        end
+      end
+
+      raise ArgumentError.new("raw_path must be array-like") if not raw_path.respond_to? :[]
+
+      new_path_array = []
+      raw_path.each do |hop|
+        if hop.kind_of? Apex::Hop
+          new_hop = hop
+        else
+          new_hop = Apex::ImmutableHop.from_raw(hop)
+        end
+        new_path_array << new_hop
+      end
+
+      return Apex::ImmutablePath.new(*new_path_array)
+    end
+
+    public
+    def each
+      @path_array.each do |hop|
+        yield(hop)
+      end
+    end
+
+    public
+    def [](idx)
+      return @path_array[idx].dup.freeze
+    end
+
+    public
+    def length
+      return @path_array.length
+    end
+
+    public
+    def eql?(other)
+      raise ArgumentError.new("The argument must be of type Path (or a child class).") if not other.kind_of? Path
+
+      return self == other
+    end
+
+    public
+    def ==(other)
+      return false if not other.respond_to? :[]
+      return false if not other.respond_to? :length
+      return false if not self.length.eql? other.length
+
+      (0..self.length - 1).each do |idx|
+        return false if not self[idx].eql? other[idx]
+      end
+
+      return true
+    end
+
+    public
+    def to_s
+      return @path_array.join(',')
+    end
+
+    public
+    def to_string_array
+      return @path_array.map {|e| e.to_s}
+    end
+
+    public
+    def to_array
+      return @path_array.dup
+    end
+
+    public
+    def unseen_hops
+        @path_array.select { |hop| !hop.seen  }
+    end
+
+    public
+    def seen_hops
+        @path_array.select { |hop| hop.seen  }
+    end
+  end
+end
diff --git a/lib/apex/frame/message.rb b/lib/apex/frame/message.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e72dc0fa63a5298f1a817006a5fa3e05abf6cee8
--- /dev/null
+++ b/lib/apex/frame/message.rb
@@ -0,0 +1,21 @@
+require 'abstractify'
+
+module Apex
+  ##
+  # An APXP compatible APRS frame, excluding the path data entierly. The
+  # UnpathedFrame and all its fields are immutable.
+  #
+  # @example Comparing frames
+  #   orig_frame = Apex.new('WI2ARD-1', 'OMG', ['WIDE2-2' 'WIDE1-1'], 'payload goes here')
+  #   diff_frame = Apex.new('WI2ARD-1', 'OMG', ['WIDE2-2' 'WIDE1-1'], 'different payload')
+  #   assert not orig_frame.eql? diff_frame
+  public
+  module Message
+
+    include Abstractify::Abstract
+
+    abstract :path_agnostic_eql?, :path_agnostic_equality?, :path_agnostic_hash, :==, :eql?, :hash
+
+    attr_accessor :source, :destination, :payload
+  end
+end
diff --git a/lib/apex/frame/path.rb b/lib/apex/frame/path.rb
index 5ae7a78dc28c6d96bc1a515f9d6e524a4c12fde3..0bbdfe39b67d8b272db41ec7d4754bd34c3fd568 100644
--- a/lib/apex/frame/path.rb
+++ b/lib/apex/frame/path.rb
@@ -1,108 +1,8 @@
-require 'apex/frame/hop'
-
 module Apex
   public
-  class Path
-    def initialize(*hops)
-      raise ArgumentError.new("Must be called with atleast one argument") if (hops.nil?) || (hops.length <= 0)
-      @path_array = []
-      last_seen = true
-      hops.each do |hop|
-        raise ArgumentError.new("All arguments must not be nil: #{hops.to_s}") if (hop.nil?)
-        raise ArgumentError.new("All arguments must be of type Hop: #{hops.class.to_s}") if not hop.kind_of? Apex::Hop
-        raise ArgumentError.new("A seen hop can not follow an unseen hop") if (hop.seen) && (!last_seen)
-        last_seen = false if not hop.seen
-        @path_array << hop
-      end
-
-      @path_array.freeze
-      freeze
-    end
-
-    public
-    def self.from_raw(raw_path)
-      raise ArgumentError.new("raw_path can not be nil") if raw_path.nil?
-
-      if raw_path.kind_of? String
-        if raw_path.include? ","
-          raise ArgumentError.new("raw_path is too short") if raw_path.length < 3
-          raw_path = raw_path.split(",")
-        else
-          raise ArgumentError.new("raw_path is too short") if raw_path.length < 1
-          raw_path = [raw_path]
-        end
-      end
-
-      raise ArgumentError.new("raw_path must be array-like") if not raw_path.respond_to? :[]
-
-      new_path_array = []
-      raw_path.each do |hop|
-        if hop.kind_of? Apex::Hop
-          new_hop = hop
-        else
-          new_hop = Apex::Hop.from_raw(hop)
-        end
-        new_path_array << new_hop
-      end
-
-      return Apex::Path.new(*new_path_array)
-    end
-
-    public
-    def each
-      @path_array.each do |hop|
-        yield(hop)
-      end
-    end
-
-    public
-    def [](idx)
-      return @path_array[idx].dup.freeze
-    end
-
-    public
-    def length
-      return @path_array.length
-    end
-
-    public
-    def eql?(other)
-      raise ArgumentError.new("The argument must be of type Path (or a child class).") if not other.kind_of? Path
-
-      return self == other
-    end
-
-    public
-    def ==(other)
-      return false if not other.respond_to? :[]
-      return false if not other.respond_to? :length
-      return false if not self.length.eql? other.length
-
-      (0..self.length - 1).each do |idx|
-        return false if not self[idx].eql? other[idx]
-      end
-
-      return true
-    end
-
-    public
-    def to_s
-      return @path_array.join(',')
-    end
-
-    public
-    def to_string_array
-      return @path_array.map {|e| e.to_s}
-    end
-
-    public
-    def unseen_hops
-        @path_array.select { |hop| !hop.seen  }
-    end
+  module Path
+    include Abstractify::Abstract
 
-    public
-    def seen_hops
-        @path_array.select { |hop| hop.seen  }
-    end
+    abstract :each, :[], :length, :eql?, :==, :to_s, :to_string_array, :to_array
   end
 end
diff --git a/lib/apex/frame/path_agnostic_immutable_frame.rb b/lib/apex/frame/path_agnostic_immutable_frame.rb
index 4863f730d620d86b68c8721ff4c5b8545a83ec6a..6f125f2ec2e3736fdf34cc33449e2ea2780efdc5 100644
--- a/lib/apex/frame/path_agnostic_immutable_frame.rb
+++ b/lib/apex/frame/path_agnostic_immutable_frame.rb
@@ -1,3 +1,5 @@
+require 'apex/frame/immutable_frame'
+
 module Apex
   private
   class PathAgnosticImmutableFrame < ImmutableFrame
diff --git a/spec/apex/encoder/aprs_kiss_spec.rb b/spec/apex/encoder/aprs_kiss_spec.rb
index 12572273f2e8225148b8db7f6685cdcbe27c38bd..97b8e9eeb246a75972b98bf735026997ef219ea3 100644
--- a/spec/apex/encoder/aprs_kiss_spec.rb
+++ b/spec/apex/encoder/aprs_kiss_spec.rb
@@ -1,9 +1,9 @@
 require_relative '../../../lib/apex'
 
 FRAME_KISS = Apex::ImmutableFrame.new(
-    Apex::Entity.from_raw('W2GMD-1'),
-    Apex::Entity.from_raw('OMG'),
-    Apex::Path.from_raw(['WIDE1-1', 'WIDE2-2']),
+    Apex::ImmutableEntity.from_raw('W2GMD-1'),
+    Apex::ImmutableEntity.from_raw('OMG'),
+    Apex::ImmutablePath.from_raw(['WIDE1-1', 'WIDE2-2']),
     'test_encode_frame'
 )
 
diff --git a/spec/apex/encoder/igate_tcp_spec.rb b/spec/apex/encoder/igate_tcp_spec.rb
index 8dbcd2c2ae661d0d7dbe8014352069d93a2786e3..db4f79e40fc9401e232e41b2e0cd2eec782a1c68 100644
--- a/spec/apex/encoder/igate_tcp_spec.rb
+++ b/spec/apex/encoder/igate_tcp_spec.rb
@@ -1,9 +1,9 @@
 require_relative '../../../lib/apex'
 
 DECODED_FRAME_IGATE = Apex::ImmutableFrame.new(
-    Apex::Entity.from_raw('W2GMD-1'),
-    Apex::Entity.from_raw('OMG'),
-    Apex::Path.from_raw(['WIDE1-1', 'WIDE2-2']),
+    Apex::ImmutableEntity.from_raw('W2GMD-1'),
+    Apex::ImmutableEntity.from_raw('OMG'),
+    Apex::ImmutablePath.from_raw(['WIDE1-1', 'WIDE2-2']),
     'test_encode_frame'
 )
 ENCODED_FRAME_IGATE = "W2GMD-1>OMG,WIDE1-1,WIDE2-2:test_encode_frame"
diff --git a/spec/apex/frame/entity_spec.rb b/spec/apex/frame/entity_spec.rb
index ef1022d900b252256c2b382e01cb6b6bb7432b51..5823238f12e9112f196817c9d3e728e5dda640b7 100644
--- a/spec/apex/frame/entity_spec.rb
+++ b/spec/apex/frame/entity_spec.rb
@@ -42,7 +42,7 @@ end
 describe Apex::Entity do
   describe ".new" do
     context "Given a valid callsign with ssid" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
       it "returns a Entity object with correct properties" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -58,7 +58,7 @@ describe Apex::Entity do
       end
     end
     context "Given a valid callsign with nil ssid" do
-      entity = Apex::Entity.new(NOSSID_ENTITY_CALLSIGN, NOSSID_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(NOSSID_ENTITY_CALLSIGN, NOSSID_ENTITY_SSID)
       it "returns a Entity object with correct properties" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -71,7 +71,7 @@ describe Apex::Entity do
       end
     end
     context "Given a valid callsign with zero for ssid" do
-      entity = Apex::Entity.new(ZEROSSID_ENTITY_CALLSIGN, ZEROSSID_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(ZEROSSID_ENTITY_CALLSIGN, ZEROSSID_ENTITY_SSID)
       it "returns a Entity object with correct properties" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -86,60 +86,60 @@ describe Apex::Entity do
     context "Given an invalid callsign with valid ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(BAD_CALLSIGN_ENTITY_CALLSIGN, BAD_CALLSIGN_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new(BAD_CALLSIGN_ENTITY_CALLSIGN, BAD_CALLSIGN_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a nil callsign with valid ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(nil, BASE_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new(nil, BASE_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a non-string callsign with valid ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(5, BASE_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new(5, BASE_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a empty string callsign with valid ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new("", BASE_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new("", BASE_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with non-integer ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, "invalid")
+          entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, "invalid")
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with ssid below 0" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(BAD_LOWSSID_ENTITY_CALLSIGN,BAD_LOWSSID_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new(BAD_LOWSSID_ENTITY_CALLSIGN,BAD_LOWSSID_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with ssid above 15" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.new(BAD_HIGHSSID_ENTITY_CALLSIGN,BAD_HIGHSSID_ENTITY_SSID)
+          entity = Apex::ImmutableEntity.new(BAD_HIGHSSID_ENTITY_CALLSIGN,BAD_HIGHSSID_ENTITY_SSID)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a lowercase callsign with valid ssid" do
-      entity = Apex::Entity.new("wi2ard", 2)
+      entity = Apex::ImmutableEntity.new("wi2ard", 2)
       it "converts the callsign to uppercase" do
         expect(entity.callsign).to eql("WI2ARD")
       end
     end
     context "Given a callsign with extra spaces before and after and valid ssid" do
-      entity = Apex::Entity.new(" WI2ARD   ", 2)
+      entity = Apex::ImmutableEntity.new(" WI2ARD   ", 2)
       it "strips the extra spaces" do
         expect(entity.callsign).to eql("WI2ARD")
       end
@@ -147,7 +147,7 @@ describe Apex::Entity do
   end
   describe ".from_raw" do
     context "Given a valid callsign with ssid" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       it "returns a Entity object" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -160,7 +160,7 @@ describe Apex::Entity do
       end
     end
     context "Given a valid callsign with 0 ssid" do
-      entity = Apex::Entity.from_raw(ZEROSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(ZEROSSID_ENTITY)
       it "returns a FrameEntity object" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -173,7 +173,7 @@ describe Apex::Entity do
       end
     end
     context "Given a valid callsign with no ssid" do
-      entity = Apex::Entity.from_raw(NOSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(NOSSID_ENTITY)
       it "returns a FrameEntity object" do
         expect(entity).not_to be_nil
         expect(entity).to be_kind_of(Apex::Entity)
@@ -188,47 +188,47 @@ describe Apex::Entity do
     context "Given an invalid callsign with valid ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.from_raw(BAD_CALLSIGN_ENTITY)
+          entity = Apex::ImmutableEntity.from_raw(BAD_CALLSIGN_ENTITY)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a entity with two hyphens" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.from_raw(BAD_HYPHEN_ENTITY)
+          entity = Apex::ImmutableEntity.from_raw(BAD_HYPHEN_ENTITY)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a entity with a hyphen but no ssid" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.from_raw(BAD_HYPHEN_NOSSID_ENTITY)
+          entity = Apex::ImmutableEntity.from_raw(BAD_HYPHEN_NOSSID_ENTITY)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a entity with a an ssid greater than 15" do
       it "throws an argument error" do
         expect {
-          entity = Apex::Entity.from_raw(BAD_HIGHSSID_ENTITY)
+          entity = Apex::ImmutableEntity.from_raw(BAD_HIGHSSID_ENTITY)
         }.to raise_error(ArgumentError)
       end
     end
   end
   describe ".callsign" do
     context "Given a Entity with valid callsign and with an ssid" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       it "then the callsign should be frozen" do
         expect(entity.callsign).to be_frozen
       end
     end
     context "Given a Entity with valid callsign and without an ssid" do
-      entity = Apex::Entity.from_raw(NOSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(NOSSID_ENTITY)
       it "then the callsign should be frozen" do
         expect(entity.callsign).to be_frozen
       end
     end
     context "Given any valid Entity" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       it "then we should not be able to set a value" do
         expect {
           entity.callsign = "BAD1B"
@@ -242,7 +242,7 @@ describe Apex::Entity do
       it "then the callsign passed to from_raw should be duplicated" do
         passed_call = "WI2AR"
         orig_call = passed_call.dup.freeze
-        entity = Apex::Entity.from_raw(passed_call)
+        entity = Apex::ImmutableEntity.from_raw(passed_call)
         passed_call << "D"
         expect(entity.callsign).to eql(orig_call)
         expect(passed_call).to eql("WI2ARD")
@@ -252,7 +252,7 @@ describe Apex::Entity do
   end
   describe ".ssid" do
     context "Given any valid Entity" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       it "then we should not be able to set a value" do
         expect {
           entity.ssid = "1"
@@ -267,7 +267,7 @@ describe Apex::Entity do
   end
   describe ".decrement_ssid" do
     context "Given a Entity that has a greater than 0 ssid" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       context "which has its ssid decremented" do
         new_entity = entity.decrement_ssid
         it "should produce a duplicated Entity" do
@@ -282,7 +282,7 @@ describe Apex::Entity do
       end
     end
     context "Given a Entity that has a ssid of 0" do
-      entity = Apex::Entity.from_raw(ZEROSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(ZEROSSID_ENTITY)
       context "which has its ssid decremented" do
         it "throws a range error" do
           expect{
@@ -294,31 +294,31 @@ describe Apex::Entity do
   end
   describe ".to_s" do
     context "Given a raw string with valid callsign with ssid" do
-      entity = Apex::Entity.from_raw(BASE_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(BASE_ENTITY)
       it "then we should produce the correct string" do
         expect(entity.to_s).to eql(BASE_ENTITY)
       end
     end
     context "Given a raw string with valid callsign with ssid of zero" do
-      entity = Apex::Entity.from_raw(ZEROSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(ZEROSSID_ENTITY)
       it "then we should produce the correct string" do
         expect(entity.to_s).to eql(NOSSID_ENTITY)
       end
     end
     context "Given a raw string with valid callsign without ssid" do
-      entity = Apex::Entity.from_raw(NOSSID_ENTITY)
+      entity = Apex::ImmutableEntity.from_raw(NOSSID_ENTITY)
       it "then we should produce the correct string" do
         expect(entity.to_s).to eql(NOSSID_ENTITY)
       end
     end
     context "Given a FrameEntity from new with valid callsign with non-zero ssid" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
       it "then we should produce the correct string" do
         expect(entity.to_s).to eql(BASE_ENTITY)
       end
     end
     context "Given a FrameEntity from new with valid callsign with ssid of 0" do
-      entity = Apex::Entity.new(ZEROSSID_ENTITY_CALLSIGN, ZEROSSID_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(ZEROSSID_ENTITY_CALLSIGN, ZEROSSID_ENTITY_SSID)
       it "then we should produce the correct string" do
         expect(entity.to_s).to eql(NOSSID_ENTITY)
       end
@@ -328,15 +328,15 @@ describe Apex::Entity do
   describe ".==" do
     context "Given one Entity and an equivelant non-Entity class with the same properties" do
       entity_equiv = EntityEquiv.new
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
       it "then equality should return true" do
         expect(entity == entity_equiv).to be_truthy
       end
     end
 
     context "Given two equivelant entitys both instaces of Entity class with the same properties" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, 0)
-      entity_equiv = Apex::Entity.new(BASE_ENTITY_CALLSIGN, nil)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, 0)
+      entity_equiv = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, nil)
       it "then equality should return true" do
         expect(entity == entity_equiv).to be_truthy
       end
@@ -344,15 +344,15 @@ describe Apex::Entity do
 
     context "Given one Entity and a equivelant non-Entity class with different properties" do
       entity_equiv = EntityEquiv.new
-      entity = Apex::Entity.new("BADCALL", BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new("BADCALL", BASE_ENTITY_SSID)
       it "then equality should return true" do
         expect(entity == entity_equiv).to be_falsey
       end
     end
 
     context "Given two equivelant entitys both instaces of Entity class with different properties" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, 0)
-      entity_equiv = Apex::Entity.new("BADCALL", nil)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, 0)
+      entity_equiv = Apex::ImmutableEntity.new("BADCALL", nil)
       it "then equality should return true" do
         expect(entity == entity_equiv).to be_falsey
       end
@@ -362,7 +362,7 @@ describe Apex::Entity do
   describe ".eql?" do
     context "Given one Entity and an equivelant non-Entity class with the same properties" do
       entity_equiv = EntityEquiv.new
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, BASE_ENTITY_SSID)
       it "throws an ArgumentError" do
         expect {
           entity.eql? entity_equiv
@@ -371,8 +371,8 @@ describe Apex::Entity do
     end
 
     context "Given two equivelant entitys both instaces of Entity class" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, 0)
-      entity_equiv = Apex::Entity.new(BASE_ENTITY_CALLSIGN, nil)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, 0)
+      entity_equiv = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, nil)
       it "then eql should return true" do
         expect(entity.eql? entity_equiv).to be_truthy
       end
@@ -380,7 +380,7 @@ describe Apex::Entity do
 
     context "Given one Entity and a equivelant non-Entity class with different properties" do
       entity_equiv = EntityEquiv.new
-      entity = Apex::Entity.new("BADCALL", BASE_ENTITY_SSID)
+      entity = Apex::ImmutableEntity.new("BADCALL", BASE_ENTITY_SSID)
       it "throws an ArgumentError" do
         expect {
           entity.eql? entity_equiv
@@ -389,8 +389,8 @@ describe Apex::Entity do
     end
 
     context "Given two equivelant entitys both instaces of Entity class with different properties" do
-      entity = Apex::Entity.new(BASE_ENTITY_CALLSIGN, 0)
-      entity_equiv = Apex::Entity.new("BADCALL", nil)
+      entity = Apex::ImmutableEntity.new(BASE_ENTITY_CALLSIGN, 0)
+      entity_equiv = Apex::ImmutableEntity.new("BADCALL", nil)
       it "then eql should return false" do
         expect(entity.eql? entity_equiv).to be_falsey
       end
diff --git a/spec/apex/frame/hop_spec.rb b/spec/apex/frame/hop_spec.rb
index b0416fc06543f0259f33dab403aeff427db23927..4f3c95d6f104e2a604b8828258aceaa0a2985ed9 100644
--- a/spec/apex/frame/hop_spec.rb
+++ b/spec/apex/frame/hop_spec.rb
@@ -68,7 +68,7 @@ end
 describe Apex::Hop do
   describe ".new" do
     context "Given a valid callsign with ssid and with seen flag" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
       it "returns a FrameHop object with correct properties" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -84,7 +84,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign with nil ssid and with seen flag" do
-      hop = Apex::Hop.new(NOSSID_HOP_CALLSIGN, NOSSID_HOP_SSID, NOSSID_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(NOSSID_HOP_CALLSIGN, NOSSID_HOP_SSID, NOSSID_HOP_SEEN)
       it "returns a FrameHop object with correct properties" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -100,7 +100,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign with zero for ssid and with seen flag" do
-      hop = Apex::Hop.new(ZEROSSID_HOP_CALLSIGN, ZEROSSID_HOP_SSID, ZEROSSID_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(ZEROSSID_HOP_CALLSIGN, ZEROSSID_HOP_SSID, ZEROSSID_HOP_SEEN)
       it "returns a FrameHop object with correct properties" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -118,74 +118,74 @@ describe Apex::Hop do
     context "Given an invalid callsign with valid ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BAD_CALLSIGN_HOP_CALLSIGN, BAD_CALLSIGN_HOP_SSID, BAD_CALLSIGN_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(BAD_CALLSIGN_HOP_CALLSIGN, BAD_CALLSIGN_HOP_SSID, BAD_CALLSIGN_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a nil callsign with valid ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(nil, BASE_HOP_SSID, BASE_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(nil, BASE_HOP_SSID, BASE_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with valid ssid and nil seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, nil)
+          hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, nil)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a non-string callsign with valid ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(5, BASE_HOP_SSID, BASE_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(5, BASE_HOP_SSID, BASE_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a empty string callsign with valid ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new("", BASE_HOP_SSID, BASE_HOP_SEEN)
+          hop = Apex::ImmutableHop.new("", BASE_HOP_SSID, BASE_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with non-integer ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BASE_HOP_CALLSIGN, "invalid", BASE_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, "invalid", BASE_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with valid ssid and non-boolean seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BASE_HOP_CALLSIGN,BASE_HOP_SSID, "invalid")
+          hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN,BASE_HOP_SSID, "invalid")
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with ssid below 0 and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BAD_LOWSSID_HOP_CALLSIGN,BAD_LOWSSID_HOP_SSID, BAD_LOWSSID_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(BAD_LOWSSID_HOP_CALLSIGN,BAD_LOWSSID_HOP_SSID, BAD_LOWSSID_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a valid callsign with ssid above 15 and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.new(BAD_HIGHSSID_HOP_CALLSIGN,BAD_HIGHSSID_HOP_SSID, BAD_HIGHSSID_HOP_SEEN)
+          hop = Apex::ImmutableHop.new(BAD_HIGHSSID_HOP_CALLSIGN,BAD_HIGHSSID_HOP_SSID, BAD_HIGHSSID_HOP_SEEN)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a lowercase callsign with valid ssid and valid seen flag" do
-      hop = Apex::Hop.new("wi2ard", 2, true)
+      hop = Apex::ImmutableHop.new("wi2ard", 2, true)
       it "converts the callsign to uppercase" do
         expect(hop.callsign).to eql("WI2ARD")
       end
     end
     context "Given a callsign with extra spaces before and after and valid ssid and valid seen flag" do
-      hop = Apex::Hop.new(" WI2ARD   ", 2, true)
+      hop = Apex::ImmutableHop.new(" WI2ARD   ", 2, true)
       it "strips the extra spaces" do
         expect(hop.callsign).to eql("WI2ARD")
       end
@@ -193,7 +193,7 @@ describe Apex::Hop do
   end
   describe ".from_raw" do
     context "Given a valid callsign with ssid and with seen flag" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "returns a FrameHop object" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -209,7 +209,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign with ssid and without seen flag" do
-      hop = Apex::Hop.from_raw(UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(UNSEEN_HOP)
       it "returns a FrameHop object" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -225,7 +225,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign with 0 ssid and with seen flag" do
-      hop = Apex::Hop.from_raw(ZEROSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(ZEROSSID_HOP)
       it "returns a FrameHop object" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -241,7 +241,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign with nil ssid and with seen flag" do
-      hop = Apex::Hop.from_raw(NOSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(NOSSID_HOP)
       it "returns a FrameHop object" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -257,7 +257,7 @@ describe Apex::Hop do
       end
     end
     context "Given a valid callsign without ssid and without seen flag" do
-      hop = Apex::Hop.from_raw(NOSSID_UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(NOSSID_UNSEEN_HOP)
       it "returns a FrameHop object" do
         expect(hop).not_to be_nil
         expect(hop).to be_kind_of(Apex::Hop)
@@ -275,47 +275,47 @@ describe Apex::Hop do
     context "Given an invalid callsign with valid ssid and valid seen flag" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.from_raw(BAD_CALLSIGN_HOP)
+          hop = Apex::ImmutableHop.from_raw(BAD_CALLSIGN_HOP)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a hop with two hyphens" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.from_raw(BAD_HYPHEN_HOP)
+          hop = Apex::ImmutableHop.from_raw(BAD_HYPHEN_HOP)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a hop with a hyphen but no ssid" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.from_raw(BAD_HYPHEN_NOSSID_HOP)
+          hop = Apex::ImmutableHop.from_raw(BAD_HYPHEN_NOSSID_HOP)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a hop with a an ssid greater than 15" do
       it "throws an argument error" do
         expect {
-          hop = Apex::Hop.from_raw(BAD_HIGHSSID_HOP)
+          hop = Apex::ImmutableHop.from_raw(BAD_HIGHSSID_HOP)
         }.to raise_error(ArgumentError)
       end
     end
   end
   describe ".callsign" do
     context "Given a FrameHop with valid callsign and with an ssid" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "then the callsign should be frozen" do
         expect(hop.callsign).to be_frozen
       end
     end
     context "Given a FrameHop with valid callsign and without an ssid" do
-      hop = Apex::Hop.from_raw(NOSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(NOSSID_HOP)
       it "then the callsign should be frozen" do
         expect(hop.callsign).to be_frozen
       end
     end
     context "Given any valid FrameHop" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "then we should not be able to set a value" do
         expect {
           hop.callsign = "BAD1B"
@@ -329,7 +329,7 @@ describe Apex::Hop do
       it "then the callsign passed to from_raw should be duplicated" do
         passed_call = "WI2AR"
         orig_call = passed_call.dup.freeze
-        hop = Apex::Hop.from_raw(passed_call)
+        hop = Apex::ImmutableHop.from_raw(passed_call)
         passed_call << "D"
         expect(hop.callsign).to eql(orig_call)
         expect(passed_call).to eql("WI2ARD")
@@ -339,7 +339,7 @@ describe Apex::Hop do
   end
   describe ".ssid" do
     context "Given any valid FrameHop" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "then we should not be able to set a value" do
         expect {
           hop.ssid = "1"
@@ -354,7 +354,7 @@ describe Apex::Hop do
   end
   describe ".seen" do
     context "Given any valid FrameHop" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "then we should not be able to set a value" do
         expect {
           hop.seen = false
@@ -364,7 +364,7 @@ describe Apex::Hop do
   end
   describe ".toggle_seen" do
     context "Given a FrameHop that has been seen" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       context "which has its seen flag toggled" do
         toggled_hop = hop.toggle_seen
         it "should produce a duplicated FrameHop" do
@@ -379,7 +379,7 @@ describe Apex::Hop do
       end
     end
     context "Given a FrameHop that has not been seen" do
-      hop = Apex::Hop.from_raw(UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(UNSEEN_HOP)
       context "which has its seen flag toggled" do
         new_hop = hop.toggle_seen
         it "should produce a duplicated FrameHop" do
@@ -396,7 +396,7 @@ describe Apex::Hop do
   end
   describe ".decrement_ssid" do
     context "Given a FrameHop that has a greater than 0 SSID" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       context "which has its ssid decremented" do
         new_hop = hop.decrement_ssid
         it "should produce a duplicated FrameHop" do
@@ -411,7 +411,7 @@ describe Apex::Hop do
       end
     end
     context "Given a FrameHop that has a SSID of 0" do
-      hop = Apex::Hop.from_raw(ZEROSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(ZEROSSID_HOP)
       context "which has its ssid decremented" do
         it "throws a range error" do
           expect{
@@ -423,67 +423,67 @@ describe Apex::Hop do
   end
   describe ".to_s" do
     context "Given a raw string with valid callsign with ssid and with seen flag" do
-      hop = Apex::Hop.from_raw(BASE_HOP)
+      hop = Apex::ImmutableHop.from_raw(BASE_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(BASE_HOP)
       end
     end
     context "Given a raw string with valid callsign with non-zero ssid and without seen flag" do
-      hop = Apex::Hop.from_raw(UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(UNSEEN_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(UNSEEN_HOP)
       end
     end
     context "Given a raw string with valid callsign with ssid of zero and without seen flag" do
-      hop = Apex::Hop.from_raw(ZEROSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(ZEROSSID_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_HOP)
       end
     end
     context "Given a raw string with valid callsign without ssid and with seen flag" do
-      hop = Apex::Hop.from_raw(NOSSID_HOP)
+      hop = Apex::ImmutableHop.from_raw(NOSSID_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_HOP)
       end
     end
     context "Given a raw string with valid callsign without ssid and without seen flag" do
-      hop = Apex::Hop.from_raw(NOSSID_UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(NOSSID_UNSEEN_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_UNSEEN_HOP)
       end
     end
     context "Given a raw string with valid callsign with ssid of 0 and without seen flag" do
-      hop = Apex::Hop.from_raw(ZEROSSID_UNSEEN_HOP)
+      hop = Apex::ImmutableHop.from_raw(ZEROSSID_UNSEEN_HOP)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_UNSEEN_HOP)
       end
     end
     context "Given a FrameHop from new with valid callsign with non-zero ssid and with seen flag" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(BASE_HOP)
       end
     end
     context "Given a FrameHop from new with valid callsign with non-zero ssid and without seen flag" do
-      hop = Apex::Hop.new(UNSEEN_HOP_CALLSIGN, UNSEEN_HOP_SSID, UNSEEN_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(UNSEEN_HOP_CALLSIGN, UNSEEN_HOP_SSID, UNSEEN_HOP_SEEN)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(UNSEEN_HOP)
       end
     end
     context "Given a FrameHop from new with valid callsign with nil ssid and with seen flag" do
-      hop = Apex::Hop.new(NOSSID_HOP_CALLSIGN, NOSSID_HOP_SSID, NOSSID_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(NOSSID_HOP_CALLSIGN, NOSSID_HOP_SSID, NOSSID_HOP_SEEN)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_HOP)
       end
     end
     context "Given a FrameHop from new with valid callsign with ssid of 0 and with seen flag" do
-      hop = Apex::Hop.new(ZEROSSID_HOP_CALLSIGN, ZEROSSID_HOP_SSID, ZEROSSID_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(ZEROSSID_HOP_CALLSIGN, ZEROSSID_HOP_SSID, ZEROSSID_HOP_SEEN)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_HOP)
       end
     end
     context "Given a FrameHop from new with valid callsign with ssid of zero and without seen flag" do
-      hop = Apex::Hop.new(ZEROSSID_UNSEEN_HOP_CALLSIGN, ZEROSSID_UNSEEN_HOP_SSID, ZEROSSID_UNSEEN_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(ZEROSSID_UNSEEN_HOP_CALLSIGN, ZEROSSID_UNSEEN_HOP_SSID, ZEROSSID_UNSEEN_HOP_SEEN)
       it "then we should produce the correct string" do
         expect(hop.to_s).to eql(NOSSID_UNSEEN_HOP)
       end
@@ -493,15 +493,15 @@ describe Apex::Hop do
   describe ".==" do
     context "Given one Hop and an equivelant non-Hop class with the same properties" do
       hop_equiv = HopEquiv.new
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
       it "then equality should return true" do
         expect(hop == hop_equiv).to be_truthy
       end
     end
 
     context "Given two equivelant hops both instaces of Hop class with the same properties" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
-      hop_equiv = Apex::Hop.new(BASE_HOP_CALLSIGN, nil, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
+      hop_equiv = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, nil, BASE_HOP_SEEN)
       it "then equality should return true" do
         expect(hop == hop_equiv).to be_truthy
       end
@@ -509,15 +509,15 @@ describe Apex::Hop do
 
     context "Given one Hop and a equivelant non-Hop class with different properties" do
       hop_equiv = HopEquiv.new
-      hop = Apex::Hop.new("BADCALL", BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new("BADCALL", BASE_HOP_SSID, BASE_HOP_SEEN)
       it "then equality should return true" do
         expect(hop == hop_equiv).to be_falsey
       end
     end
 
     context "Given two equivelant hops both instaces of Hop class with different properties" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
-      hop_equiv = Apex::Hop.new("BADCALL", nil, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
+      hop_equiv = Apex::ImmutableHop.new("BADCALL", nil, BASE_HOP_SEEN)
       it "then equality should return true" do
         expect(hop == hop_equiv).to be_falsey
       end
@@ -527,7 +527,7 @@ describe Apex::Hop do
   describe ".eql?" do
     context "Given one Hop and an equivelant non-Hop class with the same properties" do
       hop_equiv = HopEquiv.new
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, BASE_HOP_SSID, BASE_HOP_SEEN)
       it "throws an ArgumentError" do
         expect {
           hop.eql? hop_equiv
@@ -536,8 +536,8 @@ describe Apex::Hop do
     end
 
     context "Given two equivelant hops both instaces of Hop class" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
-      hop_equiv = Apex::Hop.new(BASE_HOP_CALLSIGN, nil, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
+      hop_equiv = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, nil, BASE_HOP_SEEN)
       it "then eql should return true" do
         expect(hop.eql? hop_equiv).to be_truthy
       end
@@ -545,7 +545,7 @@ describe Apex::Hop do
 
     context "Given one Hop and a equivelant non-Hop class with different properties" do
       hop_equiv = HopEquiv.new
-      hop = Apex::Hop.new("BADCALL", BASE_HOP_SSID, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new("BADCALL", BASE_HOP_SSID, BASE_HOP_SEEN)
       it "throws an ArgumentError" do
         expect {
           hop.eql? hop_equiv
@@ -554,8 +554,8 @@ describe Apex::Hop do
     end
 
     context "Given two equivelant hops both instaces of Hop class with different properties" do
-      hop = Apex::Hop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
-      hop_equiv = Apex::Hop.new("BADCALL", nil, BASE_HOP_SEEN)
+      hop = Apex::ImmutableHop.new(BASE_HOP_CALLSIGN, 0, BASE_HOP_SEEN)
+      hop_equiv = Apex::ImmutableHop.new("BADCALL", nil, BASE_HOP_SEEN)
       it "then eql should return false" do
         expect(hop.eql? hop_equiv).to be_falsey
       end
diff --git a/spec/apex/frame/path_spec.rb b/spec/apex/frame/path_spec.rb
index 9b77fa45440548302b9072778d0355fbdce8538e..be8a5add70d6e8eb346d8c34cb5acb92f967609a 100644
--- a/spec/apex/frame/path_spec.rb
+++ b/spec/apex/frame/path_spec.rb
@@ -5,27 +5,27 @@ describe Apex::Path do
     context "Given no arguments" do
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.new()
+          path = Apex::ImmutablePath.new()
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a single nil argument" do
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.new(nil)
+          path = Apex::ImmutablePath.new(nil)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a single non-Hop argument" do
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.new(5)
+          path = Apex::ImmutablePath.new(5)
         }.to raise_error(ArgumentError)
       end
     end
     context "Given a single valid hop" do
-      hop = Apex::Hop.new("WI2ARD", 4, true)
-      path = Apex::Path.new(hop)
+      hop = Apex::ImmutableHop.new("WI2ARD", 4, true)
+      path = Apex::ImmutablePath.new(hop)
       it "instantiates a Path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -41,14 +41,14 @@ describe Apex::Path do
       end
       it "the Path can not be appended" do
         expect {
-          path << Apex::Hop.from_raw("NO4CALL-6")
+          path << Apex::ImmutableHop.from_raw("NO4CALL-6")
         }.to raise_error(NoMethodError)
       end
     end
     context "Given two valid hops" do
-      hop1 = Apex::Hop.new("WI2ARD", 4, true)
-      hop2 = Apex::Hop.new("K3TXD", 0, false)
-      path = Apex::Path.new(hop1, hop2)
+      hop1 = Apex::ImmutableHop.new("WI2ARD", 4, true)
+      hop2 = Apex::ImmutableHop.new("K3TXD", 0, false)
+      path = Apex::ImmutablePath.new(hop1, hop2)
       it "instantiates a Path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -63,11 +63,11 @@ describe Apex::Path do
     end
 
     context "Given two hops where the first is unseen and second is seen" do
-      hop1 = Apex::Hop.new("WI2ARD", 4, false)
-      hop2 = Apex::Hop.new("K3TXD", 0, true)
+      hop1 = Apex::ImmutableHop.new("WI2ARD", 4, false)
+      hop2 = Apex::ImmutableHop.new("K3TXD", 0, true)
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.new(hop1, hop2)
+          path = Apex::ImmutablePath.new(hop1, hop2)
         }.to raise_error(ArgumentError)
       end
     end
@@ -75,7 +75,7 @@ describe Apex::Path do
 
   describe ".from_raw" do
     context "Given an array of two valid hops as strings" do
-      path = Apex::Path.from_raw(['WIDE2-2', "WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(['WIDE2-2', "WI2ARD"])
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -89,7 +89,7 @@ describe Apex::Path do
       end
     end
     context "Given an array of a single valid hop as a string" do
-      path = Apex::Path.from_raw(['WIDE2-2'])
+      path = Apex::ImmutablePath.from_raw(['WIDE2-2'])
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -102,7 +102,7 @@ describe Apex::Path do
       end
     end
     context "Given a single string of two valid hops" do
-      path = Apex::Path.from_raw("WIDE2-2,WI2ARD")
+      path = Apex::ImmutablePath.from_raw("WIDE2-2,WI2ARD")
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -116,7 +116,7 @@ describe Apex::Path do
       end
     end
     context "Given a single string for a single valid hop" do
-      path = Apex::Path.from_raw("WIDE2-2")
+      path = Apex::ImmutablePath.from_raw("WIDE2-2")
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -129,7 +129,7 @@ describe Apex::Path do
       end
     end
     context "Given an array of two hops as strings with space as padding" do
-      path = Apex::Path.from_raw(['  WIDE2-2   ', " WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(['  WIDE2-2   ', " WI2ARD"])
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -143,7 +143,7 @@ describe Apex::Path do
       end
     end
     context "Given a single string of two valid hops with space as padding" do
-      path = Apex::Path.from_raw("  WIDE2-2   , WI2ARD")
+      path = Apex::ImmutablePath.from_raw("  WIDE2-2   , WI2ARD")
       it "instantiates a path" do
         expect(path).to_not be_nil
         expect(path).to be_kind_of(Apex::Path)
@@ -159,14 +159,14 @@ describe Apex::Path do
     context "Given an array of two hops as strings with invalid commas appended" do
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.from_raw(['WIDE2-2,', "WI2ARD"])
+          path = Apex::ImmutablePath.from_raw(['WIDE2-2,', "WI2ARD"])
         }.to raise_error(ArgumentError)
       end
     end
     context "Given an array of a single element but with two hops as a single string" do
       it "throws an ArgumentError" do
         expect {
-          path = Apex::Path.from_raw(["WIDE2-2,WI2ARD"])
+          path = Apex::ImmutablePath.from_raw(["WIDE2-2,WI2ARD"])
         }.to raise_error(ArgumentError)
       end
     end
@@ -174,7 +174,7 @@ describe Apex::Path do
 
   describe ".each" do
     context "Given a valid path with two hops" do
-      path = Apex::Path.from_raw(["WIDE2-2", "WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(["WIDE2-2", "WI2ARD"])
       it "can be iterated over twice but no more" do
         hop_count = 0
         path.each do |hop|
@@ -187,19 +187,19 @@ describe Apex::Path do
 
   describe ".[]" do
     context "Given a valid path with two hops" do
-      path = Apex::Path.from_raw(["WIDE2-2", "WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(["WIDE2-2", "WI2ARD"])
       it "the first hop can be referenced via array notation" do
-        expect(path[0]).to eql(Apex::Hop.from_raw("WIDE2-2"))
+        expect(path[0]).to eql(Apex::ImmutableHop.from_raw("WIDE2-2"))
       end
       it "the second hop can be referenced via array notation" do
-        expect(path[1]).to eql(Apex::Hop.from_raw("WI2ARD"))
+        expect(path[1]).to eql(Apex::ImmutableHop.from_raw("WI2ARD"))
       end
     end
   end
 
   describe ".length" do
     context "Given a valid path with two hops" do
-      path = Apex::Path.from_raw(["WIDE2-2", "WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(["WIDE2-2", "WI2ARD"])
       it "the length should be exactly 2" do
         expect(path.length).to eql(2)
       end
@@ -208,7 +208,7 @@ describe Apex::Path do
 
   describe ".to_s" do
     context "Given a valid path with two hops" do
-      path = Apex::Path.from_raw(["WIDE2-2", "WI2ARD"])
+      path = Apex::ImmutablePath.from_raw(["WIDE2-2", "WI2ARD"])
       it "the string should represent the path" do
         expect(path.to_s).to eql("WIDE2-2,WI2ARD")
       end
@@ -217,7 +217,7 @@ describe Apex::Path do
 
   describe ".to_string_array" do
     context "Given a valid path with two hops" do
-      let(:path) {Apex::Path.from_raw("WIDE2-2,WI2ARD")}
+      let(:path) {Apex::ImmutablePath.from_raw("WIDE2-2,WI2ARD")}
       it "do" do
         expect(path.to_string_array).to eql(["WIDE2-2", "WI2ARD"])
       end