medo 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,6 +6,9 @@ Simple console app for managing todos on the fly :)
6
6
 
7
7
  ## The Changelog ##
8
8
 
9
+ ### v0.1.3 (28.06.2012) ###
10
+ * Add support for editing notes
11
+
9
12
  ### v0.1.1 (15.06.2012) ###
10
13
  * Add support for ree-1.8.7
11
14
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.3
data/bin/medo CHANGED
@@ -1,62 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
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
4
+ require 'medo/cli'
35
5
 
36
6
  Signal.trap("SIGINT") do
37
7
  puts "Terminating"
38
8
  exit 1
39
9
  end
40
10
 
41
- around do |global_options, command, options, arguments, cmd|
42
- FileTaskStorage.using_storage(global_options.fetch(:"tasks-file")) do |the_storage|
43
- instance_eval do
44
- eigen = class << self; self; end
45
- eigen.send(:define_method, :storage) { the_storage }
46
- end
47
-
48
- def self.choose_task(argv, tasks)
49
- input = argv.shift
50
- number = Integer(input) rescue
51
- raise(ArgumentError, "Invalid task #: #{input}")
52
- task = tasks.reject(&:done?).sort[number - 1] or raise RuntimeError,
53
- "No such task!"
54
- [task, number]
55
- end
56
-
57
- cmd.call
58
- end
59
- end
60
-
61
- run(ARGV)
11
+ app = Medo::CLI
12
+ app.run(ARGV)
62
13
 
@@ -1,5 +1,5 @@
1
1
  Feature: Add todo
2
- In order to be able to keep my in focus
2
+ In order to be able to keep myself focused
3
3
  As a user
4
4
  I want to add tasks to lists
5
5
 
@@ -0,0 +1,14 @@
1
+ Feature: Edit todo
2
+ In order to be able to correct a mistake
3
+ As a user
4
+ I want to be able to edit task description
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
+ When I successfully run `medo --tasks-file=/tmp/test-medo-tasks edit Goodbye World`
12
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks ls`
13
+ Then the output should contain "Goodbye World"
14
+ And the output should not contain "Hello World"
@@ -1,18 +1,27 @@
1
- Feature: Add note to task
1
+ Feature: Manage task notes
2
2
  In order to be able to sketch some ideas
3
3
  As a user
4
- I want to add notes to my tasks
4
+ I want to add and edit notes to my tasks
5
5
 
6
6
  Background:
7
7
  Given there's no file "/tmp/test-medo-tasks"
8
8
 
9
- Scenario: Add todo
9
+ Scenario: Add todo note
10
10
  When I successfully run `medo --tasks-file=/tmp/test-medo-tasks new Hello World`
11
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`
12
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks note add -n 1 "Trash the PC"`
13
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks note add -n 2 The Note`
14
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks show`
15
15
  Then the output should contain "Trash the PC"
16
16
  And the output should not contain "The Note"
17
- When I successfully run `medo --tasks-file=/tmp/test-medo-tasks show 2`
17
+ When I successfully run `medo --tasks-file=/tmp/test-medo-tasks show -n 2`
18
18
  Then the output should contain "The Note"
19
+
20
+ Scenario: Edit todo note
21
+ When I successfully run `medo --tasks-file=/tmp/test-medo-tasks new Hello World`
22
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks note add "Trash the PC"`
23
+ When I successfully run `medo --tasks-file=/tmp/test-medo-tasks note edit boom`
24
+ And I successfully run `medo --tasks-file=/tmp/test-medo-tasks show`
25
+ Then the output should not contain "Trash the PC"
26
+ And the output should contain "boom"
27
+
@@ -0,0 +1,4 @@
1
+ When /^I see tasks stored in (.*?)$/ do |filename|
2
+ puts File.readlines(filename)
3
+ end
4
+
@@ -5,7 +5,7 @@ require 'fileutils'
5
5
 
6
6
  ENV['PATH'] = "#{File.expand_path('../../../bin', __FILE__)}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
7
7
  ENV['GLI_DEBUG'] = "true"
8
-
8
+ ENV['RUBYLIB'] = File.expand_path('../../../lib', __FILE__)
9
9
  After do
10
10
  if defined? @tasks_file_path and File.exist?(@tasks_file_path)
11
11
  FileUtils.rm(@tasks_file_path)
@@ -1,6 +1,5 @@
1
- require 'medo/task'
2
-
3
1
  module Medo
