mastodon2 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.md
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE.md
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ doc
23
+ .yardoc
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Colin Shea
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.**
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Mastodon
2
+ A [todo.txt][ttxt] parser.
3
+
4
+ [ttxt]: http://ginatrapani.github.com/todo.txt-cli/
5
+
6
+ ## Installation
7
+
8
+ sudo gem install mastodon
9
+
10
+ ## Usage
11
+
12
+ require 'mastodon'
13
+ mast = Mastodon.new(File.readlines("todo.txt"))
14
+ # List all the projects
15
+ mast.projects
16
+ # List all the contexts
17
+ mast.contexts
18
+
19
+
20
+ ## See Also
21
+ There are other links you can take a look at. If you care to, that is.
22
+
23
+ * [Run Code Run][rcr] (continuous integration)
24
+ * [Caliper & metric\_fu report][calip]
25
+ * [RDoc.info Documentation][rdoci] ([yardoc.org][yardoc])
26
+
27
+ [rcr]: http://runcoderun.com/evaryont/mastodon
28
+ [calip]: http://getcaliper.com/caliper/project?repo=git%3A%2F%2Fgithub.com%2Fevaryont%2Fmastodon.git
29
+ [rdoci]: http://rdoc.info/projects/evaryont/mastodon
30
+ [yardoc]: http://yardoc.org/docs/evaryont-mastodon
31
+
32
+ ## Copyright
33
+ Mastodon is released under the MIT license. Copyright (C) Colin Shea 2009. For
34
+ more information, consult LICENSE.txt for more information.
data/Rakefile ADDED
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ task :default => :test
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "mastodon2"
10
+ gem.summary = %Q{A Ruby parser for todo.txt files}
11
+ gem.description = %Q{A Ruby parser for todo.txt files}
12
+ gem.email = "colin@evaryont.me"
13
+ gem.homepage = "http://evaryont.me"
14
+ gem.authors = ["Colin Shea"]
15
+ gem.add_development_dependency "riot", ">= 0"
16
+ gem.add_development_dependency "yard", ">= 0"
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+ task :test => :check_dependencies
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/*_test.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ begin
45
+ require 'reek/adapters/rake_task'
46
+ Reek::RakeTask.new do |t|
47
+ t.fail_on_error = true
48
+ t.verbose = false
49
+ t.source_files = 'lib/**/*.rb'
50
+ end
51
+ rescue LoadError
52
+ task :reek do
53
+ abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
54
+ end
55
+ end
56
+
57
+ begin
58
+ require 'roodi'
59
+ require 'roodi_task'
60
+ RoodiTask.new do |t|
61
+ t.verbose = false
62
+ end
63
+ rescue LoadError
64
+ task :roodi do
65
+ abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
66
+ end
67
+ end
68
+
69
+ begin
70
+ require 'yard'
71
+ YARD::Rake::YardocTask.new do |t|
72
+ t.files = ["lib/**/*.rb"]
73
+ end
74
+ rescue LoadError
75
+ task :yard do
76
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
77
+ end
78
+ end
79
+
80
+ namespace :release do
81
+ desc "Release to all locations: Git, GitHub and GemCutter"
82
+ task :all => ["git:release", "github:release", "gemcutter:release"]
83
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 3
4
+ :patch: 1
5
+ :build:
@@ -0,0 +1,15 @@
1
+ class String
2
+ # Given 'string', find all matches of regular expression (removed from
3
+ # +string+) and return them as an array of strings.
4
+ def pull_regex(regexp)
5
+ found_values = []
6
+
7
+ until ((value = self[regexp]).nil?)
8
+ vindex = index(value)
9
+ self[ vindex .. (vindex + value.length) ] = ""
10
+ found_values << value.match(regexp)[1]
11
+ end
12
+
13
+ return found_values
14
+ end
15
+ end
data/lib/mastodon.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'set'
2
+
3
+ require 'core_ext/string/pull_regex'
4
+
5
+ require 'mastodon/todo'
6
+
7
+ class Mastodon
8
+ # A context is: An at-sign (@) followed by one or more non-whitespace characters.
9
+ Context_Regex = /(?<!\+)\B@(\S+)/
10
+ # A project is: An plus sign (+) followed by one or more non-whitespace characters.
11
+ Project_Regex = /(?<!@)\B\+(\S+)/
12
+ # A priority is: A capital letter (A-Z) surrounded by parentheses, at the beginning of the line.
13
+ Priority_Regex = /^\(([A-Z])\)/
14
+
15
+ attr_reader :contexts, :projects, :todos
16
+
17
+ # +todo+: An array of strings (each being an individual todo item)
18
+ def initialize(todos)
19
+ @contexts = Set.new
20
+ @projects = Set.new
21
+ @todos = []
22
+
23
+ parse! todos.map{|line| line.strip}
24
+
25
+ @contexts = @contexts.to_a
26
+ @projects = @projects.to_a
27
+ end
28
+
29
+ def parse!(todos)
30
+ todos.each do |todo|
31
+ # Looping through the string, find the metadata (context, project,
32
+ # priority). Store it in a temporary variable, then clear it from
33
+ # the original string. Strip all remaining whitespace at the end.
34
+
35
+ current_contexts = []
36
+ current_projects = []
37
+ current_priority = nil
38
+
39
+ current_contexts = todo.pull_regex(Context_Regex)
40
+ unless current_contexts.empty?
41
+ @contexts.merge(current_contexts)
42
+ end
43
+
44
+ current_projects = todo.pull_regex(Project_Regex)
45
+ unless current_projects.empty?
46
+ @projects.merge(current_projects)
47
+ end
48
+
49
+ current_priority = todo.pull_regex(Priority_Regex)
50
+
51
+ todo.strip!
52
+ @todos << Mastodon::Todo.new(todo, current_contexts, current_projects, current_priority.first)
53
+ end
54
+ end
55
+
56
+ # How many todos there are.
57
+ def size
58
+ @todos.size
59
+ end
60
+
61
+ # Get an individual todo. The id and line number are the same. 0 index, not
62
+ # 1, as files are numbered. So line 3 is id 2. XXX: Change?
63
+ def [](id)
64
+ @todos[id]
65
+ end
66
+
67
+ # Find all todos that have the context @+context+
68
+ def find_context(context)
69
+ @todos.select { |todo| todo.contexts.include? context }
70
+ end
71
+
72
+ # Find all todos that have the project ++project+
73
+ def find_project(project)
74
+ @todos.select { |todo| todo.projects.include? project }
75
+ end
76
+ end
@@ -0,0 +1,30 @@
1
+ class Mastodon
2
+ class Todo < Struct.new(:text, :contexts, :projects, :priority)
3
+ include Comparable
4
+
5
+ def to_s
6
+ pri = priority ? "(#{priority})" : ""
7
+ ctx = contexts.empty? ? "" : "@#{contexts.join(' @')}"
8
+ prj = projects.empty? ? "" : "+#{projects.join(' +')}"
9
+
10
+ "#{pri} #{text} #{ctx} #{prj}".strip
11
+ end
12
+
13
+ def inspect
14
+ "#<Mastodon::Todo \"#{to_s}\">"
15
+ end
16
+
17
+ # Comparison operator: Sort todos by their priority first, then sort
18
+ # them by the text.
19
+ def <=>(other_todo)
20
+ return -1 if (priority.nil? and !other_todo.priority.nil?)
21
+
22
+ pri = (priority <=> other_todo.priority)
23
+ if pri == 0
24
+ return text <=> other_todo.text
25
+ else
26
+ return pri
27
+ end
28
+ end
29
+ end
30
+ end
data/mastodon.gemspec ADDED
@@ -0,0 +1,52 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{mastodon}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Colin Shea"]
12
+ s.date = %q{2009-12-23}
13
+ s.description = %q{Mastodon: A ruby parser for todo.txt files.
14
+
15
+ And the mastodon, like plain text, isn't extinct! (Yet.)}
16
+ s.email = %q{colin@evaryont.me}
17
+ s.extra_rdoc_files = [
18
+ "README.mkd"
19
+ ]
20
+ s.files = [
21
+ "Rakefile",
22
+ "VERSION.yml",
23
+ "lib/mastodon.rb",
24
+ "lib/mastodon/todo.rb",
25
+ "lib/mastodon/version.rb",
26
+ "test/run_tests.rb",
27
+ "test/test_helper.rb",
28
+ "test/test_mastodon.rb",
29
+ "test/todo.txt"
30
+ ]
31
+ s.homepage = %q{http://github.com/evaryont/mastodon/}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.5}
35
+ s.summary = %q{A ruby parser for todo.txt files}
36
+ s.test_files = [
37
+ "test/run_tests.rb",
38
+ "test/test_helper.rb",
39
+ "test/test_mastodon.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ else
48
+ end
49
+ else
50
+ end
51
+ end
52
+
@@ -0,0 +1,139 @@
1
+ require 'teststrap'
2
+
3
+ context "Mastodon" do
4
+ setup do
5
+ @todos = File.readlines(File.join(File.dirname(__FILE__), "todo.txt"))
6
+ Mastodon.new(@todos)
7
+ end
8
+
9
+ context "Projects" do
10
+ setup do
11
+ topic.projects
12
+ end
13
+
14
+ asserts_topic.equals ["proj", "proj2", "proj+phone", "proj/foo", "p_r_o_j", "p-r-o-j", "+proj", "@proj"]
15
+
16
+ asserts_topic.kind_of? Array
17
+ end
18
+
19
+ context "Contexts" do
20
+ setup do
21
+ topic.contexts
22
+ end
23
+
24
+ asserts_topic.equals ["con", "con2", "con@phone", "con/foo", "c_o_n", "c-o-n", "@con", "+con"]
25
+
26
+ asserts_topic.kind_of? Array
27
+ end
28
+
29
+ asserts "Non-existent contexts should return an empty array" do
30
+ topic.find_context("nosuchthing") == []
31
+ end
32
+ asserts "Non-existent projects should return an empty array" do
33
+ topic.find_project("thisprojectdoesntexist") == []
34
+ end
35
+
36
+ context "Context #2" do
37
+ setup do
38
+ topic.find_context("con2")
39
+ end
40
+ asserts "Context size should be greater than zero" do
41
+ topic.size > 0
42
+ end
43
+ asserts "First todo with the context 'con2' should be 'Multiple contexts'" do
44
+ topic.first.text == "Multiple contexts"
45
+ end
46
+ end
47
+
48
+ context "Project #2" do
49
+ setup do
50
+ topic.find_project("proj2")
51
+ end
52
+ should "greater than zero" do
53
+ topic.size > 0
54
+ end
55
+ asserts "First todo with the project 'proj2' should be 'Multiple projects'" do
56
+ topic.first.text == "Multiple projects"
57
+ end
58
+ end
59
+
60
+ context "Todo" do
61
+ #asserts(:size).equals @todos.size
62
+
63
+ asserts "all todos are of type Mastodon::Todo" do
64
+ !(topic.todos.map do |todo|
65
+ todo.is_a? Mastodon::Todo
66
+ end.index(false))
67
+ end
68
+
69
+ context "Lossless parsing: 1st Todo: Normal example" do
70
+ setup do
71
+ @todo = @todos[0].strip
72
+ topic[0]
73
+ end
74
+
75
+ should "be the same characters" do
76
+ topic.to_s.chars.to_a == @todo.chars.to_a
77
+ end
78
+ should "be the same length" do
79
+ topic.to_s.length == @todo.length
80
+ end
81
+ end
82
+
83
+ context "Lossless parsing: 8th Todo: Normal example, with priority" do
84
+ setup do
85
+ @todo = @todos[7].strip
86
+ topic[7]
87
+ end
88
+
89
+ should "be the same characters" do
90
+ topic.to_s.chars.to_a == @todo.chars.to_a
91
+ end
92
+ should "be the same length" do
93
+ topic.to_s.length == @todo.length
94
+ end
95
+ end
96
+
97
+ context "Lossless parsing: 17th Todo: Example without any metadata" do
98
+ setup do
99
+ @todo = @todos[16].strip
100
+ topic[16]
101
+ end
102
+
103
+ should "be the same characters" do
104
+ topic.to_s.chars.to_a == @todo.chars.to_a
105
+ end
106
+ should "be the same length" do
107
+ topic.to_s.length == @todo.length
108
+ end
109
+ end
110
+ end
111
+
112
+ asserts "13th todo should have the context 'con'" do
113
+ topic[13].contexts = ["con"]
114
+ end
115
+ asserts "14th todo should have the project 'proj'" do
116
+ topic[14].projects = ["proj"]
117
+ end
118
+
119
+ context "Priority" do
120
+ asserts "3rd todo should have no priority" do
121
+ topic[3].priority.nil?
122
+ end
123
+ asserts "4th todo should have no priority" do
124
+ topic[4].priority.nil?
125
+ end
126
+ asserts "5th todo should have priority A" do
127
+ topic[5].priority = "A"
128
+ end
129
+ asserts "6th todo should have priority Z" do
130
+ topic[6].priority = "Z"
131
+ end
132
+ asserts "7th todo should have priority Q" do
133
+ topic[7].priority = "Q"
134
+ end
135
+ asserts "8th todo should have no priority" do
136
+ topic[8].priority.nil?
137
+ end
138
+ end
139
+ end
data/test/teststrap.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'riot'
3
+ require 'mastodon'
4
+ require 'pp'
data/test/todo.txt ADDED
@@ -0,0 +1,17 @@
1
+ Todo @con +proj
2
+ left @ right @con
3
+ user@server email
4
+ Multiple projects +proj +proj2
5
+ Multiple contexts @con @con2
6
+ (A) Priority
7
+ (Z) All the way to Z
8
+ (Q) All mixed together @con +proj
9
+ Not a priority: (A)
10
+ Advanced contexts @con@phone @con/foo @c_o_n @c-o-n @@con
11
+ Advanced projects +proj+phone +proj/foo +p_r_o_j +p-r-o-j ++proj
12
+ Mixed symbols: +@proj @+con
13
+ @con Leading with a context
14
+ +proj Leading with a project
15
+ Google+Yahoo+Microsoft == monopoly
16
+ Google + Yahoo + Microsoft == monopoly
17
+ Ready to (ab)use
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mastodon2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Colin Shea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-29 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: riot
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: A Ruby parser for todo.txt files
36
+ email: colin@evaryont.me
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE.md
43
+ - README.md
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE.md
48
+ - README.md
49
+ - Rakefile
50
+ - VERSION.yml
51
+ - lib/core_ext/string/pull_regex.rb
52
+ - lib/mastodon.rb
53
+ - lib/mastodon/todo.rb
54
+ - mastodon.gemspec
55
+ - test/mastodon_test.rb
56
+ - test/teststrap.rb
57
+ - test/todo.txt
58
+ has_rdoc: true
59
+ homepage: http://evaryont.me
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.5
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: A Ruby parser for todo.txt files
86
+ test_files:
87
+ - test/mastodon_test.rb
88
+ - test/teststrap.rb