medo 0.1.1 → 0.1.3

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 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