4
2
  version_file = File.expand_path('../VERSION', File.dirname(__FILE__))
5
3
  VERSION = File.read(version_file).freeze
6
4
  end
5
+
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require 'tempfile'
4
+
5
+ require 'gli'
6
+ require 'medo'
7
+ require 'medo/support'
8
+ require 'medo/file_task_storage'
9
+ require 'medo/cli_support'
10
+
11
+ module Medo
12
+ class CLI
13
+ extend GLI::App
14
+ extend Medo
15
+ extend CLISupport
16
+
17
+ program_desc 'Simple CLI To-Do manager'
18
+ version VERSION
19
+
20
+ load_commands
21
+ default_command :list
22
+
23
+ desc "A file with tasks"
24
+ flag [:f, "tasks-file"], :default_value => File.join(ENV['HOME'], '.medo-tasks')
25
+
26
+ desc "Do not use colorful output"
27
+ switch "no-color", :negatable => false
28
+
29
+ around do |global_options, command, options, arguments, cmd|
30
+ FileTaskStorage.using_storage(global_options.fetch(:"tasks-file")) do |storage|
31
+ instance_eval do
32
+ eigen = class << self; self; end
33
+ {
34
+ :storage => storage,
35
+ :global_options => global_options,
36
+ :options => options,
37
+ :arguments => arguments
38
+ }.each do |method, value|
39
+ eigen.send(:define_method, method) { value }
40
+ end
41
+ end
42
+
43
+ cmd.call
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,68 @@
1
+ module Medo
2
+ module CLISupport
3
+ def load_commands
4
+ Dir.glob(File.expand_path('../commands/*', __FILE__)).each do |f|
5
+ contents = File.read(f)
6
+ class_eval contents, f, 1
7
+ end
8
+ end
9
+
10
+ def tasks
11
+ @tasks ||= storage.read
12
+ @original_tasks ||= @tasks.map(&:dup)
13
+ @tasks
14
+ end
15
+
16
+ def tasks_changed?
17
+ defined? @tasks and @tasks != @original_tasks
18
+ end
19
+
20
+ def committing_tasks
21
+ yield
22
+
23
+ if tasks_changed?
24
+ storage.write(tasks)
25
+ storage.commit
26
+ end
27
+ end
28
+
29
+ def colorize
30
+ yield unless global_options[:"no-color"] == false
31
+ end
32
+
33
+ def choose_task(select_options = {})
34
+ task_number = Integer(options[:number] || 1) rescue
35
+ raise(ArgumentError, "Invalid task #: #{task_number}")
36
+ task = tasks.reject { |t| select_options[:done] ^ t.done? }.sort[task_number - 1] or
37
+ raise(RuntimeError, "No such task!")
38
+ [task, task_number]
39
+ end
40
+
41
+ def get_input
42
+ process_input
43
+ end
44
+
45
+ def edit_input(value)
46
+ process_input do |path|
47
+ File.open(path, "w") { |f| f.write(value) }
48
+ end
49
+ end
50
+
51
+ def process_input
52
+ result = nil
53
+ if options[:editor]
54
+ path = File.join(Dir::Tmpname.tmpdir, "taketo-input-#{Time.now.to_i}")
55
+ yield path if block_given?
56
+ status = system("$EDITOR #{path}")
57
+ if status && File.exists?(path)
58
+ result = File.read(path)
59
+ FileUtils.rm(path)
60
+ end
61
+ else
62
+ result = arguments.join(" ").strip
63
+ end
64
+ result.to_s
65
+ end
66
+ end
67
+ end
68
+
@@ -1,9 +1,7 @@
1
1
  desc "Clear done todos"
2
2
  command :clear do |c|
3
3
  c.action do |global_options, options, args|
4
- tasks = storage.read.reject(&:done?)
5
- storage.write(tasks)
6
- storage.commit
4
+ committing_tasks { tasks.reject!(&:done?) }
7
5
  puts "Done tasks cleared"
8
6
  end
9
7
  end
@@ -1,13 +1,12 @@
1
1
  desc "Delete a todo"
2
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]
3
+ c.desc "Number of the task to delete"
4
+ c.flag [:n, :number]
5
+ c.default_value 1
8
6
 
9
- storage.write(tasks)
10
- storage.commit
7
+ c.action do |global_options, options, args|
8
+ task, number = choose_task
9
+ committing_tasks { tasks.delete(task) }
11
10
  puts "Task #{number} removed"
