xplanner 0.0.1
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/.gitignore +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +38 -0
- data/lib/config/savon_config.rb +57 -0
- data/lib/config/version.rb +3 -0
- data/lib/helpers/xplanner_model_helper.rb +51 -0
- data/lib/helpers/xplanner_soap_client.rb +21 -0
- data/lib/models/iteration.rb +91 -0
- data/lib/models/person.rb +64 -0
- data/lib/models/project.rb +52 -0
- data/lib/models/story.rb +88 -0
- data/lib/models/task.rb +87 -0
- data/lib/xplanner.rb +25 -0
- data/test/test_helper.rb +2 -0
- data/test/tests.rb +197 -0
- data/xplanner.gemspec +19 -0
- metadata +67 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.9)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
akami (1.2.0)
|
8
|
+
gyoku (>= 0.4.0)
|
9
|
+
nokogiri (>= 1.4.0)
|
10
|
+
builder (3.1.4)
|
11
|
+
gyoku (0.4.6)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
httpi (1.1.1)
|
14
|
+
rack
|
15
|
+
i18n (0.6.1)
|
16
|
+
multi_json (1.3.7)
|
17
|
+
nokogiri (1.5.5)
|
18
|
+
nori (1.1.3)
|
19
|
+
rack (1.4.1)
|
20
|
+
savon (1.2.0)
|
21
|
+
akami (~> 1.2.0)
|
22
|
+
builder (>= 2.1.2)
|
23
|
+
gyoku (~> 0.4.5)
|
24
|
+
httpi (~> 1.1.0)
|
25
|
+
nokogiri (>= 1.4.0)
|
26
|
+
nori (~> 1.1.0)
|
27
|
+
wasabi (~> 2.5.0)
|
28
|
+
wasabi (2.5.1)
|
29
|
+
httpi (~> 1.0)
|
30
|
+
nokogiri (>= 1.4.0)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
activesupport
|
37
|
+
nokogiri
|
38
|
+
savon
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'active_support/core_ext/hash/conversions'
|
4
|
+
require 'active_support/inflections'
|
5
|
+
|
6
|
+
# Reduce console noise.
|
7
|
+
Savon.configure do |config|
|
8
|
+
config.log = false
|
9
|
+
config.log_level = :errors
|
10
|
+
config.raise_errors = false # we'll handle our own errors
|
11
|
+
end
|
12
|
+
HTTPI.log = false
|
13
|
+
|
14
|
+
# Helper for decoding multi-ref style SOAP responses
|
15
|
+
module Savon
|
16
|
+
module SOAP
|
17
|
+
class Response
|
18
|
+
def decode_soap_response( path = [] )
|
19
|
+
hash = SoapResponseDecoder.decode( self.to_xml )
|
20
|
+
path.each { |p| hash = hash[p] }
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Decode multi-ref soap references.
|
28
|
+
class SoapResponseDecoder
|
29
|
+
def self.decode( xml_doc )
|
30
|
+
doc = Nokogiri::XML xml_doc
|
31
|
+
|
32
|
+
while( el = doc.xpath('//soapenv:Body//*[@href]').first )
|
33
|
+
id = el.attribute('href').value.gsub('#', '')
|
34
|
+
el.children = doc.xpath("//soapenv:Body//multiRef[@id='#{id}']").children()
|
35
|
+
el.remove_attribute('href')
|
36
|
+
end
|
37
|
+
|
38
|
+
hash = convert_hash_keys( Hash.from_xml( doc.to_s ) )[:envelope][:body]
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def self.underscore_key(k)
|
43
|
+
k.to_s.underscore.to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.convert_hash_keys(value)
|
47
|
+
case value
|
48
|
+
when Array
|
49
|
+
value.map { |v| convert_hash_keys(v) }
|
50
|
+
when Hash
|
51
|
+
Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] if k != 'xsi:type' }]
|
52
|
+
else
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class ModelHelper
|
3
|
+
@@soap_client = false
|
4
|
+
|
5
|
+
def self.set_soap_client( client )
|
6
|
+
@@soap_client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.invalid_usage
|
10
|
+
raise 'No SoapClient initialised'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.fetch_from_remote( rpc, payload, path, my_class )
|
14
|
+
invalid_usage unless @@soap_client
|
15
|
+
h = @@soap_client.call( rpc, payload ).decode_soap_response( path )
|
16
|
+
if h.class == Array
|
17
|
+
results = h.collect { |thing| my_class.new( thing ) }
|
18
|
+
elsif h.class == Hash
|
19
|
+
results = my_class.new( h )
|
20
|
+
end
|
21
|
+
results
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.remote_action( rpc, payload )
|
25
|
+
invalid_usage unless @@soap_client
|
26
|
+
@@soap_client.call( rpc, payload ).success?
|
27
|
+
end
|
28
|
+
|
29
|
+
def remote_action( rpc, payload )
|
30
|
+
invalid_usage unless @@soap_client
|
31
|
+
result = @@soap_client.call( rpc, payload )
|
32
|
+
result.success?
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parse_date( date )
|
36
|
+
formatter = '%Y-%m-%eT%H:%M:%S.%LZ'
|
37
|
+
DateTime.strptime( date, formatter )
|
38
|
+
end
|
39
|
+
|
40
|
+
def hashify
|
41
|
+
out = {}
|
42
|
+
instance_variables.each { |var| out[var.to_s.gsub(/@/, '').to_sym] = instance_variable_get(var) }
|
43
|
+
out
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_payload
|
47
|
+
payload = hashify.delete_if { |key, value| !key == :last_update_time }
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class SoapClient
|
3
|
+
def initialize( params )
|
4
|
+
@client = Savon.client do |wsdl, http|
|
5
|
+
wsdl.document = params[:wsdl]
|
6
|
+
http.auth.basic params[:username], params[:password]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_services
|
11
|
+
@client.wsdl.type_definitions
|
12
|
+
end
|
13
|
+
|
14
|
+
def call( rpc, payload=nil)
|
15
|
+
response = @client.request( rpc ) do
|
16
|
+
soap.body = payload unless payload.nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class Iteration < ModelHelper
|
3
|
+
attr_accessor :name,
|
4
|
+
:description,
|
5
|
+
:project_id,
|
6
|
+
:status_key,
|
7
|
+
:actual_hours,
|
8
|
+
:added_hours,
|
9
|
+
:adjusted_estimated_hours,
|
10
|
+
:days_worked,
|
11
|
+
:estimated_hours,
|
12
|
+
:overestimated_hours,
|
13
|
+
:postponed_hours,
|
14
|
+
:remaining_hours,
|
15
|
+
:start_date,
|
16
|
+
:end_date,
|
17
|
+
:underestimated_hours
|
18
|
+
|
19
|
+
attr_reader :id,
|
20
|
+
:last_update_time
|
21
|
+
|
22
|
+
|
23
|
+
def initialize( iter )
|
24
|
+
@id = iter[:id]
|
25
|
+
@name = iter[:name]
|
26
|
+
@description = iter[:description]
|
27
|
+
@project_id = iter[:project_id]
|
28
|
+
@status_key = iter[:status_key]
|
29
|
+
@actual_hours = iter[:actual_hours]
|
30
|
+
@added_hours = iter[:added_hours]
|
31
|
+
@adjusted_estimated_hours = iter[:adjusted_estimated_hours]
|
32
|
+
@days_worked = iter[:days_worked]
|
33
|
+
@estimated_hours = iter[:estimated_hours]
|
34
|
+
@overestimated_hours = iter[:overestimated_hours]
|
35
|
+
@postponed_hours = iter[:postponed_hours]
|
36
|
+
@remaining_hours = iter[:remaining_hours]
|
37
|
+
@start_date = Iteration.parse_date iter[:start_date]
|
38
|
+
@end_date = Iteration.parse_date iter[:end_date]
|
39
|
+
@last_update_time = Iteration.parse_date iter[:last_update_time]
|
40
|
+
@underestimated_hours = iter[:underestimated_hours]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.all( project_id )
|
44
|
+
rpc = :get_iterations
|
45
|
+
payload = { :projectId => project_id }
|
46
|
+
path = [:get_iterations_response, :get_iterations_return, :get_iterations_return]
|
47
|
+
fetch_from_remote( rpc, payload, path, Iteration )
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.retrieve( iteration_id )
|
51
|
+
rpc = :get_iteration
|
52
|
+
payload = { :iterationId => iteration_id }
|
53
|
+
path = [:get_iteration_response, :get_iteration_return]
|
54
|
+
fetch_from_remote( rpc, payload, path, Iteration )
|
55
|
+
end
|
56
|
+
|
57
|
+
# needs status setting
|
58
|
+
def self.create( project_id, name, description, start_date, end_date )
|
59
|
+
rpc = :add_iteration
|
60
|
+
payload = {
|
61
|
+
:iterationData => {
|
62
|
+
:project_id => project_id,
|
63
|
+
:name => name,
|
64
|
+
:description => description,
|
65
|
+
:start_date => start_date,
|
66
|
+
:end_date => end_date,
|
67
|
+
:status_key => 'inactive'
|
68
|
+
}
|
69
|
+
}
|
70
|
+
path = [:add_iteration_response, :add_iteration_return]
|
71
|
+
fetch_from_remote( rpc, payload, path, Iteration )
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.delete( id )
|
75
|
+
rpc = :remove_iteration
|
76
|
+
payload = { :id => id }
|
77
|
+
remote_action( rpc, payload )
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete
|
81
|
+
Iteration.delete( @id )
|
82
|
+
end
|
83
|
+
|
84
|
+
def save
|
85
|
+
rpc = :update
|
86
|
+
payload = { :iterationData => create_payload }
|
87
|
+
remote_action( rpc, payload )
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class Person < ModelHelper
|
3
|
+
attr_accessor :name,
|
4
|
+
:email,
|
5
|
+
:initials,
|
6
|
+
:phone,
|
7
|
+
:user_id
|
8
|
+
|
9
|
+
attr_reader :id,
|
10
|
+
:last_update_time
|
11
|
+
|
12
|
+
def initialize( p )
|
13
|
+
@id = p[:id]
|
14
|
+
@name = p[:name]
|
15
|
+
@last_update_time = Person.parse_date p[:last_update_time]
|
16
|
+
@initials = p[:initials]
|
17
|
+
@phone = p[:phone]
|
18
|
+
@user_id = p[:user_id]
|
19
|
+
@email = p[:email]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.all
|
23
|
+
rpc = :get_people
|
24
|
+
path = [:get_people_response, :get_people_return, :get_people_return]
|
25
|
+
fetch_from_remote( rpc, payload, path, Person )
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.retrieve( id )
|
29
|
+
rpc = :get_person
|
30
|
+
payload = { :id => id }
|
31
|
+
path = [:get_person_response, :get_person_return]
|
32
|
+
fetch_from_remote( rpc, payload, path, Person )
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.create( name, email, user_id, initials = '', phone = '' )
|
36
|
+
rpc = :add_person
|
37
|
+
payload = { :personData => {
|
38
|
+
:name => name,
|
39
|
+
:email => email,
|
40
|
+
:user_id => user_id,
|
41
|
+
:initials => initials,
|
42
|
+
:phone => phone
|
43
|
+
} }
|
44
|
+
path = [:add_person_response, :add_person_return]
|
45
|
+
fetch_from_remote( rpc, payload, path, Person )
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.delete( id )
|
49
|
+
rpc = :remove_person
|
50
|
+
payload = { :id => id }
|
51
|
+
remote_action( rpc, payload )
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete
|
55
|
+
Person.delete @id
|
56
|
+
end
|
57
|
+
|
58
|
+
def save
|
59
|
+
rpc = :update
|
60
|
+
payload = { :personData => create_payload }
|
61
|
+
remote_action( rpc, payload )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class Project < ModelHelper
|
3
|
+
attr_accessor :name,
|
4
|
+
:description
|
5
|
+
|
6
|
+
attr_reader :id,
|
7
|
+
:last_update_time
|
8
|
+
|
9
|
+
def initialize( p )
|
10
|
+
@id = p[:id]
|
11
|
+
@name = p[:name]
|
12
|
+
@last_update_time = Project.parse_date p[:last_update_time]
|
13
|
+
@description = p[:description]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all
|
17
|
+
rpc = :get_projects
|
18
|
+
path = [:get_projects_response, :get_projects_return, :get_projects_return]
|
19
|
+
fetch_from_remote( rpc, payload, path, Project )
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.retrieve( id )
|
23
|
+
rpc = :get_project
|
24
|
+
payload = { :id => id }
|
25
|
+
path = [:get_project_response, :get_project_return]
|
26
|
+
fetch_from_remote( rpc, payload, path, Project )
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create( name, description )
|
30
|
+
rpc = :add_project
|
31
|
+
payload = { :projectData => { :name => name, :description => description } }
|
32
|
+
path = [:add_project_response, :add_project_return]
|
33
|
+
fetch_from_remote( rpc, payload, path, Project )
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.delete( id )
|
37
|
+
rpc = :remove_project
|
38
|
+
payload = { :id => id }
|
39
|
+
remote_action( rpc, payload )
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete
|
43
|
+
Project.delete @id
|
44
|
+
end
|
45
|
+
|
46
|
+
def save
|
47
|
+
rpc = :update
|
48
|
+
payload = { :projectData => create_payload }
|
49
|
+
remote_action( rpc, payload )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/models/story.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class Story < ModelHelper
|
3
|
+
|
4
|
+
attr_accessor :actual_hours,
|
5
|
+
:adjusted_estimated_hours,
|
6
|
+
:completed,
|
7
|
+
:customer_id,
|
8
|
+
:description,
|
9
|
+
:disposition_name,
|
10
|
+
:estimated_hours,
|
11
|
+
:estimated_original_hours,
|
12
|
+
:iteration_id,
|
13
|
+
:last_update_time,
|
14
|
+
:name,
|
15
|
+
:postponed_hours,
|
16
|
+
:priority,
|
17
|
+
:remaining_hours,
|
18
|
+
:tracker_id
|
19
|
+
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
|
23
|
+
def initialize( story )
|
24
|
+
@actual_hours = story[:actual_hours]
|
25
|
+
@adjusted_estimated_hours = story[:adjusted_estimated_hours]
|
26
|
+
@completed = story[:completed]
|
27
|
+
@customer_id = story[:customer_id]
|
28
|
+
@description = story[:description]
|
29
|
+
@disposition_name = story[:disposition_name]
|
30
|
+
@estimated_hours = story[:estimated_hours]
|
31
|
+
@estimated_original_hours = story[:estimated_original_hours]
|
32
|
+
@id = story[:id]
|
33
|
+
@iteration_id = story[:iteration_id]
|
34
|
+
@last_update_time = Story.parse_date story[:last_update_time]
|
35
|
+
@name = story[:name]
|
36
|
+
@postponed_hours = story[:postponed_hours]
|
37
|
+
@priority = story[:priority]
|
38
|
+
@remaining_hours = story[:remaining_hours]
|
39
|
+
@tracker_id = story[:tracker_id]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.all( iteration_id )
|
43
|
+
rpc = :get_user_stories
|
44
|
+
payload = { :containerId => iteration_id }
|
45
|
+
path = [:get_user_stories_response, :get_user_stories_return, :get_user_stories_return]
|
46
|
+
fetch_from_remote( rpc, payload, path, Story )
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.retrieve( story_id )
|
50
|
+
rpc = :get_user_story
|
51
|
+
payload = { :userStoryId => story_id }
|
52
|
+
path = [:get_user_story_response, :get_user_story_return]
|
53
|
+
fetch_from_remote( rpc, payload, path, Story )
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.create( iteration_id, name, description, disposition = 'planned', completed = 'false', priority = '4' )
|
57
|
+
rpc = :add_user_story
|
58
|
+
payload = { :userStoryData =>{
|
59
|
+
:iteration_id =>iteration_id,
|
60
|
+
:name => name,
|
61
|
+
:description => description,
|
62
|
+
:disposition_name => disposition,
|
63
|
+
:completed => completed,
|
64
|
+
:priority => priority
|
65
|
+
}
|
66
|
+
}
|
67
|
+
path = [:add_user_story_response, :add_user_story_return]
|
68
|
+
fetch_from_remote( rpc, payload, path, Story )
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.delete( id )
|
72
|
+
rpc = :remove_user_story
|
73
|
+
payload = { :id => id }
|
74
|
+
remote_action( rpc, payload )
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete
|
78
|
+
Story.delete( @id )
|
79
|
+
end
|
80
|
+
|
81
|
+
def save
|
82
|
+
rpc = :update
|
83
|
+
payload = { :userStoryData => create_payload }
|
84
|
+
remote_action( rpc, payload )
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/lib/models/task.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module XPlanner
|
2
|
+
class Task < ModelHelper
|
3
|
+
|
4
|
+
attr_accessor :acceptor_id,
|
5
|
+
:actual_hours,
|
6
|
+
:adjusted_estimated_hours,
|
7
|
+
:completed,
|
8
|
+
:created_date,
|
9
|
+
:description,
|
10
|
+
:disposition_name,
|
11
|
+
:estimated_hours,
|
12
|
+
:estimated_original_hours,
|
13
|
+
:last_update_time,
|
14
|
+
:name,
|
15
|
+
:remaining_hours,
|
16
|
+
:story_id,
|
17
|
+
:type
|
18
|
+
|
19
|
+
attr_reader :id
|
20
|
+
|
21
|
+
|
22
|
+
def initialize( task )
|
23
|
+
@acceptor_id = task[:acceptor_id]
|
24
|
+
@actual_hours = task[:actual_hours]
|
25
|
+
@adjusted_estimated_hours = task[:adjusted_estimated_hours]
|
26
|
+
@completed = task[:completed]
|
27
|
+
@created_date = Task.parse_date task[:created_date]
|
28
|
+
@description = task[:description]
|
29
|
+
@disposition_name = task[:disposition_name]
|
30
|
+
@estimated_hours = task[:estimated_hours]
|
31
|
+
@estimated_original_hours = task[:estimated_original_hours]
|
32
|
+
@last_update_time = task[:last_update_time]
|
33
|
+
@name = task[:name]
|
34
|
+
@remaining_hours = task[:remaining_hours]
|
35
|
+
@story_id = task[:story_id]
|
36
|
+
@type = task[:type]
|
37
|
+
@id = task[:id]
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.all( story_id )
|
41
|
+
rpc = :get_tasks
|
42
|
+
payload = { :containerId => story_id }
|
43
|
+
path = [:get_taskss_response, :get_tasks_return, :get_tasks_return]
|
44
|
+
fetch_from_remote( rpc, payload, path, Task )
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.retrieve( task_id )
|
48
|
+
rpc = :get_task
|
49
|
+
payload = { :taskId => task_id }
|
50
|
+
path = [:get_task_response, :get_task_return]
|
51
|
+
fetch_from_remote( rpc, payload, path, Task )
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.create( story_id, name, description, disposition = 'planned', completed = 'false', type = 'Feature' )
|
55
|
+
rpc = :add_task
|
56
|
+
payload = { :taskData => {
|
57
|
+
:story_id => story_id,
|
58
|
+
:name => name,
|
59
|
+
:description => description,
|
60
|
+
:disposition_name => disposition,
|
61
|
+
:completed => completed,
|
62
|
+
:type => type,
|
63
|
+
:created_date => DateTime.now
|
64
|
+
}
|
65
|
+
}
|
66
|
+
path = [:add_task_response, :add_task_return]
|
67
|
+
fetch_from_remote( rpc, payload, path, Task )
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.delete( id )
|
71
|
+
rpc = :remove_task
|
72
|
+
payload = { :id => id }
|
73
|
+
remote_action( rpc, payload )
|
74
|
+
end
|
75
|
+
|
76
|
+
def delete
|
77
|
+
Task.delete( @id )
|
78
|
+
end
|
79
|
+
|
80
|
+
def save
|
81
|
+
rpc = :update
|
82
|
+
payload = { :taskData => create_payload }
|
83
|
+
remote_action( rpc, payload )
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
data/lib/xplanner.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
project_root = File.expand_path('../', __FILE__)
|
2
|
+
project_dirs = ['config', 'helpers', 'models']
|
3
|
+
|
4
|
+
project_dirs.each do |d|
|
5
|
+
Dir.glob(project_root + '/' + d + '/*.rb') {|file| require file}
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module XPlanner
|
11
|
+
def self.setup( config = {} )
|
12
|
+
url = config[:xplanner_url] ||= @@default_config[:xplanner_url]
|
13
|
+
wsdl = URI::join(url, 'soap/XPlanner?wsdl').to_s
|
14
|
+
user = config[:username] ||= @@default_config[:username]
|
15
|
+
pass = config[:password] ||= @@default_config[:password]
|
16
|
+
|
17
|
+
client_config = {
|
18
|
+
:wsdl => wsdl,
|
19
|
+
:username => user,
|
20
|
+
:password => pass
|
21
|
+
}
|
22
|
+
|
23
|
+
ModelHelper.set_soap_client SoapClient.new( client_config )
|
24
|
+
end
|
25
|
+
end
|
data/test/test_helper.rb
ADDED
data/test/tests.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
XPlanner::setup
|
3
|
+
|
4
|
+
describe 'XPlanner+ SOAP interface' do
|
5
|
+
describe 'Model: Project' do
|
6
|
+
before(:all) do
|
7
|
+
@myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'Create' do
|
11
|
+
@myProject.should be_an_instance_of XPlanner::Project
|
12
|
+
@myProject.id.should_not be_nil
|
13
|
+
@myProject.id.should_not eq( 0 )
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'Retrieve' do
|
17
|
+
this_project = XPlanner::Project.retrieve( @myProject.id )
|
18
|
+
this_project.should be_instance_of XPlanner::Project
|
19
|
+
this_project.id.should eq( @myProject.id )
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'Update' do
|
23
|
+
@myProject.description += ' O_o '
|
24
|
+
result = @myProject.save
|
25
|
+
result.should equal true
|
26
|
+
this_project = XPlanner::Project.retrieve( @myProject.id )
|
27
|
+
this_project.description.should include ' O_o '
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'Delete' do
|
31
|
+
result = @myProject.delete
|
32
|
+
result.should equal true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'Model: Iteration' do
|
37
|
+
before(:all) do
|
38
|
+
@myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
|
39
|
+
@myIteration = XPlanner::Iteration.create( @myProject.id,
|
40
|
+
'delete me',
|
41
|
+
'delete me: test iteration',
|
42
|
+
DateTime.now,
|
43
|
+
DateTime.now+5 )
|
44
|
+
end
|
45
|
+
|
46
|
+
after(:all) do
|
47
|
+
@myProject.delete
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'Create' do
|
51
|
+
@myIteration.should be_an_instance_of XPlanner::Iteration
|
52
|
+
@myIteration.id.should_not be_nil
|
53
|
+
@myIteration.id.should_not eq( 0 )
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'Retrieve' do
|
57
|
+
this_iteration = XPlanner::Iteration.retrieve( @myIteration.id )
|
58
|
+
this_iteration.should be_instance_of XPlanner::Iteration
|
59
|
+
this_iteration.id.should eq( @myIteration.id )
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'Update' do
|
63
|
+
@myIteration.description += ' O_o '
|
64
|
+
result = @myIteration.save
|
65
|
+
result.should equal true
|
66
|
+
this_iteration = XPlanner::Iteration.retrieve( @myIteration.id )
|
67
|
+
this_iteration.description.should include ' O_o '
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'Delete' do
|
71
|
+
result = @myIteration.delete
|
72
|
+
result.should equal true
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'Model: User Story' do
|
78
|
+
before(:all) do
|
79
|
+
@myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
|
80
|
+
@myIteration = XPlanner::Iteration.create( @myProject.id,
|
81
|
+
'delete me',
|
82
|
+
'delete me: test iteration',
|
83
|
+
DateTime.now,
|
84
|
+
DateTime.now+5 )
|
85
|
+
@myStory = XPlanner::Story.create( @myIteration.id, 'delete me', 'delete me: test story')
|
86
|
+
end
|
87
|
+
|
88
|
+
after(:all) do
|
89
|
+
@myIteration.delete
|
90
|
+
@myProject.delete
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'Create' do
|
94
|
+
@myStory.should be_an_instance_of XPlanner::Story
|
95
|
+
@myStory.id.should_not be_nil
|
96
|
+
@myStory.id.should_not eq( 0 )
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'Retrieve' do
|
100
|
+
this_story = XPlanner::Story.retrieve( @myStory.id )
|
101
|
+
this_story.should be_instance_of XPlanner::Story
|
102
|
+
this_story.id.should eq( @myStory.id )
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'Update' do
|
106
|
+
@myStory.description += ' O_o '
|
107
|
+
result = @myStory.save
|
108
|
+
result.should equal true
|
109
|
+
this_story = XPlanner::Story.retrieve( @myStory.id )
|
110
|
+
this_story.description.should include ' O_o '
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'Delete' do
|
114
|
+
result = @myStory.delete
|
115
|
+
result.should equal true
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
describe 'Model: Task' do
|
122
|
+
before(:all) do
|
123
|
+
@myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
|
124
|
+
@myIteration = XPlanner::Iteration.create( @myProject.id,
|
125
|
+
'delete me',
|
126
|
+
'delete me: test iteration',
|
127
|
+
DateTime.now,
|
128
|
+
DateTime.now+5 )
|
129
|
+
@myStory = XPlanner::Story.create( @myIteration.id, 'delete me', 'delete me: test story')
|
130
|
+
@myTask = XPlanner::Task.create( @myStory.id, 'delete me', 'delete me: test task')
|
131
|
+
end
|
132
|
+
|
133
|
+
after(:all) do
|
134
|
+
@myStory.delete
|
135
|
+
@myIteration.delete
|
136
|
+
@myProject.delete
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'Create' do
|
140
|
+
@myTask.should be_an_instance_of XPlanner::Task
|
141
|
+
@myTask.id.should_not be_nil
|
142
|
+
@myTask.id.should_not eq( 0 )
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'Retrieve' do
|
146
|
+
this_task = XPlanner::Task.retrieve( @myTask.id )
|
147
|
+
this_task.should be_instance_of XPlanner::Task
|
148
|
+
this_task.id.should eq( @myTask.id )
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'Update' do
|
152
|
+
@myTask.description += ' O_o '
|
153
|
+
result = @myTask.save
|
154
|
+
result.should equal true
|
155
|
+
this_task = XPlanner::Task.retrieve( @myTask.id )
|
156
|
+
this_task.description.should include ' O_o '
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'Delete' do
|
160
|
+
result = @myTask.delete
|
161
|
+
result.should equal true
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
describe 'Model: Person' do
|
167
|
+
before(:all) do
|
168
|
+
@myPerson = XPlanner::Person.create( 'delete me', 'delete@me.com', 'delete_me' )
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'Create' do
|
172
|
+
@myPerson.should be_an_instance_of XPlanner::Person
|
173
|
+
@myPerson.id.should_not be_nil
|
174
|
+
@myPerson.id.should_not eq( 0 )
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'Retrieve' do
|
178
|
+
this_person = XPlanner::Person.retrieve( @myPerson.id )
|
179
|
+
this_person.should be_instance_of XPlanner::Person
|
180
|
+
this_person.id.should eq( @myPerson.id )
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'Update' do
|
184
|
+
@myPerson.user_id += ' O_o '
|
185
|
+
result = @myPerson.save
|
186
|
+
result.should equal true
|
187
|
+
this_person = XPlanner::Person.retrieve( @myPerson.id )
|
188
|
+
this_person.user_id.should include ' O_o '
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'Delete' do
|
192
|
+
result = @myPerson.delete
|
193
|
+
result.should equal true
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
data/xplanner.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'config/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "xplanner"
|
8
|
+
gem.version = XPlanner::VERSION
|
9
|
+
gem.authors = ["whoojemaflip"]
|
10
|
+
gem.email = ["whoojemaflip@gmail.com"]
|
11
|
+
gem.description = %q{Ruby wrapper for XPlanner+ SOAP interface}
|
12
|
+
gem.summary = %q{Ruby wrapper for XPlanner+ SOAP interface}
|
13
|
+
gem.homepage = "http://github.com/whoojemaflip/xplanner"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xplanner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- whoojemaflip
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-20 00:00:00.000000000 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
description: Ruby wrapper for XPlanner+ SOAP interface
|
16
|
+
email:
|
17
|
+
- whoojemaflip@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- .rspec
|
24
|
+
- .rvmrc
|
25
|
+
- Gemfile
|
26
|
+
- Gemfile.lock
|
27
|
+
- lib/config/savon_config.rb
|
28
|
+
- lib/config/version.rb
|
29
|
+
- lib/helpers/xplanner_model_helper.rb
|
30
|
+
- lib/helpers/xplanner_soap_client.rb
|
31
|
+
- lib/models/iteration.rb
|
32
|
+
- lib/models/person.rb
|
33
|
+
- lib/models/project.rb
|
34
|
+
- lib/models/story.rb
|
35
|
+
- lib/models/task.rb
|
36
|
+
- lib/xplanner.rb
|
37
|
+
- test/test_helper.rb
|
38
|
+
- test/tests.rb
|
39
|
+
- xplanner.gemspec
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/whoojemaflip/xplanner
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.6.2
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Ruby wrapper for XPlanner+ SOAP interface
|
65
|
+
test_files:
|
66
|
+
- test/test_helper.rb
|
67
|
+
- test/tests.rb
|