Commit e167f285 authored by Robert Speicher's avatar Robert Speicher

Update Taskable to use TaskList

parent ce29e5cd
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
......@@ -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
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment