my_todo 3.1.1 → 4.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +63 -50
  3. data/Rakefile +3 -0
  4. data/bin/{my_todo → mytodo} +1 -1
  5. data/{lib/db → db}/config.yml +3 -3
  6. data/{lib/db → db}/migrate/20160912172429_create_items.rb +2 -2
  7. data/{lib/db → db}/migrate/20160913134552_create_tags.rb +1 -1
  8. data/{lib/db → db}/migrate/20160913134610_create_stubs.rb +1 -1
  9. data/{lib/db → db}/migrate/20161003121448_create_notes.rb +1 -1
  10. data/{lib/db → db}/migrate/20161005133023_add_detailed_status_to_items.rb +1 -1
  11. data/db/migrate/20161220143613_add_default_to_item_done.rb +5 -0
  12. data/{lib/db → db}/schema.rb +6 -14
  13. data/lib/my_todo.rb +4 -114
  14. data/lib/my_todo/ar_base.rb +3 -2
  15. data/lib/my_todo/models/item.rb +4 -0
  16. data/lib/my_todo/modules/actions.rb +129 -0
  17. data/lib/my_todo/modules/finders.rb +5 -3
  18. data/lib/my_todo/modules/my_todo_actions.rb +7 -6
  19. data/lib/my_todo/modules/templates.rb +1 -0
  20. data/lib/my_todo/templates/item.erb +6 -2
  21. data/lib/my_todo/templates/list.erb +3 -1
  22. data/lib/my_todo/templates/notes.erb +8 -5
  23. data/lib/my_todo/templates/results.erb +7 -1
  24. data/lib/my_todo/templates/standalone_migrations.yml.erb +4 -4
  25. data/lib/my_todo/version.rb +1 -1
  26. data/lib/setup.rb +2 -2
  27. data/my_todo.gemspec +19 -17
  28. data/spec/actions/create_spec.rb +17 -15
  29. data/spec/actions/delete_spec.rb +10 -4
  30. data/spec/actions/list_spec.rb +6 -5
  31. data/spec/actions/note_spec.rb +9 -7
  32. data/spec/actions/notes_spec.rb +6 -7
  33. data/spec/actions/rm_note_spec.rb +7 -8
  34. data/spec/actions/rm_tag_spec.rb +9 -8
  35. data/spec/actions/search_spec.rb +12 -13
  36. data/spec/actions/tag_spec.rb +12 -10
  37. data/spec/actions/update_spec.rb +5 -6
  38. data/{lib → spec}/db/todos_test.sqlite3 +0 -0
  39. data/spec/models/item_spec.rb +1 -1
  40. data/spec/models/stub_spec.rb +6 -6
  41. data/spec/spec_helper.rb +19 -5
  42. metadata +89 -76
  43. data/.standalone_migrations +0 -6
  44. data/lib/db/migrate/20161220143613_add_default_to_item_done.rb +0 -5
  45. data/lib/db/todos_development.sqlite3 +0 -0
  46. data/lib/my_todo/db/todos_test.sqlite3 +0 -0
@@ -5,9 +5,10 @@ module ArBase
5
5
  # Set path based on bin/my_todo
6
6
  path = case ENV['RAILS_ENV']
7
7
  when 'development'
8
- "#{__dir__}/../db/todos_development.sqlite3"
8
+ "#{__dir__}/../../db/todos_development.sqlite3"
9
9
  when 'test'
10
- "#{__dir__}/../db/todos_test.sqlite3"
10
+ # "#{__dir__}/../db/todos_test.sqlite3"
11
+ "#{__dir__}/../../spec/db/todos_test.sqlite3"
11
12
  else
12
13
  File.expand_path("#{`echo $HOME`.chomp}/.my_todo/data/todos_production.sqlite3", __FILE__)
13
14
  end
@@ -29,4 +29,8 @@ class Item < ActiveRecord::Base
29
29
  def update_done
30
30
  self.done = true if COMPLETE_STATUSES.include? self.detailed_status
31
31
  end
32
+
33
+ def done?
34
+ self.done == true ? 'Yes' : 'No'
35
+ end
32
36
  end
