Class: Pickler::Tracker::Story

Inherits:
Abstract
  • Object
show all
Defined in:
lib/pickler/tracker/story.rb

Constant Summary collapse

TYPES =
%w(bug feature chore release)
STATES =
%w(unscheduled unstarted started finished delivered rejected accepted)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Abstract

accessor, date_reader, #id, reader

Constructor Details

#initialize(project, attributes = {}) ⇒ Story

Returns a new instance of Story.



13
14
15
16
17
# File 'lib/pickler/tracker/story.rb', line 13

def initialize(project, attributes = {})
  @project = project
  super(attributes)
  @iteration = Iteration.new(project, @attributes["iteration"]) if @attributes["iteration"]
end

Instance Attribute Details

#labelsObject

Returns the value of attribute labels.



8
9
10
# File 'lib/pickler/tracker/story.rb', line 8

def labels
  @labels
end

#projectObject (readonly)

Returns the value of attribute project.



8
9
10
# File 'lib/pickler/tracker/story.rb', line 8

def project
  @project
end

Instance Method Details

#backlog?(as_of = Date.today) ⇒ Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/pickler/tracker/story.rb', line 56

def backlog?(as_of = Date.today)
  iteration && iteration.start >= as_of
end

#comment!(body) ⇒ Object



151
152
153
154
155
156
157
158
# File 'lib/pickler/tracker/story.rb', line 151

def comment!(body)
  response = tracker.request_xml(:post, "#{resource_url}/notes",{:text => body}.to_xml(:dasherize => false, :root => 'note'))
  if response["note"]
    Note.new(self, response["note"])
  else
    raise Pickler::Tracker::Error, Array(response["errors"]["error"]).join("\n"), caller
  end
end

#complete?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/pickler/tracker/story.rb', line 69

def complete?
  %w(finished delivered accepted).include?(current_state)
end

#current?(as_of = Date.today) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/pickler/tracker/story.rb', line 60

def current?(as_of = Date.today)
  iteration && iteration.include?(as_of)
end

#description_linesObject



123
124
125
126
127
128
129
# File 'lib/pickler/tracker/story.rb', line 123

def description_lines
  array = []
  description.to_s.each_line do |line|
    array << line.chomp
  end
  array
end

#destroyObject



170
171
172
173
174
175
176
177
# File 'lib/pickler/tracker/story.rb', line 170

def destroy
  if id
    response = tracker.request_xml(:delete, "/projects/#{project.id}/stories/#{id}", "")
    raise Error, response["message"], caller if response["message"]
    @attributes["id"] = nil
    self
  end
end

#done?(as_of = Date.today) ⇒ Boolean

In a previous iteration

Returns:

  • (Boolean)


65
66
67
# File 'lib/pickler/tracker/story.rb', line 65

def done?(as_of = Date.today)
  iteration && iteration.finish <= as_of
end

#estimateObject



135
136
137
# File 'lib/pickler/tracker/story.rb', line 135

def estimate
  @attributes["estimate"].to_i < 0 ? nil : @attributes["estimate"]
end

#estimate=(value) ⇒ Object



139
140
141
# File 'lib/pickler/tracker/story.rb', line 139

def estimate=(value)
  @attributes["estimate"] = value.nil? ? -1 : value
end

#finishObject



42
43
44
45
46
47
48
49
50
# File 'lib/pickler/tracker/story.rb', line 42

def finish
  case story_type
  when "bug", "feature"
    self.current_state = "finished" unless complete?
  when "chore", "release"
    self.current_state = "accepted"
  end
  current_state
end

#finish!Object



52
53
54
# File 'lib/pickler/tracker/story.rb', line 52

def finish!
  transition!(finish)
end

#header(format = :comment) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/pickler/tracker/story.rb', line 89

def header(format = :comment)
  case format
  when :tag
    unless labels.nil?
      "@#{url}#{labels.map {|l| " @#{l.tr(' _','_,')}"}.join}"
    else
      "# #{url}"
    end
  else
    "# #{url}"
  end
end

#iterationObject



