Class: Rubyfocus::Patch
- Inherits:
-
Object
- Object
- Rubyfocus::Patch
- Includes:
- Comparable
- Defined in:
- lib/rubyfocus/patch.rb
Overview
The patch class represents a text-file patch, storing update, delete, and creation operations. It should also be able to apply itself to an existing document.
Instance Attribute Summary collapse
-
#create ⇒ Object
Operations to be performed on a document.
-
#delete ⇒ Object
Operations to be performed on a document.
-
#fetcher ⇒ Object
The fetcher this patch belongs to.
-
#file ⇒ Object
The file the patch loads from.
-
#from_ids ⇒ Object
These record the transformation in terms of patch ID values.
-
#time ⇒ Object
The time the file was submitted.
-
#to_id ⇒ Object
These record the transformation in terms of patch ID values.
-
#update ⇒ Object
Update, delete and create methods.
-
#version ⇒ Object
What version of patch file is this? Determined from XML file.
Class Method Summary collapse
-
.from_string(fetcher, str) ⇒ Object
Load from a string.
Instance Method Summary collapse
- #<=>(o) ⇒ Object
-
#apply_to(document) ⇒ Object
Apply this patch to a document.
-
#apply_to!(document) ⇒ Object
Apply this patch to a document.
-
#can_patch?(document) ⇒ Boolean
Can we apply this patch to a given document?.
-
#initialize(fetcher = nil, file = nil) ⇒ Patch
constructor
By default we initialize patches from a file.
-
#load_data(str = nil) ⇒ Object
Loads data from the file.
-
#to_s ⇒ Object
String representation.
Constructor Details
#initialize(fetcher = nil, file = nil) ⇒ Patch
By default we initialize patches from a file. To initialize from a string, use the .from_string method. This class will lazily load data from the file proper
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rubyfocus/patch.rb', line 25 def initialize(fetcher=nil, file=nil) @fetcher = fetcher @file = file @update = [] @create = [] @delete = [] if file if File.basename(file) =~ /^(\d+)=(.*)\./ time_string = $1 self.time = if (time_string == "00000000000000") Time.at(0) else Time.parse(time_string) end ids = $2.split("+") self.to_id = ids.pop self.from_ids = ids else raise ArgumentError, "Constructed patch from a malformed patch file: #{file}." end end end |
Instance Attribute Details
#create ⇒ Object
Operations to be performed on a document
9 10 11 |
# File 'lib/rubyfocus/patch.rb', line 9 def create @create end |
#delete ⇒ Object
Operations to be performed on a document
9 10 11 |
# File 'lib/rubyfocus/patch.rb', line 9 def delete @delete end |
#fetcher ⇒ Object
The fetcher this patch belongs to. We mainly use this to work out how to fetch content for the patch proper
6 7 8 |
# File 'lib/rubyfocus/patch.rb', line 6 def fetcher @fetcher end |
#file ⇒ Object
The file the patch loads from
12 13 14 |
# File 'lib/rubyfocus/patch.rb', line 12 def file @file end |
#from_ids ⇒ Object
These record the transformation in terms of patch ID values.
18 19 20 |
# File 'lib/rubyfocus/patch.rb', line 18 def from_ids @from_ids end |
#time ⇒ Object
The time the file was submitted
21 22 23 |
# File 'lib/rubyfocus/patch.rb', line 21 def time @time end |
#to_id ⇒ Object
These record the transformation in terms of patch ID values.
18 19 20 |
# File 'lib/rubyfocus/patch.rb', line 18 def to_id @to_id end |
#update ⇒ Object
Update, delete and create methods
9 10 11 |
# File 'lib/rubyfocus/patch.rb', line 9 def update @update end |
#version ⇒ Object
What version of patch file is this? Determined from XML file
15 16 17 |
# File 'lib/rubyfocus/patch.rb', line 15 def version @version end |
Class Method Details
.from_string(fetcher, str) ⇒ Object
Load from a string.
51 52 53 54 55 |
# File 'lib/rubyfocus/patch.rb', line 51 def self.from_string(fetcher, str) n = new(fetcher) n.load_data(str) n end |
Instance Method Details
#<=>(o) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/rubyfocus/patch.rb', line 153 def <=> o if self.time.nil? if o.time.nil? 0 else -1 end else if o.time.nil? 1 else self.time <=> o.time end end end |
#apply_to(document) ⇒ Object
Apply this patch to a document. Check to make sure ids match
111 112 113 114 115 116 117 |
# File 'lib/rubyfocus/patch.rb', line 111 def apply_to(document) if can_patch?(document) apply_to!(document) else raise RuntimeError, "Patch ID mismatch (patch from_ids: [#{self.from_ids.join(", ")}], document.patch_id: #{document.patch_id}" end end |
#apply_to!(document) ⇒ Object
Apply this patch to a document.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/rubyfocus/patch.rb', line 120 def apply_to!(document) load_data # Updates depend on version! if version == 1 #V1 updates overwrite elements self.update.each{ |node| document.overwrite_element(node) } elsif version == 2 #V2 updates actually update elements self.update.each{ |node| document.update_element(node) } else raise RuntimeError, "Cannot run updates using Version #{version.inspect} OF patches!" end # Deletes remove elements self.delete.each{ |node| document.remove_element(node["id"]) } # Creates make new elements self.create.each{ |node| document.update_element(node) } # Modify current patch_id to show new value document.patch_id = self.to_id end |
#can_patch?(document) ⇒ Boolean
Can we apply this patch to a given document?
106 107 108 |
# File 'lib/rubyfocus/patch.rb', line 106 def can_patch?(document) self.from_ids.include?(document.patch_id) end |
#load_data(str = nil) ⇒ Object
Loads data from the file. Optional argument str
if you want to supply your own data, otherwise will load file data
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/rubyfocus/patch.rb', line 59 def load_data(str=nil) return if @data_loaded @data_loaded = true str ||= fetcher.patch(self.file) doc = Nokogiri::XML(str) # Root should be an <omnifocus> and have an XMLNS # XMLNS should be one of: # * http://www.omnigroup.com/namespace/OmniFocus/v1 # * http://www.omnigroup.com/namespace/OmniFocus/v2 omnifocus = doc.root if omnifocus.name == "omnifocus" xmlns = omnifocus.namespace && omnifocus.namespace.href case xmlns when "http://www.omnigroup.com/namespace/OmniFocus/v1" self.version = 1 when "http://www.omnigroup.com/namespace/OmniFocus/v2" self.version = 2 else raise ArgumentError, "Unrecognised namespace #{xmlns.inspect} for Omnifocus patch file." end else raise ArgumentError, "Root element should be <omnifocus>, instead was <#{omnifocus.name}>." end doc.root.children.select{ |n| !n.text?}.each do |child| case child["op"] when "update" @update << child when "delete" @delete << child when "reference" # Ignore! when nil @create << child else raise RuntimeError, "Rubyfocus::Patch encountered unknown operation type #{child["op"]}." end end end |
#to_s ⇒ Object
String representation
145 146 147 148 149 150 151 |
# File 'lib/rubyfocus/patch.rb', line 145 def to_s if from_ids.size == 1 "(#{from_ids.first} -> #{to_id})" else "([#{from_ids.join(", ")}] -> #{to_id})" end end |