rubyfocus 0.5.9 → 0.5.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 80ef3e4cecd0eadf4c382649ebc6e0bec02f5ef0
4
- data.tar.gz: 18d49a1f6c59c97058918fb1d6e9684c131cf467
3
+ metadata.gz: a081be1af0e05194f95e7de7e5e4452a53605971
4
+ data.tar.gz: 84f7160ffec7195233677897531a7c128eed5bb6
5
5
  SHA512:
6
- metadata.gz: 104abdd65cbbf6d662786395c28d0a4ac67febbe1fea637dee88b2f46d3d58006ad59e190e8810a126261816a29c888082995d80090d4c172de767379369e80a
7
- data.tar.gz: 04a52e5c3d0cb037c3b93d1d6082e808804045261d6a912710eb562295cdf97fd937063fb03b5b57ef3403fc580591c822d9f66975fc3a8e149b930b9a8594bf
6
+ metadata.gz: aa6f406623b728c990eb1d79877a1485437383a427563fdf16ad657e325bed552fbcecec7eeb0b59388a4e026809470dc5831a4b4de91dc0df10ec019d28b0b6
7
+ data.tar.gz: c5ca0640fc7d3643d8b1c6946dd533c9e4f1ea2f99cb6b054ce7d5f2d8ce933bb23dd672ec21b713df1bd2e3457a283ee2b141f30cbe09b8f3e006840b1e333f
data/CHANGELOG.md ADDED
@@ -0,0 +1,125 @@
1
+ # Change log
2
+
3
+ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
4
+
5
+ ## Unreleased
6
+
7
+ ### Added
8
+ * `Fetcher#encrypted?` will tell you if a fetcher is looking at an encrypted folder or not.
9
+
10
+ ### Changed
11
+
12
+ * `Document#update` will error if you try to update based on an encrypted fetcher.
13
+ * HISTORY.md is now CHANGELOG.md
14
+ * Reformatted Changelog to match KaC format
15
+
16
+ ## [0.5.11] - 2016-09-20
17
+
18
+ ### Added
19
+ * `Document#overwrite_element` now allows you to perform V1-style replacements to the database, if you really want to.
20
+ * Should now be able to deal with either V1 or V2 patch files.
21
+
22
+ ### Changed
23
+ * Major changelog reformat!
24
+
25
+ ## [0.5.10] - 2016-09-07
26
+
27
+ ### Fixed
28
+ * Projects will no longer be demoted to tasks if a project patch doesn't contain a "<project>" tag.
29
+
30
+ ## [0.5.9] - 2016-09-04
31
+
32
+ ### Fixed
33
+ * Blank entries in updates are now treated as "no change", rather than "new value is nil".
34
+
35
+ ## [0.5.8] - 2016-09-02
36
+
37
+ ### Fixed
38
+ * Projects inside folders were being reported as having no container, due to empty `<task/`> tags. Now fixed.
39
+
40
+ ## [0.5.7] - 2016-09-02
41
+
42
+ ### Fixed
43
+ * Empty `<project/>` tags in a task description will no longer cause Rubyfocus to treat said task as a project.
44
+
45
+ ## [0.5.6] - 2016-09-01
46
+
47
+ ### Added
48
+ * Added `Time.safely_parse`, which will not choke on empty strings or nil values
49
+
50
+ ### Fixed
51
+ * `conditional_set` will no longer choke on empty string for times
52
+
53
+ ## [0.5.5] - 2016-05-18
54
+
55
+ ### Fixed
56
+
57
+ * If there are no patches, `Fetcher#head`s will return the ID of the base file.
58
+ * `Fetcher#head` will now return the ID of the most recent patch, not the patch itself.
59
+ * * `RankedItem#contained_within?` will now check against all objects matching a block or hash, rather than just the first one that the document can find.
60
+
61
+ ### Added
62
+ * `Searchable` objects will now respond to `find_all`, which is an alias of `select`.
63
+
64
+ ## [0.5.4] - 2016-02-08
65
+
66
+ ### Fixed
67
+ * `LocalFetcher` will now try the default App Store location if it can't find anything at the normal location.
68
+
69
+ ## [0.5.3] - 2016-02-04
70
+
71
+ ### Fixed
72
+ * Re-did the code determining whether a task was blocked. Now tasks are considered blocked if their immediate container is blocked.
73
+ * Caching some task filters on the `Task` class was causing issues. Removed caching, which shouldn't hit performance much.
74
+
75
+ ## [0.5.2] - 2016-02-04
76
+
77
+ ### Added
78
+ * Whoops! Did I leave HTTParty out of the gem install list? My bad!
79
+
80
+ ## [0.5.1] - 2016-02-03
81
+
82
+ ### Fixed
83
+ * `Task#next_available_task` should no longer cause errors when a project has no tasks.
84
+
85
+ ## [0.5.0] - 2016-01-20
86
+
87
+ ### Added
88
+ * `Fetcher#head` returns the most recent patch.
89
+ * `Fetcher#can_reach_head_from?(id)` will inform you if you can get to the head from a given ID.
90
+
91
+ ## [0.4.0] - 2016-01-01
92
+
93
+ * Happy new year!
94
+
95
+ ### Added
96
+ * RankedItems can look at their ancestry much more easily, using RankedItem#ancestry and RankedItem#contained_within?
97
+ * Documents now forbid elements with duplicate IDs unless Document#allow_duplicate_ids is set to true.
98
+ * Patchers now treate CREATE nodes on elements whose IDs already exist in the database as UPDATE nodes
99
+
100
+ ### Changed
101
+ * Container IDRef is now located on RankedItem, rather than having several on each RankedItem subclass.
102
+
103
+ ### Fixed
104
+ * Patchers will now interpret missing parameters as "default values" e.g. project update without `status` parameter assumed to be active.
105
+
106
+ ## [0.3.1] - 2015-12-31
107
+
108
+ ### Changed
109
+ * IDRefs will now return `nil` if the relevant ID is not set.
110
+
111
+ ## [0.3.0] - 2015-10-17
112
+
113
+ ### Added
114
+ * Now supports remote syncing with the Omni Sync Server!
115
+
116
+ ## [0.2.0] - 2015-10-11
117
+
118
+ ### Changed
119
+ * Will now turn tasks into projects and projects into tasks if the user has done this in OmniFocus.
120
+ * Rubyfocus::Patch now does patch application, rather than delegating to the Fetcher.
121
+
122
+ ## [0.1.0] - 2015-10-10
123
+
124
+ ### Added
125
+ * Hello, world!
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Version: 0.5.9
1
+ # Version: 0.5.11
2
2
 
