tracco 0.0.12 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +17 -0
- data/Gemfile.lock +2 -2
- data/lib/patches/trello/member.rb +3 -3
- data/lib/tracco/effort.rb +2 -1
- data/lib/tracco/google_docs_exporter.rb +1 -1
- data/lib/tracco/member.rb +1 -1
- data/lib/tracco/tracked_card.rb +15 -5
- data/lib/tracco/tracking/effort_tracking.rb +14 -17
- data/lib/tracco/tracking/estimate_tracking.rb +1 -4
- data/lib/tracco/tracking/factory.rb +26 -0
- data/lib/tracco/trello_tracker.rb +2 -2
- data/lib/tracco/version.rb +1 -1
- data/lib/tracco.rb +1 -1
- data/spec/effort_spec.rb +1 -1
- data/spec/factories/effort_factory.rb +11 -0
- data/spec/factories/estimate_factory.rb +9 -0
- data/spec/factories/tracked_card_factory.rb +6 -7
- data/spec/spec_helper.rb +0 -38
- data/spec/support/spec_helper_methods.rb +32 -0
- data/spec/tracked_card_spec.rb +119 -77
- data/spec/tracking/card_done_tracking_spec.rb +1 -1
- data/spec/tracking/effort_tracking_spec.rb +4 -4
- data/spec/tracking/estimate_tracking_spec.rb +7 -7
- data/spec/tracking_factory_spec.rb +4 -4
- data/tracco.sublime-project +1 -1
- metadata +7 -4
- data/lib/tracco/tracking_factory.rb +0 -22
data/CHANGELOG
CHANGED
@@ -1,42 +1,59 @@
|
|
1
|
+
0.0.13 / 2013-02-27
|
2
|
+
==================
|
3
|
+
* adding muted status on Effort to be able to 'turn off' a card's specific effort
|
4
|
+
* adding a TrackedCard.efforts_between method to fetch all the cards with an effort spent in a given date range
|
5
|
+
* improving TrackedCard#trello_notifications
|
6
|
+
|
1
7
|
0.0.12
|
8
|
+
======
|
2
9
|
- Adding a TrackedCard#trello_notifications to fetch all the notifications belonging to the card
|
3
10
|
- Introducing FactoryGirl as a factory gem to simplify specs
|
4
11
|
|
5
12
|
0.0.11
|
13
|
+
======
|
6
14
|
- Adding a TrackedCard.all_tracked_cards method to fetch all cards with a valid tracking. Moreover, sorting_options can be passed to sort using a method e.g. TrackedCard.all_tracked_cards(:method => :name, :order => :desc)
|
7
15
|
|
8
16
|
0.0.10
|
17
|
+
======
|
9
18
|
- Including Mongoid::MultiParameterAttributes in Effort and Estimate to enable date params to be collected correctly by Rails app (e.g. using the Rails' date_select form helper)
|
10
19
|
|
11
20
|
0.0.8 - 0.0.9
|
21
|
+
=============
|
12
22
|
- Gem rename :)
|
13
23
|
|
14
24
|
0.0.7
|
25
|
+
=====
|
15
26
|
- Minor refactorings on the rake tasks
|
16
27
|
|
17
28
|
0.0.6
|
29
|
+
=====
|
18
30
|
- Added TrackedCard#status to track card status: :todo if no effort has been spent, :done if the card is in a DONE column, :in_progress otherwise
|
19
31
|
- Added a Members#effort_spent and #effort_spent_since to extract the overall effort tracked by a member since a given date
|
20
32
|
- Re-merged in the trello_effort_app branch to bring on the Rails app
|
21
33
|
|
22
34
|
0.0.5
|
35
|
+
=====
|
23
36
|
- Improved docs
|
24
37
|
- Improved use of this tool as a gem
|
25
38
|
|
26
39
|
0.0.4
|
40
|
+
=====
|
27
41
|
- A card moved into a DONE column is closed
|
28
42
|
|
29
43
|
0.0.3
|
44
|
+
=====
|
30
45
|
- When I send a tracking with "DONE" then the card is "closed" (aka "finished")
|
31
46
|
- Export all cards in a Google Docs spreadsheet
|
32
47
|
- When I card change its name, the tracked card should be updated too
|
33
48
|
- A card should tells its estimate error (3)
|
34
49
|
|
35
50
|
0.0.2
|
51
|
+
=====
|
36
52
|
- Very simple Rails app on a separate branch, still experimenting
|
37
53
|
- Should be able to open a Trello console with a rake task
|
38
54
|
- Avoid running the script if already run for that period
|
39
55
|
- Tracking data is now persisted in a mongo database
|
40
56
|
|
41
57
|
0.0.1
|
58
|
+
=====
|
42
59
|
- Initial Release.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tracco (0.0.
|
4
|
+
tracco (0.0.13)
|
5
5
|
bson_ext
|
6
6
|
chronic
|
7
7
|
google_drive
|
@@ -19,7 +19,7 @@ GEM
|
|
19
19
|
activesupport (3.2.12)
|
20
20
|
i18n (~> 0.6)
|
21
21
|
multi_json (~> 1.0)
|
22
|
-
addressable (2.3.
|
22
|
+
addressable (2.3.3)
|
23
23
|
bson (1.8.2)
|
24
24
|
bson_ext (1.8.2)
|
25
25
|
bson (~> 1.8.2)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Trello
|
2
2
|
class Member
|
3
3
|
# Reopening the Trello::Member class to add a notifications helper method
|
4
|
-
def
|
4
|
+
def notifications_since(starting_date)
|
5
5
|
notifications(limit:1000).select(&greater_than_or_equal_to(starting_date)).select(&tracking_notification?)
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
private
|
9
9
|
|
10
10
|
def greater_than_or_equal_to(starting_date)
|
@@ -14,7 +14,7 @@ module Trello
|
|
14
14
|
def tracking_notification?
|
15
15
|
lambda { |notification| notification.type == "mentionedOnCard" }
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
data/lib/tracco/effort.rb
CHANGED
@@ -6,11 +6,12 @@ class Effort
|
|
6
6
|
field :amount, type: BigDecimal
|
7
7
|
field :date, type: Date
|
8
8
|
field :tracking_notification_id
|
9
|
+
field :muted, type: Boolean, default: false
|
9
10
|
|
10
11
|
embeds_many :members
|
11
12
|
embedded_in :tracked_card
|
12
13
|
|
13
|
-
default_scope asc(:date)
|
14
|
+
default_scope where(muted: false).asc(:date)
|
14
15
|
|
15
16
|
validates_presence_of :amount, :date, :members
|
16
17
|
|
@@ -18,7 +18,7 @@ class GoogleDocsExporter
|
|
18
18
|
create_header(worksheet)
|
19
19
|
index = 2 # skip the header
|
20
20
|
|
21
|
-
cards = TrackedCard.
|
21
|
+
cards = TrackedCard.all_tracked_cards(:method => :first_activity_date, :order => :desc)
|
22
22
|
cards.each do |card|
|
23
23
|
print ".".color(:green)
|
24
24
|
worksheet[index, columns[:user_story_id]] = card.short_id
|
data/lib/tracco/member.rb
CHANGED
@@ -28,7 +28,7 @@ class Member
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def effort_spent(from_date=nil)
|
31
|
-
cards = TrackedCard.
|
31
|
+
cards = TrackedCard.with_effort_spent_by(username)
|
32
32
|
efforts = cards.map(&:efforts).compact.flatten
|
33
33
|
efforts = efforts.select {|e| e.date >= from_date} if from_date
|
34
34
|
efforts.select { |effort| effort.include?(self) }.inject(0) { |total, effort| total + effort.amount_per_member }
|
data/lib/tracco/tracked_card.rb
CHANGED
@@ -19,6 +19,8 @@ class TrackedCard
|
|
19
19
|
validates_presence_of :name, :short_id, :trello_id
|
20
20
|
validates_numericality_of :short_id
|
21
21
|
|
22
|
+
scope :with_effort_spent_by, ->(username){ where("efforts.members.username" => username) }
|
23
|
+
|
22
24
|
def self.find_by_trello_id(trello_id)
|
23
25
|
without_mongo_raising_errors do
|
24
26
|
find_by(trello_id: trello_id)
|
@@ -35,10 +37,9 @@ class TrackedCard
|
|
35
37
|
|
36
38
|
def self.all_tracked_cards(sorting_options = {})
|
37
39
|
cards = all.reject(&:no_tracking?)
|
38
|
-
|
39
|
-
cards
|
40
|
-
|
41
|
-
sorting_options[:order] == :desc ? cards.reverse : cards
|
40
|
+
cards.sort_by!(&sorting_options[:sort_by].to_sym) if sorting_options[:sort_by]
|
41
|
+
cards.reverse! if sorting_options[:order] == :desc
|
42
|
+
return cards
|
42
43
|
end
|
43
44
|
|
44
45
|
def self.build_from(trello_card)
|
@@ -47,6 +48,15 @@ class TrackedCard
|
|
47
48
|
new(trello_card.attributes.merge(trello_id: trello_card_id))
|
48
49
|
end
|
49
50
|
|
51
|
+
def self.efforts_between(search_options)
|
52
|
+
condition = {}
|
53
|
+
{'$gte' => :from_date, '$lte' => :to_date}.each do |selection, option_key|
|
54
|
+
condition[selection] = search_options[option_key] if search_options[option_key]
|
55
|
+
end
|
56
|
+
|
57
|
+
where("efforts.date" => condition)
|
58
|
+
end
|
59
|
+
|
50
60
|
def status
|
51
61
|
if done?
|
52
62
|
:done
|
@@ -118,7 +128,7 @@ class TrackedCard
|
|
118
128
|
|
119
129
|
def trello_notifications
|
120
130
|
notification_ids = efforts.map(&:tracking_notification_id) | estimates.map(&:tracking_notification_id)
|
121
|
-
notification_ids.map { |
|
131
|
+
notification_ids.map { |id| Trello::Notification.find(id) rescue nil }.compact.sort_by(&:date)
|
122
132
|
end
|
123
133
|
|
124
134
|
def to_s
|
@@ -2,39 +2,36 @@ module Tracking
|
|
2
2
|
class EffortTracking
|
3
3
|
include Base
|
4
4
|
|
5
|
-
#TODO: rename to 'amount' ?
|
6
|
-
#TODO: avoid recomputing effort every time using a lazy instance variable
|
7
|
-
def effort
|
8
|
-
effort_amount = convert_to_hours(raw_effort)
|
9
|
-
if effort_amount
|
10
|
-
total_effort = effort_amount * effort_members.size
|
11
|
-
Effort.new(amount: total_effort, date: date, members: effort_members, tracking_notification_id: tracking_notification.id)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
5
|
def add_to(card)
|
16
6
|
card.efforts << effort unless card.contains_effort?(effort)
|
17
7
|
end
|
18
8
|
|
9
|
+
def effort
|
10
|
+
@effort ||= Effort.new(amount: total_effort_from(raw_effort), date: date, members: effort_members, tracking_notification_id: tracking_notification.id)
|
11
|
+
end
|
12
|
+
|
19
13
|
private
|
20
14
|
|
15
|
+
def total_effort_from(raw_effort)
|
16
|
+
effort_amount = convert_to_hours(raw_effort)
|
17
|
+
total_effort = effort_amount * effort_members.size
|
18
|
+
end
|
19
|
+
|
21
20
|
def raw_effort
|
22
21
|
extract_match_from_raw_tracking(/\+#{DURATION_REGEXP}/)
|
23
22
|
end
|
24
23
|
|
25
24
|
def effort_members
|
26
|
-
@effort_members ||=
|
25
|
+
@effort_members ||= members_involved_in_the_effort.map do |username|
|
27
26
|
Member.build_from(Trello::Member.find(username))
|
28
27
|
end
|
29
|
-
|
30
|
-
@effort_members
|
31
28
|
end
|
32
29
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
30
|
+
def members_involved_in_the_effort
|
31
|
+
members_involved_in_the_effort = raw_tracking.scan(/@(\w+)/).flatten
|
32
|
+
members_involved_in_the_effort << notifier.username unless should_count_only_listed_members?
|
36
33
|
|
37
|
-
|
34
|
+
members_involved_in_the_effort
|
38
35
|
end
|
39
36
|
|
40
37
|
def should_count_only_listed_members?
|
@@ -2,11 +2,8 @@ module Tracking
|
|
2
2
|
class EstimateTracking
|
3
3
|
include Base
|
4
4
|
|
5
|
-
#TODO: rename to 'amount' ?
|
6
|
-
#TODO: avoid recomputing estimate every time using a lazy instance variable
|
7
5
|
def estimate
|
8
|
-
estimate
|
9
|
-
Estimate.new(amount: estimate, date: date, tracking_notification_id: tracking_notification.id)
|
6
|
+
@estimate ||= Estimate.new(amount: convert_to_hours(raw_estimate), date: date, tracking_notification_id: tracking_notification.id)
|
10
7
|
end
|
11
8
|
|
12
9
|
def add_to(card)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Tracking
|
2
|
+
class Factory
|
3
|
+
|
4
|
+
DURATION_REGEXP = '(\d+\.?\d*[phdg])'
|
5
|
+
|
6
|
+
@match_pairs = {}
|
7
|
+
|
8
|
+
def self.build_from(tracking_notification)
|
9
|
+
matching_pair = @match_pairs.find { |regexp, tracking_class| tracking_notification.data['text'] =~ regexp }
|
10
|
+
|
11
|
+
tracking_class = matching_pair ? matching_pair.last : Tracking::InvalidTracking
|
12
|
+
tracking_class.new(tracking_notification)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.match(match_pair)
|
18
|
+
@match_pairs.merge!(match_pair)
|
19
|
+
end
|
20
|
+
|
21
|
+
match /\[#{DURATION_REGEXP}\]/ => Tracking::EstimateTracking
|
22
|
+
match /\+#{DURATION_REGEXP}/ => Tracking::EffortTracking
|
23
|
+
match /DONE/ => Tracking::CardDoneTracking
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -10,13 +10,13 @@ class TrelloTracker
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def track(starting_date=Date.today)
|
13
|
-
notifications = tracker.
|
13
|
+
notifications = tracker.notifications_since(starting_date)
|
14
14
|
|
15
15
|
oldest, latest = boundary_dates_in(notifications)
|
16
16
|
Trello.logger.info "Processing #{notifications.size} tracking notifications (from #{oldest} to #{latest}) starting from #{starting_date}..."
|
17
17
|
|
18
18
|
notifications.each do |notification|
|
19
|
-
tracking =
|
19
|
+
tracking = Tracking::Factory.build_from(notification)
|
20
20
|
begin
|
21
21
|
tracked_card = TrackedCard.update_or_create_with(notification.card)
|
22
22
|
tracked_card.add!(tracking)
|
data/lib/tracco/version.rb
CHANGED
data/lib/tracco.rb
CHANGED
@@ -18,7 +18,7 @@ require 'tracco/tracking/estimate_tracking'
|
|
18
18
|
require 'tracco/tracking/effort_tracking'
|
19
19
|
require 'tracco/tracking/card_done_tracking'
|
20
20
|
require 'tracco/tracking/invalid_tracking'
|
21
|
-
require 'tracco/
|
21
|
+
require 'tracco/tracking/factory'
|
22
22
|
require 'tracco/trello_tracker'
|
23
23
|
require 'tracco/google_docs_exporter'
|
24
24
|
|
data/spec/effort_spec.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
+
|
2
3
|
factory :tracked_card do
|
3
|
-
sequence(:
|
4
|
-
description "any description"
|
5
|
-
sequence(:short_id, 1000) { |n| n }
|
4
|
+
sequence(:short_id, 1000)
|
6
5
|
sequence(:trello_id, 100000) { |n| "xyz#{n}" }
|
7
|
-
|
6
|
+
sequence(:name) { |n| "any_card_#{n}" }
|
7
|
+
description "any description"
|
8
|
+
done false
|
8
9
|
closed false
|
9
|
-
|
10
|
-
# embeds_many :estimates
|
11
|
-
# embeds_many :efforts
|
12
10
|
end
|
11
|
+
|
13
12
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,8 +14,6 @@ rescue Bundler::GemNotFound => e
|
|
14
14
|
exit!
|
15
15
|
end
|
16
16
|
|
17
|
-
Bundler.require(:spec)
|
18
|
-
|
19
17
|
require 'tracco'
|
20
18
|
|
21
19
|
require 'factory_girl'
|
@@ -32,39 +30,3 @@ end
|
|
32
30
|
|
33
31
|
# force test env for the mongodb configuration
|
34
32
|
TrelloConfiguration::Database.load_env("test")
|
35
|
-
|
36
|
-
|
37
|
-
## Spec Helper Methods (TODO: should we move them in a separate file?)
|
38
|
-
|
39
|
-
def unrecognized_notification
|
40
|
-
create_notification(data: { 'text' => '@trackinguser hi there!' })
|
41
|
-
end
|
42
|
-
|
43
|
-
def notification_with_message(message)
|
44
|
-
create_notification(data: { 'text' => message })
|
45
|
-
end
|
46
|
-
|
47
|
-
def create_estimate(time_measurement)
|
48
|
-
create_notification(data: { 'text' => "@trackinguser [1.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
49
|
-
end
|
50
|
-
|
51
|
-
def create_effort(time_measurement)
|
52
|
-
create_notification(data: { 'text' => "@trackinguser +4.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
53
|
-
end
|
54
|
-
|
55
|
-
def with(notification)
|
56
|
-
tracking = TrackingFactory.build_from(notification)
|
57
|
-
yield(tracking)
|
58
|
-
end
|
59
|
-
|
60
|
-
def with_message(notification_message, &block)
|
61
|
-
with(notification_with_message(notification_message), &block)
|
62
|
-
end
|
63
|
-
|
64
|
-
def create_notification(custom_params)
|
65
|
-
params = { data: { 'text' => "@trackinguser +2h" }, date: "2012-10-28T21:06:14.801Z", member_creator: stub(username: "pietrodibello") }
|
66
|
-
params.merge!(custom_params)
|
67
|
-
|
68
|
-
stub(data: params[:data], date: params[:date], member_creator: params[:member_creator]).as_null_object
|
69
|
-
end
|
70
|
-
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
def unrecognized_notification
|
3
|
+
create_notification(data: { 'text' => '@trackinguser hi there!' })
|
4
|
+
end
|
5
|
+
|
6
|
+
def notification_with_message(message)
|
7
|
+
create_notification(data: { 'text' => message })
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_estimate(time_measurement)
|
11
|
+
create_notification(data: { 'text' => "@trackinguser [1.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_effort(time_measurement)
|
15
|
+
create_notification(data: { 'text' => "@trackinguser +4.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
16
|
+
end
|
17
|
+
|
18
|
+
def with(notification)
|
19
|
+
tracking = Tracking::Factory.build_from(notification)
|
20
|
+
yield(tracking)
|
21
|
+
end
|
22
|
+
|
23
|
+
def with_message(notification_message, &block)
|
24
|
+
with(notification_with_message(notification_message), &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_notification(custom_params)
|
28
|
+
params = { data: { 'text' => "@trackinguser +2h" }, date: "2012-10-28T21:06:14.801Z", member_creator: stub(username: "pietrodibello") }
|
29
|
+
params.merge!(custom_params)
|
30
|
+
|
31
|
+
stub(data: params[:data], date: params[:date], member_creator: params[:member_creator]).as_null_object
|
32
|
+
end
|
data/spec/tracked_card_spec.rb
CHANGED
@@ -8,6 +8,11 @@ describe TrackedCard do
|
|
8
8
|
|
9
9
|
subject(:card) { build(:tracked_card) }
|
10
10
|
|
11
|
+
before(:each) do
|
12
|
+
# adding a muted effort to check that won't be counted
|
13
|
+
card.efforts << build(:effort, amount: 1000, muted: true)
|
14
|
+
end
|
15
|
+
|
11
16
|
%w{piero tommaso michele}.each do |username|
|
12
17
|
let(username.to_sym) { Member.new(username: username) }
|
13
18
|
end
|
@@ -40,60 +45,67 @@ describe TrackedCard do
|
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
|
-
describe ".
|
44
|
-
it "finds all
|
45
|
-
|
46
|
-
|
47
|
-
:efforts => [Effort.new(amount: 3, date: Date.today, members: [piero])])
|
48
|
-
card_without_tracking = create(:tracked_card)
|
48
|
+
describe ".with_effort_spent_by" do
|
49
|
+
it "finds all the cards worked by a given member" do
|
50
|
+
card = create(:tracked_card, efforts: [build(:effort, members: [piero, tommaso])])
|
51
|
+
another_card = create(:tracked_card, efforts: [build(:effort, members: [piero, michele])])
|
49
52
|
|
53
|
+
TrackedCard.with_effort_spent_by("piero").should =~ [card, another_card]
|
54
|
+
TrackedCard.with_effort_spent_by("tommaso").should == [card]
|
55
|
+
TrackedCard.with_effort_spent_by("michele").should == [another_card]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ".efforts_between" do
|
60
|
+
it "finds all the cards worked in a given date range" do
|
61
|
+
a_card = create(:tracked_card, efforts: [build(:effort, date: Date.parse("2013-01-02"))])
|
62
|
+
another_card = create(:tracked_card, efforts: [build(:effort, date: Date.parse("2013-11-03"))])
|
63
|
+
a_very_old_card = create(:tracked_card, efforts: [build(:effort, date: Date.parse("2009-11-03"))])
|
50
64
|
|
51
|
-
TrackedCard.
|
65
|
+
TrackedCard.efforts_between(from_date: Date.parse("2012-01-01")).should =~ [a_card, another_card]
|
66
|
+
TrackedCard.efforts_between(from_date: Date.parse("2013-01-01")).should =~ [a_card, another_card]
|
67
|
+
TrackedCard.efforts_between(from_date: Date.parse("2013-01-22")).should == [another_card]
|
68
|
+
TrackedCard.efforts_between(from_date: Date.parse("2014-01-22")).should == []
|
69
|
+
|
70
|
+
TrackedCard.efforts_between(from_date: Date.parse("2012-01-01"), to_date: Date.parse("2012-11-01")).should == []
|
71
|
+
TrackedCard.efforts_between(from_date: Date.parse("2012-01-01"), to_date: Date.parse("2013-02-02")).should == [a_card]
|
72
|
+
TrackedCard.efforts_between(from_date: Date.parse("2012-01-01"), to_date: Date.parse("2014-02-02")).should =~ [a_card, another_card]
|
52
73
|
end
|
74
|
+
end
|
53
75
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
76
|
+
describe ".all_tracked_cards" do
|
77
|
+
let!(:card) { create(:tracked_card, name: "AAA", estimates: [build(:estimate)], efforts: [build(:effort)]) }
|
78
|
+
let!(:another_card) { create(:tracked_card, name: "ZZZ", estimates: [build(:estimate)], efforts: [build(:effort)]) }
|
79
|
+
let!(:card_without_tracking) { create(:tracked_card) }
|
58
80
|
|
59
|
-
|
60
|
-
|
61
|
-
|
81
|
+
it "finds all tracked cards with a valid tracking" do
|
82
|
+
TrackedCard.all_tracked_cards.should =~ [card, another_card]
|
83
|
+
end
|
62
84
|
|
63
|
-
|
85
|
+
it "optionally sorts the cards using a given sorting method" do
|
86
|
+
card.update_attributes(name: "AAA")
|
87
|
+
another_card.update_attributes(name: "ZZZ")
|
64
88
|
|
65
|
-
TrackedCard.all_tracked_cards(:
|
89
|
+
TrackedCard.all_tracked_cards(:sort_by => :name).should == [card, another_card]
|
66
90
|
end
|
67
91
|
|
68
92
|
it "applies an optional sorting order" do
|
69
|
-
card
|
70
|
-
|
71
|
-
card.efforts << Effort.new(amount: 3, date: Date.today, members: [piero])
|
72
|
-
|
73
|
-
another_card = create(:tracked_card, name: "ZZZ")
|
74
|
-
another_card.estimates << Estimate.new(amount: 5, date: Date.today)
|
75
|
-
another_card.efforts << Effort.new(amount: 3, date: Date.today, members: [piero])
|
93
|
+
card.update_attributes(name: "AAA")
|
94
|
+
another_card.update_attributes(name: "ZZZ")
|
76
95
|
|
77
96
|
card_without_tracking = create(:tracked_card)
|
78
97
|
|
79
|
-
TrackedCard.all_tracked_cards(:
|
98
|
+
TrackedCard.all_tracked_cards(:sort_by => :name, :order => :desc).should == [another_card, card]
|
80
99
|
end
|
81
100
|
|
82
101
|
it "uses the ascending order as default sorting order option" do
|
83
|
-
card
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
another_card = create(:tracked_card, name: "ZZZ", short_id: 12)
|
88
|
-
another_card.estimates << Estimate.new(amount: 5, date: Date.today)
|
89
|
-
another_card.efforts << Effort.new(amount: 3, date: Date.today, members: [piero])
|
102
|
+
card.update_attributes(name: "AAA", short_id: 44)
|
103
|
+
another_card.update_attributes(name: "ZZZ", short_id: 11)
|
104
|
+
card_without_tracking.update_attributes(short_id: 3456)
|
90
105
|
|
91
|
-
|
92
|
-
|
93
|
-
TrackedCard.all_tracked_cards(:method => :short_id).should == [another_card, card]
|
106
|
+
TrackedCard.all_tracked_cards(:sort_by => :short_id).should == [another_card, card]
|
94
107
|
end
|
95
108
|
|
96
|
-
|
97
109
|
end
|
98
110
|
|
99
111
|
describe ".update_or_create_with" do
|
@@ -162,22 +174,39 @@ describe TrackedCard do
|
|
162
174
|
|
163
175
|
end
|
164
176
|
|
177
|
+
describe "card with muted effort" do
|
178
|
+
it "fetches only non-muted efforts" do
|
179
|
+
card = create(:tracked_card, efforts: [build(:effort, muted: false)])
|
180
|
+
card_with_muted_effort = create(:tracked_card, efforts: [build(:effort, muted: true)])
|
181
|
+
|
182
|
+
TrackedCard.should have(2).cards
|
183
|
+
|
184
|
+
card.efforts.should have(1).effort
|
185
|
+
|
186
|
+
card_with_muted_effort.efforts.should be_empty
|
187
|
+
card_with_muted_effort.efforts.unscoped.should have(1).effort
|
188
|
+
end
|
189
|
+
|
190
|
+
it "skips muted effort when computing the total effort on the card" do
|
191
|
+
card.efforts << build(:effort, amount: 3, muted: true)
|
192
|
+
card.efforts << build(:effort, amount: 5, muted: false)
|
193
|
+
|
194
|
+
card.total_effort.should == 5
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
165
198
|
it "has no estimates and efforts initially" do
|
166
199
|
card.estimates.should be_empty
|
167
200
|
card.efforts.should be_empty
|
168
201
|
end
|
169
202
|
|
170
203
|
it "is possible to add estimates" do
|
171
|
-
card.estimates <<
|
172
|
-
card.estimates << Estimate.new(amount: 12, date: Date.today)
|
173
|
-
|
204
|
+
card.estimates << build(:estimate) << build(:estimate)
|
174
205
|
card.estimates.should have(2).estimates
|
175
206
|
end
|
176
207
|
|
177
208
|
it "is possible to add efforts" do
|
178
|
-
card.efforts <<
|
179
|
-
card.efforts << Effort.new(amount: 5, date: Date.today, members: [tommaso])
|
180
|
-
|
209
|
+
card.efforts << build(:effort) << build(:effort)
|
181
210
|
card.efforts.should have(2).efforts
|
182
211
|
end
|
183
212
|
|
@@ -185,14 +214,26 @@ describe TrackedCard do
|
|
185
214
|
let(:first_notification) { stub("notification1", date: Date.yesterday) }
|
186
215
|
let(:second_notification) { stub("notification1", date: Date.today) }
|
187
216
|
|
188
|
-
it "
|
217
|
+
it "fetches all the card notifications from trello" do
|
189
218
|
card.estimates << Estimate.new(tracking_notification_id: "xyz987", amount: 5, date: Date.yesterday)
|
190
219
|
card.efforts << Effort.new(tracking_notification_id: "abc123", amount: 3, date: Date.today, members: [piero])
|
191
220
|
|
192
221
|
Trello::Notification.should_receive(:find).with("xyz987").and_return(second_notification)
|
193
222
|
Trello::Notification.should_receive(:find).with("abc123").and_return(first_notification)
|
223
|
+
|
194
224
|
card.trello_notifications.should == [first_notification, second_notification]
|
195
225
|
end
|
226
|
+
|
227
|
+
it "skips the notifications not found" do
|
228
|
+
card.estimates << build(:estimate, tracking_notification_id: "unexisting_id")
|
229
|
+
card.efforts << build(:effort, tracking_notification_id: "first_notification_id")
|
230
|
+
|
231
|
+
Trello::Notification.should_receive(:find).with("unexisting_id").and_raise(Trello::Error)
|
232
|
+
Trello::Notification.should_receive(:find).with("first_notification_id").and_return(first_notification)
|
233
|
+
|
234
|
+
card.trello_notifications.should == [first_notification]
|
235
|
+
end
|
236
|
+
|
196
237
|
end
|
197
238
|
|
198
239
|
describe "equality" do
|
@@ -207,7 +248,7 @@ describe TrackedCard do
|
|
207
248
|
end
|
208
249
|
|
209
250
|
describe "#add" do
|
210
|
-
let(:card) {
|
251
|
+
let(:card) { build(:tracked_card) }
|
211
252
|
let(:estimate_tracking) { Tracking::EstimateTracking.new(create_notification(data: { 'text' => "@trackinguser [1h]" })) }
|
212
253
|
|
213
254
|
it "adds an estimate from a tracking estimate notification" do
|
@@ -232,7 +273,7 @@ describe TrackedCard do
|
|
232
273
|
end
|
233
274
|
|
234
275
|
describe "#add!" do
|
235
|
-
let(:card) {
|
276
|
+
let(:card) { build(:tracked_card) }
|
236
277
|
|
237
278
|
it "saves the tracked card after adding the tracking" do
|
238
279
|
any_tracking = Tracking::EstimateTracking.new(create_notification(data: { 'text' => "@trackinguser [1h]" }))
|
@@ -248,50 +289,51 @@ describe TrackedCard do
|
|
248
289
|
end
|
249
290
|
|
250
291
|
it "computes the total effort on the card" do
|
251
|
-
card.efforts <<
|
252
|
-
card.efforts <<
|
292
|
+
card.efforts << build(:effort, amount: 3)
|
293
|
+
card.efforts << build(:effort, amount: 5)
|
253
294
|
|
254
295
|
card.total_effort.should == 3+5
|
255
296
|
end
|
256
297
|
end
|
257
298
|
|
258
299
|
describe "#last_estimate_error" do
|
300
|
+
|
259
301
|
it "is nil when the card has no estimate" do
|
260
|
-
card.efforts <<
|
302
|
+
card.efforts << build(:effort, amount: 5)
|
261
303
|
|
262
304
|
card.last_estimate_error.should be_nil
|
263
305
|
end
|
264
306
|
|
265
307
|
it "is nil when the card has no effort" do
|
266
|
-
card.efforts <<
|
308
|
+
card.efforts << build(:estimate)
|
267
309
|
|
268
310
|
card.last_estimate_error.should be_nil
|
269
311
|
end
|
270
312
|
|
271
313
|
it "is zero when actual effort is equal to estimate" do
|
272
|
-
card.estimates <<
|
273
|
-
card.efforts <<
|
314
|
+
card.estimates << build(:estimate, amount: 5)
|
315
|
+
card.efforts << build(:effort, amount: 5)
|
274
316
|
|
275
317
|
card.last_estimate_error.should == 0.0
|
276
318
|
end
|
277
319
|
|
278
320
|
it "is 100 when the actual effort is twice the given estimate" do
|
279
|
-
card.estimates <<
|
280
|
-
card.efforts <<
|
321
|
+
card.estimates << build(:estimate, amount: 5)
|
322
|
+
card.efforts << build(:effort, amount: 10)
|
281
323
|
|
282
324
|
card.last_estimate_error.should == 100.0
|
283
325
|
end
|
284
326
|
|
285
327
|
it "is -50 when the actual effort is half of the given estimate" do
|
286
|
-
card.estimates <<
|
287
|
-
card.efforts <<
|
328
|
+
card.estimates << build(:estimate, amount: 10)
|
329
|
+
card.efforts << build(:effort, amount: 5)
|
288
330
|
|
289
331
|
card.last_estimate_error.should == -50.0
|
290
332
|
end
|
291
333
|
|
292
334
|
it "is rounded with two decimal digits" do
|
293
|
-
card.estimates <<
|
294
|
-
card.efforts <<
|
335
|
+
card.estimates << build(:estimate, amount: 3)
|
336
|
+
card.efforts << build(:effort, amount: 5)
|
295
337
|
|
296
338
|
card.last_estimate_error.should == 66.67
|
297
339
|
end
|
@@ -313,9 +355,9 @@ describe TrackedCard do
|
|
313
355
|
|
314
356
|
describe "#members" do
|
315
357
|
it "lists all the members which spent some effort on the card" do
|
316
|
-
card.efforts <<
|
317
|
-
card.efforts <<
|
318
|
-
card.efforts <<
|
358
|
+
card.efforts << build(:effort, members: [piero, tommaso])
|
359
|
+
card.efforts << build(:effort, members: [tommaso])
|
360
|
+
card.efforts << build(:effort, members: [tommaso, michele])
|
319
361
|
|
320
362
|
card.members.should == [piero, tommaso, michele]
|
321
363
|
end
|
@@ -324,9 +366,9 @@ describe TrackedCard do
|
|
324
366
|
describe "#working_start_date" do
|
325
367
|
|
326
368
|
it "is the date of the first effort spent on the card" do
|
327
|
-
card.efforts <<
|
328
|
-
card.efforts <<
|
329
|
-
card.efforts <<
|
369
|
+
card.efforts << build(:effort, date: Date.today)
|
370
|
+
card.efforts << build(:effort, date: Date.yesterday)
|
371
|
+
card.efforts << build(:effort, date: Date.tomorrow)
|
330
372
|
|
331
373
|
card.working_start_date.should == Date.yesterday
|
332
374
|
end
|
@@ -334,12 +376,12 @@ describe TrackedCard do
|
|
334
376
|
|
335
377
|
describe "#first_activity_date" do
|
336
378
|
it "is the date of the first effort or estimate given on the card" do
|
337
|
-
card.estimates <<
|
338
|
-
card.estimates <<
|
339
|
-
card.estimates <<
|
379
|
+
card.estimates << build(:estimate, date: Date.yesterday)
|
380
|
+
card.estimates << build(:estimate, date: Date.yesterday.prev_day)
|
381
|
+
card.estimates << build(:estimate, date: Date.tomorrow)
|
340
382
|
|
341
|
-
card.efforts <<
|
342
|
-
card.efforts <<
|
383
|
+
card.efforts << build(:effort, date: Date.yesterday)
|
384
|
+
card.efforts << build(:effort, date: Date.today)
|
343
385
|
|
344
386
|
card.first_activity_date.should == Date.yesterday.prev_day
|
345
387
|
end
|
@@ -347,9 +389,9 @@ describe TrackedCard do
|
|
347
389
|
|
348
390
|
describe "#first_estimate_date" do
|
349
391
|
it "is the date of the first estimate given on the card" do
|
350
|
-
card.estimates <<
|
351
|
-
card.estimates <<
|
352
|
-
card.estimates <<
|
392
|
+
card.estimates << build(:estimate, date: Date.tomorrow)
|
393
|
+
card.estimates << build(:estimate, date: Date.yesterday.prev_day)
|
394
|
+
card.estimates << build(:estimate, date: Date.today)
|
353
395
|
|
354
396
|
card.first_estimate_date.should == Date.yesterday.prev_day
|
355
397
|
end
|
@@ -357,9 +399,9 @@ describe TrackedCard do
|
|
357
399
|
|
358
400
|
describe "#last_estimate_date" do
|
359
401
|
it "is the date of the last estimate given on the card" do
|
360
|
-
card.estimates <<
|
361
|
-
card.estimates <<
|
362
|
-
card.estimates <<
|
402
|
+
card.estimates << build(:estimate, date: Date.yesterday)
|
403
|
+
card.estimates << build(:estimate, date: Date.tomorrow)
|
404
|
+
card.estimates << build(:estimate, date: Date.today)
|
363
405
|
|
364
406
|
card.last_estimate_date.should == Date.tomorrow
|
365
407
|
end
|
@@ -369,7 +411,7 @@ describe TrackedCard do
|
|
369
411
|
it "is false when there's no effort or estimate tracked on the card" do
|
370
412
|
card.no_tracking?.should be_true
|
371
413
|
|
372
|
-
card.estimates <<
|
414
|
+
card.estimates << build(:estimate, date: Date.yesterday)
|
373
415
|
card.no_tracking?.should be_false
|
374
416
|
end
|
375
417
|
end
|
@@ -387,10 +429,10 @@ describe TrackedCard do
|
|
387
429
|
|
388
430
|
describe "#status" do
|
389
431
|
it "is done when is done" do
|
390
|
-
done_card = TrackedCard.new(done:true)
|
432
|
+
done_card = TrackedCard.new(done: true)
|
391
433
|
done_card.status.should == :done
|
392
434
|
|
393
|
-
done_card.efforts <<
|
435
|
+
done_card.efforts << build(:effort)
|
394
436
|
done_card.status.should == :done
|
395
437
|
end
|
396
438
|
|
@@ -398,7 +440,7 @@ describe TrackedCard do
|
|
398
440
|
card = TrackedCard.new
|
399
441
|
card.status.should == :todo
|
400
442
|
|
401
|
-
card.efforts <<
|
443
|
+
card.efforts << build(:effort)
|
402
444
|
card.status.should == :in_progress
|
403
445
|
end
|
404
446
|
end
|
@@ -7,7 +7,7 @@ module Tracking
|
|
7
7
|
it "marks the card as done" do
|
8
8
|
card = TrackedCard.new
|
9
9
|
|
10
|
-
done_tracking =
|
10
|
+
done_tracking = Tracking::Factory.build_from(notification_with_message("DONE"))
|
11
11
|
done_tracking.add_to(card)
|
12
12
|
|
13
13
|
card.done?.should be_true
|
@@ -28,7 +28,7 @@ module Tracking
|
|
28
28
|
date: "2012-10-28T21:06:14.801Z",
|
29
29
|
member_creator: stub(username: "michelepangrazzi"))
|
30
30
|
|
31
|
-
|
31
|
+
Tracking::Factory.build_from(raw_data).effort.should == Effort.new(amount: 2.0, date: Date.parse('2012-10-28'), members: [michelepangrazzi])
|
32
32
|
end
|
33
33
|
|
34
34
|
it "converts the effort in hours when the notification contains an effort in days" do
|
@@ -87,7 +87,7 @@ module Tracking
|
|
87
87
|
it "tracks the effort with the date given in the notification text, not the actual notification date" do
|
88
88
|
raw_data = create_notification(data: { 'text' => "@trackinguser 22.11.2012 +6p" }, date: "2012-09-19T12:46:13.713Z")
|
89
89
|
|
90
|
-
tracking =
|
90
|
+
tracking = Tracking::Factory.build_from(raw_data)
|
91
91
|
|
92
92
|
tracking.effort.date.should == Date.parse('2012-11-22')
|
93
93
|
end
|
@@ -95,7 +95,7 @@ module Tracking
|
|
95
95
|
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
96
96
|
raw_data = create_notification(data: { 'text' => "@trackinguser yesterday +6p" }, date: "2012-09-19T12:46:13.713Z")
|
97
97
|
|
98
|
-
tracking =
|
98
|
+
tracking = Tracking::Factory.build_from(raw_data)
|
99
99
|
|
100
100
|
tracking.effort.date.should == Date.parse('2012-09-18')
|
101
101
|
end
|
@@ -103,7 +103,7 @@ module Tracking
|
|
103
103
|
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
104
104
|
raw_data = create_notification(data: { 'text' => "@trackinguser +6p yesterday" }, date: "2012-09-19T12:46:13.713Z")
|
105
105
|
|
106
|
-
tracking =
|
106
|
+
tracking = Tracking::Factory.build_from(raw_data)
|
107
107
|
|
108
108
|
tracking.effort.date.should == Date.parse('2012-09-18')
|
109
109
|
end
|
@@ -6,34 +6,34 @@ module Tracking
|
|
6
6
|
describe "#estimate" do
|
7
7
|
|
8
8
|
it "is nil when the notification does not contain an estimate" do
|
9
|
-
|
9
|
+
Tracking::Factory.build_from(unrecognized_notification).estimate.should be_nil
|
10
10
|
end
|
11
11
|
|
12
12
|
it "is the hour-based estimate when the notification contains an estimate in hours" do
|
13
13
|
raw_data = create_notification(data: { 'text' => "@trackinguser [2h]" }, date: "2012-10-28T21:06:14.801Z")
|
14
14
|
|
15
|
-
|
15
|
+
Tracking::Factory.build_from(raw_data).estimate.should == Estimate.new(amount: 2.0, date: Date.parse('2012-10-28'))
|
16
16
|
end
|
17
17
|
|
18
18
|
it "converts the estimate in hours when the notification contains an estimate in days" do
|
19
|
-
|
20
|
-
|
19
|
+
Tracking::Factory.build_from(create_notification(data: { 'text' => "@trackinguser [1.5d]" })).estimate.amount.should == 8+4
|
20
|
+
Tracking::Factory.build_from(create_notification(data: { 'text' => "@trackinguser [1.5g]" })).estimate.amount.should == 8+4
|
21
21
|
end
|
22
22
|
|
23
23
|
it "converts the estimate in hours when the notification contains an estimate in pomodori" do
|
24
24
|
raw_data = create_notification(data: { 'text' => "@trackinguser [10p]" })
|
25
|
-
|
25
|
+
Tracking::Factory.build_from(raw_data).estimate.amount.should == 5
|
26
26
|
end
|
27
27
|
|
28
28
|
it "fetch the estimate from a complex estimate message" do
|
29
29
|
raw_data = create_notification(data: { 'text' => "@maxmazza Dobbiamo ancora lavorarci.\n@trackinguser ristimo ancora [3h] per il fix" })
|
30
|
-
|
30
|
+
Tracking::Factory.build_from(raw_data).estimate.amount.should == 3.0
|
31
31
|
end
|
32
32
|
|
33
33
|
it "tracks the effort with the date given in the notification text, not the actual notification date" do
|
34
34
|
raw_data = create_notification( data: { 'text' => "@trackinguser 22.11.2012 [6p]" }, date: "2012-09-19T12:46:13.713Z")
|
35
35
|
|
36
|
-
tracking =
|
36
|
+
tracking = Tracking::Factory.build_from(raw_data)
|
37
37
|
|
38
38
|
tracking.estimate.date.should == Date.parse('2012-11-22')
|
39
39
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Tracking::Factory do
|
4
4
|
|
5
5
|
TIME_MEASUREMENTS = {
|
6
6
|
hours: 'h',
|
@@ -11,7 +11,7 @@ describe TrackingFactory do
|
|
11
11
|
|
12
12
|
context "unknown tracking format" do
|
13
13
|
it "builds an invalid tracking instance" do
|
14
|
-
|
14
|
+
Tracking::Factory.build_from(unrecognized_notification).class.should == Tracking::InvalidTracking
|
15
15
|
|
16
16
|
with_message("@trackinguser +30m") { |tracking| tracking.class.should == Tracking::InvalidTracking }
|
17
17
|
end
|
@@ -21,13 +21,13 @@ describe TrackingFactory do
|
|
21
21
|
|
22
22
|
context "estimate tracking notification in #{time_measurement}" do
|
23
23
|
it "builds an estimate tracking instance" do
|
24
|
-
|
24
|
+
Tracking::Factory.build_from(create_estimate(time_measurement)).class.should == Tracking::EstimateTracking
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
context "effort tracking notification in #{time_measurement}" do
|
29
29
|
it "builds an effort tracking instance" do
|
30
|
-
|
30
|
+
Tracking::Factory.build_from(create_effort(time_measurement)).class.should == Tracking::EffortTracking
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
data/tracco.sublime-project
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracco
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-trello
|
@@ -272,8 +272,8 @@ files:
|
|
272
272
|
- lib/tracco/tracking/card_done_tracking.rb
|
273
273
|
- lib/tracco/tracking/effort_tracking.rb
|
274
274
|
- lib/tracco/tracking/estimate_tracking.rb
|
275
|
+
- lib/tracco/tracking/factory.rb
|
275
276
|
- lib/tracco/tracking/invalid_tracking.rb
|
276
|
-
- lib/tracco/tracking_factory.rb
|
277
277
|
- lib/tracco/trello_authorize.rb
|
278
278
|
- lib/tracco/trello_configuration.rb
|
279
279
|
- lib/tracco/trello_tracker.rb
|
@@ -284,6 +284,8 @@ files:
|
|
284
284
|
- script/mate.sh
|
285
285
|
- spec/effort_spec.rb
|
286
286
|
- spec/estimate_spec.rb
|
287
|
+
- spec/factories/effort_factory.rb
|
288
|
+
- spec/factories/estimate_factory.rb
|
287
289
|
- spec/factories/tracked_card_factory.rb
|
288
290
|
- spec/integration/trello_authorization_spec.rb
|
289
291
|
- spec/integration/trello_tracker_spec.rb
|
@@ -291,6 +293,7 @@ files:
|
|
291
293
|
- spec/patches/trello/card_spec.rb
|
292
294
|
- spec/spec_helper.rb
|
293
295
|
- spec/support/database_cleaner.rb
|
296
|
+
- spec/support/spec_helper_methods.rb
|
294
297
|
- spec/tracked_card_spec.rb
|
295
298
|
- spec/tracking/card_done_tracking_spec.rb
|
296
299
|
- spec/tracking/effort_tracking_spec.rb
|
@@ -315,7 +318,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
315
318
|
version: '0'
|
316
319
|
segments:
|
317
320
|
- 0
|
318
|
-
hash:
|
321
|
+
hash: 1645942165596305334
|
319
322
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
320
323
|
none: false
|
321
324
|
requirements:
|
@@ -1,22 +0,0 @@
|
|
1
|
-
class TrackingFactory
|
2
|
-
|
3
|
-
DURATION_REGEXP = '(\d+\.?\d*[phdg])'
|
4
|
-
|
5
|
-
@match_pairs = {}
|
6
|
-
|
7
|
-
def self.match(match_pair)
|
8
|
-
@match_pairs.merge!(match_pair)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.build_from(tracking_notification)
|
12
|
-
matching_pair = @match_pairs.find { |regexp, tracking_class| tracking_notification.data['text'] =~ regexp }
|
13
|
-
|
14
|
-
tracking_class = matching_pair ? matching_pair.last : Tracking::InvalidTracking
|
15
|
-
tracking_class.new(tracking_notification)
|
16
|
-
end
|
17
|
-
|
18
|
-
match /\[#{DURATION_REGEXP}\]/ => Tracking::EstimateTracking
|
19
|
-
match /\+#{DURATION_REGEXP}/ => Tracking::EffortTracking
|
20
|
-
match /DONE/ => Tracking::CardDoneTracking
|
21
|
-
|
22
|
-
end
|