@@ -0,0 +1,129 @@
1
+ module MyTodo
2
+ module Actions
3
+ def self.included(thor)
4
+ thor.class_eval do
5
+
6
+ desc 'list <STATUS>', 'List todo items. Default: undone, [all], [done], [undone]'
7
+ def list(status='undone')
8
+ @status = status
9
+ print_list
10
+ end
11
+
12
+ desc "create \"<BODY>\" <TAGS> [Default: general]>", 'Create a todo item with optional and tags'
13
+ def create(body, *tags)
14
+ @body = body
15
+ @tags = tags.any? ? tags : %w[Default]
16
+
17
+ begin
18
+ create_item
19
+ print_item
20
+ rescue ActiveRecord::RecordInvalid => e
21
+ say e.message
22
+ end
23
+ end
24
+
25
+ desc 'update <ID> "<BODY>" <DONE>', 'Update a todo item'
26
+ def update(id, body=nil, done=nil)
27
+ @item = Item.find_by_id(id)
28
+ @body = body.nil? ? @item.body : body
29
+ @done = done.nil? ? @item.done : done
30
+
31
+ begin
32
+ update_item
33
+ print_item
34
+ rescue ActiveRecord::RecordInvalid => e
35
+ say e.message
36
+ end
37
+ end
38
+
39
+ desc 'delete <ID>', 'Destroy a todo item'
40
+ # option :id, required: true
41
+ def delete(id)
42
+ @item = Item.find_by_id(id)
43
+
44
+ begin
45
+ item.destroy!
46
+ say 'Item Deleted'
47
+ rescue StandardError => e
48
+ say e.message
49
+ end
50
+ end
51
+
52
+ desc 'search "<TEXT>"', 'Find a todo by item body, tag name, status or note body'
53
+ def search(text="")
54
+ @text = text
55
+ @items = Item.ransack(body_or_detailed_status_or_tags_name_or_notes_body_cont: @text).result
56
+ print_search_results
57
+ end
58
+
59
+ desc 'tag <ID> <TAGS>', 'Add tags to a todo item'
60
+ def tag(id, *tags)
61
+ @item = Item.find_by_id(id)
62
+
63
+ begin
64
+ if tags.any?
65
+ @banner = "Tags added to todo #{@item.id}"
66
+ tags.each {|tag| @item.tags.create!(name: tag)}
67
+ @item = @item.reload
68
+ print_item
69
+ end
70
+ rescue StandardError => e
71
+ say e.message
72
+ end
73
+ end
74
+
75
+ desc 'rm_tag <ID> <TAGS>', 'Remove tags from a todo item'
76
+ def rm_tag(id, *tags)
77
+ @item = Item.find_by_id(id)
78
+
79
+ begin
80
+ if tags.any?
81
+ @banner = "Tags removed from item #{@item.id}"
82
+ @item.tags.where(name: tags).destroy_all
83
+ print_item
84
+ end
85
+ rescue StandardError => e
86
+ say e.message
87
+ end
88
+ end
89
+
90
+ desc 'note <ID> "<TEXT>"', 'Adds note to a todo item'
91
+ def note(id, text="")
92
+ @item = Item.find_by_id(id)
93
+
94
+ begin
95
+ @item.notes.create(body: text) unless text.empty?
96
+ print_notes
97
+ rescue StandardError => e
98
+ say e.message
99
+ end
100
+ end
101
+
102
+ desc 'rm_note <ID> <NOTE_IDS>', 'Remove notes from todo item'
103
+ def rm_note(id, *note_ids)
104
+ @item = Item.find_by_id(id)
105
+
106
+ begin
107
+ @banner = "Note removed from item: #{@item.id}"
108
+ @item.notes.where(id: note_ids).destroy_all
109
+ print_item
110
+ rescue StandardError => e
111
+ say e.message
112
+ end
113
+ end
114
+
115
+ desc 'notes <ID>', 'Display notes for a todo item'
116
+ def notes(id)
117
+ @item = Item.find_by_id(id)
118
+
119
+ begin
120
+ print_notes
121
+ rescue StandardError => e
122
+ say e.message
123
+ end
124
+ end
125
+
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,6 +1,6 @@
1
1
  module Finders
2
2
  def item
