taskmapper 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.travis.yml +4 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +20 -0
- data/NOTES +18 -0
- data/README.md +296 -0
- data/Rakefile +40 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/bin/tm +7 -0
- data/examples/tm_example.rb +11 -0
- data/examples/tm_example_2.rb +11 -0
- data/examples/tm_example_3.rb +21 -0
- data/examples/tm_example_4.rb +17 -0
- data/lib/taskmapper.rb +53 -0
- data/lib/taskmapper/authenticator.rb +2 -0
- data/lib/taskmapper/cli/commands/config.rb +100 -0
- data/lib/taskmapper/cli/commands/console.rb +35 -0
- data/lib/taskmapper/cli/commands/generate.rb +112 -0
- data/lib/taskmapper/cli/commands/generate/provider.rb +5 -0
- data/lib/taskmapper/cli/commands/generate/provider/comment.rb +14 -0
- data/lib/taskmapper/cli/commands/generate/provider/project.rb +26 -0
- data/lib/taskmapper/cli/commands/generate/provider/provider.rb +25 -0
- data/lib/taskmapper/cli/commands/generate/provider/ticket.rb +12 -0
- data/lib/taskmapper/cli/commands/help.rb +9 -0
- data/lib/taskmapper/cli/commands/help/config +27 -0
- data/lib/taskmapper/cli/commands/help/console +13 -0
- data/lib/taskmapper/cli/commands/help/generate +19 -0
- data/lib/taskmapper/cli/commands/help/help +7 -0
- data/lib/taskmapper/cli/commands/help/project +13 -0
- data/lib/taskmapper/cli/commands/help/ticket +14 -0
- data/lib/taskmapper/cli/commands/project.rb +140 -0
- data/lib/taskmapper/cli/commands/ticket.rb +145 -0
- data/lib/taskmapper/cli/common.rb +28 -0
- data/lib/taskmapper/cli/init.rb +77 -0
- data/lib/taskmapper/comment.rb +97 -0
- data/lib/taskmapper/common.rb +81 -0
- data/lib/taskmapper/dummy/comment.rb +27 -0
- data/lib/taskmapper/dummy/dummy.rb +28 -0
- data/lib/taskmapper/dummy/project.rb +42 -0
- data/lib/taskmapper/dummy/ticket.rb +43 -0
- data/lib/taskmapper/exception.rb +2 -0
- data/lib/taskmapper/helper.rb +72 -0
- data/lib/taskmapper/project.rb +145 -0
- data/lib/taskmapper/provider.rb +82 -0
- data/lib/taskmapper/tester/comment.rb +18 -0
- data/lib/taskmapper/tester/project.rb +19 -0
- data/lib/taskmapper/tester/tester.rb +28 -0
- data/lib/taskmapper/tester/ticket.rb +19 -0
- data/lib/taskmapper/ticket.rb +154 -0
- data/spec/project_spec.rb +84 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/taskmapper-cli_spec.rb +60 -0
- data/spec/taskmapper-exception_spec.rb +160 -0
- data/spec/taskmapper_spec.rb +13 -0
- data/spec/ticket_spec.rb +56 -0
- data/taskmapper.gemspec +118 -0
- metadata +189 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Base
|
3
|
+
# The comment class
|
4
|
+
#
|
5
|
+
# This will probably one of the most troublesome parts of creating a provider for taskmapper
|
6
|
+
# since there are so many different ways comments are handled by different APIs.
|
7
|
+
# Keep in mind that if you do need to change/overwrite the methods, you will most likely
|
8
|
+
# only need to overwrite #find_by_id, #find_by_attributes, #search, and possibly #initialize
|
9
|
+
# as long as their parameters conform to what the find method expects.
|
10
|
+
#
|
11
|
+
# Here are the expected attributes:
|
12
|
+
#
|
13
|
+
# * author
|
14
|
+
# * body
|
15
|
+
# * id
|
16
|
+
# * created_at
|
17
|
+
# * updated_at
|
18
|
+
# * ticket_id
|
19
|
+
# * project_id
|
20
|
+
class Comment < Hashie::Mash
|
21
|
+
include TaskMapper::Provider::Common
|
22
|
+
include TaskMapper::Provider::Helper
|
23
|
+
extend TaskMapper::Provider::Helper
|
24
|
+
attr_accessor :system, :system_data
|
25
|
+
API = nil # Replace with your comment's API's Class
|
26
|
+
|
27
|
+
# Find comment
|
28
|
+
# You can also retrieve an array of all comments by not specifying any query.
|
29
|
+
#
|
30
|
+
# * find(<project_id>, <ticket_id>) or find(<project_id>, <ticket_id>, :all) - Returns an array of all comments
|
31
|
+
# * find(<project_id>, <ticket_id>, ##) - Returns a comment based on that id or some other primary (unique) attribute
|
32
|
+
# * find(<project_id>, <ticket_id>, [#, #, #]) - Returns many comments with these ids
|
33
|
+
# * find(<project_id>, <ticket_id>, :first, :name => 'Project name') - Returns the first comment based on the comment's attribute(s)
|
34
|
+
# * find(<project_id>, <ticket_id>, :last, :name => 'Some project') - Returns the last comment based on the comment's attribute(s)
|
35
|
+
# * find(<project_id>, <ticket_id>, :all, :name => 'Test Project') - Returns all comments based on the given attribute(s)
|
36
|
+
def self.find(project_id, ticket_id, *options)
|
37
|
+
first, attributes = options
|
38
|
+
if first.nil? or (first == :all and attributes.nil?)
|
39
|
+
self.find_by_attributes(project_id, ticket_id)
|
40
|
+
elsif first.is_a? Array
|
41
|
+
first.collect { |id| self.find_by_id(project_id, ticket_id, id) }
|
42
|
+
elsif first == :first
|
43
|
+
comments = attributes.nil? ? self.find_by_attributes(project_id, ticket_id) : self.find_by_attributes(project_id, ticket_id, attributes)
|
44
|
+
comments.first
|
45
|
+
elsif first == :last
|
46
|
+
comments = attributes.nil? ? self.find_by_attributes(project_id, ticket_id) : self.find_by_attributes(project_id, ticket_id, attributes)
|
47
|
+
comments.last
|
48
|
+
elsif first == :all
|
49
|
+
self.find_by_attributes(project_id, ticket_id, attributes)
|
50
|
+
else
|
51
|
+
self.find_by_id(project_id, ticket_id, first)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# The first of whatever comment
|
56
|
+
def self.first(project_id, ticket_id, *options)
|
57
|
+
self.find(project_id, ticket_id, :first, *options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# The last of whatever comment
|
61
|
+
def self.last(project_id, ticket_id, *options)
|
62
|
+
self.find(project_id, ticket_id, :last, *options)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Accepts an integer id and returns the single comment instance
|
66
|
+
# Must be defined by the provider
|
67
|
+
def self.find_by_id(project_id, ticket_id, id)
|
68
|
+
if self::API.is_a? Class
|
69
|
+
self.new self::API.find(id, :params => {:project_id => project_id, :ticket_id => ticket_id})
|
70
|
+
else
|
71
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Accepts an attributes hash and returns all comments matching those attributes in an array
|
76
|
+
# Should return all comments if the attributes hash is empty
|
77
|
+
# Must be defined by the provider
|
78
|
+
def self.find_by_attributes(project_id, ticket_id, attributes = {})
|
79
|
+
if self::API.is_a? Class
|
80
|
+
self.search(project_id, ticket_id, attributes)
|
81
|
+
else
|
82
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# This is a helper method to find
|
87
|
+
def self.search(project_id, ticket_id, options = {}, limit = 1000)
|
88
|
+
if self::API.is_a? Class
|
89
|
+
comments = self::API.find(:all, :params => {:project_id => project_id, :ticket_id => ticket_id}).collect { |comment| self.new comment }
|
90
|
+
search_by_attribute(comments, options, limit)
|
91
|
+
else
|
92
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
# Common module
|
3
|
+
# contains method definitions common to all or most of the models
|
4
|
+
module Common
|
5
|
+
module ClassMethods
|
6
|
+
# Create a something.
|
7
|
+
# Basically, a .new and .save in the same call. The default method assumes it is passed a
|
8
|
+
# single hash with attribute information
|
9
|
+
def create(*options)
|
10
|
+
if self::API.is_a? Class
|
11
|
+
something = self::API.new(*options)
|
12
|
+
something.save
|
13
|
+
self.new something
|
14
|
+
else
|
15
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Automatic extension of class methods on include
|
21
|
+
def self.included(base)
|
22
|
+
base.extend ClassMethods
|
23
|
+
end
|
24
|
+
|
25
|
+
# The initializer
|
26
|
+
# It tries to do a default system for ActiveResource-based api providers
|
27
|
+
def initialize(*options)
|
28
|
+
@system_data ||= {}
|
29
|
+
@cache ||= {}
|
30
|
+
first = options.shift
|
31
|
+
case first
|
32
|
+
when Hash
|
33
|
+
super(first.to_hash)
|
34
|
+
else
|
35
|
+
@system_data[:client] = first
|
36
|
+
self.prefix_options ||= @system_data[:client].prefix_options if @system_data[:client].prefix_options
|
37
|
+
super(first.attributes)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Update the something and save
|
42
|
+
# As opposed to update which just updates the attributes
|
43
|
+
def update!(*options)
|
44
|
+
update(*options)
|
45
|
+
save
|
46
|
+
end
|
47
|
+
|
48
|
+
# Save changes to this project
|
49
|
+
# Returns true (success) or false (failure) or nil (no changes)
|
50
|
+
def save
|
51
|
+
if @system_data and (something = @system_data[:client]) and something.respond_to?(:attributes)
|
52
|
+
changes = 0
|
53
|
+
something.attributes.each do |k, v|
|
54
|
+
if self.send(k) != v
|
55
|
+
something.send(k + '=', self.send(k))
|
56
|
+
changes += 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
something.save if changes > 0
|
60
|
+
else
|
61
|
+
raise TaskMapper::Exception.new("#{self.class.name}::#{this_method} method must be implemented by the provider")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Delete this project
|
66
|
+
# Returns true (success) or false(failure)
|
67
|
+
def destroy
|
68
|
+
if @system_data and @system_data[:client] and @system_data[:client].respond_to?(:destroy)
|
69
|
+
return @system_data[:client].destroy
|
70
|
+
else
|
71
|
+
raise TaskMapper::Exception.new("#{self.class.name}::#{this_method} method must be implemented by the provider")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def respond_to?(symbol, include_private = false)
|
76
|
+
result = super(symbol)
|
77
|
+
return true if result or @system_data.nil? or @system_data[:client].nil?
|
78
|
+
@system_data[:client].respond_to?(symbol, include_private)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Dummy
|
3
|
+
# This is the Comment class for the Dummy provider
|
4
|
+
class Comment < TaskMapper::Provider::Base::Comment
|
5
|
+
|
6
|
+
|
7
|
+
def self.find_by_id(id)
|
8
|
+
self.new({:id => id})
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find_by_attributes(*options)
|
12
|
+
[self.new(*options)]
|
13
|
+
end
|
14
|
+
|
15
|
+
# You don't need to define an initializer, this is only here to initialize dummy data
|
16
|
+
def initialize(project_id, ticket_id, *options)
|
17
|
+
data = {:id => rand(1000), :status => ['lol', 'rofl', 'lmao', 'lamo', 'haha', 'heh'][rand(6)],
|
18
|
+
:priority => rand(10), :summary => 'Tickets ticket ticket ticket', :resolution => false,
|
19
|
+
:created_at => Time.now, :updated_at => Time.now, :description => 'Ticket ticket ticket ticket laughing',
|
20
|
+
:assignee => 'lol-man'}
|
21
|
+
@system = :dummy
|
22
|
+
super(data.merge(options.first || {}))
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
# This is the Dummy Provider
|
3
|
+
#
|
4
|
+
# It doesn't really do anything, it exists in order to test the basic functionality of taskmapper
|
5
|
+
# and to provide an example the basics of what is to be expected from the providers.
|
6
|
+
#
|
7
|
+
# Note that the initial provider name is a module rather than a class. TaskMapper.new
|
8
|
+
# extends on an instance-based fashion. If you would rather initialize using code that is
|
9
|
+
# closer to:
|
10
|
+
#
|
11
|
+
# TaskMapper::Provider::Dummy.new(authentication)
|
12
|
+
#
|
13
|
+
# You will have to do a little magic trick and define new on the provider as a wrapper
|
14
|
+
# around the TaskMapper.new call.
|
15
|
+
module Dummy
|
16
|
+
include TaskMapper::Provider::Base
|
17
|
+
# An example of what to do if you would like to do TaskMapper::Provider::Dummy.new(...)
|
18
|
+
# rather than TaskMapper.new(:dummy, ...)
|
19
|
+
def self.new(authentication = {})
|
20
|
+
TaskMapper.new(:dummy, authentication)
|
21
|
+
# maybe do some other stuff
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
%w| project ticket comment |.each do |f|
|
27
|
+
require File.dirname(__FILE__) + '/' + f +'.rb'
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Dummy
|
3
|
+
# This is the Project class for the Dummy provider
|
4
|
+
class Project < TaskMapper::Provider::Base::Project
|
5
|
+
|
6
|
+
def self.find_by_id(id)
|
7
|
+
self.new({:id => id})
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find_by_attributes(*options)
|
11
|
+
[self.new(*options)]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.create(*attributes)
|
15
|
+
self.new(*attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
# You should define @system and @system_data here.
|
19
|
+
# The data stuff is just to initialize fake data. In a real provider, you would use the API
|
20
|
+
# to grab the information and then initialize based on that info.
|
21
|
+
# @system_data would hold the API's model/instance for reference
|
22
|
+
def initialize(*options)
|
23
|
+
data = {:id => rand(1000).to_i, :name => 'Dummy', :description => 'Mock!-ing Bird',
|
24
|
+
:created_at => Time.now, :updated_at => Time.now}
|
25
|
+
@system = :dummy
|
26
|
+
super(data.merge(options.first || {}))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Nothing to save so we always return true
|
30
|
+
# ...unless it's an odd numbered second on Friday the 13th. muhaha!
|
31
|
+
def save
|
32
|
+
time = Time.now
|
33
|
+
!(time.wday == 5 and time.day == 13 and time.to_i % 2 == 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Nothing to update, so we always return true
|
37
|
+
def update!(*options)
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Dummy
|
3
|
+
# The Dummy Provider's Ticket class
|
4
|
+
class Ticket < TaskMapper::Provider::Base::Ticket
|
5
|
+
@system = :dummy
|
6
|
+
|
7
|
+
def self.find_by_id(project_id, ticket_id)
|
8
|
+
self.new(project_id, {:id => ticket_id})
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find_by_attributes(*ticket_attributes)
|
12
|
+
[self.new(*ticket_attributes)]
|
13
|
+
end
|
14
|
+
|
15
|
+
# You don't need to define an initializer, this is only here to initialize dummy data
|
16
|
+
def initialize(project_id, *options)
|
17
|
+
data = {:id => rand(1000), :status => ['lol', 'rofl', 'lmao', 'lamo', 'haha', 'heh'][rand(6)],
|
18
|
+
:priority => rand(10), :summary => 'Tickets ticket ticket ticket', :resolution => false,
|
19
|
+
:created_at => Time.now, :updated_at => Time.now, :description => 'Ticket ticket ticket ticket laughing',
|
20
|
+
:assignee => 'lol-man', :project_id => project_id}
|
21
|
+
@system = :dummy
|
22
|
+
super(data.merge(options.first || {}))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Nothing to save so we always return true
|
26
|
+
# ...unless it's the Ides of March and the second is divisible by three. muhaha!
|
27
|
+
def save
|
28
|
+
time = Time.now
|
29
|
+
!(time.wday == 15 and time.day == 3 and time.to_i % 3 == 0)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Nothing to close, so we always return true
|
33
|
+
def close
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
# Nothing to destroy so we always return true
|
38
|
+
def destroy
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
# Contains a series of helper methods
|
3
|
+
module Helper
|
4
|
+
|
5
|
+
# Current method name reflection
|
6
|
+
# http://www.ruby-forum.com/topic/75258#895630
|
7
|
+
# Call when raising 'implemented by the provider' exceptions
|
8
|
+
def this_method
|
9
|
+
caller[0][/`([^']*)'/, 1]
|
10
|
+
end
|
11
|
+
|
12
|
+
# A helper method for easy finding
|
13
|
+
def easy_finder(api, symbol, options, at_index = 0)
|
14
|
+
if api.is_a? Class
|
15
|
+
return api if options.length == 0 and symbol == :first
|
16
|
+
options.insert(at_index, symbol) if options[at_index].is_a?(Hash)
|
17
|
+
api.find(*options)
|
18
|
+
else
|
19
|
+
raise TaskMapper::Exception.new("#{Helper.name}::#{this_method} method must be implemented by the provider")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# This is a search filter that all parameters are passed through
|
24
|
+
# Redefine this method in your classes if you need specific functionality
|
25
|
+
def search_filter(k)
|
26
|
+
k
|
27
|
+
end
|
28
|
+
|
29
|
+
def provider_parent(klass)
|
30
|
+
TaskMapper::Provider.const_get(klass.to_s.split('::')[-2])
|
31
|
+
end
|
32
|
+
|
33
|
+
# Goes through all the things and returns results that match the options attributes hash
|
34
|
+
def search_by_attribute(things, options = {}, limit = 1000)
|
35
|
+
things.find_all do |thing|
|
36
|
+
options.inject(true) do |memo, kv|
|
37
|
+
break unless memo
|
38
|
+
key, value = kv
|
39
|
+
begin
|
40
|
+
memo &= thing.send(key) == value
|
41
|
+
rescue NoMethodError
|
42
|
+
memo = false
|
43
|
+
end
|
44
|
+
memo
|
45
|
+
end and (limit -= 1) > 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a filter-like string from a hash
|
50
|
+
# If array_join is given, arrays are joined rather than having their own separated key:values
|
51
|
+
#
|
52
|
+
# ex: filter_string({:name => 'some value', :tags => ['abc', 'def']}) = "name:'some value' tag:abc tag:def"
|
53
|
+
def filter_string(filter = {}, array_join = nil)
|
54
|
+
filter.inject('') do |mem, kv|
|
55
|
+
key, value = kv
|
56
|
+
if value.is_a?(Array)
|
57
|
+
if !array_join.nil?
|
58
|
+
mem += value.inject('') { |m, v|
|
59
|
+
v = "\"#{v}\"" if v.to_s.include?(' ')
|
60
|
+
m+= "#{key}:#{v}"
|
61
|
+
}
|
62
|
+
return mem
|
63
|
+
else
|
64
|
+
value = value.join(array_join)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
value = "\"#{value}\"" if value.to_s.include?(' ')
|
68
|
+
mem += "#{key}:#{value} "
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Base
|
3
|
+
# This is the base Project class for providers
|
4
|
+
#
|
5
|
+
# Providers should inherit this class and redefine the methods
|
6
|
+
#
|
7
|
+
# Each provider should have their own @system defined.
|
8
|
+
# For example, taskmapper-unfuddle's @system is :unfuddle and taskmapper-lighthouse's
|
9
|
+
# @system is :lighthouse.
|
10
|
+
#
|
11
|
+
# Methods that must be implemented by the provider
|
12
|
+
#
|
13
|
+
# * self.find_by_id
|
14
|
+
# * self.find_by_attributes
|
15
|
+
#
|
16
|
+
# Methods that might need to be implemented by the provider
|
17
|
+
# * tickets
|
18
|
+
# * ticket
|
19
|
+
# * initialize
|
20
|
+
# * update
|
21
|
+
# * destroy
|
22
|
+
# * self.create
|
23
|
+
#
|
24
|
+
# Methods that would probably be okay if the provider left it alone:
|
25
|
+
#
|
26
|
+
# * self.find - although you can define your own to optimize it a bit
|
27
|
+
# * update!
|
28
|
+
#
|
29
|
+
# A provider should define as many attributes as feasibly possible. The list below are
|
30
|
+
# some guidelines as to what attributes are necessary, if your provider's api does not
|
31
|
+
# implement them, point it to an attribute that is close to it. (for example, a name
|
32
|
+
# can point to title. Remember to alias it in your class!)
|
33
|
+
#
|
34
|
+
# * id
|
35
|
+
# * name
|
36
|
+
# * created_at
|
37
|
+
# * updated_at
|
38
|
+
# * description
|
39
|
+
class Project < Hashie::Mash
|
40
|
+
include TaskMapper::Provider::Common
|
41
|
+
include TaskMapper::Provider::Helper
|
42
|
+
extend TaskMapper::Provider::Helper
|
43
|
+
attr_accessor :system, :system_data
|
44
|
+
API = nil #Replace with your api digestor's class.
|
45
|
+
|
46
|
+
# Find project
|
47
|
+
# You can also retrieve an array of all projects by not specifying any query.
|
48
|
+
#
|
49
|
+
# * find() or find(:all) - Returns an array of all projects
|
50
|
+
# * find(##) - Returns a project based on that id or some other primary (unique) attribute
|
51
|
+
# * find([#, #, #]) - Returns many projects with these ids
|
52
|
+
# * find(:first, :name => 'Project name') - Returns the first project based on the project's attribute(s)
|
53
|
+
# * find(:last, :name => 'Some project') - Returns the last project based on the project's attribute(s)
|
54
|
+
# * find(:all, :name => 'Test Project') - Returns all projects based on the given attribute(s)
|
55
|
+
def self.find(*options)
|
56
|
+
first = options.shift
|
57
|
+
attributes = options.shift
|
58
|
+
if first.nil? or (first == :all and attributes.nil?)
|
59
|
+
self.find_by_attributes
|
60
|
+
elsif first.is_a? Array
|
61
|
+
first.collect { |id| self.find_by_id(id) }
|
62
|
+
elsif first == :first
|
63
|
+
projects = attributes.nil? ? self.find_by_attributes : self.find_by_attributes(attributes)
|
64
|
+
projects.first
|
65
|
+
elsif first == :last
|
66
|
+
projects = attributes.nil? ? self.find_by_attributes : self.find_by_attributes(attributes)
|
67
|
+
projects.last
|
68
|
+
elsif first == :all
|
69
|
+
self.find_by_attributes(attributes)
|
70
|
+
else
|
71
|
+
self.find_by_id(first)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# The first of whatever project
|
76
|
+
def self.first(*options)
|
77
|
+
self.find(:first, *options)
|
78
|
+
end
|
79
|
+
|
80
|
+
# The last of whatever project
|
81
|
+
def self.last(*options)
|
82
|
+
self.find(:last, *options)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Accepts an integer id and returns the single project instance
|
86
|
+
# Must be defined by the provider
|
87
|
+
def self.find_by_id(id)
|
88
|
+
if self::API.is_a? Class
|
89
|
+
self.new self::API.find(id)
|
90
|
+
else
|
91
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Accepts an attributes hash and returns all projects matching those attributes in an array
|
96
|
+
# Should return all projects if the attributes hash is empty
|
97
|
+
# Must be defined by the provider
|
98
|
+
def self.find_by_attributes(attributes = {})
|
99
|
+
if self::API.is_a? Class
|
100
|
+
self.search(attributes)
|
101
|
+
else
|
102
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# This is a helper method to find
|
107
|
+
def self.search(options = {}, limit = 1000)
|
108
|
+
if self::API.is_a? Class
|
109
|
+
projects = self::API.find(:all).collect { |project| self.new project }
|
110
|
+
search_by_attribute(projects, options, limit)
|
111
|
+
else
|
112
|
+
raise TaskMapper::Exception.new("#{self.name}::#{this_method} method must be implemented by the provider")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Asks the provider's api for the tickets associated with the project,
|
117
|
+
# returns an array of Ticket objects.
|
118
|
+
def tickets(*options)
|
119
|
+
options.insert 0, id
|
120
|
+
easy_finder(provider_parent(self.class)::Ticket, :all, options, 1)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Very similar to tickets, and is practically an alias of it
|
124
|
+
# however this returns the ticket class if no parameter is given
|
125
|
+
# unlike tickets which returns an array of all tickets when given no parameters
|
126
|
+
def ticket(*options)
|
127
|
+
options.insert(0, id) if options.length > 0
|
128
|
+
easy_finder(provider_parent(self.class)::Ticket, :first, options, 1)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Create a ticket
|
132
|
+
def ticket!(*options)
|
133
|
+
options[0].merge!(:project_id => id) if options.first.is_a?(Hash)
|
134
|
+
provider_parent(self.class)::Ticket.create(*options)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Define some provider specific initalizations
|
138
|
+
def initialize(*options)
|
139
|
+
# @system_data = {'some' => 'data}
|
140
|
+
super(*options)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|