jira-ruby 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/README.rdoc +259 -0
  2. data/Rakefile +9 -0
  3. data/example.rb +47 -4
  4. data/jira-ruby.gemspec +5 -3
  5. data/lib/jira.rb +21 -7
  6. data/lib/jira/base.rb +466 -0
  7. data/lib/jira/base_factory.rb +49 -0
  8. data/lib/jira/client.rb +79 -8
  9. data/lib/jira/has_many_proxy.rb +43 -0
  10. data/lib/jira/http_error.rb +16 -0
  11. data/lib/jira/resource/attachment.rb +12 -0
  12. data/lib/jira/resource/comment.rb +14 -0
  13. data/lib/jira/resource/component.rb +4 -9
  14. data/lib/jira/resource/issue.rb +49 -5
  15. data/lib/jira/resource/issuetype.rb +10 -0
  16. data/lib/jira/resource/priority.rb +10 -0
  17. data/lib/jira/resource/project.rb +24 -3
  18. data/lib/jira/resource/status.rb +10 -0
  19. data/lib/jira/resource/user.rb +14 -0
  20. data/lib/jira/resource/version.rb +10 -0
  21. data/lib/jira/resource/worklog.rb +16 -0
  22. data/lib/jira/version.rb +2 -2
  23. data/spec/integration/attachment_spec.rb +26 -0
  24. data/spec/integration/comment_spec.rb +55 -0
  25. data/spec/integration/component_spec.rb +25 -52
  26. data/spec/integration/issue_spec.rb +50 -47
  27. data/spec/integration/issuetype_spec.rb +27 -0
  28. data/spec/integration/priority_spec.rb +27 -0
  29. data/spec/integration/project_spec.rb +32 -24
  30. data/spec/integration/status_spec.rb +27 -0
  31. data/spec/integration/user_spec.rb +25 -0
  32. data/spec/integration/version_spec.rb +43 -0
  33. data/spec/integration/worklog_spec.rb +55 -0
  34. data/spec/jira/base_factory_spec.rb +46 -0
  35. data/spec/jira/base_spec.rb +555 -0
  36. data/spec/jira/client_spec.rb +12 -12
  37. data/spec/jira/has_many_proxy_spec.rb +45 -0
  38. data/spec/jira/{resource/http_error_spec.rb → http_error_spec.rb} +1 -1
  39. data/spec/jira/resource/attachment_spec.rb +20 -0
  40. data/spec/jira/resource/issue_spec.rb +83 -0
  41. data/spec/jira/resource/project_factory_spec.rb +3 -3
  42. data/spec/jira/resource/project_spec.rb +28 -0
  43. data/spec/jira/resource/worklog_spec.rb +24 -0
  44. data/spec/mock_responses/attachment/10000.json +20 -0
  45. data/spec/mock_responses/component/10000.invalid.put.json +5 -0
  46. data/spec/mock_responses/issue.json +1108 -0
  47. data/spec/mock_responses/issue/10002.invalid.put.json +6 -0
  48. data/spec/mock_responses/issue/10002.json +13 -1
  49. data/spec/mock_responses/issue/10002.put.missing_field_update.json +6 -0
  50. data/spec/mock_responses/issue/10002/comment.json +65 -0
  51. data/spec/mock_responses/issue/10002/comment.post.json +29 -0
  52. data/spec/mock_responses/issue/10002/comment/10000.json +29 -0
  53. data/spec/mock_responses/issue/10002/comment/10000.put.json +29 -0
  54. data/spec/mock_responses/issue/10002/worklog.json +98 -0
  55. data/spec/mock_responses/issue/10002/worklog.post.json +30 -0
  56. data/spec/mock_responses/issue/10002/worklog/10000.json +31 -0
  57. data/spec/mock_responses/issue/10002/worklog/10000.put.json +30 -0
  58. data/spec/mock_responses/issuetype.json +42 -0
  59. data/spec/mock_responses/issuetype/5.json +8 -0
  60. data/spec/mock_responses/priority.json +42 -0
  61. data/spec/mock_responses/priority/1.json +8 -0
  62. data/spec/mock_responses/project/SAMPLEPROJECT.issues.json +1108 -0
  63. data/spec/mock_responses/project/SAMPLEPROJECT.json +15 -1
  64. data/spec/mock_responses/status.json +37 -0
  65. data/spec/mock_responses/status/1.json +7 -0
  66. data/spec/mock_responses/user?username=admin.json +17 -0
  67. data/spec/mock_responses/version.post.json +7 -0
  68. data/spec/mock_responses/version/10000.invalid.put.json +5 -0
  69. data/spec/mock_responses/version/10000.json +11 -0
  70. data/spec/mock_responses/version/10000.put.json +7 -0
  71. data/spec/spec_helper.rb +7 -12
  72. data/spec/support/matchers/have_attributes.rb +11 -0
  73. data/spec/support/matchers/have_many.rb +9 -0
  74. data/spec/support/matchers/have_one.rb +5 -0
  75. data/spec/support/shared_examples/integration.rb +174 -0
  76. metadata +139 -24
  77. data/README.markdown +0 -81
  78. data/lib/jira/resource/base.rb +0 -148
  79. data/lib/jira/resource/base_factory.rb +0 -44
  80. data/lib/jira/resource/http_error.rb +0 -17
  81. data/spec/jira/resource/base_factory_spec.rb +0 -36
  82. data/spec/jira/resource/base_spec.rb +0 -292
