Skip to content
Snippets Groups Projects
Commit e167f285 authored by Robert Speicher's avatar Robert Speicher
Browse files

Update Taskable to use TaskList

parent ce29e5cd
No related branches found
No related tags found
No related merge requests found
require 'task_list'
# Contains functionality for objects that can have task lists in their
# descriptions. Task list items can be added with Markdown like "* [x] Fix
# bugs".
#
# Used by MergeRequest and Issue
module Taskable
TASK_PATTERN_MD = /^(?<bullet> *[*-] *)\[(?<checked>[ xX])\]/.freeze
TASK_PATTERN_HTML = /^<li>(?<p_tag>\s*<p>)?\[(?<checked>[ xX])\]/.freeze
# Change the state of a task list item for this Taskable. Edit the object's
# description by finding the nth task item and changing its checkbox
# placeholder to "[x]" if +checked+ is true, or "[ ]" if it's false.
# Note: task numbering starts with 1
def update_nth_task(n, checked)
index = 0
check_char = checked ? 'x' : ' '
# Called by `TaskList::Summary`
def task_list_items
return [] if description.blank?
 
# Do this instead of using #gsub! so that ActiveRecord detects that a field
# has changed.
self.description = self.description.gsub(TASK_PATTERN_MD) do |match|
index += 1
case index
when n then "#{$LAST_MATCH_INFO[:bullet]}[#{check_char}]"
else match
end
@task_list_items ||= description.scan(TaskList::Filter::ItemPattern).collect do |item|
# ItemPattern strips out the hyphen, but Item requires it. Rabble rabble.
TaskList::Item.new("- #{item}")
end
end
 
save
def tasks
@tasks ||= TaskList.new(self)
end
 
# Return true if this object's description has any task list items.
def tasks?
description && description.match(TASK_PATTERN_MD)
tasks.summary.items?
end
 
# Return a string that describes the current state of this Taskable's task
# list items, e.g. "20 tasks (12 done, 8 unfinished)"
def task_status
return nil unless description
num_tasks = 0
num_done = 0
description.scan(TASK_PATTERN_MD) do
num_tasks += 1
num_done += 1 unless $LAST_MATCH_INFO[:checked] == ' '
end
return '' if description.blank?
 
"#{num_tasks} tasks (#{num_done} done, #{num_tasks - num_done} unfinished)"
sum = tasks.summary
"#{sum.item_count} tasks (#{sum.complete_count} done, #{sum.incomplete_count} unfinished)"
end
end
Loading
Loading
@@ -4,27 +4,13 @@
# subject { Issue or MergeRequest }
shared_examples 'a Taskable' do
before do
subject.description = <<EOT.gsub(/ {6}/, '')
subject.description = <<-EOT.strip_heredoc
* [ ] Task 1
* [x] Task 2
* [x] Task 3
* [ ] Task 4
* [ ] Task 5
EOT
end
it 'updates the Nth task correctly' do
subject.update_nth_task(1, true)
expect(subject.description).to match(/\[x\] Task 1/)
subject.update_nth_task(2, true)
expect(subject.description).to match('\[x\] Task 2')
subject.update_nth_task(3, false)
expect(subject.description).to match('\[ \] Task 3')
subject.update_nth_task(4, false)
expect(subject.description).to match('\[ \] Task 4')
EOT
end
 
it 'returns the correct task status' do
Loading
Loading
@@ -33,10 +19,14 @@ EOT
expect(subject.task_status).to match('3 unfinished')
end
 
it 'knows if it has tasks' do
expect(subject.tasks?).to be_truthy
describe '#tasks?' do
it 'returns true when object has tasks' do
expect(subject.tasks?).to eq true
end
 
subject.description = 'Now I have no tasks'
expect(subject.tasks?).to be_falsey
it 'returns false when object has no tasks' do
subject.description = 'Now I have no tasks'
expect(subject.tasks?).to eq false
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment