rubyfocus 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -6
- data/lib/rubyfocus/document.rb +30 -7
- data/lib/rubyfocus/includes/idref.rb +1 -1
- data/lib/rubyfocus/items/context.rb +0 -1
- data/lib/rubyfocus/items/folder.rb +0 -2
- data/lib/rubyfocus/items/item.rb +2 -10
- data/lib/rubyfocus/items/ranked_item.rb +19 -0
- data/lib/rubyfocus/items/task.rb +1 -1
- data/lib/rubyfocus/patch.rb +16 -29
- data/version.txt +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63565e849764d58187bc270c714a509aec780ff5
|
4
|
+
data.tar.gz: 91c1408da7a1764a625d0ebd1434441dde52cd79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f2925e0baae0e08eaf043a7dea9120446ab15b99729f9319c3c47e73feafe7246262879fa409734f0fce6e7566571a3711e3023d56217ec83af77a33ebdaad7
|
7
|
+
data.tar.gz: 119909f3d146a97f0d4cd7b3fd0c1afff0425220c8acfd235f6635609a3fe2fdfd33f3106bf51cbc85481a65c43dc991a01f68cf1f4d5110e91b5d2421c10166
|
data/README.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
# Version: 0.4.0
|
2
|
+
|
1
3
|
Rubyfocus is a one-way (read-only) ruby bridge to OmniFocus. Analyse, store, inspect, or play with your projects and tasks in OmniFocus from the comfort and flexibility of ruby!
|
2
4
|
|
3
5
|
# Installation
|
4
6
|
|
5
|
-
|
7
|
+
## Via rubygems
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install rubyfocus
|
11
|
+
```
|
6
12
|
|
7
13
|
## Via git
|
8
14
|
|
@@ -16,7 +22,7 @@ Now build and install it!
|
|
16
22
|
|
17
23
|
```
|
18
24
|
gem build rubyfocus.gemspec
|
19
|
-
gem install rubyfocus-0.
|
25
|
+
gem install rubyfocus-0.3.0.gem
|
20
26
|
```
|
21
27
|
|
22
28
|
# Usage
|
@@ -64,13 +70,13 @@ d.projects.first.tasks
|
|
64
70
|
|
65
71
|
What if you want to select only certain projects? Sure, you can use standard `Array#find` or `Array#select` methods, but you can also make use of a hash of values:
|
66
72
|
|
67
|
-
```
|
73
|
+
```ruby
|
68
74
|
d.projects.select(name: "Sample project")
|
69
75
|
```
|
70
76
|
|
71
77
|
Once you have your objects, you can query them for more information:
|
72
78
|
|
73
|
-
```
|
79
|
+
```ruby
|
74
80
|
t = d.tasks.first
|
75
81
|
t.name # => "Sample task"
|
76
82
|
t.project.name # => "Sample project"
|
@@ -102,11 +108,25 @@ Rubyfocus makes use of this by fetching and reading OmniFocus' local store on yo
|
|
102
108
|
|
103
109
|
Other goals include:
|
104
110
|
|
105
|
-
*
|
106
|
-
*
|
111
|
+
* Registering with the Omni Sync Server, so you don't need to always delete + reinstantiate the database.
|
112
|
+
* Determining when you're "detached" from the latest version on the OSS.
|
113
|
+
* A couple of example projects using rubyfocus (especially a static webpage generator for kanban)
|
107
114
|
|
108
115
|
# History
|
109
116
|
|
117
|
+
## 0.4.0 // 2016-01-01
|
118
|
+
|
119
|
+
* Happy new year!
|
120
|
+
* [Modified] Container IDRef is now located on RankedItem, rather than having several on each RankedItem subclass.
|
121
|
+
* [New] RankedItems can look at their ancestry much more easily, using RankedItem#ancestry and RankedItem#contained_within?
|
122
|
+
* [New] Documents now forbid elements with duplicate IDs unless Document#allow_duplicate_ids is set to true.
|
123
|
+
* [New] Patchers now treate CREATE nodes on elements whose IDs already exist in the database as UPDATE nodes
|
124
|
+
* [Fixed] Patchers will now interpret missing parameters as "default values" e.g. project update without `status` parameter assumed to be active.
|
125
|
+
|
126
|
+
## 0.3.1 // 2015-12-31
|
127
|
+
|
128
|
+
* [Bugfix] IDRefs will now return +nil+ if the relevant ID is not set.
|
129
|
+
|
110
130
|
## 0.3.0 // 2015-10-17
|
111
131
|
|
112
132
|
* [New] Now supports remote syncing with the Omni Sync Server!
|
data/lib/rubyfocus/document.rb
CHANGED
@@ -53,7 +53,7 @@ class Rubyfocus::Document
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# Initialize with a URL, for remote fetching.
|
56
|
-
# Not implemented yet
|
56
|
+
# Not implemented yet TODO implement
|
57
57
|
def self.from_url(url)
|
58
58
|
raise RuntimeError, "Rubyfocus::Document.from_url not yet implemented."
|
59
59
|
# new(Rubyfocus::RemoteFetcher.new(url))
|
@@ -96,9 +96,22 @@ class Rubyfocus::Document
|
|
96
96
|
end
|
97
97
|
private :ivar_for
|
98
98
|
|
99
|
-
# Add an element. Element should be a Project, Task, Context, Folder, or Setting
|
100
|
-
#
|
101
|
-
|
99
|
+
# Add an element. Element should be a Project, Task, Context, Folder, or Setting.
|
100
|
+
# If overwrite set to false and ID already occurs in the document, throw an error.
|
101
|
+
# If ID is nil, throw an error.
|
102
|
+
def add_element(e, overwrite:false)
|
103
|
+
# Error check
|
104
|
+
raise(Rubyfocus::DocumentElementException, "Adding element to document, but it has no ID.") if e.id.nil?
|
105
|
+
raise(Rubyfocus::DocumentElementException, "Adding element to document, but element with this ID already exists.") if !overwrite && has_id?(e.id)
|
106
|
+
|
107
|
+
# Otherwise, full steam ahead
|
108
|
+
e.document = self
|
109
|
+
|
110
|
+
if (dupe_element = self[e.id]) && overwrite
|
111
|
+
remove_element(dupe_element)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Add to the correct array
|
102
115
|
dest = ivar_for(e)
|
103
116
|
if dest
|
104
117
|
dest << e
|
@@ -108,12 +121,12 @@ class Rubyfocus::Document
|
|
108
121
|
end
|
109
122
|
|
110
123
|
# Remove an element from the document.
|
111
|
-
# We assume whoever does this is smart enough to also set the element's #document value
|
112
|
-
# to nil
|
113
124
|
def remove_element(e)
|
114
125
|
e = self[e] if e.is_a?(String)
|
115
126
|
return if e.nil?
|
116
127
|
|
128
|
+
e.document = nil
|
129
|
+
|
117
130
|
dest = ivar_for(e)
|
118
131
|
if dest
|
119
132
|
dest.delete(e)
|
@@ -131,16 +144,26 @@ class Rubyfocus::Document
|
|
131
144
|
# For Searchable include
|
132
145
|
alias_method :array, :elements
|
133
146
|
|
147
|
+
|
134
148
|
#-------------------------------------------------------------------------------
|
135
149
|
# Find elements from id
|
136
150
|
def [] search_id
|
137
151
|
self.elements.find{ |elem| elem.id == search_id }
|
138
152
|
end
|
139
153
|
|
154
|
+
# Check if the document has an element of a given ID
|
155
|
+
def has_id?(id)
|
156
|
+
self.elements.any?{ |e| e.id == id }
|
157
|
+
end
|
158
|
+
|
140
159
|
#---------------------------------------
|
141
160
|
# YAML export
|
142
161
|
|
143
162
|
def save(file)
|
144
163
|
File.open(file, "w"){ |io| io.puts YAML::dump(self) }
|
145
164
|
end
|
146
|
-
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#-------------------------------------------------------------------------------
|
168
|
+
# Exceptions
|
169
|
+
class Rubyfocus::DocumentElementException < Exception; end
|
@@ -6,7 +6,7 @@ module Rubyfocus
|
|
6
6
|
name_id = "#{name}_id".to_sym
|
7
7
|
attr_accessor name_id
|
8
8
|
define_method(name) do
|
9
|
-
return document &&
|
9
|
+
return document && (id_value = send(name_id)) && document.find(id_value)
|
10
10
|
end
|
11
11
|
|
12
12
|
define_method("#{name}=") do |o|
|
data/lib/rubyfocus/items/item.rb
CHANGED
@@ -13,8 +13,6 @@ class Rubyfocus::Item
|
|
13
13
|
attr_accessor :id, :added, :modified, :document
|
14
14
|
|
15
15
|
def initialize(document=nil, n=nil)
|
16
|
-
self.document = document
|
17
|
-
|
18
16
|
case n
|
19
17
|
when Nokogiri::XML::Element
|
20
18
|
apply_xml(n)
|
@@ -24,6 +22,8 @@ class Rubyfocus::Item
|
|
24
22
|
send(setter,v) if respond_to?(setter)
|
25
23
|
end
|
26
24
|
end
|
25
|
+
|
26
|
+
document.add_element(self) if document
|
27
27
|
end
|
28
28
|
|
29
29
|
def apply_xml(n)
|
@@ -45,14 +45,6 @@ class Rubyfocus::Item
|
|
45
45
|
inspect_properties.each_with_object({}){ |s,hsh| hsh[s] = self.send(s) }
|
46
46
|
end
|
47
47
|
|
48
|
-
#---------------------------------------
|
49
|
-
# Document set/get methods
|
50
|
-
def document= d
|
51
|
-
@document.remove_element(self) if @document
|
52
|
-
@document = d
|
53
|
-
@document.add_element(self) if @document
|
54
|
-
end
|
55
|
-
|
56
48
|
#-------------------------------------------------------------------------------
|
57
49
|
# Private inspect methods
|
58
50
|
|
@@ -1,6 +1,25 @@
|
|
1
1
|
class Rubyfocus::RankedItem < Rubyfocus::NamedItem
|
2
2
|
attr_accessor :rank
|
3
3
|
|
4
|
+
# Ranked items also happen to be contained items
|
5
|
+
idref :container
|
6
|
+
|
7
|
+
# Retrieve a full list of the parents of this item. [0] = immediate parent
|
8
|
+
def ancestry
|
9
|
+
if container
|
10
|
+
[container] + container.ancestry
|
11
|
+
else
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Is this item contained within another? You may supply an object, string or integer ID, hash of properties,
|
17
|
+
# or proc to run on each item.
|
18
|
+
def contained_within?(object)
|
19
|
+
object = document.find(object) if [String, Fixnum, Hash, Proc].include?(object.class)
|
20
|
+
ancestry.include?(object)
|
21
|
+
end
|
22
|
+
|
4
23
|
def apply_xml(n)
|
5
24
|
super(n)
|
6
25
|
conditional_set(:rank, n.at_xpath("xmlns:rank")){ |e| e.inner_html.to_i }
|
data/lib/rubyfocus/items/task.rb
CHANGED
data/lib/rubyfocus/patch.rb
CHANGED
@@ -92,45 +92,32 @@ class Rubyfocus::Patch
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
# Apply this patch to a document.
|
95
|
+
# Apply this patch to a document.
|
96
96
|
def apply_to!(document)
|
97
97
|
# Updates modify elements
|
98
|
-
self.update.each
|
99
|
-
|
100
|
-
|
101
|
-
# Tasks can become projects and v.v.: check this.
|
102
|
-
if [Rubyfocus::Task, Rubyfocus::Project].include?(elem.class)
|
103
|
-
should_be_project = (node.at_xpath("xmlns:project") != nil)
|
104
|
-
if (elem.class == Rubyfocus::Project) && !should_be_project
|
105
|
-
elem.document = nil # Remove this from current document
|
106
|
-
elem = elem.to_task # Convert to task
|
107
|
-
elem.document = document # Insert again!
|
108
|
-
elsif (elem.class == Rubyfocus::Task) && should_be_project
|
109
|
-
elem.document = nil # Remove this from current document
|
110
|
-
elem = elem.to_project # Convert to task
|
111
|
-
elem.document = document # Insert again!
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
elem.apply_xml(node) if elem
|
116
|
-
end
|
117
|
-
|
98
|
+
self.update.each{ |node| update_node(document, node) }
|
99
|
+
|
118
100
|
# Deletes remove elements
|
119
|
-
self.delete.each
|
120
|
-
document.remove_element(node["id"])
|
121
|
-
end
|
101
|
+
self.delete.each{ |node| document.remove_element(node["id"]) }
|
122
102
|
|
123
103
|
# Creates make new elements
|
124
|
-
self.create.each
|
125
|
-
if Rubyfocus::Parser.parse(document, node).nil?
|
126
|
-
raise RuntimeError, "Encountered unparsable XML during patch reading: #{node}."
|
127
|
-
end
|
128
|
-
end
|
104
|
+
self.create.each{ |node| update_node(document, node) }
|
129
105
|
|
130
106
|
# Modify current patch_id to show new value
|
131
107
|
document.patch_id = self.to_id
|
132
108
|
end
|
133
109
|
|
110
|
+
# Atomic node update code
|
111
|
+
def update_node(document, node)
|
112
|
+
# Create new element with correct ID. Then add to document, overwriting previous element(s)
|
113
|
+
new_node = Rubyfocus::Parser.parse(nil, node)
|
114
|
+
if new_node
|
115
|
+
document.add_element(new_node, overwrite: true)
|
116
|
+
else
|
117
|
+
raise(RuntimeError, "Encountered unparsable XML during patch reading: #{node}.")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
134
121
|
# String representation
|
135
122
|
def to_s
|
136
123
|
if from_ids.size == 1
|
data/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyfocus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan-Yves Ruzicka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|