3
- @item ||= Item.where(id: options[:id]).first
3
+ @item ||= Item.find_by_id(@id)
4
4
  end
5
5
 
6
6
  def item_notes
@@ -8,13 +8,15 @@ module Finders
8
8
  end
9
9
 
10
10
  def all_items
11
- @items = case options[:status]
11
+ @items = case @status
12
12
  when 'all'
13
13
  Item.all
14
14
  when 'done'
15
15
  Item.where(done: true)
16
- else
16
+ when 'undone'
17
17
  Item.where(done: false)
18
+ else
19
+ say 'Unknown status!'
18
20
  end
19
21
  end
20
22
 
@@ -4,16 +4,17 @@ module MyTodoActions
4
4
  @status = ask("Choose a status for item", default: set_default_status)
5
5
  end
6
6
 
7
- def create_item(options)
8
- @item = Item.new(options.except(:tags))
7
+ def create_item
8
+ @banner = 'Item Created'
9
+ @item = Item.new(body: @body)
9
10
  assign_detailed_status
10
11
  @item.save!
11
12
  set_tags
12
13
  end
13
14
 
14
- def update_item(options)
15
- item.assign_attributes(options)
16
- @item = item #Find a better way!!!!
15
+ def update_item
16
+ @banner = 'Item Updated'
17
+ @item.assign_attributes(body: @body, done: @done)
17
18
  assign_detailed_status
18
19
  item.save!
19
20
  end
@@ -24,7 +25,7 @@ module MyTodoActions
24
25
  end
25
26
 
26
27
  def set_tags
27
- options[:tags].split(' ').each{|tag| @item.tags.create(name: tag) } if options[:tags]
28
+ @tags.each{|tag| @item.tags.create(name: tag) } if @tags
28
29
  end
29
30
 
30
31
  def set_default_status
@@ -1,5 +1,6 @@
1
1
  module Templates
2
2
  def print_list
3
+ all_items
3
4
  say ERB.new(File.read("#{__dir__}/../templates/list.erb"), nil, '-').result(binding)
4
5
  end
5
6
 
@@ -1,2 +1,6 @@
1
- ID: <%= item.id %> | Created On: <%= item.created_at.strftime("%Y-%m-%d") %> | Tags: <%= item.tags.map(&:name).join(', ') %> | Status: <%= item.detailed_status %> | Complete: <%= item.done %>
2
- <%= item.body %>
1
+ <%= @banner %>
2
+
3
+ id: <%= @item.id %> notes: <%= @item.notes.size %> tags: <%= @item.tags.map(&:name).join(', ') %>
4
+ created: <%= @item.created_at.strftime("%Y-%m-%d") %> status: <%= @item.detailed_status %> (done: <%= @item.done? %>)
5
+
6
+ <%= @item.body %>
@@ -1,6 +1,8 @@
1
+ Items Found: <%= @items.count %>
1
2
 
2
3
  <% @items.each do |item| -%>
3
- ID: <%= item.id %> | Created On: <%= item.created_at.strftime("%Y-%m-%d") %> | Tags: <%= item.tags.map(&:name).join(', ') %> | Status: <%= item.detailed_status %> | Complete: <%= item.done %> | Notes: <%= item.notes.size %>
4
+ id: <%= item.id %> notes: <%= item.notes.size %> tags: <%= item.tags.map(&:name).join(', ') %>
5
+ created: <%= item.created_at.strftime("%Y-%m-%d") %> status: <%= item.detailed_status %> (done: <%= item.done? %>)
4
6
 
5
7
  <%= item.body %>
6
8
  <%= '*' * 100 %>
@@ -1,9 +1,12 @@
1
- <% if item_notes.any? -%>
2
- Notes for <%= item.id %>: <%= item.body %>
3
- <% item_notes.each do |note| -%>
4
- ID: <%= note.id %> | Created On: <%= note.created_at.strftime("%Y-%m-%d")%>
1
+ <% if @item.notes.any? -%>
2
+ notes for item <%= @item.id %>: <%= @item.body %>
3
+
4
+ <% @item.notes.each do |note| -%>
5
+ id: <%= note.id %>
6
+ created: <%= note.created_at.strftime("%Y-%m-%d")%>
7
+
5
8
  <%= note.body %>
6
9
  <% end %>
7
10
  <% else -%>
8
- No Notes for item <%= item.id %>
11
+ No Notes for item <%= @item.id %>
9
12
  <% end %>
@@ -1,6 +1,12 @@
1
+ Items Found: <%= @items.count %>
2
+
3
+ Search Text: <%= @text %>
1
4
 
2
5
  <% @items.each do |item| -%>
3
- ID: <%= item.id %> | Created On: <%= item.created_at.strftime("%Y-%m-%d") %> | Tags: <%= item.tags.map(&:name).join(', ') %> | Status: <%= item.detailed_status %> | Complete: <%= item.done %> | Notes: <%= item.notes.count %>
6
+
7
+ id: <%= item.id %> notes: <%= item.notes.size %> tags: <%= item.tags.map(&:name).join(', ') %>
8
+ created: <%= item.created_at.strftime("%Y-%m-%d") %> status: <%= item.detailed_status %> (done: <%= item.done? %>)
9
+
4
10
  <%= item.body %>
5
11
 
6
12
  <% if item.notes.any? -%>
@@ -1,6 +1,6 @@
1
1
  db:
2
- seeds: <%= GEM_DIR %>/lib/db/seeds.rb
3
- migrate: <%= GEM_DIR %>/lib/db/migrate
4
- schema: <%= GEM_DIR %>/lib/db/schema.rb
2
+ seeds: <%= GEM_DIR %>/db/seeds.rb
3
+ migrate: <%= GEM_DIR %>/db/migrate
4
+ schema: <%= GEM_DIR %>/db/schema.rb
5
5
  config:
6
- database: <%= GEM_DIR %>/lib/db/config.yml
6
+ database: <%= GEM_DIR %>/db/config.yml
@@ -1,3 +1,3 @@
1
1
  module MyTodo
2
- VERSION = "3.1.1"
2
+ VERSION = "4.0.0.pre1"
3
3
  end
@@ -16,11 +16,11 @@ class Setup < Thor
16
16
  `mkdir -p #{HOME_DIR}/.my_todo/data`
17
17
  say "Created .my_todo in #{HOME_DIR}"
18
18
  end
19
- template "config.yml.erb", "#{__dir__}/../lib/db/config.yml", force: true
19
+ template "config.yml.erb", "#{GEM_DIR}/db/config.yml", force: true
20
20
  end
21
21
 
22
22
  desc 'standard_migrations_override', 'Generate SM override file'
23
23
  def standard_migrations_override
24
- template "standalone_migrations.yml.erb", "#{__dir__}/../.standalone_migrations", force: true
24
+ template "standalone_migrations.yml.erb", "#{GEM_DIR}/.standalone_migrations", force: true
25
25
  end
26
26
  end
@@ -14,28 +14,30 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/vmcilwain/my_todo"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.files = Dir["{bin,lib}/**/*", "LICENSE.txt", "README.md", ".standalone_migrations", 'Rakefile', 'Gemfile', 'my_todo.gemspec']
17
+ spec.files = Dir["{bin,lib,db}/**/*", "LICENSE.txt", "README.md", 'Rakefile', 'Gemfile', 'my_todo.gemspec']
18
18
  spec.test_files = Dir["spec/**/*"]
19
19
  spec.bindir = "bin"
20
- spec.executables = ['my_todo']
20
+ spec.executables = ['mytodo']
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.12"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "rspec", "~> 3.0"
26
- spec.add_development_dependency "factory_girl_rails", "~> 4.7.0"
27
- spec.add_development_dependency "database_cleaner", "~> 1.5.3"
28
- spec.add_development_dependency 'shoulda-matchers', '~> 3.1'
29
- spec.add_development_dependency 'byebug', '~> 9.0.5'
23
+ spec.add_development_dependency "rspec", "~> 3.8.0"
24
+ spec.add_development_dependency "factory_bot_rails", "~> 4.11.1"
25
+ spec.add_development_dependency "database_cleaner", "~> 1.7.0"
26
+ spec.add_development_dependency 'shoulda-matchers', '~> 3.1.2'
27
+ spec.add_development_dependency 'byebug', '~> 10.0.2'
30
28
  spec.add_development_dependency 'yard', '~> 0.9.5'