12
11
  end
13
12
  end
@@ -1,13 +1,12 @@
1
1
  desc "Mark todo as done"
2
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
3
+ c.desc "Number of the task to mark as done"
4
+ c.flag [:n, :number]
5
+ c.default_value 1
8
6
 
9
- storage.write(tasks)
10
- storage.commit
7
+ c.action do |global_options, options, args|
8
+ task, number = choose_task
9
+ committing_tasks { task.done }
11
10
  puts "Task #{number} done"
12
11
  end
13
12
  end
@@ -0,0 +1,16 @@
1
+ desc "Edit a todo"
2
+ command :edit do |c|
3
+ c.desc "Use EDITOR"
4
+ c.switch [:e, :editor]
5
+
6
+ c.desc "Number of the task to edit"
7
+ c.flag [:n, :number]
8
+ c.default_value 1
9
+
10
+ c.action do |global_options, options, args|
11
+ task, number = choose_task
12
+ task_description = get_input
13
+ committing_tasks { task.description = task_description }
14
+ puts "Task #{number} edited"
15
+ end
16
+ end
@@ -2,15 +2,16 @@ require 'medo/text_task_writer'
2
2
 
3
3
  desc "List all todos"
4
4
  command [:list, :ls] do |c|
5
- c.action do |global_options, options, args|
6
- tasks = storage.read
5
+ c.desc "Number only done tasks"
6
+ c.switch ["number-done"], :negatable => false
7
7
 
8
+ c.action do |global_options, options, args|
8
9
  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
10
+ writer = NumbersDecorator.decorate(TextTaskWriter.new,
11
+ :done => options[:"number-done"] == false)
12
+ colorize { ColorsDecorator.decorate(writer) }
13
13
  writer.add_tasks(tasks)
14
14
  writer.write
15
15
  end
16
16
  end
17
+
@@ -1,15 +1,12 @@
1
1
  desc "Create a todo"
2
2
  command :new do |c|
3
- c.action do |global_options, options, args|
4
- tasks = storage.read
3
+ c.desc "Use EDITOR"
4
+ c.switch [:e, :editor]
5
5
 
6
- task_description = args.join(" ")
6
+ c.action do |global_options, options, args|
7
+ task_description = get_input
7
8
  task, number = Task.new(task_description)
8
-
9
- tasks << task
10
-
11
- storage.write(tasks)
12
- storage.commit
9
+ committing_tasks { tasks << task }
13
10
  puts "Task added"
14
11
  end
15
12
  end
@@ -1,18 +1,29 @@
1
1
  desc "Add note to a todo"
2
2
  command :note do |c|
3
- c.action do |global_options, options, args|
4
- tasks = storage.read
3
+ c.desc "Number of the task to add note to"
4
+ c.flag [:n, :number]
5
+ c.default_value 1
5
6
 
6
- task, number = choose_task(args, tasks)
7
+ c.desc "Use EDITOR"
8
+ c.switch [:e, :editor]
7
9
 
8
- note = args.join(" ").strip
9
- raise ArgumentError, "No note given" if note.empty?
10
-
11
- task.notes << note
10
+ c.command :add do |ca|
11
+ ca.action do |global_options, options, args|
12
+ task, number = choose_task
13
+ note = get_input
14
+ raise ArgumentError, "No note given" if note.empty?
15
+ committing_tasks { task.notes << note }
16
+ puts "Note for task #{number} added"
17
+ end
18
+ end
12
19
 
13
- storage.write(tasks)
14
- storage.commit
15
- puts "Note for task #{number} added"
20
+ c.command :edit do |ce|
21
+ ce.action do |global_options, options, args|
22
+ task, number = choose_task
23
+ note = edit_input(task.notes)
24
+ committing_tasks { task.notes = note }
25
+ puts "Note for task #{number} edited"
26
+ end
16
27
  end
17
28
  end
18
29
 
@@ -0,0 +1,12 @@
1
+ desc "Reset task"
2
+ command :reset do |c|
3
+ c.desc "Number of the task to mark reset"
4
+ c.flag [:n, :number]
5
+ c.default_value 1
6
+
7
+ c.action do |global_options, options, args|
8
+ task, number = choose_task(:done => true)
9
+ committing_tasks { task.reset }
10
+ puts "Task #{number} was reset"
11
+ end
12
+ end