gmoney 0.4.3 → 0.4.4

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.
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{gmoney}
5
- s.version = "0.4.3"
5
+ s.version = "0.4.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Justin Spradlin"]
9
- s.date = %q{2010-03-02}
9
+ s.date = %q{2010-04-13}
10
10
  s.description = %q{A gem for interacting with the Google Finance API}
11
11
  s.email = %q{jspradlin@gmail.com}
12
12
  s.extra_rdoc_files = ["README.rdoc", "lib/extensions/fixnum.rb", "lib/extensions/nil_class.rb", "lib/extensions/string.rb", "lib/gmoney.rb", "lib/gmoney/authentication_request.rb", "lib/gmoney/feed_parser.rb", "lib/gmoney/gf_request.rb", "lib/gmoney/gf_response.rb", "lib/gmoney/gf_service.rb", "lib/gmoney/gf_session.rb", "lib/gmoney/portfolio.rb", "lib/gmoney/portfolio_feed_parser.rb", "lib/gmoney/position.rb", "lib/gmoney/position_feed_parser.rb", "lib/gmoney/transaction.rb", "lib/gmoney/transaction_feed_parser.rb"]
@@ -1,3 +1,5 @@
1
+ # = Fixnum
2
+ # GMoney Fixnum Extensions
1
3
  class Fixnum
2
4
  def portfolio_id
3
5
  self.to_s.portfolio_id
@@ -1,3 +1,5 @@
1
+ # = NilClass
2
+ # GMoney NilClass Extensions
1
3
  class NilClass
2
4
  def blank?
3
5
  respond_to?(:empty?) ? empty? : !self
@@ -1,7 +1,20 @@
1
+ # = String
2
+ # GMoney String Extensions
1
3
  class String
4
+ # = ParseError
5
+ # Incorrect id/url parsing
2
6
  class ParseError < StandardError; end
7
+
8
+ # = PortfolioParseError
9
+ # Incorrect portfolio id/url parsing
3
10
  class PortfolioParseError < ParseError; end
11
+
12
+ # = PositionParseError
13
+ # Incorrect position id/url parsing
4
14
  class PositionParseError < ParseError; end
15
+
16
+ # = TransactionParseError
17
+ # Incorrect transaction id/url parsing
5
18
  class TransactionParseError < ParseError; end
6
19
 
7
20
  @@portfolio_re = /\d+/
@@ -11,7 +24,6 @@ class String
11
24
  @@transaction_re = /\d+\/[a-zA-Z]+:[a-zA-Z]+\/\d+/
12
25
  @@transaction_re_in = /^\d+\/[a-zA-Z]+:[a-zA-Z]+\/\d+$/
13
26
 
14
-
15
27
  def camel_to_us
16
28
  add_us = gsub(/(.)([A-Z][a-z]+)/, '\1_\2')
17
29
  add_us.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase
@@ -26,17 +38,17 @@ class String
26
38
  end
27
39
 
28
40
  def position_feed_id
29
- portfolio = self[self.rindex('portfolios/')+11..index('/positions')-1]
41
+ portfolio = finance_feed_id_helper('portfolios', 11)
30
42
  position = self[rindex('/')+1..-1]
31
43
  "#{portfolio}/#{position}"
32
44
  end
33
45
 
34
46
  def transaction_feed_id
35
- portfolio = self[self.rindex('portfolios/')+11..index('/positions')-1]
36
- position = self[self.rindex('positions/')+10..index('/transactions')-1]
47
+ portfolio = finance_feed_id_helper('portfolios', 11)
48
+ position = finance_feed_id_helper('positions', 10)
37
49
  transaction = self[rindex('/')+1..-1]
38
50
  "#{portfolio}/#{position}/#{transaction}"
39
- end
51
+ end
40
52
 
41
53
  def portfolio_id
42
54
  if self[@@transaction_re_in] || self[@@position_re_in] || self[@@portfolio_re_in]
@@ -70,5 +82,12 @@ class String
70
82
 
