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 ADDED
@@ -0,0 +1,7 @@
1
+ *.tar.gz
2
+ *.zip
3
+ .DS_Store
4
+ info
5
+ .rspec
6
+ .rvmrc
7
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem 'savon'
4
+ gem 'nokogiri'
5
+ gem 'activesupport'
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,3 @@
1
+ module XPlanner
2
+ VERSION = '0.0.1'
3
+ 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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ require 'rspec'
2
+ require File.expand_path('../../lib/xplanner', __FILE__)
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