rally_rest_api 0.6.13 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -9,6 +9,7 @@ lib/rally_rest_api/rest_builder.rb
9
9
  lib/rally_rest_api/timeout_catching_rest_builder.rb
10
10
  lib/rally_rest_api/rest_object.rb
11
11
  lib/rally_rest_api/typedef.rb
12
+ lib/rally_rest_api/ruport.rb
12
13
  lib/rally_rest_api/version.rb
13
14
  Manifest.txt
14
15
  Rakefile
@@ -23,5 +24,3 @@ test/rest_object_spec.rb
23
24
  test/tc_rest_query.rb
24
25
  test/test_helper.rb
25
26
  test/rest_builder_spec.rb
26
- lib/rally_rest_api/timeout_catching_rest_builder.rb
27
-
data/README.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  rally-rest-api -- A Ruby-ized interface to Rally's REST webservice API
2
2
 
3
3
  ==Introduction:
4
- Rally Software Development's on-demand agile software life-cycle management services offers webservices API's for its customers. The API comes in both SOAP and REST style interfaces. This library is for accessing the REST API using Ruby. For more information about Rally's webservice APIs see https://rally1.rallydev.com/slm/doc/webservice/index.jsp.
4
+ Rally Software Development's on-demand agile software life-cycle management service offers webservices API's for its customers. The API comes in both SOAP and REST style interfaces. This library is for accessing the REST API using Ruby. For more information about Rally's webservice APIs see https://rally1.rallydev.com/slm/doc/webservice/index.jsp.
5
5
 
6
6
  This API provides full access to all CRUD operations and a rich interface to the query facility. An Enumerable interface is provided for the paginated query results.
7
7
 
@@ -16,13 +16,20 @@ RallyRestAPI is the entry point to the api. Each instance corresponds to one use
16
16
  :password => Your Rally login password. Username and password will be remembered by this
17
17
  instance of the API and all objects created and read by this instance.
18
18
  :base_url => The base url for the system you are talking to. Defaults to https://rally1.rallydev.com/slm/
19
- :raise_on_warning => true|false or the exception class you would like raised. If true, RuntimeError will be raised.
20
19
  :logger => A logger to log to. There is interesting logging info for DEBUG and INFO
20
+ :builder => A builder is the Class responsible for the HTTP level protocol. Defaults to RestBuilder
21
+ :version => The version of the API you want to talk to. Defaults to "current"
21
22
 
22
23
  == Rest Object:
23
- All rally resources referenced by the api are of type RestObject, there are no subclasses. In its initial form a RestObject is just a URL representing a resource. This URL is accessed using RestObject#ref. When more information is requested about the object, the API will read the content of that resource. This read is done lazily and transparently.
24
+ All rally resources referenced by the api are of type RestObject, there only a few subclasses. In its initial form a RestObject is just a URL representing a resource. This URL is accessed using RestObject#ref. When more information is requested about the object, the API will read the content of that resource. This read is done lazily and transparently.
24
25
 
25
- Objects can reference other objects in Rally. When establishing these relationships using this API, they are done using RestObjects. For example, to associate a user story to a defect, you would use the 'requirement' association on defect to reference the User Story. Here 'defect' and 'user_story' already exist, and the variables contain RestObjects representing them:
26
+ RestObject makes heavy use of method_missing to achieve its dynamism. The XML for each resource is parsed into a nested Hash where the keys of the Hash are the Ruby-ized Elements names of the XML, and the values of the hash are the string values of the elements, or other RestObjects (in the case of references between objects), or collections of both. This allows the API to respond to chained method invocations like:
27
+
28
+ rally.user.subscription.workspaces.first.projects.first.iterations.first.name
29
+
30
+ Traversals across object references (RestObjects) cause a lazy read of that resource.
31
+
32
+ When establishing object relationships between objects, during create or update, they are done using RestObjects. For example, to associate a user story to a defect, you would use the 'requirement' association on defect to reference the User Story. Here 'defect' and 'user_story' already exist, and the variables contain RestObjects representing them:
26
33
 
27
34
  defect.update(:requirement => user_story)
28
35
 
@@ -92,10 +99,15 @@ RallyRestAPI#find is the interface to the query syntax of Rally's webservice API
92
99
  In addition to the type, #find accepts other arguments as a hash:
93
100
 
94
101
  :pagesize => <number> - The number of results per page. Max of 100
95
- :start => <number> - The record number to start with. Assuming more then page size records.
96
- :fetch => <boolean> - If this is set to true then entire objects will be returned inside the query result. If set to false (the default) then only object references will be returned.
97
- :workspace - If not present, then the query will run in the user's default workspace. If present, this should be the RestObject containing the workspace the user wants to search in.
98
- :project - If not set, or specified as "null" then the "parent project" in the given workspace is used. If set, this should be the RestObject containing the project. Furthermore, if set you may omit the workspace parameter because the workspace will be inherited from the project.
102
+ :start => <number> - The record number to start with. Assuming more than page size records.
103
+ :fetch => <boolean> - If this is set to true then entire objects will be returned inside the query
104
+ result. If set to false (the default) then only object references will be returned. Fetching full
105
+ objects will prevent another read when utilizing the results.
106
+ :workspace - If not present, then the query will run in the user's default workspace. If present,
107
+ this should be the RestObject containing the workspace the user wants to search in.
108
+ :project - If not set, or specified as "null" then the "parent project" in the given workspace is used.
109
+ If set, this should be the RestObject containing the project. Furthermore, if set you may omit the workspace
110
+ parameter because the workspace will be inherited from the project.
99
111
  :project_scope_up - Default is true. In addition to the specified project, include projects above the specified one.