71
83
  def blank?
72
84
  respond_to?(:empty?) ? self.strip.empty? : !self
73
- end
85
+ end
86
+
87
+ private
88
+
89
+ def finance_feed_id_helper(finance_object, offset)
90
+ f_objs = finance_object == 'portfolios' ? ['portfolios/', '/positions'] : ['positions/', '/transactions']
91
+ self[self.rindex(f_objs[0])+offset..index(f_objs[1])-1]
92
+ end
74
93
  end
@@ -1,8 +1,7 @@
1
1
  # Justin Spradlin
2
- # www.fiascode.com
2
+ # www.justinspradlin.com
3
3
  # (C) 2010
4
4
 
5
-
6
5
  $:.unshift File.expand_path(File.dirname(__FILE__))
7
6
 
8
7
  require 'date'
@@ -28,7 +27,7 @@ require 'gmoney/transaction'
28
27
  require 'gmoney/transaction_feed_parser'
29
28
 
30
29
  module GMoney
31
- VERSION = '0.4.3'
30
+ VERSION = '0.4.4'
32
31
  GF_URL = "http://finance.google.com/finance"
33
32
  GF_FEED_URL = "#{GF_URL}/feeds/default"
34
33
  GF_PORTFOLIO_FEED_URL = "#{GF_FEED_URL}/portfolios"
@@ -40,8 +39,7 @@ module GMoney
40
39
  BUY = 'Buy'
41
40
  SELL = 'Sell'
42
41
  SELL_SHORT = 'Sell Short'
43
- BUY_TO_COVER = 'Buy to Cover'
44
-
42
+ BUY_TO_COVER = 'Buy to Cover'
45
43
 
46
44
  def self.version
47
45
  VERSION
@@ -1,5 +1,14 @@
1
1
  module GMoney
2
+ # = AuthenticationRequest
3
+ #
4
+ # Authenticates the user's account with Google
5
+ #
2
6
  class AuthenticationRequest
7
+
8
+ # = AuthError
9
+ #
10
+ # Thrown when there is a network or Authentication error.
11
+ #
3
12
  class AuthError < StandardError;end
4
13
 
5
14
  AUTH_URL = 'https://www.google.com/accounts/ClientLogin'
@@ -1,4 +1,9 @@
1
1
  module GMoney
2
+ # = FeedParser
3
+ #
4
+ # Parses Atom feeds that are returned from the Google Finance API
5
+ # and converts its data into Ruby objects.
6
+ #
2
7
  class FeedParser
3
8
  def self.parse_feed(feed, feed_class, options = {:feed_link => true, :symbol => false})
4
9
  doc = REXML::Document.new(feed)
@@ -1,4 +1,8 @@
1
1
  module GMoney
2
+ # = GFRequest
3
+ #
4
+ # Wraps Requests that are sent to Google via GMoney
5
+ #
2
6
  class GFRequest
3
7
  attr_accessor :url, :body, :method, :headers
4
8
 
@@ -11,6 +15,7 @@ module GMoney
11
15
  @method ||= :get
12
16
  @headers ||= {}
13
17
  @headers['GData-Version'] = GF_GOOGLE_DATA_VERSION
18
+ @headers['Authorization'] = "GoogleLogin auth=#{GFSession.auth_token}"
14
19
  end
15
20
  end
16
21
  end
@@ -1,4 +1,8 @@
1
1
  module GMoney
2
+ # = GFResponse
3
+ #
4
+ # Wraps Responses that are received from Google
5
+ #
2
6
  class GFResponse
3
7
  attr_accessor :status_code, :body, :headers
4
8
  end
@@ -3,6 +3,10 @@ require 'net/https'
3
3
  require 'uri'
4
4
 
5
5
  module GMoney
6
+ # = GFService
7
+ #
8
+ # Used to send and receive RESTful request/responses from Google
9
+ #
6
10
  class GFService
7
11
  def self.send_request(request)
8
12
  url = URI.parse(request.url)
