Module: Taskable

Included in:
Issuable
Defined in:
app/models/concerns/taskable.rb

Overview

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

Constant Summary collapse

COMPLETED =
'completed'
INCOMPLETE =
'incomplete'
COMPLETE_PATTERN =
/\[[xX]\]/.freeze
INCOMPLETE_PATTERN =
/\[[[:space:]]\]/.freeze
ITEM_PATTERN =
%r{
  ^
  (?:(?:>\s{0,4})*)             # optional blockquote characters
  ((?:\s*(?:[-+*]|(?:\d+\.)))+) # list prefix (one or more) required - task item has to be always in a list
  \s+                           # whitespace prefix has to be always presented for a list item
  (                             # checkbox
    #{COMPLETE_PATTERN}|#{INCOMPLETE_PATTERN}
  )
  (\s.+)                        # followed by whitespace and some text.
}x.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_tasks(content) ⇒ Object


27
28
29
30
31
# File 'app/models/concerns/taskable.rb', line 27

def self.get_tasks(content)
  content.to_s.scan(ITEM_PATTERN).map do |prefix, checkbox, label|
    TaskList::Item.new("#{prefix} #{checkbox}", label.strip)
  end
end

.get_updated_tasks(old_content:, new_content:) ⇒ Object


33
34
35
36
37
38
39
40
41
42
43
# File 'app/models/concerns/taskable.rb', line 33

def self.get_updated_tasks(old_content:, new_content:)
  old_tasks = get_tasks(old_content)
  new_tasks = get_tasks(new_content)

  new_tasks.select.with_index do |new_task, i|
    old_task = old_tasks[i]
    next unless old_task

    new_task.source == old_task.source && new_task.complete? != old_task.complete?
  end
end

Instance Method Details

#task_completion_statusObject


82
83
84
85
86
87
# File 'app/models/concerns/taskable.rb', line 82

def task_completion_status
  @task_completion_status ||= {
      count: tasks.summary.item_count,
      completed_count: tasks.summary.complete_count
  }
end

#task_list_itemsObject

Called by `TaskList::Summary`


46
47
48
49
50
# File 'app/models/concerns/taskable.rb', line 46

def task_list_items
  return [] if description.blank?

  @task_list_items ||= Taskable.get_tasks(description) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end

#task_status(short: false) ⇒ Object

Return a string that describes the current state of this Taskable's task list items, e.g. “12 of 20 tasks completed”


63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/models/concerns/taskable.rb', line 63

def task_status(short: false)
  return '' if description.blank?

  prep, completed = if short
                      ['/', '']
                    else
                      [' of ', ' completed']
                    end

  sum = tasks.summary
  "#{sum.complete_count}#{prep}#{sum.item_count} #{'task'.pluralize(sum.item_count)}#{completed}"
end

#task_status_shortObject

Return a short string that describes the current state of this Taskable's task list items – for small screens


78
79
80
# File 'app/models/concerns/taskable.rb', line 78

def task_status_short
  task_status(short: true)
end

#tasksObject


52
53
54
# File 'app/models/concerns/taskable.rb', line 52

def tasks
  @tasks ||= TaskList.new(self)
end

#tasks?Boolean

Return true if this object's description has any task list items.

Returns:

  • (Boolean)

57
58
59
# File 'app/models/concerns/taskable.rb', line 57

def tasks?
  tasks.summary.items?
end