100
112
  :project_scope_down - Default is true. In addition to the specified project, include child projects below the current one.
101
113
 
@@ -108,4 +120,12 @@ The return from #find is always a QueryResult. The QueryResult provides an inter
108
120
 
109
121
  Because of the paginated nature of the result list, deleting elements while using #each is undefined.
110
122
 
123
+ If you have Ruport installed (http://www.rubyreports.org), QueryResult will have a #to_table method included. #to_table takes an array of symbols that define the columns in the table:
124
+
125
+ defects = rally.find(:defect, :fetch => true) { equal :state, "Open }
126
+ table = defects.to_table([:name, :severity, :priority, :owner])
127
+ table.to_pdf
128
+
129
+ See rubyreports.org for more information about creating reports with Ruport.
130
+
111
131
  See the rdoc for RestQuery for more query examples.
@@ -1 +1,7 @@
1
- Dir[File.join(File.dirname(__FILE__), 'rally_rest_api/**/*.rb')].sort.each { |lib| require lib }
1
+ Dir[File.join(File.dirname(__FILE__), 'rally_rest_api/**/*.rb')].sort.each { |lib| require lib }
2
+ begin
3
+ require 'rubygems'
4
+ require 'ruport'
5
+ require 'rally_rest_api/ruport'
6
+ rescue LoadError
7
+ end
@@ -8,27 +8,27 @@ class String # :nodoc: all
8
8
  alias :to_q :to_s
9
9
  end
10
10
 
11
- class Fixnum
11
+ class Fixnum # :nodoc: all
12
12
  alias :to_q :to_s
13
13
  end
14
14
 
15
15
  class Symbol # :nodoc: all
16
- def to_q
17
- self.to_s.to_camel
18
- end
16
+ def to_q
17
+ self.to_s.to_camel
18
+ end
19
19
  end
20
20
 
21
- class NilClass
21
+ class NilClass # :nodoc: all
22
22
  def to_q
23
23
  "null"
24
24
  end
25
25
  end
26
26
 
27
- class TrueClass
27
+ class TrueClass # :nodoc: all
28
28
  alias :to_q :to_s
29
29
  end
30
30
 
31
- class FalseClass
31
+ class FalseClass # :nodoc: all
32
32
  alias :to_q :to_s
33
33
  end
34
34
 
@@ -81,6 +81,8 @@ end
81
81
  # \_or_ works in the same fashion. _and_s and _or_s may be nested as needed. See the test cases for RestQuery for
82
82
  # more complex examples
83
83
  #
84
+ # If you have ruport installed, you may also call to_table on a QueryResult to convert the result to a Ruport::Data:Table
85
+ #
84
86
  class RestQuery
85
87
  attr_reader :type
86
88
 
@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/rest_object'
4
4
  #
5
5
  # QueryResult is a wrapper around the xml returned from a webservice
6
6
  # query operation. A query could result in a large number of hits
7
- # being returned, therefore the query result is paged into page_size
7
+ # being returned, therefore the results are paged into page_size
8
8
  # chunks (20 by default). QueryResult will seamlessly deal with the
9
9
  # paging when using the #each iterator.
10
10
  #
@@ -76,7 +76,7 @@ class QueryResult < RestObject
76
76
  end
77
77
 
78
78
  protected
79
- def parse_collections_as_hash?
79
+ def parse_collections_as_hash? # :nodoc:
80
80
  false
81
81
  end
82
82
 
@@ -85,7 +85,7 @@ class QueryResult < RestObject
85
85
  !element.attributes["ref"].nil?
86
86
  end
87
87
 
88
- def terminal?(node)
88
+ def terminal?(node) # :nodoc:
89
89
  !node.has_elements? || ref?(node)
90
90
  end
91
91
 
@@ -8,7 +8,7 @@ require 'ostruct'
8
8
  #
9
9
  class RallyRestAPI
10
10
 
11
- attr_reader :username, :password, :base_url, :raise_on_warning, :logger, :builder
11
+ attr_reader :username, :password, :base_url, :logger, :builder
12
12
  attr_accessor :parse_collections_as_hash
13
13
 
14
14
  ALLOWED_TYPES = %w[subscription workspace project iteration release defect defect_suite test_case
@@ -21,7 +21,8 @@ class RallyRestAPI
21
21
  # * username - The Rally username
22
22
  # * password - The password for the named user
23
23
  # * base_url - The base url of the system. Defaults to https://rally1.rallydev.com/slm
24
- # * raise_on_warn - true|false|Exception Class. If you want exceptions raised on warnings. Default is false. if 'true' RuntimeException will be raised. If ExceptionClass, then an instance of that will be raised.
24
+ # * version - The RallyWebservices Version. Defaults to 'current', which will always be the most
25
+ # recent version of the api. Pass the value as a String, "1.0", "1.01" for example.
25
26
  # * logger - a Logger to log to.
26
27
  #
27
28
  def initialize(options = {})
@@ -32,30 +33,34 @@ class RallyRestAPI
32
33
  @username = options[:username]
33
34
  @password = options[:password]
34
35
  @base_url = options[:base_url] || "https://rally1.rallydev.com/slm"
35
- @raise_on_warning = options[:raise_on_warning]
36
+ @version = options[:version] || "current"
36
37
  @logger = options[:logger]
37
38
  @parse_collections_as_hash = options[:parse_collections_as_hash] || false
38
39
 
39
40
  if options[:builder]
40
41
  builder = options[:builder]
41
42
  else
42
- builder = RestBuilder.new(@base_url, @username, @password)
43
+ builder = RestBuilder.new(@base_url, @username, @password, @version)
43
44
  end
44
45
  builder.logger = @logger if @logger
45
46
  @builder = builder
46
47
  end
47
48
 
49
+ def marshal_dump
50
+ [@username, @password, @base_url, @version, @builder, @parse_collections_as_hash]
51
+ end
52
+
53
+ def marshal_load(stuff)
54
+ @username, @password, @base_url, @version, @builder, @parse_collections_as_hash = *stuff
55
+ end
56
+
57
+
48
58
  # return an instance of User, for the currently logged in user.
49
59
  def user
50
- RestObject.new(self, builder.read_rest("#{@base_url}/webservice/1.0/user", @username, @password))
60
+ RestObject.new(self, builder.read_rest("#{@base_url}/webservice/#{@version}/user", @username, @password))
51
61
  end
52
62
  alias :start :user # :nodoc:
53
63
 
54
- # This is deprecated, use create instead
55
- def method_missing(type, args, &block) # :nodoc:
56
- raise "'#{type}' is not a supported method. Use create() instead"
57
- end
58
-
59
64
  # Create an object.
60
65
  # type - The type to create, as a symbol (e.g. :test_case)
61
66
  # values - The attributes of the new object.
@@ -82,7 +87,7 @@ class RallyRestAPI
82
87
  query(query)
83
88
  end
84
89
 
85
- # find all object of a given type. Base types work also (.e.g :artifact)
90
+ # find all object of a given type. Base types work also (e.g. :artifact)
86
91
  def find_all(type, args = {})
87
92
  find(type, args) { gt :object_i_d, "0" }
88
93
  end
@@ -98,12 +103,12 @@ class RallyRestAPI
98
103
  end
99
104
 
100
105
  def query(query) # :nodoc:
101
- query_url = "#{@base_url}/webservice/1.0/#{query.type.to_s.to_camel}?" << query.to_q
106
+ query_url = "#{@base_url}/webservice/#{@version}/#{query.type.to_s.to_camel}?" << query.to_q
102
107
  xml = builder.read_rest(query_url, @username, @password)
103
108
  QueryResult.new(query, self, xml)
104
109
  end
105
110
 
106
- # Should rest_objects parse into hashes
111
+ # Should rest_objects collection parse into hashes
107
112
  def parse_collections_as_hash?
108
113
  @parse_collections_as_hash
109
114
  end
@@ -9,8 +9,16 @@ class RestBuilder # :nodoc:
9
9
  attr_reader :base_url, :username, :password
10
10
  attr_accessor :logger
11
11
 
12
- def initialize(base_url, username, password)
13
- @base_url, @username, @password = base_url, username, password
12
+ def initialize(base_url, username, password, version = "current")
13
+ @base_url, @username, @password, @version = base_url, username, password, version
14
+ end
15
+
16
+ def marshal_dump
17
+ [@username, @password, @base_url, @version]
18
+ end
19
+
20
+ def marshal_load(stuff)
21
+ @username, @password, @base_url, @version = *stuff
14
22
  end
15
23
 
16
24
  # create_rest - convert slm builder style:
@@ -27,7 +35,7 @@ class RestBuilder # :nodoc:
27
35
  b = create_builder
28
36
  xml = b.__send__(type, &builder_block(args))
29
37
 
30
- result = post_xml("#{self.base_url}/webservice/1.0/#{type}/create", xml, username, password)
38
+ result = post_xml("#{self.base_url}/webservice/#{@version}/#{type}/create", xml, username, password)
31
39
  doc = REXML::Document.new result
32
40
  doc.root.elements["Object"].to_s
33
41
  end
@@ -99,12 +107,6 @@ class RestBuilder # :nodoc:
99
107
  sym.to_s.split("_").map { |word| word.capitalize }.join
100
108
  end
101
109
 
102
- # def cameler(sym)
103
- # cam = camel_case_word(sym).split("").to_a
104
- # cam[0] = (cam.first.downcase)
105
- # cam.to_s
106
- # end
107
-
108
110
  # Because we are adapting to the xml builder as such:
109
111
  # We say to the RallyRestAPI:
110
112
  # slm.create(:feature, :name => "feature name")
@@ -163,6 +165,7 @@ class RestBuilder # :nodoc:
163
165
  end
164
166
  end
165
167
 
168
+
166
169
  # Convert the values of the hash passed to the RestApi appropiatly
167
170
  # RestObject --> a hash with the ref value
168
171
  # nil --> "null" ref values
@@ -18,6 +18,13 @@ require 'builder/blankslate'
18
18
  # will be carried out as the same user as their RallyRestAPI.
19
19
  #
20
20
  #
21
+
22
+ class FancyHash < Hash # :nodoc: all
23
+ def method_missing(sym, *args)
24
+ self[sym]
25
+ end
26
+ end
27
+
21
28
  class RestObject
22
29
 
23
30
  attr_reader :username, :password, :rally_rest
@@ -26,6 +33,10 @@ class RestObject
26
33
  @rally_rest = rally_rest
27
34
  @document_content = document_content
28
35
  @username, @password = @rally_rest.username, @rally_rest.password
36
+ parse_document
37
+ end
38
+
39
+ def parse_document
29
40
  @document = REXML::Document.new @document_content
30
41
  if !ref?(@document.root)
31
42
  @elements = parse(@document.root)
@@ -34,6 +45,15 @@ class RestObject
34
45
  end
35
46
  end
36
47
 
48
+ def marshal_dump
49
+ [@rally_rest, @document_content, @username, @password]
50
+ end
51
+
52
+ def marshal_load(stuff)
53
+ @rally_rest, @document_content, @username, @password = *stuff
54
+ parse_document
55
+ end
56
+
37
57
  private
38
58
  def terminal?(node)
39
59
  !node.has_elements?
@@ -57,13 +77,7 @@ class RestObject
57
77
  end
58
78
 
59
79
  # Convert nodes with children into Hashes
60
- elements = {}
61
- class << elements
62
- def method_missing(sym, *args)
63
- value = self[sym]
64
- value
65
- end
66
- end
80
+ elements = FancyHash.new
67
81
 
68
82
  #Add all the element's children to the hash.
69
83
  node.each_element do |e|
@@ -141,9 +155,10 @@ class RestObject
141
155
  alias :to_q :ref
142
156
 
143
157
  # The name of the object, without having to read the entire body
144
- def name
145
- @document.root.attributes["refObjectName"]
146
- end
158
+ def name
159
+ @document.root.attributes["refObjectName"]
160
+ end
161
+ alias :to_s :name
147
162
 
148
163
  # The type of the underlying resource
149
164
  def type
@@ -202,7 +217,6 @@ class RestObject
202
217
  # update the resource. This will re-read the resource after the update
203
218
  def update(args)
204
219
  builder.update_rest(self.type, self.ref, args, @username, @password)
205
- # need to deal with the block, setting up contexts etc
206
220
  self.elements(true)
207
221
  end
208
222
 
@@ -212,9 +226,10 @@ class RestObject
212
226
  end
213
227
 
214
228
  def method_missing(sym, *args) # :nodoc:
215
- value = self.elements[sym]
216
- # raise "No matching element named #{sym}. Known values are #{self.elements.keys.join(' ')}." unless self.elements.has_key? sym
217
- value
229
+ self.elements[sym]
230
+ # Sometimes the xml returned has no element for things that are simply null. Without
231
+ # asking the typedef, I have no way to know if the element exists, or has been ommited.
232
+ # It would not be hard to ask the typedef, but they are expensive to load. It should be an option
218
233
  end
219
234
 
220
235
 
@@ -0,0 +1,30 @@
1
+ # Add Ruport (http://rubyreports.org/) support to the RallyRestAPI.
2
+ # This will add a method, #to_table, to QueryResult
3
+ #
4
+ # For example:
5
+ # table = rally_api.find(:defect) { equal :state, "Open" }.to_table([:formatted_i_d, :name, :owner])
6
+ # table.to_pdf
7
+ #
8
+ begin
9
+ require 'rubygems'
10
+ require 'ruport'
11
+ rescue LoadError ; raise "You must 'gem install ruport' to use rally_rest_api/ruport" ; end
12
+
13
+ # Ruport can deal with anything that has a #to_hash
14
+ class RestObject
15
+ def to_hash # :nodoc
16
+ elements
17
+ end
18
+ end
19
+
20
+ class QueryResult
21
+ # return a Ruport::Data::Table. Takes an array of columns for the report
22
+ # defects = rally.find(:defect, :fetch => true) { equal :state, "Open }
23
+ # table = defects.to_table([:name, :severity, :priority, :owner])
24
+ # table.to_pdf
25
+ def to_table(columns = [])
26
+ table = Ruport::Data::Table.new(:column_names => columns)
27
+ self.each { |i| table << i }
28
+ table
29
+ end
30
+ end
@@ -1,5 +1,4 @@
1
-
2
- class TimeoutCatchingRestBuilder < RestBuilder
1
+ class TimeoutCatchingRestBuilder < RestBuilder # :nodoc all
3
2
  def send_request(url, req, username, password)
4
3
  begin
5
4
  super
@@ -15,14 +15,17 @@ class TypeDefinition < RestObject # :nodoc:
15
15
  end
16
16
 
17
17
  def self.get_type_definition(workspace, type)
18
+ get_type_definitions(workspace).find { |td| td.element_name == type }
19
+ end
20
+
21
+ def self.get_type_definitions(workspace)
18
22
  # This is a hack - having to do with parse_collections_as_hash?
19
23
  typedefs = case workspace.type_definitions
20
- when Hash : workspace.type_definitions.values.flatten
21
- when Array : workspace.type_definitions
24
+ when Hash : workspace.type_definitions.values.flatten
25
+ when Array : workspace.type_definitions
22
26
  end
23
- typedef = typedefs.find { |td| td.element_name == type }
24
- # end hack
25
- TypeDefinition.new(typedef.rally_rest, typedef.body)
27
+ # end hack
28
+ typedefs.map { |td| TypeDefinition.new(td.rally_rest, td.body) }
26
29
  end
27
30
 
28
31
  def self.make_key(workspace, type)
@@ -97,6 +100,10 @@ class TypeDefinition < RestObject # :nodoc:
97
100
  typedef
98
101
  end
99
102
 
103
+ def type_as_symbol
104
+ underscore(element_name).intern
105
+ end
106
+
100
107
  protected
101
108
  def parse_collections_as_hash?
102
109
  true
@@ -1,8 +1,8 @@
1
1
  module RallyRestVersion #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 6
5
- TINY = 13
4
+ MINOR = 7
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -6,9 +6,9 @@ require 'logger'
6
6
  require 'rally_rest_api'
7
7
 
8
8
 
9
- context "An attribute definition for a custom dropdown" do
9
+ describe "An attribute definition for a custom dropdown" do
10
10
 
11
- setup do
11
+ before(:each) do
12
12
  @b = Builder::XmlMarkup.new(:indent => 2)
13
13
  @b.instruct!
14
14
 
@@ -33,27 +33,27 @@ context "An attribute definition for a custom dropdown" do
33
33
  @attrdef = AttributeDefinition.new(fake_rally_rest, RestObject.new(fake_rally_rest, xml).elements)
34
34
  end
35
35
 
36
- specify "should have 'Custom Dropdown' as the name" do
36
+ it "should have 'Custom Dropdown' as the name" do
37
37
  @attrdef.name.should == "Custom Dropdown"
38
38
  end
39
39
 
40
- specify "should return an arry of allowed values" do
41
- @attrdef.allowed_values.should_be_instance_of Array
40
+ it "should return an arry of allowed values" do
41
+ @attrdef.allowed_values.should be_instance_of(Array)
42
42
  end
43
-
44
- specify "should have 2 allowd values" do
43
+
44
+ it "should have 2 allowd values" do
45
45
  @attrdef.allowed_values.length.should == 2
46
46
  end
47
47
 
48
- specify "should not return an array of hashes" do
49
- @attrdef.allowed_values.each { |value| value.should_not_be_instance_of Hash }
48
+ it "should not return an array of hashes" do
49
+ @attrdef.allowed_values.each { |value| value.should_not be_instance_of(Hash) }
50
50
  end
51
51
 
52
- specify "allowed_values should match" do
52
+ it "allowed_values should match" do
53
53
  @attrdef.allowed_values.should == [nil, "Actor"]
54
54
  end
55
55
 
56
- specify "should have 'AttributeDefinition' as the type" do
56
+ it "should have 'AttributeDefinition' as the type" do
57
57
  @attrdef.type.should == "AttributeDefinition"
58
58
  end
59
59
 
@@ -1,8 +1,8 @@
1
1
  require 'test_helper'
2
2
 
3
- context "A QueryResult" do
3
+ describe "A QueryResult" do
4
4
 
5
- setup do
5
+ before(:each) do
6
6
  @api = RallyRestAPI.new(:parse_collections_as_hash => true)
7
7
  end
8
8
 
@@ -27,59 +27,59 @@ context "A QueryResult" do
27
27
  QueryResult.new(nil, @api, xml)
28
28
  end
29
29
 
30
- specify "should have the total result count" do
31
- make_result(20, 20, 1).total_result_count.should_be 20
30
+ it "should have the total result count" do
31
+ make_result(20, 20, 1).total_result_count.should equal(20)
32
32
  end
33
33
 
34
- specify "should have the page size" do
35
- make_result(20, 20, 1).page_size.should_be 20
34
+ it "should have the page size" do
35
+ make_result(20, 20, 1).page_size.should equal(20)
36
36
  end
37
37
 
38
- specify "should have the start_index" do
39
- make_result(20, 20, 1).start_index.should_be 1
38
+ it "should have the start_index" do
39
+ make_result(20, 20, 1).start_index.should equal(1)
40
40
  end
41
41
 
42
- specify "should have no more pages when no results are returned" do
43
- make_result(0, 20, 0).more_pages?.should_be false
42
+ it "should have no more pages when no results are returned" do
43
+ make_result(0, 20, 0).more_pages?.should equal(false)
44
44
  end
45
45
 
46
- specify "should have not more pages when the total result count is less then the page size" do
47
- make_result(1, 20, 1).more_pages?.should_be false
48
- make_result(19, 20, 1).more_pages?.should_be false
49
- make_result(20, 20, 1).more_pages?.should_be false
46
+ it "should have not more pages when the total result count is less then the page size" do
47
+ make_result(1, 20, 1).more_pages?.should equal(false)
48
+ make_result(19, 20, 1).more_pages?.should equal(false)
49
+ make_result(20, 20, 1).more_pages?.should equal(false)
50
50
  end
51
51
 
52
- specify "should have more pages when total result count is more then the page size" do
53
- make_result(21, 20, 1).more_pages?.should_be true
54
- make_result(39, 20, 1).more_pages?.should_be true
52
+ it "should have more pages when total result count is more then the page size" do
53
+ make_result(21, 20, 1).more_pages?.should equal(true)
54
+ make_result(39, 20, 1).more_pages?.should equal(true)
55
55
  end
56
56
 
57
- specify "an empty query should not iteratate on each" do
57
+ it "an empty query should not iteratate on each" do
58
58
  start = 0
59
59
  make_result(0, 20, 0).each { start += 1 }
60
- start.should_be 0
60
+ start.should equal(0)
61
61
  end
62
62
 
63
- specify "a page of results should match the page size" do
64
- make_result(20, 20, 1).results.length.should_be 20
63
+ it "a page of results should match the page size" do
64
+ make_result(20, 20, 1).results.length.should equal(20)
65
65
  end
66
66
 
67
- specify "results should be in the same order as returned" do
67
+ it "results should be in the same order as returned" do
68
68
  result = make_result(20, 20, 1)
69
- result.results.length.should_be 20
69
+ result.results.length.should equal(20)
70
70
  result.results[0].name.should == "name0"
71
71
  result.results[19].name.should == "name19"
72
72
  end
73
73
 
74
- specify "should return RestObjects for results" do
75
- make_result.each { |o| o.should_be_instance_of RestObject }
74
+ it "should return RestObjects for results" do
75
+ make_result.each { |o| o.should be_instance_of(RestObject) }
76
76
  end
77
77
  end
78
78
 
79
79
 
80
- context "A QueryResult with full objects" do
80
+ describe "A QueryResult with full objects" do
81
81
 
82
- setup do
82
+ before(:each) do
83
83
  @api = RallyRestAPI.new(:parse_collections_as_hash => true)
84
84
  end
85
85
 
@@ -116,11 +116,11 @@ context "A QueryResult with full objects" do
116
116
  yield Builder::XmlMarkup.new(:indent => 2)
117
117
  end
118
118
 
119
- specify "should return RestObjects for results" do
120
- make_result.each { |o| o.should_be_instance_of RestObject }
119
+ it "should return RestObjects for results" do
120
+ make_result.each { |o| o.should be_instance_of(RestObject) }
121
121
  end
122
122
 
123
- specify "full object collections should lazy load only once" do
123
+ it "full object collections should lazy load only once" do
124
124
  rest_builder = mock("RestBuilder")
125
125
  rest_builder.
126
126
  should_receive(:read_rest).
@@ -156,8 +156,8 @@ context "A QueryResult with full objects" do
156
156
  }
157
157
  end
158
158
 
159
- object.total_result_count.should_be 2
160
- object.results.should_be_instance_of Array
159
+ object.total_result_count.should equal(2)
160
+ object.results.should be_instance_of(Array)
161
161
  object.each_with_index do |c, i|
162
162
  c.name.should == "Card#{i + 1}"
163
163
  c.description.should == "Description#{i + 1}"
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- context "a RestBuilder " do
3
+ describe "a RestBuilder " do
4
4
 
5
5
  def xml
6
6
  b = Builder::XmlMarkup.new
@@ -8,13 +8,13 @@ context "a RestBuilder " do
8
8
  yield b
9
9
  end
10
10
 
11
- setup do
11
+ before(:each) do
12
12
  @username = "username"
13
13
  @password = "password"
14
14
  @builder = RestBuilder.new(nil, @username, @password)
15
15
  end
16
16
 
17
- specify "should produce correct xml for flat xml" do
17
+ it "should produce correct xml for flat xml" do
18
18
  expected_xml = xml do |b|
19
19
  b.defect(:ref => "url") {
20
20
  b.Name "foo"
@@ -24,7 +24,7 @@ context "a RestBuilder " do
24
24
  @builder.update_rest(:defect, "url", {:name => "foo"}, @username, @password)
25
25
  end
26
26
 
27
- specify "should produce correct xml for nested values" do
27
+ it "should produce correct xml for nested values" do
28
28
  expected_xml = xml do |b|
29
29
  b.defect(:ref => "url") {
30
30
  b.Name "foo"
@@ -1,9 +1,9 @@
1
1
 
2
2
  require 'test_helper'
3
3
 
4
- context "a RestObject" do
4
+ describe RestObject do
5
5
 
6
- setup do
6
+ before(:each) do
7
7
  @api = RallyRestAPI.new
8
8
  end
9
9
 
@@ -23,14 +23,14 @@ context "a RestObject" do
23
23
  yield Builder::XmlMarkup.new(:indent => 2)
24
24
  end
25
25
 
26
- specify "should return the type of the resource from a ref" do
26
+ it "should return the type of the resource from a ref" do
27
27
  o = rest_object_xml do |b|
28
28
  b.Object(:refObjectName => "name", :ref => "ref", :type => "Defect")
29
29
  end
30
30
  o.type.should == "Defect"
31
31
  end
32
32
 
33
- specify "should return the type of the resource from full object" do
33
+ it "should return the type of the resource from full object" do
34
34
  o = rest_object_xml do |b|
35
35
  b.Defect(:refObjectName => "name", :ref => "ref") {
36
36
  b.Name("name")
@@ -39,7 +39,7 @@ context "a RestObject" do
39
39
  o.type.should == "Defect"
40
40
  end
41
41
 
42
- specify "should return the ref of the resource " do
42
+ it "should return the ref of the resource " do
43
43
  o = rest_object_xml do |b|
44
44
  b.Defect(:refObjectName => "name", :ref => "ref") {
45
45
  b.Name("name")
@@ -48,7 +48,7 @@ context "a RestObject" do
48
48
  o.ref.should == "ref"
49
49
  end
50
50
 
51
- specify "should return the oid" do
51
+ it "should return the oid" do
52
52
  o = rest_object_xml do |b|
53
53
  b.Defect(:refObjectName => "name", :ref => "ref") {
54
54
  b.Name("name")
@@ -58,31 +58,31 @@ context "a RestObject" do
58
58
  o.oid.should == "12345"
59
59
  end
60
60
 
61
- specify "should underscore element names" do
61
+ it "should underscore element names" do
62
62
  o = rest_object(%Q(<Object ref="bla">
63
63
  <TextNode>text</TextNode>
64
64
  </Object>))
65
- o.text_node.should_not_be nil
66
- o.TextNode.should_be nil
67
- o.Text_Node.should_be nil
68
- o.textnode.should_be nil
65
+ o.text_node.should_not equal nil
66
+ o.TextNode.should equal(nil)
67
+ o.Text_Node.should equal(nil)
68
+ o.textnode.should equal(nil)
69
69
  end
70
70
 
71
- specify "should underscore elements ending in 'ID' correctly" do
71
+ it "should underscore elements ending in 'ID' correctly" do
72
72
  o = rest_object(%Q(<Object ref="bla">
73
73
  <SalesforceCaseID>12345</SalesforceCaseID>
74
74
  </Object>))
75
75
  o.salesforce_case_i_d.should == "12345"
76
76
  end
77
77
 
78
- specify "should return text nodes" do
78
+ it "should return text nodes" do
79
79
  xml = %Q(<Object ref="bla">
80
80
  <TextNode>text</TextNode>
81
81
  </Object>)
82
82
  rest_object(xml).text_node.should == "text"
83
83
  end
84
84
 
85
- specify "should return nested text nodes" do
85
+ it "should return nested text nodes" do
86
86
  xml = %Q(<Object ref="bla">
87
87
  <Nested>
88
88
  <TextNode>text</TextNode>
@@ -91,7 +91,7 @@ context "a RestObject" do
91
91
  rest_object(xml).nested.text_node.should == "text"
92
92
  end
93
93
 
94
- specify "ref elements should lazy read" do
94
+ it "should lazy read ref elements" do
95
95
  rest_builder = mock("RestBuilder")
96
96
  rest_builder.
97
97
  should_receive(:read_rest).
@@ -111,7 +111,7 @@ context "a RestObject" do
111
111
  object.description.should == "Description"
112
112
  end
113
113
 
114
- specify "nested ref elements should lazy read" do
114
+ it "should lazy read nested ref elements" do
115
115
  rest_builder = mock("RestBuilder")
116
116
  rest_builder.
117
117
  should_receive(:read_rest).
@@ -130,12 +130,12 @@ context "a RestObject" do
130
130
  b.TestCase(:ref => "http", :refObjectName => "name1")
131
131
  }
132
132
  end
133
- object.test_case.should_be_instance_of RestObject
133
+ object.test_case.should be_instance_of(RestObject)
134
134
  object.test_case.type.should == "TestCase"
135
135
  object.test_case.description.should == "Description"
136
136
  end
137
137
 
138
- specify "nested ref elements should lazy read only once" do
138
+ it "should lazy read only once nested ref elements" do
139
139
  rest_builder = mock("RestBuilder")
140
140
  rest_builder.
141
141
  should_receive(:read_rest).
@@ -159,7 +159,7 @@ context "a RestObject" do
159
159
  object.test_case.description.should == "Description"
160
160
  end
161
161
 
162
- specify "full object collections should lazy load only once" do
162
+ it "should lazy load only once full object collections" do
163
163
  rest_builder = mock("RestBuilder")
164
164
  rest_builder.
165
165
  should_receive(:read_rest).
@@ -191,14 +191,43 @@ context "a RestObject" do
191
191
  }
192
192
  end
193
193
 
194
- object.results.length.should_be 2
195
- object.results.should_be_instance_of Array
194
+ object.results.length.should equal(2)
195
+ object.results.should be_instance_of(Array)
196
196
  object.results.first.description.should == "Description1"
197
197
  object.results.first.iteration.start_date.should == "12/12/01"
198
198
  object.results.first.iteration.start_date.should == "12/12/01"
199
199
  end
200
200
 
201
- specify "collections are parsed as arrays " do
201
+ it "should dump and load" do
202
+
203
+ @api = RallyRestAPI.new
204
+
205
+ object = rest_object_xml do |b|
206
+ b.QueryResult {
207
+ b.Results {
208
+ b.Card(:ref => "http", :refObjectName => "Card1") {
209
+ b.Name("Card1")
210
+ b.Description("Description1")
211
+ b.Iteration(:ref => "http", :refObjectName => "name1")
212
+ }
213
+ b.Card(:ref => "http", :refObjectName => "Card2") {
214
+ b.Name("Card2")
215
+ b.Description("Description2")
216
+ b.Iteration(:ref => "http", :refObjectName => "name1")
217
+ }
218
+ }
219
+ }
220
+ end
221
+
222
+ new_object = Marshal.load(Marshal.dump(object))
223
+
224
+ new_object.results.length.should equal(2)
225
+ new_object.results.should be_instance_of(Array)
226
+ new_object.results.first.description.should == "Description1"
227
+ end
228
+
229
+
230
+ it "should parse collections as arrays " do
202
231
  @api = RallyRestAPI.new(:parse_collections_as_hash => false)
203
232
 
204
233
  object = rest_object_xml do |b|
@@ -210,11 +239,11 @@ context "a RestObject" do
210
239
  }
211
240
  }
212
241
  end
213
- object.tasks.should_be_instance_of Array
214
- object.tasks.length.should_be 3
242
+ object.tasks.should be_instance_of(Array)
243
+ object.tasks.length.should equal(3)
215
244
  end
216
245
 
217
- specify "collections are parsed as hashes " do
246
+ it "should parse collections as hashes " do
218
247
  @api = RallyRestAPI.new(:parse_collections_as_hash => true)
219
248
 
220
249
  object = rest_object_xml do |b|
@@ -226,11 +255,11 @@ context "a RestObject" do
226
255
  }
227
256
  }
228
257
  end
229
- object.tasks.should_be_instance_of Hash
230
- object.tasks.length.should_be 3
258
+ object.tasks.should be_instance_of(Hash)
259
+ object.tasks.length.should equal(3)
231
260
  end
232
261
 
233
- specify "when collections are parsed as hashes, dup names should be in arrays " do
262
+ it "should dup names into arrays, when collections are parsed as hashes" do
234
263
  @api = RallyRestAPI.new(:parse_collections_as_hash => true)
235
264
 
236
265
  object = rest_object_xml do |b|
@@ -242,13 +271,13 @@ context "a RestObject" do
242
271
  }
243
272
  }
