Class: Rubyfocus::Document

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Searchable

#find, #select

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

#contextsObject (readonly)

A number of arrays into which elements may fit



15
16
17
# File 'lib/rubyfocus/document.rb', line 15

def contexts
  @contexts
end

#fetcherObject

This is the fetcher object, used to fetch new data



22
23
24
# File 'lib/rubyfocus/document.rb', line 22

def fetcher
  @fetcher
end

#foldersObject (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_idObject

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

#projectsObject (readonly)

A number of arrays into which elements may fit



15
16
17
# File 'lib/rubyfocus/document.rb', line 15

def projects
  @projects
end

#settingsObject (readonly)

A number of arrays into which elements may fit



15
16
17
# File 'lib/rubyfocus/document.rb', line 15

def settings
  @settings
end

#tasksObject (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_localObject

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

Raises:

  • (RuntimeError)


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



150
151
152
# File 'lib/rubyfocus/document.rb', line 150

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

#elementsObject Also known as: array


Searchable stuff



140
141
142
# File 'lib/rubyfocus/document.rb', line 140

def elements
	@tasks + @projects + @contexts + @folders + @settings
end

#has_id?(id) ⇒ Boolean

Check if the document has an element of a given ID

Returns:

  • (Boolean)


155
156
157
# File 'lib/rubyfocus/document.rb', line 155

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



162
163
164
# File 'lib/rubyfocus/document.rb', line 162

def save(file)
	File.open(file, "w"){ |io| io.puts YAML::dump(self) }
end

#updateObject


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