3
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!
4
4
 
@@ -22,7 +22,7 @@ Now build and install it!
22
22
 
23
23
  ```
24
24
  gem build rubyfocus.gemspec
25
- gem install rubyfocus-0.5.9.gem
25
+ gem install rubyfocus-0.5.11.gem
26
26
  ```
27
27
 
28
28
  # Usage
@@ -70,6 +70,7 @@ class Rubyfocus::Document
70
70
  # Use the linked fetcher to update the document
71
71
  def update
72
72
  if fetcher
73
+ raise RuntimeError, "Rubyfocus cannot currently read encrypted databases." if fetcher.encrypted?
73
74
  fetcher.update_full(self)
74
75
  else
75
76
  raise RuntimeError, "Tried to update a document with no fetcher."
@@ -137,8 +138,8 @@ class Rubyfocus::Document
137
138
 
138
139
  # Update an element in-place by applying xml. This method also takes into account:
139
140
  # * new nodes (i.e. silently creates if required)
140
- # * tasks upgraded to projects
141
- # * projects downgraded to tasks
141
+ # * tasks upgraded to projects (if task has a non-empty <project> element)
142
+ # * projects downgraded to tasks (if project has an empty <project> element)
142
143
  # Note that unlike add_element, this takes pure XML
143
144
  def update_element(node)
144
145
  element = self[node["id"]]
@@ -146,13 +147,24 @@ class Rubyfocus::Document
146
147
  # Does element already exist?
147
148
  if element
148
149
  # Quick check: is it a task being upgraded to a project?
149
- if element.class == Rubyfocus::Task && Rubyfocus::Project.matches_node?(node)
150
+ # Upgrade criteria: non-empty project tag
151
+ if(
152
+ element.class == Rubyfocus::Task &&
153
+ (node / "project *").size > 0
154
+ )
155
+
150
156
  # Upgrade
151
157
  new_node = element.to_project
152
158
  new_node.apply_xml(node)
153
159
  add_element(new_node, overwrite:true)
154
160
  # or is the project being downgraded to a task?
155
- elsif element.class == Rubyfocus::Project && !Rubyfocus::Project.matches_node?(node)
161
+ # Downgrade criteria: presence of an empty project tag
162
+ elsif(
163
+ element.class == Rubyfocus::Project &&
164
+ (node / "project").size > 0 &&
165
+ (node / "project *").size == 0
166
+ )
167
+
156
168
  # Downgrade
157
169
  new_node = element.to_task
158
170
  new_node.apply_xml(node)
@@ -167,6 +179,21 @@ class Rubyfocus::Document
167
179
  end
168
180
  end
169
181
 
182
+ # Update an element in-place by creating a new element, deleting the old, and adding the new.
183
+ # This method is chiefly used for patching OF documents using V1 patches. Properties not explicitly
184
+ # mentioned in the patch are reverted to their default values.
185
+ # This method also takes into account:
186
+ # * new nodes (i.e. silently creates if required)
187
+ # * tasks upgraded to projects (if task has a <project> element)
188
+ # * projects downgraded to tasks (if project has no <project> element)
189
+ # Note that unlike add_element, this takes pure XML
190
+ def overwrite_element(node)
191
+ element = self[node["id"]]
192
+ self.remove_element(element) if element
193
+
194
+ Rubyfocus::Parser.parse(self, node)
195
+ end
196
+
170
197
  #-------------------------------------------------------------------------------
171
198
  # Searchable stuff
172
199
  def elements
@@ -56,6 +56,11 @@ class Rubyfocus::Fetcher
56
56
  return false
57
57
  end
58
58
 
59
+ # Is this fetcher encrypted?
60
+ def encrypted?
61
+ raise RuntimeError, "Method Fetcher#encrypted? called for abstract class Fetcher."
62
+ end
63
+
59
64
  #---------------------------------------
60
65
  # Patching methods
61
66
 
@@ -52,6 +52,11 @@ class Rubyfocus::LocalFetcher < Rubyfocus::Fetcher
52
52
  coder.map = {"location" => @location}
53
53
  end
54
54
 
55
+ # Is this fetcher fetching encrypted data?
56
+ def encrypted?
57
+ File.exists?(File.join(self.location, "encrypted"))
58
+ end
59
+
55
60
  #---------------------------------------
56
61
  # Location file setters and getters
57
62
 
@@ -49,26 +49,35 @@ class Rubyfocus::OSSFetcher < Rubyfocus::Fetcher
49
49
  end
50
50
  end
51
51
 
52
- # Fetches a list of every patch file
53
- def patches
54
- @patches ||= begin
52
+ # Fetches a list of all files contained within the database
53
+ def files
54
+ @files ||= begin
55
55
  response = self.fetcher.get(url, digest_auth: auth).body
56
56
  # Text is in first table, let's assume
57
57
  table = response[/<table>(.*?)<\/table>/m,1]
58
58
  if table
59
- links = table.scan(/<a href="([^"]+)"/).flatten.select{ |f| f.end_with?(".zip") }
60
- links.map{ |u| Rubyfocus::Patch.new(self,u) }
59
+ table.scan(/<a href="([^"]+)"/).flatten
61
60
  else
62
61
  []
63
62
  end
64
63
  end
65
64
  end
66
65
 
66
+ # Fetches a list of every patch file
67
+ def patches
68
+ @patches ||= files.select{ |f| f.end_with?(".zip") }.map{ |u| Rubyfocus::Patch.new(self,u) }
69
+ end
70
+
67
71
  # Fetches the contents of a given patch file
68
72
  def patch(file)
69
73
  fetch_file(file)
70
74
  end
71
75
 
76
+ # Is this encrypted?
77
+ def encrypted?
78
+ files.find{ |f| File.basename(f) == "encrypted" }
79
+ end
80
+
72
81
  # Save to disk
73
82
  def encode_with(coder)
