xml_active 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +52 -6
- data/lib/xml_active.rb +146 -50
- data/lib/xml_active/version.rb +1 -1
- metadata +40 -66
    
        data/README.rdoc
    CHANGED
    
    | @@ -84,7 +84,7 @@ XML Active relies on the XML documents created by ActiveRecord in that it utilis | |
| 84 84 |  | 
| 85 85 | 
             
            === Database Schema
         | 
| 86 86 |  | 
| 87 | 
            -
            XML Active will detect the primary key of the tables in your schema even if is a name other than  | 
| 87 | 
            +
            XML Active will detect the primary key of the tables in your schema even if is a name other than <b>id</b>.  It will use the primary key to match records for update or deletion or creation when they don't exist.  Given this it's very important that the tables that you wish to synchronise have a primary key with auto increment.  The good news is by default Rails will create a primary key field called <b>id</b> that is auto-increment.  At this time XML Active doesn't support compound primary keys.
         | 
| 88 88 |  | 
| 89 89 | 
             
            === The Model
         | 
| 90 90 |  | 
| @@ -110,7 +110,7 @@ At this stage XML Active has been tested with a limited number of associations. | |
| 110 110 |  | 
| 111 111 | 
             
            == Examples
         | 
| 112 112 |  | 
| 113 | 
            -
            Now to the meaty part, the examples.  XML Active currenly uses "Nokogiri" | 
| 113 | 
            +
            Now to the meaty part, the examples.  XML Active currenly uses "Nokogiri"(http://nokogiri.org/) to do its XML parsing so you can provide either a <b>Nokogiri::XML::Element</b> or raw XML.
         | 
| 114 114 |  | 
| 115 115 | 
             
            === New Functions
         | 
| 116 116 |  | 
| @@ -154,11 +154,57 @@ Following is an example: | |
| 154 154 |  | 
| 155 155 | 
             
            You can combine any of the options (:create, :update or :destroy) and XML Active will only perform the actions provided in the options.  However if you use the :sync option then all other options are ignored.  Following are the current options:
         | 
| 156 156 |  | 
| 157 | 
            -
            *  | 
| 157 | 
            +
            * <b>:update</b> records in the database that match those in the provided XML document based on classes in the model, associations and the primary key.
         | 
| 158 158 |  | 
| 159 | 
            -
            *  | 
| 159 | 
            +
            * <b>:create</b> records in the database that exist in the provided XML document but not in the database. Matching is based on classes in the model, associations and the primary key.
         | 
| 160 160 |  | 
| 161 | 
            -
            *  | 
| 161 | 
            +
            * <b>:destroy</b> records in the database that don't exist in the provided XML document. Matching is based on classes in the model, associations and the primary key.  This respects validation by using the ActiveRecord destroy rather than delete.
         | 
| 162 162 |  | 
| 163 | 
            -
            *  | 
| 163 | 
            +
            * <b>:sync</b> is really the combination of :create, :update and :destroy. Using this option will cause XML Active to ignore :create, :update and :destroy options and will proceed to make your database records match those in the XML document.
         | 
| 164 164 |  | 
| 165 | 
            +
            === One to One Associations
         | 
| 166 | 
            +
            XML Active supports has_one association with all options and following arr the behaviours of XML Active with each option:
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            <b>:update</b>
         | 
| 169 | 
            +
             | 
| 170 | 
            +
            * <i>Record exists in XML but not in DB</i>: No Action
         | 
| 171 | 
            +
            * <i>Record exists in DB but not in XML</i>: No Action
         | 
| 172 | 
            +
            * <i>Record exists in XML and in DB</i>: DB record is updated if identifying features (eg id) match
         | 
| 173 | 
            +
             | 
| 174 | 
            +
            <b>:create</b>
         | 
| 175 | 
            +
             | 
| 176 | 
            +
            * <i>Record exists in XML but not in DB</i>: A new record in the DB is created
         | 
| 177 | 
            +
            * <i>Record exists in DB but not in XML</i>: No Action
         | 
| 178 | 
            +
            * <i>Record exists in XML and in DB</i>: No Action
         | 
| 179 | 
            +
             | 
| 180 | 
            +
            <b>:destroy</b>
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            * <i>Record exists in XML but not in DB</i>: No Action
         | 
| 183 | 
            +
            * <i>Record exists in DB but not in XML</i>: The DB Record is Destroyed
         | 
| 184 | 
            +
            * <i>Record exists in XML and in DB</i>: DB record is destroyed if identifying features (eg id) don't match
         | 
| 185 | 
            +
             | 
| 186 | 
            +
            <b>:sync</b>
         | 
| 187 | 
            +
             | 
| 188 | 
            +
            * <i>Record exists in XML but not in DB</i>: A new record in the DB is created
         | 
| 189 | 
            +
            * <i>Record exists in DB but not in XML</i>: The DB Record is Destroyed
         | 
| 190 | 
            +
            * <i>Record exists in XML and in DB</i>: DB record is replaced if identifying features (eg id) don't match but if they do then the DB record is updated
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            === Versions
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            * 0.0.2 First Release
         | 
| 195 | 
            +
            * 0.0.3 Addition of support for One to One associations and various bug fixes
         | 
| 196 | 
            +
             | 
| 197 | 
            +
            === Future Features
         | 
| 198 | 
            +
             | 
| 199 | 
            +
            * <b>Dry Run</b> allow xml_active to do a dry run and report potentail changes rather than making them
         | 
| 200 | 
            +
            * <b>Events</b> Event hooks in key locations
         | 
| 201 | 
            +
            * <b>Selective Upates</b> Specify a set of active record objects to effect and leave all the rest alone
         | 
| 202 | 
            +
            * <b>Many to Many</b> Tested support for has_and_belongs_to_many
         | 
| 203 | 
            +
            * <b>Polymorphic Associations</b> Tested support for these associations
         | 
| 204 | 
            +
             | 
| 205 | 
            +
            === Testing
         | 
| 206 | 
            +
            In order to perform testing I created an application specifically for the task.  The resulting application is stored on GitHub: https://github.com/michael-harrison/xml_active_bubble
         | 
| 207 | 
            +
             | 
| 208 | 
            +
            At this stage xml_active has been tested with Rails 3.0.7, 3.1.0 and 3.2.2
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            This testing will be incorporated in the primary repo in the next major release
         | 
    
        data/lib/xml_active.rb
    CHANGED
    
    | @@ -23,21 +23,36 @@ module XmlActive | |
| 23 23 | 
             
                  end
         | 
| 24 24 |  | 
| 25 25 | 
             
                  records = []
         | 
| 26 | 
            -
                  if self. | 
| 26 | 
            +
                  if self.name.pluralize.underscore.eql? current_node.name.underscore
         | 
| 27 27 | 
             
                    ids = []
         | 
| 28 | 
            -
             | 
| 28 | 
            +
             | 
| 29 | 
            +
                    if current_node.attributes['type'].try(:value) == "array"
         | 
| 29 30 | 
             
                      current_node.element_children.each do |node|
         | 
| 30 31 | 
             
                        record = self.one_from_xml(node, options)
         | 
| 31 | 
            -
                         | 
| 32 | 
            -
             | 
| 32 | 
            +
                        if record
         | 
| 33 | 
            +
                          ids[ids.length] = record[primary_key.to_sym]
         | 
| 34 | 
            +
                          records[records.length] = record
         | 
| 35 | 
            +
                        end
         | 
| 33 36 | 
             
                      end
         | 
| 34 37 | 
             
                    else
         | 
| 35 | 
            -
                      records[records.length] = self.one_from_xml | 
| 38 | 
            +
                      records[records.length] = self.one_from_xml current_node
         | 
| 36 39 | 
             
                    end
         | 
| 37 40 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 41 | 
            +
             | 
| 42 | 
            +
                    if options.include?(:sync)
         | 
| 43 | 
            +
                      if ids.length > 0
         | 
| 44 | 
            +
                        self.destroy_all [self.primary_key.to_s + " not in (?)", ids.collect]
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    elsif options.include?(:destroy)
         | 
| 47 | 
            +
                      if ids.length > 0
         | 
| 48 | 
            +
                        self.destroy_all [self.primary_key.to_s + " not in (?)", ids.collect]
         | 
| 49 | 
            +
                      else
         | 
| 50 | 
            +
                        self.destroy_all
         | 
| 51 | 
            +
                      end
         | 
| 40 52 | 
             
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  elsif self.name.underscore.equ current_node.name.underscore
         | 
| 55 | 
            +
                    raise "The supplied XML (#{current_node.name}) is a single instance of '#{self.name}'. Please use one_from_xml"
         | 
| 41 56 | 
             
                  else
         | 
| 42 57 | 
             
                    raise "The supplied XML (#{current_node.name}) cannot be mapped to this class (#{self.name})"
         | 
| 43 58 | 
             
                  end
         | 
| @@ -46,60 +61,150 @@ module XmlActive | |
| 46 61 | 
             
                end
         | 
| 47 62 |  | 
| 48 63 | 
             
                def one_from_xml(xml, options = [])
         | 
| 49 | 
            -
                  if xml.is_a? | 
| 50 | 
            -
                    doc = Nokogiri::XML | 
| 64 | 
            +
                  if xml.is_a? String
         | 
| 65 | 
            +
                    doc = Nokogiri::XML xml
         | 
| 51 66 | 
             
                    current_node = doc.children.first
         | 
| 52 67 | 
             
                  else
         | 
| 53 68 | 
             
                    current_node = xml
         | 
| 54 69 | 
             
                  end
         | 
| 55 70 |  | 
| 56 | 
            -
                  if  | 
| 71 | 
            +
                  if xml_node_matches_class(current_node)
         | 
| 72 | 
            +
                    # Load or create a new record
         | 
| 57 73 | 
             
                    pk_value = 0
         | 
| 58 | 
            -
                    pk_node = current_node.xpath | 
| 74 | 
            +
                    pk_node = current_node.xpath self.primary_key.to_s
         | 
| 59 75 | 
             
                    if pk_node
         | 
| 60 76 | 
             
                      begin
         | 
| 61 | 
            -
                        ar = find | 
| 77 | 
            +
                        ar = find pk_node.text
         | 
| 62 78 | 
             
                        pk_value = pk_node.text
         | 
| 63 79 | 
             
                      rescue
         | 
| 64 80 | 
             
                        # No record exists, create a new one
         | 
| 65 | 
            -
                         | 
| 81 | 
            +
                        if options.include?(:sync) or options.include?(:create)
         | 
| 82 | 
            +
                          ar = self.new
         | 
| 83 | 
            +
                        else
         | 
| 84 | 
            +
                          # must have only have :destroy and/or :update so exit
         | 
| 85 | 
            +
                          return nil
         | 
| 86 | 
            +
                        end
         | 
| 66 87 | 
             
                      end
         | 
| 67 88 | 
             
                    else
         | 
| 68 89 | 
             
                      # No primary key value, must be a new record
         | 
| 69 | 
            -
                       | 
| 90 | 
            +
                      if options.include?(:sync) or options.include?(:create)
         | 
| 91 | 
            +
                        ar = self.new
         | 
| 92 | 
            +
                      else
         | 
| 93 | 
            +
                        # must have only have :destroy and/or :update so exit
         | 
| 94 | 
            +
                        return nil
         | 
| 95 | 
            +
                      end
         | 
| 70 96 | 
             
                    end
         | 
| 71 97 |  | 
| 72 | 
            -
                     | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 98 | 
            +
                    # Check through associations and apply sync appropriately
         | 
| 99 | 
            +
                    self.reflect_on_all_associations.each do |association|
         | 
| 100 | 
            +
                      if ActiveRecord::Reflection::AssociationReflection.method_defined? :foreign_key
         | 
| 101 | 
            +
                        # Support for Rails 3.1 and later
         | 
| 102 | 
            +
                        foreign_key = association.foreign_key
         | 
| 103 | 
            +
                      elsif ActiveRecord::Reflection::AssociationReflection.method_defined? :primary_key_name
         | 
| 104 | 
            +
                        # Support for Rails earlier than 3.1
         | 
| 105 | 
            +
                        foreign_key = association.primary_key_name
         | 
| 106 | 
            +
                      else
         | 
| 107 | 
            +
                        raise "Unsupported version of ActiveRecord. Unable to identify the foreign key."
         | 
| 108 | 
            +
                      end
         | 
| 109 | 
            +
                      case
         | 
| 110 | 
            +
                        when association.macro == :has_many, association.macro == :has_and_belongs_to_many
         | 
| 111 | 
            +
                          # Check to see if xml contains elements for the association
         | 
| 112 | 
            +
                          if pk_value == 0
         | 
| 113 | 
            +
                            containers = current_node.xpath("//#{self.name.underscore}[#{self.primary_key}=#{pk_node.text}]/#{association.name}")
         | 
| 114 | 
            +
                          else
         | 
| 115 | 
            +
                            containers = current_node.xpath("//#{self.name.underscore}[#{self.primary_key}=#{pk_value}]/#{association.name}")
         | 
| 116 | 
            +
                          end
         | 
| 117 | 
            +
                          if containers.count > 0
         | 
| 118 | 
            +
                            container = containers[0]
         | 
| 119 | 
            +
                            klass = association.klass
         | 
| 120 | 
            +
                            child_ids = []
         | 
| 121 | 
            +
                            container.element_children.each do |single_obj|
         | 
| 122 | 
            +
                              # TODO: Allow for child node that doesn't have a primary key value
         | 
| 123 | 
            +
                              child_ids[child_ids.length] = single_obj.xpath(self.primary_key.to_s).text
         | 
| 124 | 
            +
                              new_record = klass.one_from_xml(single_obj, options)
         | 
| 125 | 
            +
                              if (new_record != nil)
         | 
| 126 | 
            +
                                ar.__send__(container.name.underscore.to_sym) << new_record
         | 
| 127 | 
            +
                              end
         | 
| 128 | 
            +
                            end
         | 
| 75 129 |  | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 130 | 
            +
                            if pk_value != 0
         | 
| 131 | 
            +
                              if options.include?(:sync)
         | 
| 132 | 
            +
                                if child_ids.length > 0
         | 
| 133 | 
            +
                                  klass.destroy_all [klass.primary_key.to_s + " not in (?) and #{foreign_key} = ?", child_ids.collect, pk_value]
         | 
| 134 | 
            +
                                end
         | 
| 135 | 
            +
                              elsif options.include?(:destroy)
         | 
| 136 | 
            +
                                if child_ids.length > 0
         | 
| 137 | 
            +
                                  klass.destroy_all [klass.primary_key.to_s + " not in (?) and #{foreign_key} = ?", child_ids.collect, pk_value]
         | 
| 138 | 
            +
                                else
         | 
| 139 | 
            +
                                  klass.destroy_all
         | 
| 140 | 
            +
                                end
         | 
| 141 | 
            +
                              end
         | 
| 142 | 
            +
                            end
         | 
| 143 | 
            +
                          end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                        when association.macro == :has_one
         | 
| 146 | 
            +
                          single_objects = current_node.xpath("//#{self.name.underscore}[#{self.primary_key}=#{pk_value}]/#{association.name}")
         | 
| 83 147 | 
             
                          klass = association.klass
         | 
| 84 | 
            -
                           | 
| 85 | 
            -
                           | 
| 86 | 
            -
                             | 
| 87 | 
            -
                             | 
| 88 | 
            -
             | 
| 89 | 
            -
                               | 
| 148 | 
            +
                          record = klass.where(foreign_key => pk_value).all
         | 
| 149 | 
            +
                          if single_objects.count == 1
         | 
| 150 | 
            +
                            # Check to see if the already record exists
         | 
| 151 | 
            +
                            if record.count == 1
         | 
| 152 | 
            +
                              db_pk_value = record[0][klass.primary_key]
         | 
| 153 | 
            +
                              xml_pk_value = Integer(single_objects[0].element_children.xpath("//#{self.name.underscore}/#{klass.primary_key}").text)
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                              if db_pk_value != xml_pk_value
         | 
| 156 | 
            +
                                # Different record in xml
         | 
| 157 | 
            +
                                if options.include?(:sync) or options.include?(:destroy)
         | 
| 158 | 
            +
                                  # Delete the one in the database
         | 
| 159 | 
            +
                                  klass.destroy(record[0][klass.primary_key])
         | 
| 160 | 
            +
                                end
         | 
| 161 | 
            +
                              end
         | 
| 162 | 
            +
                            elsif record.count > 1
         | 
| 163 | 
            +
                              raise "Too many records for one to one association in the database. Found #{record.count} records of '#{association.name}' for association with '#{self.name}'"
         | 
| 164 | 
            +
                            end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                            if options.include?(:create) or options.include?(:update) or options.include?(:sync)
         | 
| 167 | 
            +
                              new_record = klass.one_from_xml(single_objects[0], options)
         | 
| 168 | 
            +
                              if new_record != nil
         | 
| 169 | 
            +
                                new_record[foreign_key.to_sym] = ar[self.primary_key]
         | 
| 170 | 
            +
                                new_record.save!
         | 
| 171 | 
            +
                              end
         | 
| 172 | 
            +
                            end
         | 
| 173 | 
            +
                          elsif single_objects.count > 1
         | 
| 174 | 
            +
                            # There are more than one associations
         | 
| 175 | 
            +
                            raise "Too many records for one to one association in the provided XML. Found #{single_objects.count} records of '#{association.name}' for association with '#{self.name}'"
         | 
| 176 | 
            +
                          else
         | 
| 177 | 
            +
                            # There are no records in the XML
         | 
| 178 | 
            +
                            if record.count > 0 and options.include?(:sync) or options.include?(:destroy)
         | 
| 179 | 
            +
                              # Found some in the database: destroy then
         | 
| 180 | 
            +
                              klass.destroy_all("#{foreign_key} = #{pk_value}")
         | 
| 90 181 | 
             
                            end
         | 
| 91 182 | 
             
                          end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 183 | 
            +
             | 
| 184 | 
            +
                        when association.macro == :belongs_to
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                        else
         | 
| 187 | 
            +
                          raise "unsupported association #{association.macro} for #{association.name  } on #{self.name}"
         | 
| 188 | 
            +
                      end
         | 
| 189 | 
            +
                    end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                    if options.include? :update or options.include? :sync or options.include? :create
         | 
| 192 | 
            +
                      # Process the attributes
         | 
| 193 | 
            +
                      current_node.element_children.each do |node|
         | 
| 194 | 
            +
                        node_name = node.name.underscore.to_sym
         | 
| 195 | 
            +
                        association = self.reflect_on_association node_name
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                        if association.nil?
         | 
| 198 | 
            +
                          if node.attributes['nil'].try(:value)
         | 
| 199 | 
            +
                            ar[node_name] = nil
         | 
| 200 | 
            +
                          else
         | 
| 201 | 
            +
                            ar[node_name] = node.text
         | 
| 94 202 | 
             
                          end
         | 
| 95 203 | 
             
                        end
         | 
| 96 | 
            -
                      else
         | 
| 97 | 
            -
                        # Attribute
         | 
| 98 | 
            -
                        ar[sym] = node.text
         | 
| 99 204 | 
             
                      end
         | 
| 100 205 | 
             
                    end
         | 
| 101 206 |  | 
| 102 | 
            -
                    if options.include? | 
| 207 | 
            +
                    if options.include? :sync
         | 
| 103 208 | 
             
                      # Doing complete synchronisation with XML
         | 
| 104 209 | 
             
                      ar.save
         | 
| 105 210 | 
             
                    elsif options.include?(:create) and ar.new_record?
         | 
| @@ -114,20 +219,11 @@ module XmlActive | |
| 114 219 | 
             
                  end
         | 
| 115 220 | 
             
                end
         | 
| 116 221 |  | 
| 117 | 
            -
                def  | 
| 118 | 
            -
                   | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
                def xml_node_matches_many_of_class(xml_node)
         | 
| 122 | 
            -
                  self.name.pluralize.downcase.eql?(xml_node.name.downcase)
         | 
| 123 | 
            -
                end
         | 
| 124 | 
            -
             | 
| 125 | 
            -
                def xml_node_is_association(xml_node)
         | 
| 126 | 
            -
                  attr = xml_node.attributes["type"]
         | 
| 127 | 
            -
                  if (attr)
         | 
| 128 | 
            -
                    attr.value == "array"
         | 
| 222 | 
            +
                def xml_node_matches_class(xml_node)
         | 
| 223 | 
            +
                  if xml_node.attributes['type'].blank?
         | 
| 224 | 
            +
                    xml_node.name.underscore == self.name.underscore
         | 
| 129 225 | 
             
                  else
         | 
| 130 | 
            -
                     | 
| 226 | 
            +
                    xml_node.attributes['type'].value.underscore == self.name.underscore
         | 
| 131 227 | 
             
                  end
         | 
| 132 228 | 
             
                end
         | 
| 133 229 | 
             
              end
         | 
| @@ -135,4 +231,4 @@ end | |
| 135 231 |  | 
| 136 232 | 
             
            class ActiveRecord::Base
         | 
| 137 233 | 
             
              include XmlActive
         | 
| 138 | 
            -
            end
         | 
| 234 | 
            +
            end
         | 
    
        data/lib/xml_active/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,61 +1,46 @@ | |
| 1 | 
            -
            --- !ruby/object:Gem::Specification | 
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: xml_active
         | 
| 3 | 
            -
            version: !ruby/object:Gem::Version | 
| 4 | 
            -
               | 
| 5 | 
            -
              prerelease:  | 
| 6 | 
            -
              segments: 
         | 
| 7 | 
            -
              - 0
         | 
| 8 | 
            -
              - 0
         | 
| 9 | 
            -
              - 2
         | 
| 10 | 
            -
              version: 0.0.2
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.3
         | 
| 5 | 
            +
              prerelease: 
         | 
| 11 6 | 
             
            platform: ruby
         | 
| 12 | 
            -
            authors: | 
| 7 | 
            +
            authors:
         | 
| 13 8 | 
             
            - Michael Harrison
         | 
| 14 9 | 
             
            autorequire: 
         | 
| 15 10 | 
             
            bindir: bin
         | 
| 16 11 | 
             
            cert_chain: []
         | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
            dependencies: 
         | 
| 21 | 
            -
            - !ruby/object:Gem::Dependency 
         | 
| 12 | 
            +
            date: 2012-03-25 00:00:00.000000000 Z
         | 
| 13 | 
            +
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 22 15 | 
             
              name: nokogiri
         | 
| 23 | 
            -
               | 
| 24 | 
            -
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 16 | 
            +
              requirement: &70136090689960 !ruby/object:Gem::Requirement
         | 
| 25 17 | 
             
                none: false
         | 
| 26 | 
            -
                requirements: | 
| 27 | 
            -
                - -  | 
| 28 | 
            -
                  - !ruby/object:Gem::Version | 
| 29 | 
            -
                     | 
| 30 | 
            -
                    segments: 
         | 
| 31 | 
            -
                    - 0
         | 
| 32 | 
            -
                    version: "0"
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - ! '>='
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '0'
         | 
| 33 22 | 
             
              type: :runtime
         | 
| 34 | 
            -
              version_requirements: *id001
         | 
| 35 | 
            -
            - !ruby/object:Gem::Dependency 
         | 
| 36 | 
            -
              name: rake
         | 
| 37 23 | 
             
              prerelease: false
         | 
| 38 | 
            -
               | 
| 24 | 
            +
              version_requirements: *70136090689960
         | 
| 25 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 26 | 
            +
              name: rake
         | 
| 27 | 
            +
              requirement: &70136090688920 !ruby/object:Gem::Requirement
         | 
| 39 28 | 
             
                none: false
         | 
| 40 | 
            -
                requirements: | 
| 41 | 
            -
                - -  | 
| 42 | 
            -
                  - !ruby/object:Gem::Version | 
| 43 | 
            -
                     | 
| 44 | 
            -
                    segments: 
         | 
| 45 | 
            -
                    - 0
         | 
| 46 | 
            -
                    version: "0"
         | 
| 29 | 
            +
                requirements:
         | 
| 30 | 
            +
                - - ! '>='
         | 
| 31 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            +
                    version: '0'
         | 
| 47 33 | 
             
              type: :development
         | 
| 48 | 
            -
               | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 34 | 
            +
              prerelease: false
         | 
| 35 | 
            +
              version_requirements: *70136090688920
         | 
| 36 | 
            +
            description: XML Active is an extension of ActiveRecord that provides features to
         | 
| 37 | 
            +
              synchronise an ActiveRecord Model with a supplied XML document
         | 
| 38 | 
            +
            email:
         | 
| 51 39 | 
             
            - michael@focalpause.com
         | 
| 52 40 | 
             
            executables: []
         | 
| 53 | 
            -
             | 
| 54 41 | 
             
            extensions: []
         | 
| 55 | 
            -
             | 
| 56 42 | 
             
            extra_rdoc_files: []
         | 
| 57 | 
            -
             | 
| 58 | 
            -
            files: 
         | 
| 43 | 
            +
            files:
         | 
| 59 44 | 
             
            - .gitignore
         | 
| 60 45 | 
             
            - Gemfile
         | 
| 61 46 | 
             
            - README.rdoc
         | 
| @@ -63,39 +48,28 @@ files: | |
| 63 48 | 
             
            - lib/xml_active.rb
         | 
| 64 49 | 
             
            - lib/xml_active/version.rb
         | 
| 65 50 | 
             
            - xml_active.gemspec
         | 
| 66 | 
            -
            has_rdoc: true
         | 
| 67 51 | 
             
            homepage: https://github.com/michael-harrison/xml_active
         | 
| 68 52 | 
             
            licenses: []
         | 
| 69 | 
            -
             | 
| 70 53 | 
             
            post_install_message: 
         | 
| 71 54 | 
             
            rdoc_options: []
         | 
| 72 | 
            -
             | 
| 73 | 
            -
            require_paths: 
         | 
| 55 | 
            +
            require_paths:
         | 
| 74 56 | 
             
            - lib
         | 
| 75 | 
            -
            required_ruby_version: !ruby/object:Gem::Requirement | 
| 57 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 76 58 | 
             
              none: false
         | 
| 77 | 
            -
              requirements: | 
| 78 | 
            -
              - -  | 
| 79 | 
            -
                - !ruby/object:Gem::Version | 
| 80 | 
            -
                   | 
| 81 | 
            -
             | 
| 82 | 
            -
                  - 0
         | 
| 83 | 
            -
                  version: "0"
         | 
| 84 | 
            -
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 59 | 
            +
              requirements:
         | 
| 60 | 
            +
              - - ! '>='
         | 
| 61 | 
            +
                - !ruby/object:Gem::Version
         | 
| 62 | 
            +
                  version: '0'
         | 
| 63 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 85 64 | 
             
              none: false
         | 
| 86 | 
            -
              requirements: | 
| 87 | 
            -
              - -  | 
| 88 | 
            -
                - !ruby/object:Gem::Version | 
| 89 | 
            -
                   | 
| 90 | 
            -
                  segments: 
         | 
| 91 | 
            -
                  - 0
         | 
| 92 | 
            -
                  version: "0"
         | 
| 65 | 
            +
              requirements:
         | 
| 66 | 
            +
              - - ! '>='
         | 
| 67 | 
            +
                - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                  version: '0'
         | 
| 93 69 | 
             
            requirements: []
         | 
| 94 | 
            -
             | 
| 95 70 | 
             
            rubyforge_project: xml_active
         | 
| 96 | 
            -
            rubygems_version: 1. | 
| 71 | 
            +
            rubygems_version: 1.8.10
         | 
| 97 72 | 
             
            signing_key: 
         | 
| 98 73 | 
             
            specification_version: 3
         | 
| 99 | 
            -
            summary: xml_active 0.0. | 
| 74 | 
            +
            summary: xml_active 0.0.3
         | 
| 100 75 | 
             
            test_files: []
         | 
| 101 | 
            -
             |