data/README.markdown DELETED
@@ -1,81 +0,0 @@
1
- Jira 5 API Gem
2
- ==============
3
-
4
- Links to JIRA REST API documentation
5
- ------------------------------------
6
- * [Overview](https://developer.atlassian.com/display/JIRADEV/JIRA+REST+APIs)
7
- * [Reference](http://docs.atlassian.com/jira/REST/5.0-rc1/)
8
-
9
-
10
- Setting up the JIRA SDK
11
- -----------------------
12
- On Mac OS,
13
-
14
- brew install atlassian-plugin-sdk
15
-
16
- Otherwise:
17
-
18
- * Download the SDK from https://developer.atlassian.com/ (You will need
19
- an Atlassian login for this)
20
- * Unpack the dowloaded archive
21
- * From within the archive directory, run:
22
-
23
- ./bin/atlas-run-standalone --product jira --version 5.0-rc2
24
-
25
- Once this is running, you should be able to connect to
26
- [http://localhost:2990/] and login to the JIRA admin system using `admin:admin`
27
-
28
- You'll need to create a dummy project and probably some issues to test using
29
- this library.
30
-
31
- Configuring JIRA to use OAuth
32
- -----------------------------
33
- From the Jira API tutorial
34
-
35
- > The first step is to register a new consumer in JIRA. This is done through
36
- > the Application Links administration screens in JIRA. Create a new
37
- > Application Link.
38
- > [Administration/Plugins/Application Links](http://localhost:2990/jira/plugins/servlet/applinks/listApplicationLinks)
39
- >
40
- > When creating the Application Link use a placeholder URL or the correct URL
41
- > to your client (e.g. `http://localhost:3000`), if your client can be reached
42
- > via HTTP and choose the Generic Application type. After this Application Link
43
- > has been created, edit the configuration and go to the incoming
44
- > authentication configuration screen and select OAuth. Enter in this the
45
- > public key and the consumer key which your client will use when making
46
- > requests to JIRA.
47
-
48
- This public key and consumer key will need to be generated by the Gem user, using OpenSSL
49
- or similar to generate the public key and the provided rake task to generate the consumer
50
- key.
51
-
52
- > After you have entered all the information click OK and ensure OAuth authentication is
53
- > enabled.
54
-
55
- Using the API Gem in your application
56
- -------------------------------------
57
- The JiraApi gem requires the consumer key and public certificate file (which are generated in their respective rake tasks) to initialize an access token for using the Jira API. These two pieces of information are applied globally to your application, with separate JiraApi::Client objects created on a per-user basis.
58
-
59
- An example initializer which sets the key and certificate filename in a pair of globals is shown below, myapp/config/initializers/jira\_api.rb:
60
-
61
- $CONSUMER_KEY = 'cbaec507669c65979b6b6eefdb1c5bb0' #Your consumer key. Can be generated by rake jira_api:generate_public_cert
62
- $PUBLIC_CERT_FILE = 'rsakey.pem' #Location of the Private Key File (generated by rake jira_api:generate_public_cert
63
-
64
- This allows acces to the variables when a session is being set up.
65
- The following sample controller shows how to set up and initialize an access token for a particular user session.
66
- (Note that the callback url is defined in the Jira application link interface, and can be placed wherever suits you best in your application. The session#callback method is simply an example)
67
-
68
- \#TODO cannot pass params hash straight into init\_access\_token method - errors with a missing parameter exception
69
-
70
- class SessionsController < ApplicationController
71
- def create
72
- session[:client] = JiraApi::Client.new($CONSUMER_KEY, '', :private_key_file => $PUBLIC_CERT_FILE)
73
- session[:request_token] = session[:client].request_token #Generate the request token
74
- redirect_to session[:request_token].authorize_url #Redirect to Jira to authorize the token
75
- end
76
-
77
- def callback
78
- session[:client].init_access_token(:oauth_verifier => params[:oauth_verifier]) #Initialize the access token
79
- redirect_to root_url #Redirect to the desired page after initializing the access token
80
- end
81
- end
@@ -1,148 +0,0 @@
1
- module Jira
2
- module Resource
3
-
4
- class Base
5
-
6
- attr_reader :client
7
- attr_accessor :expanded, :deleted, :attrs
8
- alias :expanded? :expanded
9
- alias :deleted? :deleted
10
-
11
- def initialize(client, options = {})
12
- @client = client
13
- @attrs = options[:attrs] || {}
14
- @expanded = options[:expanded] || false
15
- @deleted = false
16
- end
17
-
18
- # The class methods are never called directly, they are always
19
- # invoked from a BaseFactory subclass instance.
20
- def self.all(client)
21
- response = client.get(rest_base_path(client))
22
- json = parse_json(response.body)
23
- json.map do |attrs|
24
- self.new(client, :attrs => attrs)
25
- end
26
- end
27
-
28
- def self.find(client, key)
29
- instance = self.new(client)
30
- instance.attrs[key_attribute.to_s] = key
31
- instance.fetch
32
- instance
33
- end
34
-
35
- def self.build(client, attrs)
36
- self.new(client, :attrs => attrs)
37
- end
38
-
39
- def self.rest_base_path(client)
40
- client.options[:rest_base_path] + '/' + self.endpoint_name
41
- end
42
-
43
- def self.endpoint_name
44
- self.name.split('::').last.downcase
45
- end
46
-
47
- def self.key_attribute
48
- :key
49
- end
50
-
51
- def self.parse_json(string)
52
- JSON.parse(string)
53
- end
54
-
55
- def respond_to?(method_name)
56
- if attrs.keys.include? method_name.to_s
57
- true
58
- else
59
- super(method_name)
60
- end
61
- end
62
-
63
- def method_missing(method_name, *args, &block)
64
- if attrs.keys.include? method_name.to_s
65
- attrs[method_name.to_s]
66
- else
67
- super(method_name)
68
- end
69
- end
70
-
71
- def rest_base_path
72
- # Just proxy this to the class method
73
- self.class.rest_base_path(client)
74
- end
75
-
76
- def fetch(reload = false)
77
- return if expanded? && !reload
78
- response = client.get(url)
79
- set_attrs_from_response(response)
80
- @expanded = true
81
- end
82
-
83
- def save(attrs)
84
- http_method = new_record? ? :post : :put
85
- response = client.send(http_method, url, attrs.to_json)
86
- set_attrs(attrs, false)
87
- set_attrs_from_response(response)
88
- @expanded = false
89
- true
90
- end
91
-
92
- def set_attrs_from_response(response)
93
- unless response.body.nil? or response.body.length < 2
94
- json = self.class.parse_json(response.body)
95
- set_attrs(json)
96
- end
97
- end
98
-
99
- # Set the current attributes from a hash. If clobber is true, any existing
100
- # hash values will be clobbered by the new hash, otherwise the hash will
101
- # be deeply merged into attrs. The target paramater is for internal use only
102
- # and should not be used.
103
- def set_attrs(hash, clobber=true, target = nil)
104
- target ||= @attrs
105
- if clobber
106
- target.merge!(hash)
107
- hash
108
- else
109
- hash.each do |k, v|
110
- if v.is_a?(Hash)
111
- set_attrs(v, clobber, target[k])
112
- else
113
- target[k] = v
114
- end
115
- end
116
- end
117
- end
118
-
119
- def delete
120
- client.delete(url)
121
- @deleted = true
122
- end
123
-
124
- def url
125
- if @attrs['self']
126
- @attrs['self']
127
- elsif @attrs[self.class.key_attribute.to_s]
128
- rest_base_path + "/" + @attrs[self.class.key_attribute.to_s].to_s
129
- else
130
- rest_base_path
131
- end
132
- end
133
-
134
- def to_s
135
- "#<#{self.class.name}:#{object_id} @attrs=#{@attrs.inspect}>"
136
- end
137
-
138
- def to_json
139
- attrs.to_json
140
- end
141
-
142
- def new_record?
143
- @attrs['id'].nil?
144
- end
145
- end
146
-
147
- end
148
- end
@@ -1,44 +0,0 @@
1
- module Jira
2
- module Resource
3
-
4
- # This is the base class for all the Jira resource factory instances.
5
- class BaseFactory
6
-
7
- attr_reader :client
8
-
9
- def initialize(client)
10
- @client = client
11
- end
12
-
13
- # Return the name of the class which this factory generates, i.e.
14
- # Jira::Resource::FooFactory creates Jira::Resource::Foo instances.
15
- def target_class
16
- # Need to do a little bit of work here as Module.const_get doesn't work
17
- # with nested class names, i.e. Jira::Resource::Foo.
18
- #
19
- # So create a method chain from the class componenets. This code will
20
- # unroll to:
21
- # Module.const_get('Jira').const_get('Resource').const_get('Foo')
22
- #
23
- target_class_name = self.class.name.sub(/Factory$/, '')
24
- class_components = target_class_name.split('::')
25
-
26
- class_components.inject(Module) do |mod, const_name|
27
- mod.const_get(const_name)
28
- end
29
- end
30
-
31
- def all
32
- target_class.all(@client)
33
- end
34
-
35
- def find(key)
36
- target_class.find(@client, key)
37
- end
38
-
39
- def build(attrs={})
40
- target_class.build(@client, attrs)
41
- end
42
- end
43
- end
44
- end
@@ -1,17 +0,0 @@
1
- require 'forwardable'
2
- module Jira
3
- module Resource
4
-
5
- class HTTPError < StandardError
6
- extend Forwardable
7
-
8
- delegate [:message, :code] => :response
9
- attr_reader :response
10
-
11
- def initialize(response)
12
- @response = response
13
- end
14
-
15
- end
16
- end
17
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Jira::Resource::BaseFactory do
4
-
5
- class Jira::Resource::FooFactory < Jira::Resource::BaseFactory ; end
6
- class Jira::Resource::Foo ; end
7
-
8
- let(:client) { mock() }
9
- subject { Jira::Resource::FooFactory.new(client) }
10
-
11
- it "initializes correctly" do
12
- subject.class.should == Jira::Resource::FooFactory
13
- subject.client.should == client
14
- subject.target_class.should == Jira::Resource::Foo
15
- end
16
-
17
- it "proxies all to the target class" do
18
- Jira::Resource::Foo.should_receive(:all).with(client)
19
- subject.all
20
- end
21
-
22
- it "proxies find to the target class" do
23
- Jira::Resource::Foo.should_receive(:find).with(client, 'FOO')
24
- subject.find('FOO')
25
- end
26
-
27
- it "returns the target class" do
28
- subject.target_class.should == Jira::Resource::Foo
29
- end
30
-
31
- it "proxies build to the target class" do
32
- attrs = mock()
33
- Jira::Resource::Foo.should_receive(:build).with(client, attrs)
34
- subject.build(attrs)
35
- end
36
- end
@@ -1,292 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Jira::Resource::Base do
4
-
5
- class Jira::Resource::Deadbeef < Jira::Resource::Base ; end
6
-
7
- let(:client) { mock() }
8
- let(:attrs) { mock() }
9
-
10
- subject { Jira::Resource::Deadbeef.new(client, :attrs => attrs) }
11
-
12
- it "assigns the client and attrs" do
13
- subject.client.should == client
14
- subject.attrs.should == attrs
15
- end
16
-
17
- it "returns all the deadbeefs" do
18
- response = mock()
19
- response.should_receive(:body).and_return('[{"self":"http://deadbeef/","key":"FOO"}]')
20
- client.should_receive(:get).with('/jira/rest/api/2/deadbeef').and_return(response)
21
- Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
22
- deadbeefs = Jira::Resource::Deadbeef.all(client)
23
- deadbeefs.length.should == 1
24
- first = deadbeefs.first
25
- first.class.should == Jira::Resource::Deadbeef
26
- first.attrs['self'].should == 'http://deadbeef/'
27
- first.attrs['key'].should == 'FOO'
28
- first.expanded?.should be_false
29
- end
30
-
31
- it "finds a deadbeef by key" do
32
- response = mock()
33
- response.stub(:body).and_return('{"self":"http://deadbeef/","key":"FOO"}')
34
- client.should_receive(:get).with('/jira/rest/api/2/deadbeef/FOO').and_return(response)
35
- Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
36
- deadbeef = Jira::Resource::Deadbeef.find(client, 'FOO')
37
- deadbeef.client.should == client
38
- deadbeef.attrs['self'].should == 'http://deadbeef/'
39
- deadbeef.attrs['key'].should == 'FOO'
40
- deadbeef.expanded?.should be_true
41
- end
42
-
43
- it "builds a deadbeef" do
44
- deadbeef = Jira::Resource::Deadbeef.build(client, 'key' => "FOO" )
45
- deadbeef.expanded?.should be_false
46
-
47
- deadbeef.client.should == client
48
- deadbeef.attrs['key'].should == 'FOO'
49
- end
50
-
51
- it "returns the endpoint name" do
52
- subject.class.endpoint_name.should == 'deadbeef'
53
- end
54
-
55
-
56
- describe "rest_base_path" do
57
-
58
- before(:each) do
59
- client.should_receive(:options).and_return(:rest_base_path => '/deadbeef/bar')
60
- end
61
-
62
- it "returns the rest_base_path" do
63
- subject.rest_base_path.should == '/deadbeef/bar/deadbeef'
64
- end
65
-
66
- it "has a class method that returns the rest_base_path" do
67
- subject.class.rest_base_path(client).should == '/deadbeef/bar/deadbeef'
68
- end
69
- end
70
-
71
- it "parses json" do
72
- described_class.parse_json('{"foo":"bar"}').should == {"foo" => "bar"}
73
- end
74
-
75
- describe "dynamic instance methods" do
76
-
77
- let(:attrs) { {'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy'} }
78
- subject { Jira::Resource::Deadbeef.new(client, :attrs => attrs) }
79
-
80
- it "responds to each of the top level attribute names" do
81
- subject.should respond_to(:foo)
82
- subject.should respond_to('flum')
83
- subject.should respond_to(:object_id)
84
-
85
- subject.foo.should == 'bar'
86
- subject.flum.should == 'goo'
87
-
88
- # Should not override existing method names, but should still allow
89
- # access to their values via the attrs[] hash
90
- subject.object_id.should_not == 'dummy'
91
- subject.attrs['object_id'].should == 'dummy'
92
- end
93
- end
94
-
95
- describe "fetch" do
96
-
97
- subject { Jira::Resource::Deadbeef.new(client, :attrs => {'key' => 'FOO'}) }
98
-
99
- describe "not cached" do
100
-
101
- before(:each) do
102
- response = mock()
103
- response.stub(:body).and_return('{"self":"http://deadbeef/","key":"FOO"}')
104
- client.should_receive(:get).with('/jira/rest/api/2/deadbeef/FOO').and_return(response)
105
- Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
106
- end
107
-
108
- it "sets expanded to true after fetch" do
109
- subject.expanded?.should be_false
110
- subject.fetch
111
- subject.expanded?.should be_true
112
- end
113
-
114
- it "performs a fetch" do
115
- subject.expanded?.should be_false
116
- subject.fetch
117
- subject.self.should == "http://deadbeef/"
118
- subject.key.should == "FOO"
119
- end
120
-
121
- it "performs a fetch if already fetched and force flag is true" do
122
- subject.expanded = true
123
- subject.fetch(true)
124
- end
125
-
126
- end
127
-
128
- describe "cached" do
129
- it "doesn't perform a fetch if already fetched" do
130
- subject.expanded = true
131
- client.should_not_receive(:get)
132
- subject.fetch
133
- end
134
- end
135
-
136
- end
137
-
138
- describe "save" do
139
-
140
- let(:response) { mock() }
141
-
142
- subject { Jira::Resource::Deadbeef.new(client) }
143
-
144
- before(:each) do
145
- subject.should_receive(:url).and_return('/foo/bar')
146
- end
147
-
148
- it "POSTs a new record" do
149
- response.stub(:body => '{"id":"123"}')
150
- subject.stub(:new_record? => true)
151
- client.should_receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
152
- subject.save("foo" => "bar").should be_true
153
- subject.id.should == "123"
154
- subject.expanded.should be_false
155
- end
156
-
157
- it "PUTs an existing record" do
158
- response.stub(:body => nil)
159
- subject.stub(:new_record? => false)
160
- client.should_receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
161
- subject.save("foo" => "bar").should be_true
162
- subject.expanded.should be_false
163
- end
164
-
165
- it "merges attrs on save" do
166
- response.stub(:body => nil)
167
- client.should_receive(:post).with('/foo/bar','{"foo":{"fum":"dum"}}').and_return(response)
168
- subject.attrs = {"foo" => {"bar" => "baz"}}
169
- subject.save({"foo" => {"fum" => "dum"}})
170
- subject.foo.should == {"bar" => "baz", "fum" => "dum"}
171
- end
172
-
173
- end
174
-
175
- describe "set_attrs" do
176
- it "merges hashes correctly when clobber is true (default)" do
177
- subject.attrs = {"foo" => {"bar" => "baz"}}
178
- subject.set_attrs({"foo" => {"fum" => "dum"}})
179
- subject.foo.should == {"fum" => "dum"}
180
- end
181
-
182
- it "merges hashes correctly when clobber is false" do
183
- subject.attrs = {"foo" => {"bar" => "baz"}}
184
- subject.set_attrs({"foo" => {"fum" => "dum"}}, false)
185
- subject.foo.should == {"bar" => "baz", "fum" => "dum"}
186
- end
187
- end
188
-
189
- describe "delete" do
190
-
191
- before(:each) do
192
- client.should_receive(:delete).with('/foo/bar')
193
- subject.stub(:url => '/foo/bar')
194
- end
195
-
196
- it "flags itself as deleted" do
197
- subject.deleted?.should be_false
198
- subject.delete
199
- subject.deleted?.should be_true
200
- end
201
-
202
- it "sends a DELETE request" do
203
- subject.delete
204
- end
205
-
206
- end
207
-
208
- describe "new_record?" do
209
-
210
- it "returns true for new_record? when new object" do
211
- subject.attrs.stub(:[]).with('id').and_return(nil)
212
- subject.new_record?.should be_true
213
- end
214
-
215
- it "returns false for new_record? when id is set" do
216
- subject.attrs.stub(:[]).with('id').and_return('123')
217
- subject.new_record?.should be_false
218
- end
219
-
220
- end
221
-
222
- describe 'url' do
223
- it "returns self as the URL if set" do
224
- attrs.stub(:[]).with('self').and_return('http://foo/bar')
225
- subject.url.should == "http://foo/bar"
226
- end
227
-
228
- it "generates the URL from key if self not set" do
229
- attrs.stub(:[]).with('self').and_return(nil)
230
- attrs.stub(:[]).with('key').and_return('FOO')
231
- subject.stub(:rest_base_path => 'http://foo/bar')
232
- subject.url.should == "http://foo/bar/FOO"
233
- end
234
-
235
- it "generates the URL from rest_base_path if self and key not set" do
236
- attrs.stub(:[]).with('self').and_return(nil)
237
- attrs.stub(:[]).with('key').and_return(nil)
238
- subject.stub(:rest_base_path => 'http://foo/bar')
239
- subject.url.should == "http://foo/bar"
240
- end
241
- end
242
-
243
- it "returns the formatted attrs from to_s" do
244
- subject.attrs.stub(:[]).with('foo').and_return('bar')
245
- subject.attrs.stub(:[]).with('dead').and_return('beef')
246
-
247
- subject.to_s.should match(/#<Jira::Resource::Deadbeef:\d+ @attrs=#{attrs.inspect}>/)
248
- end
249
-
250
- it "returns the key attribute" do
251
- subject.class.key_attribute.should == :key
252
- end
253
-
254
- it "converts to json" do
255
- subject.attrs.stub(:to_json => '{"foo":"bar","dead":"beef"}')
256
-
257
- subject.to_json.should == '{"foo":"bar","dead":"beef"}'
258
- end
259
-
260
- describe "extract attrs from response" do
261
-
262
- subject { Jira::Resource::Deadbeef.new(client, :attrs => {}) }
263
-
264
- it "sets the attrs from a response" do
265
- response = mock()
266
- response.stub(:body).and_return('{"foo":"bar"}')
267
-
268
- subject.set_attrs_from_response(response).should == {'foo' => 'bar'}
269
- subject.foo.should == "bar"
270
- end
271
-
272
- it "doesn't clobber existing attrs not in response" do
273
- response = mock()
274
- response.stub(:body).and_return('{"foo":"bar"}')
275
-
276
- subject.attrs = {'flum' => 'flar'}
277
- subject.set_attrs_from_response(response).should == {'foo' => 'bar'}
278
- subject.foo.should == "bar"
279
- subject.flum.should == "flar"
280
- end
281
-
282
- it "handles nil response body" do
283
- response = mock()
284
- response.stub(:body).and_return(nil)
285
-
286
- subject.attrs = {'flum' => 'flar'}
287
- subject.set_attrs_from_response(response).should be_nil
288
- subject.flum.should == 'flar'
289
- end
290
- end
291
-
292
- end