74
83
  coder.map = {
@@ -42,10 +42,13 @@ class Rubyfocus::Project < Rubyfocus::Task
42
42
 
43
43
  #First, set project
44
44
  p = n.at_xpath("xmlns:project")
45
- conditional_set(:singleton, p.at_xpath("xmlns:singleton")) { |e| e.inner_html == "true" }
46
- conditional_set(:review_interval, p.at_xpath("xmlns:review-interval") ) { |e| Rubyfocus::ReviewPeriod.from_string(e.inner_html) }
47
- conditional_set(:last_review, p.at_xpath("xmlns:last-review")) { |e| Time.safely_parse e.inner_html }
48
- conditional_set(:status, p.at_xpath("xmlns:status")) { |e| e.inner_html.to_sym }
45
+ # We're not always going to have a project! And this *doesn't* mean that this project is demoted
46
+ if p
47
+ conditional_set(:singleton, p.at_xpath("xmlns:singleton")) { |e| e.inner_html == "true" }
48
+ conditional_set(:review_interval, p.at_xpath("xmlns:review-interval") ) { |e| Rubyfocus::ReviewPeriod.from_string(e.inner_html) }
49
+ conditional_set(:last_review, p.at_xpath("xmlns:last-review")) { |e| Time.safely_parse e.inner_html }
50
+ conditional_set(:status, p.at_xpath("xmlns:status")) { |e| e.inner_html.to_sym }
51
+ end
49
52
  end
50
53
 
51
54
  alias_method :singleton?, :singleton
@@ -11,6 +11,9 @@ class Rubyfocus::Patch
11
11
  # The file the patch loads from
12
12
  attr_accessor :file
13
13
 
14
+ # What version of patch file is this? Determined from XML file
15
+ attr_accessor :version
16
+
14
17
  # These record the transformation in terms of patch ID values.
15
18
  attr_accessor :from_ids, :to_id
16
19
 
@@ -59,6 +62,26 @@ class Rubyfocus::Patch
59
62
 
60
63
  str ||= fetcher.patch(self.file)
61
64
  doc = Nokogiri::XML(str)
65
+
66
+ # Root should be an <omnifocus> and have an XMLNS
67
+ # XMLNS should be one of:
68
+ # * http://www.omnigroup.com/namespace/OmniFocus/v1
69
+ # * http://www.omnigroup.com/namespace/OmniFocus/v2
70
+ omnifocus = doc.root
71
+ if omnifocus.name == "omnifocus"
72
+ xmlns = omnifocus.namespace && omnifocus.namespace.href
73
+ case xmlns
74
+ when "http://www.omnigroup.com/namespace/OmniFocus/v1"
75
+ self.version = 1
76
+ when "http://www.omnigroup.com/namespace/OmniFocus/v2"
77
+ self.version = 2
78
+ else
79
+ raise ArgumentError, "Unrecognised namespace #{xmlns.inspect} for Omnifocus patch file."
80
+ end
81
+ else
82
+ raise ArgumentError, "Root element should be <omnifocus>, instead was <#{omnifocus.name}>."
83
+ end
84
+
62
85
  doc.root.children.select{ |n| !n.text?}.each do |child|
63
86
  case child["op"]
64
87
  when "update"
@@ -95,8 +118,18 @@ class Rubyfocus::Patch
95
118
 
96
119
  # Apply this patch to a document.
97
120
  def apply_to!(document)
98
- # Updates modify elements
99
- self.update.each{ |node| document.update_element(node) }
121
+ load_data
122
+
123
+ # Updates depend on version!
124
+ if version == 1
125
+ #V1 updates overwrite elements
126
+ self.update.each{ |node| document.overwrite_element(node) }
127
+ elsif version == 2
128
+ #V2 updates actually update elements
129
+ self.update.each{ |node| document.update_element(node) }
130
+ else
131
+ raise RuntimeError, "Cannot run updates using Version #{version.inspect} OF patches!"
132
+ end
100
133
 
101
134
  # Deletes remove elements
102
135
  self.delete.each{ |node| document.remove_element(node["id"]) }
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.5.9
1
+ 0.5.11
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.5.9
4
+ version: 0.5.11
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: 2016-09-04 00:00:00.000000000 Z
11
+ date: 2016-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -78,7 +78,7 @@ extensions: []
78
78
  extra_rdoc_files:
79
79
  - README.md
80
80
  files:
81
- - HISTORY.md
81
+ - CHANGELOG.md
82
82
  - README.md
83
83
  - lib/rubyfocus.rb
84
84
  - lib/rubyfocus/core_ext.rb
@@ -131,4 +131,3 @@ signing_key:
131
131
  specification_version: 4
132
132
  summary: Pure ruby bridge to OmniFocus.
133
133
  test_files: []
134
- has_rdoc:
data/HISTORY.md DELETED
@@ -1,81 +0,0 @@
1
- # History
2
-
3
- ## 0.5.9 // 2016-09-04
4
-
5
- Further Omnifocus database format changes result in shennanigans with rubyfocus. All fixed.
6
-
7
- * [Fixed] Blank entries in updates are now treated as "no change", rather than "new value is nil".
8
-
9
- ## 0.5.8 // 2016-09-02
10
-
11
- Heading off edge cases, again a result of the new Omnifocus database format
12
-
13
- * [Fixed] Projects inside folders were being reported as having no container, due to empty `<task/`> tags. Now fixed.
14
-
15
- ## 0.5.7 // 2016-09-02
16
-
17
- A quick fix for the new OF database format
18
-
19
- * [Fixed] Empty `<project/>` tags in a task description will no longer cause Rubyfocus to treat said task as a project.
20
-
21
- ## 0.5.6 // 2016-09-01
22
-
23
- * [New] Added `Time.safely_parse`, which will not choke on empty strings or nil values
24
- * [Fixed] `conditional_set` will no longer choke on empty string for times
25
-
26
- ## 0.5.5 // 2016-05-18
27
-
28
- * [Fixed] If there are no patches, `Fetcher#head`s will return the ID of the base file.
29
- * [Fixed] `Fetcher#head` will now return the ID of the most recent patch, not the patch itself.
30
- * [New] `Searchable` objects will now respond to `find_all`, which is an alias of `select`.
31
- * [Fixed] `RankedItem#contained_within?` will now check against all objects matching a block or hash, rather than just the first one that the document can find.
32
-
33
- ## 0.5.4 // 2016-02-08
34
-
35
- * [Fixed] `LocalFetcher` will now try the default App Store location if it can't find anything at the normal location.
36
-
37
- ## 0.5.3 // 2016-02-04
38
-
39
- * [Fixed] Re-did the code determining whether a task was blocked. Now tasks are considered blocked if their immediate container is blocked.
40
- * [Fixed] Caching some task filters on the `Task` class was causing issues. Removed caching, which shouldn't hit performance much.
41
-
42
- ## 0.5.2 // 2016-02-04
43
-
44
- * [Fixed] Whoops! Did I leave HTTParty out of the gem install list? My bad!
45
-
46
- ## 0.5.1 // 2016-02-03
47
-
48
- * [Fixed] `Task#next_available_task` should no longer cause errors when a project has no tasks.
49
-
50
- ## 0.5.0 // 2016-01-20
51
-
52
- Now work out how close to (or far from) the head of your document you are!
53
-
54
- * [New] `Fetcher#head` returns the most recent patch.
55
- * [New] `Fetcher#can_reach_head_from?(id)` will inform you if you can get to the head from a given ID.
56
-
57
- ## 0.4.0 // 2016-01-01
58
-
59
- * Happy new year!
60
- * [Modified] Container IDRef is now located on RankedItem, rather than having several on each RankedItem subclass.
61
- * [New] RankedItems can look at their ancestry much more easily, using RankedItem#ancestry and RankedItem#contained_within?
62
- * [New] Documents now forbid elements with duplicate IDs unless Document#allow_duplicate_ids is set to true.
63
- * [New] Patchers now treate CREATE nodes on elements whose IDs already exist in the database as UPDATE nodes
64
- * [Fixed] Patchers will now interpret missing parameters as "default values" e.g. project update without `status` parameter assumed to be active.
65
-
66
- ## 0.3.1 // 2015-12-31
67
-
68
- * [Bugfix] IDRefs will now return `nil` if the relevant ID is not set.
69
-
70
- ## 0.3.0 // 2015-10-17
71
-
72
- * [New] Now supports remote syncing with the Omni Sync Server!
73
-
74
- ## 0.2.0 // 2015-10-11
75
-
76
- * [Bugfix] Will now turn tasks into projects and projects into tasks if the user has done this in OmniFocus.
77
- * [Bugfix] Rubyfocus::Patch now does patch application, rather than delegating to the Fetcher.
78
-
79
- ## 0.1.0 // 2015-10-10
80
-
81
- * Hello, world!