ardekantur-taskomaly 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +8 -0
- data/README.rdoc +54 -0
- data/Rakefile +73 -0
- data/lib/api.rb +125 -0
- data/lib/paper.rb +52 -0
- data/lib/project.rb +19 -0
- data/lib/task.rb +80 -0
- data/lib/taskomaly.rb +1 -0
- metadata +61 -0
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
taskomaly: access tasko and taskpaper files in ruby
|
2
|
+
Copyright (C) 2008 Ardekantur
|
3
|
+
|
4
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
5
|
+
|
6
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
7
|
+
|
8
|
+
Please see <http://www.gnu.org/licenses/> for the full version of this license.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= taskomaly
|
2
|
+
|
3
|
+
access your Tasko or TaskPaper papers. in ruby.
|
4
|
+
|
5
|
+
== you need to clean your room
|
6
|
+
|
7
|
+
=== make it a project
|
8
|
+
|
9
|
+
proj = Taskomaly::Project.new 'Room Cleaning'
|
10
|
+
|
11
|
+
=== add some tasks to it
|
12
|
+
|
13
|
+
proj.add 'put away clean laundry'
|
14
|
+
proj.add 'wash dirty dishes'
|
15
|
+
|
16
|
+
=== tag those suckas up
|
17
|
+
|
18
|
+
proj.add 'file taxes @april @15'
|
19
|
+
proj.tasks.last.tags # [:april, :"15"]
|
20
|
+
|
21
|
+
proj.add 'organize shelf'
|
22
|
+
proj.tasks.last.tag :knickknacks, 1000, 'september'
|
23
|
+
proj.tasks.last.tags # [:knickknacks, :"1000", :september]
|
24
|
+
|
25
|
+
== working with tasko
|
26
|
+
|
27
|
+
t = Taskomaly::With :user => 9999, :key => 'd9cca721a735dac4efe709e0f3518373'
|
28
|
+
|
29
|
+
or, create this file:
|
30
|
+
|
31
|
+
# ~/.tasks.yml
|
32
|
+
user: 9999
|
33
|
+
key: d9cca721a735dac4efe709e0f3518373
|
34
|
+
|
35
|
+
and do this:
|
36
|
+
|
37
|
+
t = Taskomaly::From '~/.tasks.yml'
|
38
|
+
|
39
|
+
=== getting your papers
|
40
|
+
|
41
|
+
t.get :papers # ['Paper One', 'Paper Two']
|
42
|
+
p = t.papers.first
|
43
|
+
|
44
|
+
puts p.name # 'Paper One'
|
45
|
+
puts p.body # duh
|
46
|
+
|
47
|
+
=== change + upload
|
48
|
+
|
49
|
+
p.body["@today"] = "@tomorrow"
|
50
|
+
p.save # true if groovy, false if failed
|
51
|
+
|
52
|
+
=== made a mistake? refresh from the server
|
53
|
+
|
54
|
+
p.refresh # true if groovy, false if failed
|
data/Rakefile
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'hanna/rdoctask'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rubygems/specification'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
GEM = "taskomaly"
|
9
|
+
GEM_VERSION = "0.0.8"
|
10
|
+
AUTHOR = "Ardekantur"
|
11
|
+
EMAIL = "greystone@ardekantur.com"
|
12
|
+
HOMEPAGE = "http://github.com/ardekantur/taskomaly"
|
13
|
+
SUMMARY = "use taskpaper papers and tasko in ruby"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = GEM
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README.rdoc", "LICENSE"]
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = s.summary
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
|
27
|
+
# Uncomment this to add a dependency
|
28
|
+
# s.add_dependency "foo"
|
29
|
+
|
30
|
+
s.require_path = 'lib'
|
31
|
+
s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{lib,specs}/**/*")
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
35
|
+
pkg.gem_spec = spec
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "install the gem locally"
|
39
|
+
task :install => [:package] do
|
40
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "create a gemspec file"
|
44
|
+
task :make_spec do
|
45
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
46
|
+
file.puts spec.to_ruby
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Run all specs"
|
51
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
52
|
+
t.spec_files = FileList['spec/*.rb']
|
53
|
+
t.spec_opts = ['--color']
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "generate rdoc documentation"
|
57
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
58
|
+
rdoc.rdoc_files.include('README.rdoc', 'LICENSE' ).
|
59
|
+
include('lib/**/*.rb')
|
60
|
+
|
61
|
+
rdoc.main = "README.rdoc"
|
62
|
+
rdoc.rdoc_dir = 'doc' # rdoc output folder
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "run rspec + rcov"
|
66
|
+
Spec::Rake::SpecTask.new("spec:rcov") do |t|
|
67
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
68
|
+
t.rcov_opts = ['--exclude', "spec/,rcov.rb,rspec.rb,spec*,gems*"]
|
69
|
+
t.rcov = true
|
70
|
+
t.rcov_dir = 'doc/coverage'
|
71
|
+
end
|
72
|
+
|
73
|
+
task :default => :spec
|
data/lib/api.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module Taskomaly
|
6
|
+
|
7
|
+
def self.From file
|
8
|
+
return API.new(:config => file)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.With hash
|
12
|
+
return API.new(hash)
|
13
|
+
end
|
14
|
+
|
15
|
+
class API
|
16
|
+
|
17
|
+
SERVICE = 'http://taskodone.com/api'
|
18
|
+
SUPPORTED_ACTIONS = [ :papers, :paper, :rename, :edit, :new, :delete ]
|
19
|
+
|
20
|
+
attr_reader :response
|
21
|
+
attr_reader :papers
|
22
|
+
|
23
|
+
# Creates an instance of the API processor with +hash+ passed a set of configuration
|
24
|
+
# options in a hash. +hash+ should either be a Tasko user ID and API key (in this case
|
25
|
+
# +:user+ and +:key+), or a file where those keys are located in YAML format (in this case
|
26
|
+
# +:config+).
|
27
|
+
def initialize hash
|
28
|
+
@config = {}
|
29
|
+
|
30
|
+
raise ArgumentError,
|
31
|
+
'please specify either :user and :key or :config' unless (hash.has_key? :user and hash.has_key? :key) or (hash.has_key? :config)
|
32
|
+
|
33
|
+
@config['user'] = hash[:user] if hash.has_key? :user
|
34
|
+
@config['key'] = hash[:key] if hash.has_key? :key
|
35
|
+
|
36
|
+
if hash.has_key? :config
|
37
|
+
begin
|
38
|
+
@config = parse_config(File.expand_path(hash[:config]))
|
39
|
+
rescue
|
40
|
+
raise ArgumentError, "unable to load from file #{hash[:config]}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
# The user ID specified in the API configuration.
|
47
|
+
def user; @config['user']; end
|
48
|
+
|
49
|
+
# The API key specified in the API configuration.
|
50
|
+
def key; @config['key']; end
|
51
|
+
|
52
|
+
# Request something from the server. See SUPPORTED_ACTIONS for what is possible to retrieve
|
53
|
+
# and send. A brief summary follows:
|
54
|
+
#
|
55
|
+
# <tt>api.request :papers</tt>:: retrieve a list of all papers the user has saved to Tasko.
|
56
|
+
# <tt>api.request :paper, 'Paper Name'</tt>:: return the single paper with the name passed to +request+.
|
57
|
+
# <tt>api.request :rename, 'Old Paper Name', 'New Paper Name'</tt>:: rename one of the papers in the account.
|
58
|
+
# <tt>api.request :edit, 'Paper Name', 'Paper Body'</tt>:: save a new version of the document to Tasko.
|
59
|
+
def request type, *args
|
60
|
+
raise ArgumentError, "invalid send request type #{type}" unless SUPPORTED_ACTIONS.include? type
|
61
|
+
|
62
|
+
begin
|
63
|
+
@req = request_generator
|
64
|
+
@response = @req.send :post, (base_payload type, *args)
|
65
|
+
rescue SocketError
|
66
|
+
raise 'the site appears to be unavailable'
|
67
|
+
rescue
|
68
|
+
raise 'there was an error processing your request'
|
69
|
+
end
|
70
|
+
|
71
|
+
return handle_response(type, *args)
|
72
|
+
end
|
73
|
+
|
74
|
+
alias :get :request
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def handle_response type, *args
|
79
|
+
doc = REXML::Document.new @response
|
80
|
+
case type
|
81
|
+
when :papers
|
82
|
+
@papers = doc.elements.to_a('//string').map { |m| m.text }
|
83
|
+
return @papers
|
84
|
+
when :paper
|
85
|
+
@data = doc.elements.to_a('//string').map { |m| m.text }
|
86
|
+
return Taskomaly::Paper.new( args.first, @data.last, self )
|
87
|
+
when :edit
|
88
|
+
@data = doc.elements.to_a('//string').map { |m| m.text }
|
89
|
+
return true if @data.size > 0
|
90
|
+
end
|
91
|
+
|
92
|
+
return false
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
def request_generator
|
97
|
+
RestClient::Resource.new SERVICE
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_config config_filepath
|
101
|
+
YAML::load_file config_filepath
|
102
|
+
end
|
103
|
+
|
104
|
+
def base_payload method_name, *args
|
105
|
+
params = ''
|
106
|
+
extra_data = ([] << args).flatten.compact
|
107
|
+
if extra_data
|
108
|
+
extra_data.each do |data|
|
109
|
+
type = (data.class == Fixnum) ? 'integer' : 'string'
|
110
|
+
params += "<param><value><#{type}>#{data}</#{type}></value></param>\n"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
<<-XML
|
114
|
+
<methodCall><methodName>#{method_name}</methodName>
|
115
|
+
<params>
|
116
|
+
<param><value><int>#{user}</int></value></param>
|
117
|
+
<param><value><string>#{key}</string></value></param>
|
118
|
+
#{params}
|
119
|
+
</params></methodCall>
|
120
|
+
XML
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
data/lib/paper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Taskomaly
|
2
|
+
|
3
|
+
class Paper
|
4
|
+
|
5
|
+
attr_accessor :name, :body
|
6
|
+
|
7
|
+
def self.From file
|
8
|
+
raise ArgumentError, "file #{file} does not exist" unless File.exist? file
|
9
|
+
return Paper.new(
|
10
|
+
file.gsub(/\.\w+$/, '').gsub(/^.*\//, '').gsub(/[-_]/, ' ').split(' ').each{|word| word.capitalize! }.join(' '),
|
11
|
+
File.open(file, "r").readlines.join
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize name, body = "", api = nil
|
16
|
+
@name = name
|
17
|
+
@body = body
|
18
|
+
@api = api
|
19
|
+
parse_body
|
20
|
+
end
|
21
|
+
|
22
|
+
def api
|
23
|
+
return @api
|
24
|
+
end
|
25
|
+
|
26
|
+
def save
|
27
|
+
return false unless @api
|
28
|
+
return @api.request(:edit, @name, @body)
|
29
|
+
end
|
30
|
+
|
31
|
+
def refresh
|
32
|
+
return false unless @api
|
33
|
+
@body = (@api.request :paper, @name).body
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
|
37
|
+
def projects
|
38
|
+
@projects
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def parse_body
|
44
|
+
@projects = []
|
45
|
+
@body.split("\n").each do |line|
|
46
|
+
@projects << line.gsub(/:\s*$/, '').gsub(/ /, '_').downcase.to_sym if line =~ /^.*:\s*$/
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/lib/project.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Taskomaly
|
2
|
+
|
3
|
+
class Project
|
4
|
+
|
5
|
+
attr_accessor :name, :tasks
|
6
|
+
|
7
|
+
def initialize name
|
8
|
+
@name = name
|
9
|
+
@tasks = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add task
|
13
|
+
@tasks << Task.new(task) if task.class == String
|
14
|
+
@tasks << task if task.class == Taskomaly::Task
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/lib/task.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module Taskomaly
|
2
|
+
|
3
|
+
TAG_REGEX = /\@\w+/
|
4
|
+
|
5
|
+
def self.Do task
|
6
|
+
return Task.new(task)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Task
|
10
|
+
|
11
|
+
attr_accessor :desc, :tags
|
12
|
+
|
13
|
+
def initialize description
|
14
|
+
@desc, @tags = parse(description)
|
15
|
+
@delimiter = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Tag a task. Duplicate tags are ignored.
|
19
|
+
#
|
20
|
+
# t = Taskomaly::Do 'wash the dishes'
|
21
|
+
# t.tag :kitchen
|
22
|
+
# puts t.tags # [:kitchen]
|
23
|
+
# t.tag :sink, :july, 4
|
24
|
+
# puts t.tags # [:kitchen, :sink, :july, :"4"]
|
25
|
+
#
|
26
|
+
def tag *args
|
27
|
+
@tags = [] unless @tags
|
28
|
+
@tags = (@tags + args.map { |tag| tag.to_s.to_sym } ).uniq
|
29
|
+
end
|
30
|
+
|
31
|
+
# Remove tags from a task.
|
32
|
+
#
|
33
|
+
# t = Taskomaly::Do 'wash the dishes @kitchen'
|
34
|
+
# t.untag :kitchen
|
35
|
+
# puts t.display # "wash the dishes"
|
36
|
+
def untag *args
|
37
|
+
return unless @tags
|
38
|
+
@tags = (@tags - args)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Display the task, with tags appended to the end.
|
42
|
+
#
|
43
|
+
# t = Taskomaly::Do 'wash the dishes'
|
44
|
+
# t.tag :kitchen
|
45
|
+
# puts t.display # "wash the dishes @kitchen"
|
46
|
+
def display
|
47
|
+
"#{@desc} #{@tags.collect { |tag| '@' + tag.to_s }.join(@delimiter || ' ')}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Change how listing tags are delimited. +delimiter+ is a string, like <tt>','</tt>,
|
51
|
+
# that will be used to join tags. +symmetric_spacing+ is a boolean value
|
52
|
+
# that determines whether or not the delimiter should be separated by tags
|
53
|
+
# on both sides, or just the right side.
|
54
|
+
# Some examples:
|
55
|
+
#
|
56
|
+
# t = Taskomaly::Do 'wash the dishes @dishes @sink @other'
|
57
|
+
# t.display # 'wash the dishes @dishes @sink @other'
|
58
|
+
#
|
59
|
+
# t.delimit_with ','
|
60
|
+
# t.display # 'wash the dishes @dishes, @sink, @other'
|
61
|
+
#
|
62
|
+
# t.delimit_with '/'
|
63
|
+
# t.display # 'wash the dishes @dishes/ @sink/ @other'
|
64
|
+
# t.delimit_with '/', true
|
65
|
+
# t.display # 'wash the dishes @dishes / @sink / @other'
|
66
|
+
#
|
67
|
+
def delimit_with delimiter, symmetric_spacing = false
|
68
|
+
@delimiter = (symmetric_spacing ? ' ' : '') + delimiter + ' '
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def parse description
|
75
|
+
return description.gsub(TAG_REGEX, '').strip.squeeze(' '), description.scan(TAG_REGEX).map { |tag| tag.to_s.gsub(/^\@/, '').to_sym }.uniq
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/lib/taskomaly.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
%w/ api paper project task /.each { |x| require x }
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ardekantur-taskomaly
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ardekantur
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: use taskpaper papers and tasko in ruby
|
17
|
+
email: greystone@ardekantur.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- lib/api.rb
|
30
|
+
- lib/paper.rb
|
31
|
+
- lib/project.rb
|
32
|
+
- lib/task.rb
|
33
|
+
- lib/taskomaly.rb
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://github.com/ardekantur/taskomaly
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: use taskpaper papers and tasko in ruby
|
60
|
+
test_files: []
|
61
|
+
|