244
273
  end
245
- object.tasks.should_be_instance_of Hash
246
- object.tasks.length.should_be 2
247
- object.tasks["task2"].should_be_instance_of Array
248
- object.tasks["task2"].length.should_be 2
274
+ object.tasks.should be_instance_of(Hash)
275
+ object.tasks.length.should equal(2)
276
+ object.tasks["task2"].should be_instance_of(Array)
277
+ object.tasks["task2"].length.should equal(2)
249
278
  end
250
279
 
251
- specify "when collections are parsed as hashes, unnamed elements should be in arrays " do
280
+ it "should parse unnamed elements into arrays when collections are parsed as hashes" do
252
281
  @api = RallyRestAPI.new(:parse_collections_as_hash => true)
253
282
 
254
283
  object = rest_object_xml do |b|
@@ -260,12 +289,12 @@ context "a RestObject" do
260
289
  }
261
290
  }
262
291
  end
263
- object.tasks.should_be_instance_of Array
264
- object.tasks.length.should_be 3
292
+ object.tasks.should be_instance_of(Array)
293
+ object.tasks.length.should equal(3)
265
294
  end
266
295
 
267
296
 
268
- specify "should lazy read from collections" do
297
+ it "should lazy read from collections" do
269
298
  rest_builder = mock("RestBuilder")
270
299
  rest_builder.
271
300
  should_receive(:read_rest).
data/test/spec_typedef.rb CHANGED
@@ -4,9 +4,9 @@ require 'logger'
4
4
  require 'rally_rest_api'
5
5
 
6
6
 
7
- context "A Test Case type definition with 2 collection attribues, 1 object attributes, and 1 string attribute" do
7
+ describe "A Test Case type definition with 2 collection attribues, 1 object attributes, and 1 string attribute" do
8
8
 
9
- setup do
9
+ before(:each) do
10
10
  @b = Builder::XmlMarkup.new(:indent => 2)
11
11
  @b.instruct!
12
12
 
@@ -36,48 +36,53 @@ context "A Test Case type definition with 2 collection attribues, 1 object attri
36
36
  @typedef = TypeDefinition.new(OpenStruct.new(:username => "", :password => "", :logger => nil), xml)
37
37
  end
38
38
 
39
- specify "all attribute keys are symbols" do
40
- @typedef.attributes.keys.each { |a| a.should_be_instance_of Symbol }
39
+ it "all attribute keys are symbols" do
40
+ @typedef.attributes.keys.each { |a| a.should be_instance_of(Symbol) }
41
41
  end
42
42
 
43
- specify "there should be 2 collection attributes" do
43
+ it "there should be 2 collection attributes" do
44
44
  @typedef.collection_attributes.size.should == 2
45
45
  end
46
46
 
47
- specify "the :test_case_result attribute should exist" do
48
- @typedef.collection_attributes[:test_case_result].should_not_be_nil
47
+ it "the :test_case_result attribute should exist" do
48
+ @typedef.collection_attributes[:test_case_result].should_not be_nil
49
49
  end
50
50
 
51
- specify "All the collection attributes keys should be symbols" do
52
- @typedef.collection_attributes.keys.each { |a| a.should_be_instance_of Symbol }
51
+ it "All the collection attributes keys should be symbols" do
52
+ @typedef.collection_attributes.keys.each { |a| a.should be_instance_of(Symbol) }
53
53
  end
54
54
 
55
- specify "there should be 1 object attribute" do
55
+ it "there should be 1 object attribute" do
56
56
  @typedef.object_attributes.size.should == 1
57
57
  end
58
58
 
59
- specify "the :requirement attribute should exist" do
60
- @typedef.object_attributes[:requirement].should_not_be_nil
59
+ it "the :requirement attribute should exist" do
60
+ @typedef.object_attributes[:requirement].should_not be_nil
61
61
  end
62
62
 
63
- specify "should have 2 constrained attributes" do
63
+ it "should have 2 constrained attributes" do
64
64
  @typedef.constrained_attributes.size.should == 2
