Class: Rubyfocus::Document
- Inherits:
-
Object
- Object
- Rubyfocus::Document
- Includes:
- Searchable
- Defined in:
- lib/rubyfocus/document.rb
Overview
The Document is how rubyfocus stores an OmniFocus document, both locally and otherwise. A Document contains a number of arrays of contexts, settings, folders, projects, and tasks, and is also able to keep track of what patch it’s up to, for updating.
You can initialize a document through Document.new(doc), where doc is either an XML string, or a Nokogiri XML document (or nil). Alternatively, you can initialize through Document.from_file(file), which reads the file and parses it as XML
You add XML to the document by running Document::apply_xml(doc), which takes all children of the root XML node, tries to turn each child into a relevant object, and adds it to the document. This is done using the private ivar_for method, as well as add_element(e), which you can use to add individual objects.
Instance Attribute Summary collapse
-
#contexts ⇒ Object
readonly
A number of arrays into which elements may fit.
-
#fetcher ⇒ Object
This is the fetcher object, used to fetch new data.
-
#folders ⇒ Object
readonly
A number of arrays into which elements may fit.
-
#patch_id ⇒ Object
This is the identifier of the current patch level.
-
#projects ⇒ Object
readonly
A number of arrays into which elements may fit.
-
#settings ⇒ Object
readonly
A number of arrays into which elements may fit.
-
#tasks ⇒ Object
readonly
A number of arrays into which elements may fit.
Class Method Summary collapse
-
.from_local ⇒ Object
Initialize from the local repo.
-
.from_url(url) ⇒ Object
Initialize with a URL, for remote fetching.
-
.from_xml(file) ⇒ Object
…or from file! If you provide it with an XML file, it’ll load up without a fetcher.
-
.load_from_file(file_location) ⇒ Object
Load from a a hash.
Instance Method Summary collapse
-
#[](search_id) ⇒ Object
——————————————————————————- Find elements from id.
-
#add_element(e, overwrite: false) ⇒ Object
Add an element.
-
#apply_xml(doc) ⇒ Object
——————————————————————————- Apply XML!.
-
#elements ⇒ Object
(also: #array)
——————————————————————————- Searchable stuff.
-
#has_id?(id) ⇒ Boolean
Check if the document has an element of a given ID.
-
#initialize(doc = nil) ⇒ Document
constructor
Initalise with one of: * a Nokogiri document * a string * a fetcher subclass.
-
#remove_element(e) ⇒ Object
Remove an element from the document.
-
#save(file) ⇒ Object
————————————— YAML export.
-
#update ⇒ Object
————————————— Use the linked fetcher to update the document.
-
#update_element(node) ⇒ Object
Update an element in-place by applying xml.
Methods included from Searchable
Constructor Details
#initialize(doc = nil) ⇒ Document
Initalise with one of:
-
a Nokogiri document
-
a string
-
a fetcher subclass
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/rubyfocus/document.rb', line 28 def initialize(doc=nil) %w(contexts settings projects folders tasks).each{ |s| instance_variable_set("@#{s}", Rubyfocus::SearchableArray.new) } if doc if doc.is_a?(String) apply_xml(Nokogiri::XML(doc)) elsif doc.is_a?(Nokogiri::XML) apply_xml(doc) elsif doc.kind_of?(Rubyfocus::Fetcher) self.fetcher = doc base = Nokogiri::XML(doc.base) self.apply_xml(base) self.patch_id = doc.base_id end end end |
Instance Attribute Details
#contexts ⇒ Object (readonly)
A number of arrays into which elements may fit
15 16 17 |
# File 'lib/rubyfocus/document.rb', line 15 def contexts @contexts end |
#fetcher ⇒ Object
This is the fetcher object, used to fetch new data
22 23 24 |
# File 'lib/rubyfocus/document.rb', line 22 def fetcher @fetcher end |
#folders ⇒ Object (readonly)
A number of arrays into which elements may fit
15 16 17 |
# File 'lib/rubyfocus/document.rb', line 15 def folders @folders end |
#patch_id ⇒ Object
This is the identifier of the current patch level. This also determines which patches can be applied to the current document.
19 20 21 |
# File 'lib/rubyfocus/document.rb', line 19 def patch_id @patch_id end |
#projects ⇒ Object (readonly)
A number of arrays into which elements may fit
15 16 17 |
# File 'lib/rubyfocus/document.rb', line 15 def projects @projects end |
#settings ⇒ Object (readonly)
A number of arrays into which elements may fit
15 16 17 |
# File 'lib/rubyfocus/document.rb', line 15 def settings @settings end |
#tasks ⇒ Object (readonly)
A number of arrays into which elements may fit
15 16 17 |
# File 'lib/rubyfocus/document.rb', line 15 def tasks @tasks end |
Class Method Details
.from_local ⇒ Object
Initialize from the local repo
51 52 53 |
# File 'lib/rubyfocus/document.rb', line 51 def self.from_local new(Rubyfocus::LocalFetcher.new) end |
.from_url(url) ⇒ Object
Initialize with a URL, for remote fetching. Not implemented yet TODO implement
57 58 59 60 |
# File 'lib/rubyfocus/document.rb', line 57 def self.from_url(url) raise RuntimeError, "Rubyfocus::Document.from_url not yet implemented." # new(Rubyfocus::RemoteFetcher.new(url)) end |
.from_xml(file) ⇒ Object
…or from file! If you provide it with an XML file, it’ll load up without a fetcher.
46 47 48 |
# File 'lib/rubyfocus/document.rb', line 46 def self.from_xml(file) new(File.read(file)) end |
.load_from_file(file_location) ⇒ Object
Load from a a hash
63 64 65 66 67 |
# File 'lib/rubyfocus/document.rb', line 63 def self.load_from_file(file_location) d = YAML::load_file(file_location) d.fetcher.reset d end |
Instance Method Details
#[](search_id) ⇒ Object
Find elements from id
182 183 184 |
# File 'lib/rubyfocus/document.rb', line 182 def [] search_id self.elements.find{ |elem| elem.id == search_id } end |
#add_element(e, overwrite: false) ⇒ Object
Add an element. Element should be a Project, Task, Context, Folder, or Setting. If overwrite set to false and ID already occurs in the document, throw an error. If ID is nil, throw an error.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rubyfocus/document.rb', line 102 def add_element(e, overwrite:false) # Error check raise(Rubyfocus::DocumentElementException, "Adding element to document, but it has no ID.") if e.id.nil? raise(Rubyfocus::DocumentElementException, "Adding element to document, but element with this ID already exists.") if !overwrite && has_id?(e.id) # Otherwise, full steam ahead e.document = self if (dupe_element = self[e.id]) && overwrite remove_element(dupe_element) end # Add to the correct array dest = ivar_for(e) if dest dest << e else raise ArgumentError, "You passed a #{e.class} to Document#add_element - I don't know what to do with this." end end |
#apply_xml(doc) ⇒ Object
Apply XML!
81 82 83 84 85 |
# File 'lib/rubyfocus/document.rb', line 81 def apply_xml(doc) doc.root.children.select{ |e| !e.text? }.each do |node| elem = Rubyfocus::Parser.parse(self, node) end end |
#elements ⇒ Object Also known as: array
Searchable stuff
172 173 174 |
# File 'lib/rubyfocus/document.rb', line 172 def elements @tasks + @projects + @contexts + @folders + @settings end |
#has_id?(id) ⇒ Boolean
Check if the document has an element of a given ID
187 188 189 |
# File 'lib/rubyfocus/document.rb', line 187 def has_id?(id) self.elements.any?{ |e| e.id == id } end |
#remove_element(e) ⇒ Object
Remove an element from the document.
124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/rubyfocus/document.rb', line 124 def remove_element(e) e = self[e] if e.is_a?(String) return if e.nil? e.document = nil dest = ivar_for(e) if dest dest.delete(e) else raise ArgumentError, "You passed a #{e.class} to Document#remove_element - I don't know what to do with this." end end |
#save(file) ⇒ Object
YAML export
194 195 196 |
# File 'lib/rubyfocus/document.rb', line 194 def save(file) File.open(file, "w"){ |io| io.puts YAML::dump(self) } end |
#update ⇒ Object
Use the linked fetcher to update the document
71 72 73 74 75 76 77 |
# File 'lib/rubyfocus/document.rb', line 71 def update if fetcher fetcher.update_full(self) else raise RuntimeError, "Tried to update a document with no fetcher." end end |
#update_element(node) ⇒ Object
Update an element in-place by applying xml. This method also takes into account:
-
new nodes (i.e. silently creates if required)
-
tasks upgraded to projects
-
projects downgraded to tasks
Note that unlike add_element, this takes pure XML
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/rubyfocus/document.rb', line 143 def update_element(node) element = self[node["id"]] # Does element already exist? if element # Quick check: is it a task being upgraded to a project? if element.class == Rubyfocus::Task && Rubyfocus::Project.matches_node?(node) # Upgrade new_node = element.to_project new_node.apply_xml(node) add_element(new_node, overwrite:true) # or is the project being downgraded to a task? elsif element.class == Rubyfocus::Project && !Rubyfocus::Project.matches_node?(node) # Downgrade new_node = element.to_task new_node.apply_xml(node) add_element(new_node, overwrite:true) else # Update in-place element.apply_xml(node) end else # Create a new node and add it Rubyfocus::Parser.parse(self,node) end end |