medo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +12 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +20 -0
- data/README.md +14 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/bin/medo +59 -0
- data/features/add_notes.feature +18 -0
- data/features/add_task.feature +12 -0
- data/features/list_tasks.feature +25 -0
- data/features/step_definitions/add_task_steps.rb +3 -0
- data/features/step_definitions/list_tasks_steps.rb +6 -0
- data/features/support/env.rb +14 -0
- data/lib/medo.rb +6 -0
- data/lib/medo/commands/clear.rb +9 -0
- data/lib/medo/commands/delete.rb +13 -0
- data/lib/medo/commands/done.rb +13 -0
- data/lib/medo/commands/list.rb +16 -0
- data/lib/medo/commands/new.rb +15 -0
- data/lib/medo/commands/note.rb +18 -0
- data/lib/medo/commands/show.rb +19 -0
- data/lib/medo/file_task_storage.rb +53 -0
- data/lib/medo/json_task_reader.rb +31 -0
- data/lib/medo/json_task_writer.rb +33 -0
- data/lib/medo/support.rb +6 -0
- data/lib/medo/support/decorator.rb +40 -0
- data/lib/medo/task.rb +63 -0
- data/lib/medo/task_reader.rb +8 -0
- data/lib/medo/task_writer.rb +21 -0
- data/lib/medo/terminal.rb +6 -0
- data/lib/medo/text_task_writer.rb +137 -0
- data/lib/medo/text_task_writer/decorators/colors_decorator.rb +28 -0
- data/lib/medo/text_task_writer/decorators/numbers_decorator.rb +37 -0
- data/spec/lib/file_task_storage_spec.rb +59 -0
- data/spec/lib/json_task_reader_spec.rb +26 -0
- data/spec/lib/json_task_writer_spec.rb +32 -0
- data/spec/lib/task_reader_spec.rb +9 -0
- data/spec/lib/task_spec.rb +101 -0
- data/spec/lib/task_writer_spec.rb +18 -0
- data/spec/lib/text_task_writer_spec.rb +106 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/task_stubs_spec_helper.rb +41 -0
- metadata +189 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
aruba (0.4.11)
|
5
|
+
childprocess (>= 0.2.3)
|
6
|
+
cucumber (>= 1.1.1)
|
7
|
+
ffi (>= 1.0.11)
|
8
|
+
rspec (>= 2.7.0)
|
9
|
+
builder (3.0.0)
|
10
|
+
childprocess (0.3.2)
|
11
|
+
ffi (~> 1.0.6)
|
12
|
+
cucumber (1.2.0)
|
13
|
+
builder (>= 2.1.2)
|
14
|
+
diff-lcs (>= 1.1.3)
|
15
|
+
gherkin (~> 2.10.0)
|
16
|
+
json (>= 1.4.6)
|
17
|
+
diff-lcs (1.1.3)
|
18
|
+
ffi (1.0.11)
|
19
|
+
gherkin (2.10.0)
|
20
|
+
json (>= 1.4.6)
|
21
|
+
gli (2.0.0.rc4)
|
22
|
+
json (1.7.3)
|
23
|
+
multi_json (1.3.6)
|
24
|
+
rainbow (1.1.4)
|
25
|
+
rake (0.9.2.2)
|
26
|
+
rspec (2.10.0)
|
27
|
+
rspec-core (~> 2.10.0)
|
28
|
+
rspec-expectations (~> 2.10.0)
|
29
|
+
rspec-mocks (~> 2.10.0)
|
30
|
+
rspec-core (2.10.1)
|
31
|
+
rspec-expectations (2.10.0)
|
32
|
+
diff-lcs (~> 1.1.3)
|
33
|
+
rspec-mocks (2.10.1)
|
34
|
+
simplecov (0.6.4)
|
35
|
+
multi_json (~> 1.0)
|
36
|
+
simplecov-html (~> 0.5.3)
|
37
|
+
simplecov-html (0.5.3)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
aruba (~> 0.4)
|
44
|
+
gli (>= 2.0.0.rc4)
|
45
|
+
rainbow (~> 1.1)
|
46
|
+
rake (~> 0.9)
|
47
|
+
rspec (~> 2.10)
|
48
|
+
simplecov (~> 0.6)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Vladimir
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Medo #
|
2
|
+
|
3
|
+
Simple console app for managing todos on the fly :)
|
4
|
+
|
5
|
+
[![Build Status](https://secure.travis-ci.org/v-yarotsky/medo.png)](http://travis-ci.org/v-yarotsky/medo)
|
6
|
+
|
7
|
+
## The Changelog ##
|
8
|
+
|
9
|
+
### v0.1.0 (15.06.2012) ###
|
10
|
+
* Store tasks in JSON
|
11
|
+
* Add the 'show' command
|
12
|
+
* Add colorful output
|
13
|
+
* Make output fit terminal
|
14
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake'
|
14
|
+
require 'rake/testtask'
|
15
|
+
require 'cucumber'
|
16
|
+
require 'cucumber/rake/task'
|
17
|
+
|
18
|
+
Rake::TestTask.new do |t|
|
19
|
+
t.test_files = Dir.glob('spec/**/*_spec.rb')
|
20
|
+
t.verbose = true
|
21
|
+
end
|
22
|
+
|
23
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
24
|
+
t.cucumber_opts = "features --tags ~@wip --format pretty -x"
|
25
|
+
t.fork = false
|
26
|
+
end
|
27
|
+
|
28
|
+
task :default => [:test, :features]
|
29
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/medo
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'gli'
|
8
|
+
require 'medo'
|
9
|
+
require 'medo/support'
|
10
|
+
require 'medo/file_task_storage'
|
11
|
+
rescue LoadError => e #development
|
12
|
+
raise if $loaded
|
13
|
+
$:.unshift File.expand_path('../../lib', __FILE__) #load what we work on, even if gem installed
|
14
|
+
require 'bundler'
|
15
|
+
Bundler.setup(:default)
|
16
|
+
$loaded = true
|
17
|
+
retry
|
18
|
+
end
|
19
|
+
|
20
|
+
include GLI::App
|
21
|
+
include Medo
|
22
|
+
|
23
|
+
program_desc 'Simple CLI To-Do manager'
|
24
|
+
version VERSION
|
25
|
+
|
26
|
+
commands_from 'medo/commands'
|
27
|
+
|
28
|
+
default_command :list
|
29
|
+
|
30
|
+
desc "A file with tasks"
|
31
|
+
flag [:f, "tasks-file"], :default_value => File.join(ENV['HOME'], '.medo-tasks')
|
32
|
+
|
33
|
+
desc "Do not use colorful output"
|
34
|
+
switch "no-color", :negatable => false
|
35
|
+
|
36
|
+
Signal.trap("SIGINT") do
|
37
|
+
puts "Terminating"
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
|
41
|
+
around do |global_options, command, options, arguments, cmd|
|
42
|
+
FileTaskStorage.using_storage(global_options.fetch(:"tasks-file")) do |the_storage|
|
43
|
+
define_singleton_method(:storage) { the_storage }
|
44
|
+
|
45
|
+
def self.choose_task(argv, tasks)
|
46
|
+
input = argv.shift
|
47
|
+
number = Integer(input) rescue
|
48
|
+
raise(ArgumentError, "Invalid task #: #{input}")
|
49
|
+
task = tasks.reject(&:done?).sort[number - 1] or raise RuntimeError,
|
50
|
+
"No such task!"
|
51
|
+
[task, number]
|
52
|
+
end
|
53
|
+
|
54
|
+
cmd.call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
run(ARGV)
|
59
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Add note to task
|
2
|
+
In order to be able to sketch some ideas
|
3
|
+
As a user
|
4
|
+
I want to add notes to my tasks
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given there's no file "/tmp/test-medo-tasks"
|
8
|
+
|
9
|
+
Scenario: Add todo
|
10
|
+
When I successfully run `medo --tasks-file=/tmp/test-medo-tasks new Hello World`
|
11
|
+
And I successfully run `medo --tasks-file=/tmp/test-medo-tasks new Goodbye Windows`
|
12
|
+
And I successfully run `medo --tasks-file=/tmp/test-medo-tasks note 1 "Trash the PC"`
|
13
|
+
And I successfully run `medo --tasks-file=/tmp/test-medo-tasks note 2 The Note`
|
14
|
+
And I successfully run `medo --tasks-file=/tmp/test-medo-tasks show 1`
|
15
|
+
Then the output should contain "Trash the PC"
|
16
|
+
And the output should not contain "The Note"
|
17
|
+
When I successfully run `medo --tasks-file=/tmp/test-medo-tasks show 2`
|
18
|
+
Then the output should contain "The Note"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Add todo
|
2
|
+
In order to be able to keep my in focus
|
3
|
+
As a user
|
4
|
+
I want to add tasks to lists
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given there's no file "/tmp/test-medo-tasks"
|
8
|
+
|
9
|
+
Scenario: Add todo
|
10
|
+
When I successfully run `medo --tasks-file=/tmp/test-medo-tasks new Hello World`
|
11
|
+
And I successfully run `medo --tasks-file=/tmp/test-medo-tasks ls`
|
12
|
+
Then the output should contain "Hello World"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: List tasks
|
2
|
+
In order to keep myseld focused
|
3
|
+
As a user
|
4
|
+
I want to be able to view my current tasks
|
5
|
+
|
6
|
+
Scenario: List tasks
|
7
|
+
Given I have the following tasks in "/tmp/test-medo-tasks"
|
8
|
+
"""
|
9
|
+
[
|
10
|
+
{"done": false, "description": "Buy Milk", "created_at": "2012-01-05 12:36:00 +0300", "completed_at": null, "notes": ["at least 6% fat"]},
|
11
|
+
{"done": true, "description": "Buy Butter", "created_at": "2012-01-05 12:40:00 +0300", "completed_at": "2012-01-05 13:00:00 +0300", "notes": []}
|
12
|
+
]
|
13
|
+
|
14
|
+
"""
|
15
|
+
When I successfully run `medo --no-color --tasks-file="/tmp/test-medo-tasks"`
|
16
|
+
Then the output should contain "Buy Milk"
|
17
|
+
And the output should contain "Buy Butter"
|
18
|
+
|
19
|
+
Scenario: There are no tasks
|
20
|
+
Given I have the following tasks in "/tmp/test-medo-tasks"
|
21
|
+
"""
|
22
|
+
|
23
|
+
"""
|
24
|
+
When I successfully run `medo --no-color --tasks-file="/tmp/test-medo-tasks"`
|
25
|
+
Then the output should contain "no tasks"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'aruba/cucumber'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
ENV['PATH'] = "#{File.expand_path('../../../bin', __FILE__)}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
7
|
+
ENV['GLI_DEBUG'] = "true"
|
8
|
+
|
9
|
+
After do
|
10
|
+
if defined? @tasks_file_path and File.exist?(@tasks_file_path)
|
11
|
+
FileUtils.rm(@tasks_file_path)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/lib/medo.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
desc "Delete a todo"
|
2
|
+
command [:delete, :rm] do |c|
|
3
|
+
c.action do |global_options, options, args|
|
4
|
+
tasks = storage.read
|
5
|
+
|
6
|
+
task, number = choose_task(args, tasks)
|
7
|
+
tasks -= [task]
|
8
|
+
|
9
|
+
storage.write(tasks)
|
10
|
+
storage.commit
|
11
|
+
puts "Task #{number} removed"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
desc "Mark todo as done"
|
2
|
+
command :done do |c|
|
3
|
+
c.action do |global_options, options, args|
|
4
|
+
tasks = storage.read
|
5
|
+
|
6
|
+
task, number = choose_task(args, tasks)
|
7
|
+
task.done
|
8
|
+
|
9
|
+
storage.write(tasks)
|
10
|
+
storage.commit
|
11
|
+
puts "Task #{number} done"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'medo/text_task_writer'
|
2
|
+
|
3
|
+
desc "List all todos"
|
4
|
+
command [:list, :ls] do |c|
|
5
|
+
c.action do |global_options, options, args|
|
6
|
+
tasks = storage.read
|
7
|
+
|
8
|
+
include TextTaskWriter::Decorators
|
9
|
+
writer = NumbersDecorator.decorate(TextTaskWriter.new)
|
10
|
+
|
11
|
+
#waiting for fix of https://github.com/davetron5000/gli/pull/90
|
12
|
+
ColorsDecorator.decorate(writer) unless global_options[:"no-color"] == false
|
13
|
+
writer.add_tasks(tasks)
|
14
|
+
writer.write
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
desc "Create a todo"
|
2
|
+
command :new do |c|
|
3
|
+
c.action do |global_options, options, args|
|
4
|
+
tasks = storage.read
|
5
|
+
|
6
|
+
task_description = args.join(" ")
|
7
|
+
task, number = Task.new(task_description)
|
8
|
+
|
9
|
+
tasks << task
|
10
|
+
|
11
|
+
storage.write(tasks)
|
12
|
+
storage.commit
|
13
|
+
puts "Task added"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
desc "Add note to a todo"
|
2
|
+
command :note do |c|
|
3
|
+
c.action do |global_options, options, args|
|
4
|
+
tasks = storage.read
|
5
|
+
|
6
|
+
task, number = choose_task(args, tasks)
|
7
|
+
|
8
|
+
note = args.join(" ").strip
|
9
|
+
raise ArgumentError, "No note given" if note.empty?
|
10
|
+
|
11
|
+
task.notes << note
|
12
|
+
|
13
|
+
storage.write(tasks)
|
14
|
+
storage.commit
|
15
|
+
puts "Note for task #{number} added"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'medo/text_task_writer'
|
2
|
+
|
3
|
+
desc "Show particular note"
|
4
|
+
command [:show, :cat] do |c|
|
5
|
+
c.action do |global_options, options, args|
|
6
|
+
tasks = storage.read
|
7
|
+
|
8
|
+
include TextTaskWriter::Decorators
|
9
|
+
writer = NumbersDecorator.decorate(TextTaskWriter.new)
|
10
|
+
|
11
|
+
#waiting for fix of https://github.com/davetron5000/gli/pull/90
|
12
|
+
ColorsDecorator.decorate(writer) unless global_options[:"no-color"] == false
|
13
|
+
|
14
|
+
task, number = choose_task(args, tasks)
|
15
|
+
writer.add_tasks([task])
|
16
|
+
writer.write
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'medo/json_task_reader'
|
4
|
+
require 'medo/json_task_writer'
|
5
|
+
|
6
|
+
module Medo
|
7
|
+
class FileTaskStorage
|
8
|
+
def self.using_storage(filename)
|
9
|
+
storage = self.new(filename)
|
10
|
+
yield storage
|
11
|
+
ensure
|
12
|
+
storage.dispose if storage
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(filename, reader_class = JsonTaskReader, writer_class = JsonTaskWriter)
|
16
|
+
@filename, @reader_class, @writer_class = filename, reader_class, writer_class
|
17
|
+
FileUtils.touch(@filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read
|
21
|
+
begin
|
22
|
+
File.open(@filename, "rb") do |f|
|
23
|
+
@reader_class.new(f).read
|
24
|
+
end
|
25
|
+
rescue => e
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(tasks)
|
31
|
+
serializer = @writer_class.new(tempfile)
|
32
|
+
serializer.add_tasks(tasks)
|
33
|
+
serializer.write
|
34
|
+
ensure
|
35
|
+
tempfile.close
|
36
|
+
end
|
37
|
+
|
38
|
+
def commit
|
39
|
+
FileUtils.cp(tempfile.path, @filename)
|
40
|
+
end
|
41
|
+
|
42
|
+
def dispose
|
43
|
+
tempfile.unlink
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def tempfile
|
49
|
+
@tempfile ||= Tempfile.new(File.basename(@filename), :binmode => true)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|