@@ -1,4 +1,10 @@
1
1
  module GMoney
2
+
3
+ # = GFSession
4
+ #
5
+ # Holds the authenicated user's token which is need
6
+ # for each request sent to Google
7
+ #
2
8
  class GFSession
3
9
 
4
10
  def self.login(email, password, opts={})
@@ -14,5 +20,10 @@ module GMoney
14
20
  def self.email
15
21
  @email
16
22
  end
23
+
24
+ def self.logout
25
+ @email = nil
26
+ @auth_token = nil
27
+ end
17
28
  end
18
29
  end
@@ -1,7 +1,24 @@
1
1
  module GMoney
2
+ # = Portfolio
3
+ #
4
+ # A Google Finace API Portfolio holds a collection of Positions
5
+ # and their associated Transactions
6
+ #
7
+ # > portfolio = GMoney::Portfolio.new
8
+ # > portfolio.title = "My New Portfolio"
9
+ # > portfolio.save #returns portfolio object
10
+ #
2
11
  class Portfolio
3
- class PortfolioRequestError < StandardError;end
12
+ # = PortfolioRequestError
13
+ # Invalid request actions or identifiers
14
+ class PortfolioRequestError < StandardError;end
15
+
16
+ # = PortfolioDeleteError
17
+ # Invalid delete action or identifier
4
18
  class PortfolioDeleteError < StandardError;end
19
+
20
+ # = PortfolioSaveError
21
+ # Invalid save action or identifier
5
22
  class PortfolioSaveError < StandardError;end
6
23
 
7
24
  attr_accessor :title, :currency_code
@@ -51,7 +68,7 @@ module GMoney
51
68
  url += "?returns=true" if options[:returns]
52
69
  portfolios = []
53
70
 
54
- response = GFService.send_request(GFRequest.new(url, :headers => {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}"}))
71
+ response = GFService.send_request(GFRequest.new(url))
55
72
 
56
73
  if response.status_code == HTTPOK
57
74
  portfolios = PortfolioFeedParser.parse_portfolio_feed(response.body)
@@ -59,7 +76,7 @@ module GMoney
59
76
  raise PortfolioRequestError, response.body
60
77
  end
61
78
 
62
- portfolios.each { |p| p.instance_variable_set("@positions", p.positions(options))} if options[:eager]
79
+ portfolios.each { |port| port.instance_variable_set("@positions", port.positions(options))} if options[:eager]
63
80
 
64
81
  return portfolios[0] if portfolios.size == 1
65
82
 
@@ -77,7 +94,7 @@ module GMoney
77
94
 
78
95
  #Some firewalls block HTTP PUT messages. To get around this, you can include a
79
96
  #X-HTTP-Method-Override: PUT header in a POST request
80
- headers = {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}", "Content-Type" => "application/atom+xml"}
97
+ headers = {"Content-Type" => "application/atom+xml"}
81
98
  headers["X-HTTP-Method-Override"] = "PUT" if @id #if there is already an @id defined then we are updating a portfolio
82
99
 
83
100
  request = GFRequest.new(url, :method => :post, :body => atom_string, :headers => headers)
@@ -97,7 +114,7 @@ module GMoney
97
114
  #X-HTTP-Method-Override: DELETE header in a POST request
98
115
  def self.delete_portfolio(id)
99
116
  url = "#{GF_PORTFOLIO_FEED_URL}/#{id}"
100
- response = GFService.send_request(GFRequest.new(url, :method => :post, :headers => {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}", "X-HTTP-Method-Override" => "DELETE"}))
117
+ response = GFService.send_request(GFRequest.new(url, :method => :post, :headers => {"X-HTTP-Method-Override" => "DELETE"}))
101
118
  raise PortfolioDeleteError, response.body if response.status_code != HTTPOK
102
119
  end
103
120
 
@@ -1,4 +1,8 @@
1
1
  module GMoney
2
+ # = PortfolioFeedParser
3
+ #
4
+ # Parses Portfolio feeds returned from the Google Finance API
5
+ #
2
6
  class PortfolioFeedParser < FeedParser
3
7
  def self.parse_portfolio_feed(portfolio_feed)
4
8
  parse_feed(portfolio_feed, Portfolio)
@@ -1,6 +1,20 @@
1
1
  module GMoney
2
+ # = Position
3
+ #
4
+ # The Google Finace API allows users to view position information
5
+ # for the securities (i.e. Positions) in their portfolios.
6
+ # To read a position use the following code:
7
+ #
8
+ # > positions = GMoney::Position.find(9) #returns all of a user's positions within a given portfolio, i.e. Portfolio "9"
9
+ # > position = GMoney::Position.find("9/NASDAQ:GOOG") #returns a specific position within a given portfolio
10
+ #
2
11
  class Position
12
+ # = PositionRequestError
13
+ # Invalid request actions or identifiers
3
14
  class PositionRequestError < StandardError; end
15
+
16
+ # = PositionDeleteError
17
+ # Invalid delete actions or identifiers
4
18
  class PositionDeleteError < StandardError; end
5
19
 
6
20
  attr_reader :id, :updated, :title, :feed_link, :exchange, :symbol, :shares,
@@ -39,7 +53,7 @@ module GMoney
39
53
  positions = []
40
54
  url += "?returns=true" if options[:returns]
41
55
 
42
- response = GFService.send_request(GFRequest.new(url, :headers => {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}"}))
56
+ response = GFService.send_request(GFRequest.new(url))
43
57
 
44
58
  if response.status_code == HTTPOK
45
59
  positions = PositionFeedParser.parse_position_feed(response.body) if response.status_code == 200
@@ -1,4 +1,8 @@
1
1
  module GMoney
2
+ # = PositionFeedParser
3
+ #
4
+ # Parses Position feeds returned from the Google Finance API
5
+ #
2
6
  class PositionFeedParser < FeedParser
3
7
  def self.parse_position_feed(position_feed)
4
8
  parse_feed(position_feed, Position, {:feed_link => true, :symbol => true})
@@ -1,8 +1,31 @@
1
1
  module GMoney
2
+ # = Transaction
3
+ #
4
+ # The Google Finace API allows for the buying and selling
5
+ # of securities (i.e. Positions) through Transactions. To
6
+ # create a valid Transaction use the following code:
7
+ #
8
+ # > transaction.portfolio = 9 #Must be a valid portfolio id
9
+ # > transaction.ticker = 'nyse:c' #Must be a valid ticker symbol
10
+ # > transaction.type = GMoney::BUY #Must be one of the following: Buy, Sell, Sell Short, Buy to Cover
11
+ # > transaction.save #returns transaction object
12
+ #
2
13
  class Transaction
3
- class TransactionRequestError < StandardError; end
4
- class TransactionDeleteError < StandardError;end
14
+ # = TransactionRequestError
15
+ # Invalid request actions or identifiers
16
+ class TransactionRequestError < StandardError; end
17
+
18
+ # = TransactionDeleteError
19
+ # Invalid delete action or identifier
20
+ class TransactionDeleteError < StandardError;end
21
+
22
+ # = TransactionSaveError
23
+ # Invalid save action or identifier
5
24
  class TransactionSaveError < StandardError;end
25
+
26
+ # = TransactionIdError
27
+ # Don't allow users to modify the portfolio or position of
28
+ # a transaction that has already been created.
6
29
  class TransactionIdError < StandardError;end
7
30
 
8
31
  attr_reader :id, :updated, :title
@@ -28,18 +51,18 @@ module GMoney
28
51
  end
29
52
  end
30
53
 
31
- def portfolio=(p)
54
+ def portfolio=(port)
32
55
  raise TransactionIdError, "You can't modify the portfolio for a Transaction that already has an id" if @id
33
- @portfolio = p
56
+ @portfolio = port
34
57
  end
35
58
 
36
- def ticker=(t)
59
+ def ticker=(tick)
37
60
  raise TransactionIdError, "You can't modify the ticker for a Transaction that already has an id" if @id
38
- @ticker = t
61
+ @ticker = tick
39
62
  end
40
63
 
41
64
  def self.find(id, options={})
42
- find_by_url("#{GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}", options)
65
+ find_by_url(transaction_url(id), options)
43
66
  end
44
67
 
45
68
  def save
@@ -58,7 +81,7 @@ module GMoney
58
81
  def self.find_by_url(url, options={})
59
82
  transactions = []
60
83
 
61
- response = GFService.send_request(GFRequest.new(url, :headers => {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}"}))
84
+ response = GFService.send_request(GFRequest.new(url))
62
85
 
63
86
  if response.status_code == HTTPOK
64
87
  transactions = TransactionFeedParser.parse_transaction_feed(response.body)
@@ -75,8 +98,7 @@ module GMoney
75
98
  #To overcome this problem the google doc say to use a post request with
76
99
  #the X-HTTP-Method-Override set to "DELETE"
77
100
  def self.delete_transaction(id)
78
- url = "#{GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}"
79
- response = GFService.send_request(GFRequest.new(url, :method => :post, :headers => {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}", "X-HTTP-Method-Override" => "DELETE"}))
101
+ response = GFService.send_request(GFRequest.new(transaction_url(id), :method => :post, :headers => {"X-HTTP-Method-Override" => "DELETE"}))
80
102
  raise TransactionDeleteError, response.body if response.status_code != HTTPOK
81
103
  end
82
104
 
@@ -101,7 +123,7 @@ module GMoney
101
123
 
102
124
  #Some firewalls block HTTP PUT messages. To get around this, you can include a
103
125
  #X-HTTP-Method-Override: PUT header in a POST request
104
- headers = {"Authorization" => "GoogleLogin auth=#{GFSession.auth_token}", "Content-Type" => "application/atom+xml"}
126
+ headers = {"Content-Type" => "application/atom+xml"}
105
127
  headers["X-HTTP-Method-Override"] = "PUT" if @id #if there is already an @id defined then we are updating a transaction
106
128
 
107
129
  request = GFRequest.new(url, :method => :post, :body => atom_string, :headers => headers)
@@ -125,7 +147,11 @@ module GMoney
125
147
  [BUY, SELL, SELL_SHORT, BUY_TO_COVER].include?(@type)
126
148
  end
127
149
 
128
- private :save_transaction, :is_valid_transaction?, :is_valid_transaction_type?
150
+ def transaction_url(id)
151
+ "#{GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}"
152
+ end
153
+
154
+ private :save_transaction, :is_valid_transaction?, :is_valid_transaction_type?, :transaction_url
129
155
  private_class_method :find_by_url, :delete_transaction
130
156
  end
131
157
  end
@@ -1,4 +1,8 @@
1
1
  module GMoney
2
+ # = TransactionFeedParser
3
+ #
4
+ # Parses Transaction feeds returned from the Google Finance API
5
+ #
2
6
  class TransactionFeedParser < FeedParser
3
7
  def self.parse_transaction_feed(transaction_feed)
4
8
  parse_feed(transaction_feed, Transaction, {:feed_link => false})
@@ -14,7 +14,7 @@ describe GMoney::Portfolio do
14
14
  @url = "#{GMoney::GF_URL}/feeds/default/portfolios"
15
15
 
16
16
  @gf_request = GMoney::GFRequest.new(@url)
17
- @gf_request.method = :get
17
+ @gf_request.method = :get
18
18
 
19
19
  @gf_response = GMoney::GFResponse.new
20
20
  @gf_response.status_code = 200
@@ -198,10 +198,8 @@ describe GMoney::Portfolio do
198
198
  lambda { portfolio.save }.should raise_error(GMoney::Portfolio::PortfolioSaveError, 'A Portfolio with this name already exists.')
199
199
  end
200
200
 
201
- def portfolio_helper(url, id = nil, options = {})
202
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
203
-
204
- GMoney::GFRequest.should_receive(:new).with(url, :headers => {"Authorization" => "GoogleLogin auth=toke"}).and_return(@gf_request)
201
+ def portfolio_helper(url, id = nil, options = {})
202
+ GMoney::GFRequest.should_receive(:new).with(url).and_return(@gf_request)
205
203
 
206
204
  GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
207
205
 
@@ -215,10 +213,8 @@ describe GMoney::Portfolio do
215
213
  portfolios = id ? GMoney::Portfolio.find(id, options) : GMoney::Portfolio.all(options)
216
214
  end
217
215
 
218
- def portfolio_delete_helper(url)
219
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
220
-
221
- GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :headers => {"Authorization" => "GoogleLogin auth=toke", "X-HTTP-Method-Override" => "DELETE"}).and_return(@gf_request)
216
+ def portfolio_delete_helper(url)
217
+ GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :headers => {"X-HTTP-Method-Override" => "DELETE"}).and_return(@gf_request)
222
218
 
223
219
  GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
224
220
  end
@@ -229,11 +225,9 @@ describe GMoney::Portfolio do
229
225
 
230
226
  atom_string = "<?xml version='1.0'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:gf='http://schemas.google.com/finance/2007' xmlns:gd='http://schemas.google.com/g/2005'><title type='text'>#{title}</title> <gf:portfolioData currencyCode='#{currency_code}'/></entry>"
231
227
 
232
- url = portfolio.id ? portfolio.id : GMoney::GF_PORTFOLIO_FEED_URL
233
-
234
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
228
+ url = portfolio.id ? portfolio.id : GMoney::GF_PORTFOLIO_FEED_URL
235
229
 
236
- headers = {"Authorization" => "GoogleLogin auth=toke", "Content-Type" => "application/atom+xml"}
230
+ headers = {"Content-Type" => "application/atom+xml"}
237
231
  headers["X-HTTP-Method-Override"] = "PUT" if portfolio.id
238
232
 
239
233
  GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :body => atom_string, :headers => headers).and_return(@gf_request)
@@ -144,12 +144,10 @@ describe GMoney::Position do
144
144
  end
145
145
 
146
146
  def position_helper(id, options = {})
147
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
148
-
149
147
  url = "#{GMoney::GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}"
150
148
  send_url = options[:returns] ? (url + '?returns=true') : url
151
149
 
152
- GMoney::GFRequest.should_receive(:new).with(send_url, :headers => {"Authorization" => "GoogleLogin auth=toke"}).and_return(@gf_request)
150
+ GMoney::GFRequest.should_receive(:new).with(send_url).and_return(@gf_request)
153
151
 
154
152
  GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
155
153
 
@@ -18,7 +18,7 @@ describe GMoney::GFRequest do
18
18
 
19
19
  it "should be able to take header parameters as a Hash" do
20
20
  gfrequest_with_header_hash = GMoney::GFRequest.new('http://someurl.com', {:headers => {:header1 => 'some header'}})
21
- gfrequest_with_header_hash.headers.should == {:header1 => 'some header', "GData-Version" => 2}
21
+ gfrequest_with_header_hash.headers.should == {:header1 => 'some header', "GData-Version" => 2, "Authorization" => "GoogleLogin auth="}
22
22
  end
23
23
 
24
24
  it "should not accept random options" do
@@ -123,6 +123,7 @@ describe GMoney::GFService do
123
123
  def set_header_expectations(req)
124
124
  req.should_receive(:[]=).with(:h1, "header 1").any_number_of_times
125
125
  req.should_receive(:[]=).with(:h2, "header 2").any_number_of_times
126
- req.should_receive(:[]=).with("GData-Version", 2).any_number_of_times
126
+ req.should_receive(:[]=).with("GData-Version", 2).any_number_of_times
127
+ req.should_receive(:[]=).with("Authorization", "GoogleLogin auth=").any_number_of_times
127
128
  end
128
129
  end
@@ -29,4 +29,23 @@ describe GMoney::GFSession do
29
29
  GMoney::GFSession.login('email@example.com', 'password')
30
30
  GMoney::GFSession.email.should be_eql('email@example.com')
31
31
  end
32
+
33
+ it "should allow users to logout" do
34
+ @auth_request.should_receive(:auth_token).with({}).and_return('toke')
35
+
36
+ GMoney::AuthenticationRequest.should_receive(:new).with('email@example.com', 'password').once.and_return(@auth_request)
37
+ GMoney::GFSession.login('email@example.com', 'password')
38
+
39
+ GMoney::GFSession.email.should be_eql('email@example.com')
40
+ GMoney::GFSession.auth_token.should be_eql('toke')
41
+
42
+ GMoney::GFSession.logout
43
+
44
+ GMoney::GFSession.email.should be_nil
45
+ GMoney::GFSession.auth_token.should be_nil
46
+ end
47
+
48
+ after(:all) do
49
+ GMoney::GFSession.logout
50
+ end
32
51
  end
@@ -268,13 +268,21 @@ describe GMoney::Transaction do
268
268
  lambda { transaction.save }.should raise_error(GMoney::Transaction::TransactionSaveError, "Some of the values submitted are not valid and have been ignored.")
269
269
 
270
270
  end
271
+
272
+ it "should create a url out of a Portfolio id" do
273
+ #Set methods to public visibility for testing
274
+ GMoney::Transaction.send(:public, *GMoney::Transaction.private_instance_methods)
275
+ trans = GMoney::Transaction.new
276
+ transaction_string = trans.transaction_url("123/NASDAQ:GOOG/23")
277
+ transaction_string.should be_eql("#{GMoney::GF_PORTFOLIO_FEED_URL}/123/positions/NASDAQ:GOOG/transactions/23")
278
+ end
271
279
 
272
280
  def transaction_helper(id, options={})
273
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
274
-
275
281
  url = "#{GMoney::GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}"
276
282
 
277
- GMoney::GFRequest.should_receive(:new).with(url, :headers => {"Authorization" => "GoogleLogin auth=toke"}).and_return(@gf_request)
283
+ GMoney::Transaction.should_receive(:transaction_url).with(id).and_return(url)
284
+
285
+ GMoney::GFRequest.should_receive(:new).with(url).and_return(@gf_request)
278
286
 
279
287
  GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
280
288
 
@@ -282,9 +290,9 @@ describe GMoney::Transaction do
282
290
  end
283
291
 
284
292
  def transaction_delete_helper(url)
285
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
293
+ GMoney::Transaction.should_receive(:transaction_url).and_return(url)
286
294
 
287
- GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :headers => {"Authorization" => "GoogleLogin auth=toke", "X-HTTP-Method-Override" => "DELETE"}).and_return(@gf_request)
295
+ GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :headers => {"X-HTTP-Method-Override" => "DELETE"}).and_return(@gf_request)
288
296
 
289
297
  GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
290
298
  end
@@ -304,9 +312,7 @@ describe GMoney::Transaction do
304
312
 
305
313
  url = transaction.id ? transaction.id : "#{GMoney::GF_PORTFOLIO_FEED_URL}/#{transaction.portfolio}/positions/#{transaction.ticker}/transactions"
306
314
 
307
- GMoney::GFSession.should_receive(:auth_token).and_return('toke')
308
-
309
- headers = {"Authorization" => "GoogleLogin auth=toke", "Content-Type" => "application/atom+xml"}
315
+ headers = {"Content-Type" => "application/atom+xml"}
310
316
  headers["X-HTTP-Method-Override"] = "PUT" if transaction.id
311
317
 
312
318
  GMoney::GFRequest.should_receive(:new).with(url, :method => :post, :body => atom_string, :headers => headers).and_return(@gf_request)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gmoney
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Spradlin
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-03-02 00:00:00 -05:00
12
+ date: 2010-04-13 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15