todo-txt 0.1

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.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Todo.txt
2
+
3
+ This is a Ruby client library for Gina Trapani's [todo.txt](https://github.com/ginatrapani/todo.txt-cli/). It allows for easy parsing of task lists and tasks in the todo.txt format.
4
+
5
+ # Installation
6
+
7
+ Installation is very simple. The project is packaged as a Ruby gem and can be installed by running:
8
+
9
+ gem install todo-txt
10
+
11
+ # Usage
12
+
13
+ ## Todo::List
14
+
15
+ A `Todo::List` object encapsulates your todo.txt file. You initialise it by passing the path to your todo.txt to the constructor:
16
+
17
+ ``` ruby
18
+ require 'todo-txt'
19
+
20
+ list = Todo::List.new "path/to/todo.txt"
21
+ ```
22
+
23
+ `Todo::List` subclasses `Array` so it has all of the standard methods that are available on an array. It is, basically, an array of `Todo::Task` items.
24
+
25
+ ### Filtering
26
+
27
+ You can filter your todo list by priority, project, context or a combination of all three with ease.
28
+
29
+ ``` ruby
30
+ require 'todo-txt
31
+
32
+ list = Todo::List.new "path/to/todo.txt"
33
+
34
+ list.by_priority "A"
35
+ # => Contains a Todo::List object with only priority A tasks.
36
+
37
+ list.by_context "@code"
38
+ # => Returns a new Todo::List with only tasks that have a @code context.
39
+
40
+ list.by_project "+manhatten"
41
+ # => Returns a new Todo::List with only tasks that are part of the
42
+ +manhatten project (see what I did there?)
43
+
44
+ # And you can combine these, like so
45
+ list.by_project("+manhatten").by_priority("B")
46
+ ```
47
+
48
+ ## Todo::Task
49
+
50
+ A `Todo::Task` object can be created from a standard task string if you don't want to use the `Todo::List` approach (though using `Todo::List` is recommended).
51
+
52
+ ``` ruby
53
+ require 'todo-txt'
54
+
55
+ task = Todo::Task.new "(A) This task is top priority! +project @context"
56
+
57
+ task.priority
58
+ # => "A"
59
+
60
+ task.contexts
61
+ # => ["@context"]
62
+
63
+ task.projects
64
+ # => ["+project"]
65
+
66
+ task.text
67
+ # => "This task is top priority!"
68
+
69
+ task.orig
70
+ # => "(A) This task is top priority! +project @context"
71
+ ```
72
+
73
+ ### Comparable
74
+
75
+ The `Todo::Task` object includes the `Comparable` mixin. It compares with other tasks and sorts by priority in descending order.
76
+
77
+ ``` ruby
78
+ task1 = Todo::Task.new "(A) Priority A."
79
+ task2 = Todo::Task.new "(B) Priority B."
80
+
81
+ task1 > task2
82
+ # => true
83
+
84
+ task1 == task2
85
+ # => false
86
+
87
+ task2 > task1
88
+ # => false
89
+ ```
90
+
91
+ Tasks without a priority will always be less than a task with a priority.
92
+
93
+ # Requirements
94
+
95
+ The todo-txt gem requires Ruby 1.9.2 or higher. It doesn't currently run on 1.8.7.
data/lib/todo-txt.rb ADDED
@@ -0,0 +1,5 @@
1
+ # Require all files in the main lib directory
2
+ Dir[File.dirname(__FILE__) + '/todo-txt/*.rb'].each do |file|
3
+ require file
4
+ end
5
+
@@ -0,0 +1,87 @@
1
+ module Todo
2
+ class List < Array
3
+ # Initializes a Todo List object with a path to the corresponding todo.txt
4
+ # file. For example, if your todo.txt file is located at:
5
+ #
6
+ # /home/sam/Dropbox/todo/todo.txt
7
+ #
8
+ # You would initialize this object like do:
9
+ #
10
+ # list = Todo::List.new "/home/sam/Dropbox/todo/todo-txt"
11
+ #
12
+ # Alternately, you can initialize this object with an array of strings or
13
+ # tasks. If the array is of strings, the strings will be converted into
14
+ # tasks. You can supply a mixed list of string and tasks if you wish.
15
+ #
16
+ # Example:
17
+ #
18
+ # array = Array.new
19
+ # array.push "(A) A string task!"
20
+ # array.push Todo::Task.new("(A) An actual task!")
21
+ #
22
+ # list = Todo::List.new array
23
+ def initialize list
24
+ if list.is_a? Array
25
+ # No file path was given.
26
+ @path = nil
27
+
28
+ # If path is an array, loop over it, adding to self.
29
+ list.each do |task|
30
+ # If it's a string, make a new task out of it.
31
+ if task.is_a? String
32
+ self.push Todo::Task.new task
33
+ # If it's a task, just add it.
34
+ elsif task.is_a? Todo::Task
35
+ self.push task
36
+ end
37
+ end
38
+ elsif list.is_a? String
39
+ @path = list
40
+
41
+ # Read in lines from file, create Todo::Tasks out of them and push them
42
+ # onto self.
43
+ File.open(list) do |file|
44
+ file.each_line { |line| self.push Todo::Task.new line }
45
+ end
46
+ end
47
+ end
48
+
49
+ # The path to the todo.txt file that you supplied when you created the
50
+ # Todo::List object.
51
+ def path
52
+ @path
53
+ end
54
+
55
+ # Filters the list by priority and returns a new list.
56
+ #
57
+ # Example:
58
+ #
59
+ # list = Todo::List.new "/path/to/list"
60
+ # list.by_priority "A" #=> Will be a new list with only priority A tasks
61
+ def by_priority priority
62
+ Todo::List.new self.select { |task| task.priority == priority }
63
+ end
64
+
65
+ # Filters the list by context and returns a new list.
66
+ #
67
+ # Example:
68
+ #
69
+ # list = Todo::List.new "/path/to/list"
70
+ # list.by_context "@context" #=> Will be a new list with only tasks
71
+ # containing "@context"
72
+ def by_context context
73
+ Todo::List.new self.select { |task| task.contexts.include? context }
74
+ end
75
+
76
+ # Filters the list by project and returns a new list.
77
+ #
78
+ # Example:
79
+ #
80
+ # list = Todo::List.new "/path/to/list"
81
+ # list.by_project "+project" #=> Will be a new list with only tasks
82
+ # containing "+project"
83
+ def by_project project
84
+ Todo::List.new self.select { |task| task.projects.include? project }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,114 @@
1
+ module Todo
2
+ class Task
3
+ include Comparable
4
+
5
+ # The regular expression used to match contexts.
6
+ def self.contexts_regex
7
+ /(?:\s+|^)@\w+/
8
+ end
9
+
10
+ # The regex used to match projects.
11
+ def self.projects_regex
12
+ /(?:\s+|^)\+\w+/
13
+ end
14
+
15
+ # The regex used to match priorities.
16
+ def self.priotity_regex
17
+ /^\([A-Za-z]\)\s+/
18
+ end
19
+
20
+ # Creates a new task. The argument that you pass in must be a string.
21
+ def initialize task
22
+ @orig = task
23
+ end
24
+
25
+ # Returns the original content of the task.
26
+ #
27
+ # Example:
28
+ #
29
+ # task = Todo::Task.new "(A) @context +project Hello!"
30
+ # task.orig #=> "(A) @context +project Hello!"
31
+ def orig
32
+ @orig
33
+ end
34
+
35
+ # Returns the priority, if any.
36
+ #
37
+ # Example:
38
+ #
39
+ # task = Todo::Task.new "(A) Some task."
40
+ # task.priority #=> "A"
41
+ #
42
+ # task = Todo::Task.new "Some task."
43
+ # task.priority #=> nil
44
+ def priority
45
+ @priority ||= if orig =~ self.class.priotity_regex
46
+ orig[1]
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ # Retrieves an array of all the @context annotations.
53
+ #
54
+ # Example:
55
+ #
56
+ # task = Todo:Task.new "(A) @context Testing!"
57
+ # task.context #=> ["@context"]
58
+ def contexts
59
+ @contexts ||= orig.scan(self.class.contexts_regex).map { |item| item.strip }
60
+ end
61
+
62
+ # Retrieves an array of all the +project annotations.
63
+ #
64
+ # Example:
65
+ #
66
+ # task = Todo:Task.new "(A) +test Testing!"
67
+ # task.projects #=> ["+test"]
68
+ def projects
69
+ @projects ||= orig.scan(self.class.projects_regex).map { |item| item.strip }
70
+ end
71
+
72
+ # Gets just the text content of the todo, without the priority, contexts
73
+ # and projects annotations.
74
+ #
75
+ # Example:
76
+ #
77
+ # task = Todo::Task.new "(A) @test Testing!"
78
+ # task.text #=> "Testing!"
79
+ def text
80
+ @text ||= orig.
81
+ gsub(self.class.priotity_regex, '').
82
+ gsub(self.class.contexts_regex, '').
83
+ gsub(self.class.projects_regex, '').
84
+ strip
85
+ end
86
+
87
+ # Compares the priorities of two tasks.
88
+ #
89
+ # Example:
90
+ #
91
+ # task1 = Todo::Task.new "(A) Priority A."
92
+ # task2 = Todo::Task.new "(B) Priority B."
93
+ #
94
+ # task1 > task2
95
+ # # => true
96
+ #
97
+ # task1 == task2
98
+ # # => false
99
+ #
100
+ # task2 > task1
101
+ # # => false
102
+ def <=> other_task
103
+ if self.priority.nil? and other_task.priority.nil?
104
+ 0
105
+ elsif other_task.priority.nil?
106
+ 1
107
+ elsif self.priority.nil?
108
+ -1
109
+ else
110
+ other_task.priority <=> self.priority
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,5 @@
1
+ (A) Crack the Da Vinci Code.
2
+ (B) +winning Win.
3
+ @context Give it some context.
4
+ Just a POD: Plain old task.
5
+ (C) +project @context This one has it all!
@@ -0,0 +1 @@
1
+ require_relative '../lib/todo-txt'
@@ -0,0 +1,71 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Todo::List do
4
+ # A helper method to grab the test data list.
5
+ def list
6
+ Todo::List.new(File.dirname(__FILE__) + '/../data/todo.txt')
7
+ end
8
+
9
+ it 'should grab a list of Todo::Tasks' do
10
+ list.each do |task|
11
+ task.class.should == Todo::Task
12
+ end
13
+
14
+ # This is a little bit fragile but it helps me sleep at night.
15
+ list[0].priority.should == "A"
16
+ end
17
+
18
+ it 'should be able to filter by priority' do
19
+ list.by_priority("A").each do |task|
20
+ task.priority.should == "A"
21
+ end
22
+
23
+ # Make sure some data was actually checked
24
+ list.by_priority("A").length.should be > 0
25
+ end
26
+
27
+ it 'should be able to filter by context' do
28
+ list.by_context("@context").each do |task|
29
+ task.contexts.should include "@context"
30
+ end
31
+
32
+ # Make sure some data was actually checked
33
+ list.by_context("@context").length.should be > 0
34
+ end
35
+
36
+ it 'should be able to filter by project' do
37
+ list.by_project("+project").each do |task|
38
+ task.projects.should include "+project"
39
+ end
40
+
41
+ # Make sure some data was actually checked
42
+ list.by_project("+project").length.should be > 0
43
+ end
44
+
45
+ it 'should be able to filter by project, context and priority' do
46
+ filtered = list.by_project("+project").
47
+ by_context("@context").
48
+ by_priority("C")
49
+
50
+ filtered.each do |task|
51
+ task.projects.should include "+project"
52
+ task.contexts.should include "@context"
53
+ task.priority.should == "C"
54
+ end
55
+
56
+ # Make sure some data was actually checked
57
+ filtered.length.should be > 0
58
+ end
59
+
60
+ it 'should be sortable' do
61
+ list.sort.each_cons(2) do |task_a, task_b|
62
+ task_a.should be <= task_b
63
+ end
64
+
65
+ # Make sure some data was actually checked
66
+ list.sort.length.should be > 0
67
+
68
+ # Class should still be Todo::List
69
+ list.sort.class.should == Todo::List
70
+ end
71
+ end
@@ -0,0 +1,67 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Todo::Task do
4
+ it 'should recognise priorities' do
5
+ task = Todo::Task.new "(A) Hello world!"
6
+ task.priority.should == "A"
7
+ end
8
+
9
+ it 'should only recognise priorities at the start of a task' do
10
+ task = Todo::Task.new "Hello, world! (A)"
11
+ task.priority.should == nil
12
+ end
13
+
14
+ it 'should recognise contexts' do
15
+ task = Todo::Task.new "Hello, world! @test"
16
+ task.contexts.should == ["@test"]
17
+ end
18
+
19
+ it 'should recognise multiple contexts' do
20
+ task = Todo::Task.new "Hello, world! @test @test2"
21
+ task.contexts.should == ["@test", "@test2"]
22
+ end
23
+
24
+ it 'should recognise projects' do
25
+ task = Todo::Task.new "Hello, world! +test"
26
+ task.projects.should == ["+test"]
27
+ end
28
+
29
+ it 'should recognise multiple projects' do
30
+ task = Todo::Task.new "Hello, world! +test +test2"
31
+ task.projects.should == ["+test", "+test2"]
32
+ end
33
+
34
+ it 'should retain the original task' do
35
+ task = Todo::Task.new "(A) This is an awesome task, yo. +winning"
36
+ task.orig.should == "(A) This is an awesome task, yo. +winning"
37
+ end
38
+
39
+ it 'should be able to get just the text, no contexts etc.' do
40
+ task = Todo::Task.new "(B) This is a sweet task. @context +project"
41
+ task.text.should == "This is a sweet task."
42
+ end
43
+
44
+ it 'should be comparable' do
45
+ task1 = Todo::Task.new "(A) Top priority, y'all!"
46
+ task2 = Todo::Task.new "(B) Not quite so high."
47
+
48
+ assertion = task1 > task2
49
+ assertion.should == true
50
+ end
51
+
52
+ it 'should be comparable to task without priority' do
53
+ task1 = Todo::Task.new "Top priority, y'all!"
54
+ task2 = Todo::Task.new "(B) Not quite so high."
55
+
56
+ assertion = task1 < task2
57
+ assertion.should == true
58
+ end
59
+
60
+ it 'should be able to compare two tasks without priority' do
61
+ task1 = Todo::Task.new "Top priority, y'all!"
62
+ task2 = Todo::Task.new "Not quite so high."
63
+
64
+ assertion = task1 == task2
65
+ assertion.should == true
66
+ end
67
+ end
data/todo-txt.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{todo-txt}
3
+ s.version = "0.1"
4
+ s.date = %q{2011-08-19}
5
+ s.authors = ["Sam Rose"]
6
+ s.email = %q{samwho@lbak.co.uk}
7
+ s.summary = %q{A client library for parsing todo.txt files.}
8
+ s.homepage = %q{http://lbak.co.uk}
9
+ s.description = %q{Allows for simple parsing of todo.txt files, as per Gina Trapani's todo.txt project.}
10
+ s.required_ruby_version = '>= 1.9.2'
11
+ s.license = 'GPL-2'
12
+
13
+ # Add all files to the files parameter.
14
+ s.files = []
15
+ Dir["**/*.*"].each { |path| s.files.push path }
16
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todo-txt
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sam Rose
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-19 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Allows for simple parsing of todo.txt files, as per Gina Trapani's todo.txt
15
+ project.
16
+ email: samwho@lbak.co.uk
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - spec/todo-txt/list_spec.rb
23
+ - spec/todo-txt/task_spec.rb
24
+ - spec/data/todo.txt
25
+ - spec/spec_helper.rb
26
+ - todo-txt.gemspec
27
+ - lib/todo-txt/list.rb
28
+ - lib/todo-txt/task.rb
29
+ - lib/todo-txt.rb
30
+ homepage: http://lbak.co.uk
31
+ licenses:
32
+ - GPL-2
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 1.9.2
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.8
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: A client library for parsing todo.txt files.
55
+ test_files: []