19
20
21
22
23
24
# File 'lib/pickler/tracker/story.rb', line 19

def iteration
  unless current_state == 'unscheduled' || defined?(@iteration)
    @iteration = project.stories(:id => id, :includedone => true).first.iteration
  end
  @iteration
end

#notesObject



131
132
133
# File 'lib/pickler/tracker/story.rb', line 131

def notes
  [@attributes["notes"]].flatten.compact.map {|n| Note.new(self,n)}
end

#resource_urlObject



179
180
181
# File 'lib/pickler/tracker/story.rb', line 179

def resource_url
  ["/projects/#{project.id}/stories",id].compact.join("/")
end

#saveObject



183
184
185
186
187
188
189
190
191
# File 'lib/pickler/tracker/story.rb', line 183

def save
  response = tracker.request_xml(id ? :put : :post,  resource_url, to_xml(false))
  if response["story"]
    initialize(project, response["story"])
    true
  else
    Array(response["errors"]["error"])
  end
end

#save!Object



193
194
195
196
197
198
199
# File 'lib/pickler/tracker/story.rb', line 193

def save!
  errors = save
  if errors != true
    raise Pickler::Tracker::Error, Array(errors).join("\n"), caller
  end
  self
end

#startable?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/pickler/tracker/story.rb', line 73

def startable?
  %w(unscheduled unstarted rejected).include?(current_state)
end

#suggested_basename(user_override = nil) ⇒ Object



143
144
145
146
147
148
149
# File 'lib/pickler/tracker/story.rb', line 143

def suggested_basename(user_override = nil)
  if user_override.to_s !~ /\A-?\z/
    user_override
  else
    name.to_s.empty? ? id.to_s : name.gsub(/[^\w-]+/,'_').downcase
  end
end

#to_s(format = :comment) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/pickler/tracker/story.rb', line 81

def to_s(format = :comment)
  to_s = "#{header(format)}\n#{story_type.capitalize}: #{name}\n"
  description_lines.each do |line|
    to_s << "  #{line}".rstrip << "\n"
  end
  to_s
end

#to_s=(body) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/pickler/tracker/story.rb', line 102

def to_s=(body)
  if body =~ /\A[@|#]https?\b\S*(\s+@\S+)*\s*$/
    self.labels = body[/\A@.*/].split(/\s+/)[1..-1].map {|l| l[1..-1].tr('_,',' _')}
  end
  body = body.sub(/\A(?:[@#].*\n)+/,'')
  if body =~ /\A(\w+): (.*)/
    self.story_type = $1.downcase
    self.name = $2
    description = $'
  else
    self.story_type = "feature"
    self.name = body[/.*/]
    description = $'
  end
  self.description = description.gsub(/\A\n+|\n+\Z/,'') + "\n"
  if description_lines.all? {|l| l.empty? || l =~ /^  /}
    self.description.gsub!(/^  /,'')
  end
  self
end

#to_xml(force_labels = true) ⇒ Object



160
161
162
163
164
165
166
167
168
# File 'lib/pickler/tracker/story.rb', line 160

def to_xml(force_labels = true)
  hash = @attributes.reject do |k,v|
    !%w(current_state deadline description estimate name owned_by requested_by story_type).include?(k)
  end
  if force_labels || !id || normalize_labels(@attributes["labels"]) != labels
    hash["labels"] = labels.join(", ")
  end
  hash.to_xml(:dasherize => false, :root => "story")
end

#trackerObject



77
78
79
# File 'lib/pickler/tracker/story.rb', line 77

def tracker
  project.tracker
end

#transition!(state) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/pickler/tracker/story.rb', line 30

def transition!(state)
  raise Pickler::Tracker::Error, "Invalid state #{state}", caller unless STATES.include?(state)
  self.current_state = state
  if id
    xml = "<story><current_state>#{state}</current_state></story>"
    error = tracker.request_xml(:put, resource_url, xml).fetch("errors",{})["error"] || true
  else
    error = save
  end
  raise Pickler::Tracker::Error, Array(error).join("\n"), caller unless error == true
end