65
65
  end
66
66
 
67
- specify "should have 2 cusom attributes" do
67
+ it "should have 2 cusom attributes" do
68
68
  @typedef.custom_attributes.size.should == 2
69
69
  end
70
70
 
71
- specify "should have 1 custom_constrained_attributes" do
72
- @typedef.custom_constrained_attributes.size.should_be 1
73
- @typedef.custom_dropdown_attributes.size.should_be 1
71
+ it "should have 1 custom_constrained_attributes" do
72
+ @typedef.custom_constrained_attributes.size.should equal(1)
73
+ @typedef.custom_dropdown_attributes.size.should equal(1)
74
74
  end
75
75
 
76
- specify "#attributes should return instances of AttributeDefinitions" do
77
- @typedef.attributes.values.each { |attrdef| attrdef.should_be_instance_of AttributeDefinition }
76
+ it "#attributes should return instances of AttributeDefinitions" do
77
+ @typedef.attributes.values.each { |attrdef| attrdef.should be_instance_of(AttributeDefinition) }
78
78
  end
79
79
 
80
- specify "parent should be nil" do
81
- @typedef.parent.should_be_nil
80
+ it "should have a nil parent" do
81
+ @typedef.parent.should be_nil
82
82
  end
83
+
84
+ it "should not throw exception Marshalling" do
85
+ lambda { Marshal.dump(@typedef) }.should_not raise_error Exception
86
+ end
87
+
83
88
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: rally_rest_api
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.6.13
7
- date: 2007-03-08 00:00:00 -07:00
6
+ version: 0.7.0
7
+ date: 2007-06-04 00:00:00 -06:00
8
8
  summary: A ruby-ized interface to Rally's REST webservices API
9
9
  require_paths:
10
10
  - lib
@@ -40,6 +40,7 @@ files:
40
40
  - lib/rally_rest_api/timeout_catching_rest_builder.rb
41
41
  - lib/rally_rest_api/rest_object.rb
42
42
  - lib/rally_rest_api/typedef.rb
43
+ - lib/rally_rest_api/ruport.rb
43
44
  - lib/rally_rest_api/version.rb
44
45
  - Manifest.txt
45
46
  - Rakefile
@@ -91,5 +92,5 @@ dependencies:
91
92
  requirements:
92
93
  - - ">="
93
94
  - !ruby/object:Gem::Version
94
- version: 1.1.7
95
+ version: 1.2.0
95
96
  version: