xplanner 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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