31
- spec.add_development_dependency 'simplecov', '~> 0.12.0'
32
- spec.add_development_dependency 'codeclimate-test-reporter'
33
- spec.add_dependency 'activerecord', '~> 5.0.0.1'
34
- spec.add_dependency 'activesupport', '~> 5.0.0.1'
35
- spec.add_dependency 'thor', '~> 0.19.1'
36
- spec.add_dependency 'standalone_migrations', '~> 5.0.0'
37
- spec.add_dependency 'sqlite3', '~> 1.3.11'
38
- spec.add_dependency 'ransack', '~> 1.8.2'
29
+ spec.add_development_dependency 'simplecov', '~> 0.16.1'
30
+ spec.add_development_dependency 'faker'
31
+ spec.add_development_dependency 'rubocop-rspec'
32
+ # spec.add_development_dependency 'codeclimate-test-reporter'
33
+ spec.add_dependency "bundler", "~> 1.16.0"
34
+ spec.add_dependency "rake", "~> 12.3.1"
35
+ spec.add_dependency 'activerecord', '~> 5.2.1'
36
+ spec.add_dependency 'activesupport', '~> 5.2.1'
37
+ spec.add_dependency 'thor', '~> 0.20.0'
38
+ spec.add_dependency 'standalone_migrations', '~> 5.2.6'
39
+ spec.add_dependency 'sqlite3', '~> 1.3.13'
40
+ spec.add_dependency 'ransack', '~> 2.0.1'
39
41
 
40
42
  spec.metadata["yard.run"] = "yri"
41
43
  spec.post_install_message = "Don't forget to migrate the db. `my_todo rake db:migrate`"
@@ -6,9 +6,10 @@ describe MyTodo do
6
6
  end
7
7
 
8
8
  describe 'create' do
9
- before do
10
- expect(Thor::LineEditor).to receive(:readline).with("Choose a status for item (1) ", {:default=>1}).and_return("")
11
- end
9
+ let(:body) {Faker::Lorem.words(5).join("\s")}
10
+ let(:statuses) {"0: None\n1: In Progress\n2: Waiting Feedback\n3: Complete\n4: Punted"}
11
+
12
+ before {expect(Thor::LineEditor).to receive(:readline).with("Choose a status for item (1) ", {default:1}).and_return("")}
12
13
 
13
14
  context 'successful creation' do
14
15
  describe 'creation without tags or setting done attribute' do
@@ -17,46 +18,47 @@ describe MyTodo do
17
18
  end
18
19
 
19
20
  it 'creates a todo item' do
20
- expect{MyTodo::Todo.start(%w(create --body=wierdness_of_text))}.to change{Item.count}.by(1)
21
+ expect{MyTodo::Todo.start(['create', body])}.to change{Item.count}.by(1)
21
22
  end
22
23
 
23
24
  it "sets tags to 'default' when tags option is not present" do
24
- MyTodo::Todo.start(%w[create --body=wierdness_of_text])
25
+ MyTodo::Todo.start(['create', body])
25
26
  todo = Item.last
26
- expect(todo.tags.map(&:name)).to eq ['default']
27
+ expect(todo.tags.map(&:name)).to eq ['Default']
27
28
  end
28
29
 
29
30
  it 'sets done to false by when done option is not present' do
30
- MyTodo::Todo.start(%w[create --body=wierdness_of_text])
31
+ MyTodo::Todo.start(['create', body])
31
32
  todo = Item.last
32
33
  expect(todo.done).to eq false
33
34
  end
34
35
 
35
36
  it 'displays the created todo item' do
36
- expect{MyTodo::Todo.start(%w(create --body=wierdness_of_text))}.to output("ToDo CREATED!\n0: None\n1: In Progress\n2: Waiting Feedback\n3: Complete\n4: Punted\nID: 1 | Created On: #{Date.today} | Tags: default | Status: In Progress | Complete: false\nwierdness_of_text\n").to_stdout
37
+ expect{MyTodo::Todo.start(['create', body])}.to output("#{statuses}\nItem Created\n\nid: 1 notes: 0 tags: Default\ncreated: #{Date.today} status: In Progress (done: No) \n\n#{body}\n").to_stdout
37
38
  end
38
39
  end
39
40
 
40
41
  describe 'creation with tags and without setting done attribute' do
41
42
  it 'creates associated tag' do
42
- expect{MyTodo::Todo.start(%w[create --body=wierdness_of_text --tags=tag1])}.to change{Tag.count}.by(1)
43
+ expect{MyTodo::Todo.start(['create', body, 'tag1'])}.to change{Tag.count}.by(1)
43
44
  end
44
45
 
45
46
  it 'displays the created todo item with tag' do
46
- expect{MyTodo::Todo.start(%w(create --body=wierdness_of_text --tags=tag1))}.to output("ToDo CREATED!\n0: None\n1: In Progress\n2: Waiting Feedback\n3: Complete\n4: Punted\nID: 1 | Created On: #{Date.today} | Tags: tag1 | Status: In Progress | Complete: false\nwierdness_of_text\n").to_stdout
47
+ expect{MyTodo::Todo.start(['create', body, 'tag1'])}.to output("#{statuses}\nItem Created\n\nid: 1 notes: 0 tags: tag1\ncreated: #{Date.today} status: In Progress (done: No) \n\n#{body}\n").to_stdout
47
48
  end
48
49
  end
49
50
 
50
- describe 'create with tags' do
51
- it 'displays the created to item with complete set to true' do
52
- expect{MyTodo::Todo.start(%w[create --body=wierdness_of_text])}.to output("ToDo CREATED!\n0: None\n1: In Progress\n2: Waiting Feedback\n3: Complete\n4: Punted\nID: 1 | Created On: #{Date.today} | Tags: default | Status: In Progress | Complete: false\nwierdness_of_text\n").to_stdout
51
+ describe 'create a completed item' do
52
+ xit 'displays the created to item with complete set to true', 'look into being able to set this option again' do
53
+ expect{MyTodo::Todo.start(['create', body])}.to output("#{statuses}\nItem Created\n\nid: 1 notes: 0 tags: Default\ncreated: #{Date.today} status: In Progress (done: Yes) \n\n#{body}\n").to_stdout
53
54
  end
54
55
  end
55
56
  end
56
57
 
57
58
  context 'unsuccessful creation' do
58
- it 'returns error message when body is missing' do
59
- expect{MyTodo::Todo.start(%w(create))}.to output("ToDo CREATED!\n0: None\n1: In Progress\n2: Waiting Feedback\n3: Complete\n4: Punted\nValidation failed: Body can't be blank\n").to_stdout
59
+ xit 'returns error message when body is missing', 'look into being able to set this option again' do
60
+ expect{MyTodo::Todo.start(['create'])}.to output("ERROR: \"my_todo create\" was called with no arguments\n
61
+ Usage: \"my_todo create \"<BODY>\" <TAGS> [Default: general]>\"").to_stdout
60
62
  end
61
63
  end
62
64
  end
@@ -2,14 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  describe MyTodo do
4
4
  describe 'delete' do
5
- before {@todo = FactoryGirl.create(:item)}
6
-
5
+ let(:todo) {FactoryBot.create(:item)}
6
+
7
+ before {todo}
8
+
7
9
  it 'destroys todo item' do
8
- expect{MyTodo::Todo.start(%W(delete --id=#{@todo.id}))}.to change{Item.count}.by(-1)
10
+ expect{MyTodo::Todo.start(['delete', todo.id])}.to change{Item.count}.by(-1)
9
11
  end
10
12
 
11
13
  it 'returns nil exception if todo item is invalid' do
12
- expect{MyTodo::Todo.start(%W[delete --id=#{@todo.id + 1}])}.to output("undefined method `destroy!' for nil:NilClass\n").to_stdout
14
+ expect{MyTodo::Todo.start(['delete', todo.id + 1])}.to output("undefined method `destroy!' for nil:NilClass\n").to_stdout
15
+ end
16
+
17
+ it 'displays a notice' do
18
+ expect{MyTodo::Todo.start(['delete', todo.id])}.to output("Item Deleted\n").to_stdout
13
19
  end
14
20
  end
15
21
  end