jspradlin-gmoney 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest +42 -0
- data/README.rdoc +29 -0
- data/Rakefile +25 -0
- data/gmoney.gemspec +30 -0
- data/lib/extensions/string.rb +10 -0
- data/lib/gmoney.rb +39 -0
- data/lib/gmoney/authentication_request.rb +52 -0
- data/lib/gmoney/feed_parser.rb +37 -0
- data/lib/gmoney/gf_request.rb +15 -0
- data/lib/gmoney/gf_response.rb +5 -0
- data/lib/gmoney/gf_service.rb +46 -0
- data/lib/gmoney/gf_session.rb +18 -0
- data/lib/gmoney/portfolio.rb +34 -0
- data/lib/gmoney/portfolio_feed_parser.rb +7 -0
- data/lib/gmoney/position.rb +33 -0
- data/lib/gmoney/position_feed_parser.rb +7 -0
- data/lib/gmoney/transaction.rb +21 -0
- data/lib/gmoney/transaction_feed_parser.rb +9 -0
- data/spec/authentication_request_spec.rb +101 -0
- data/spec/fixtures/cacert.pem +67 -0
- data/spec/fixtures/default_portfolios_feed.xml +45 -0
- data/spec/fixtures/empty_portfolio_feed.xml +24 -0
- data/spec/fixtures/portfolio_9_feed.xml +25 -0
- data/spec/fixtures/portfolio_feed_with_returns.xml +69 -0
- data/spec/fixtures/positions_feed_for_portfolio_14.xml +13 -0
- data/spec/fixtures/positions_feed_for_portfolio_9.xml +63 -0
- data/spec/fixtures/positions_feed_for_portfolio_9r.xml +130 -0
- data/spec/fixtures/transactions_feed_for_GOOG.xml +78 -0
- data/spec/gmoney_spec.rb +9 -0
- data/spec/portfolio_feed_parser_spec.rb +41 -0
- data/spec/portfolio_spec.rb +96 -0
- data/spec/position_feed_parser_spec.rb +39 -0
- data/spec/position_spec.rb +80 -0
- data/spec/request_spec.rb +29 -0
- data/spec/response_spec.rb +18 -0
- data/spec/service_spec.rb +127 -0
- data/spec/session_spec.rb +32 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/string_spec.rb +40 -0
- data/spec/transaction_feed_parser_spec.rb +29 -0
- data/spec/transaction_spec.rb +46 -0
- metadata +114 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8'?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gf='http://schemas.google.com/finance/2007' xmlns:gd='http://schemas.google.com/g/2005'>
|
3
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions</id>
|
4
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
5
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
6
|
+
<title type='text'>GMoney Test</title>
|
7
|
+
<link rel='alternate' type='text/html' href='http://finance.google.com/finance/portfolio?action=view&pid=9' />
|
8
|
+
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions' />
|
9
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions?returns=true' />
|
10
|
+
<openSearch:totalResults>5</openSearch:totalResults>
|
11
|
+
<openSearch:startIndex>1</openSearch:startIndex>
|
12
|
+
<openSearch:itemsPerPage>5</openSearch:itemsPerPage>
|
13
|
+
<entry>
|
14
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:JAVA</id>
|
15
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
16
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
17
|
+
<title type='text'>Sun Microsystems, Inc.</title>
|
18
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AJAVA' />
|
19
|
+
<gd:feedLink href='http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:JAVA/transactions' />
|
20
|
+
<gf:positionData gainPercentage='0.1182926829' return1w='-0.01967213115' return1y='0.09390243902' return3m='0.09390243902' return3y='0.09390243902' return4w='0.09390243902' return5y='0.09390243902' returnOverall='0.09390243902'
|
21
|
+
returnYTD='0.09390243902' shares='75.0'>
|
22
|
+
<gf:costBasis>
|
23
|
+
<gd:money amount='615.0' currencyCode='USD' />
|
24
|
+
</gf:costBasis>
|
25
|
+
<gf:daysGain>
|
26
|
+
<gd:money amount='0.0' currencyCode='USD' />
|
27
|
+
</gf:daysGain>
|
28
|
+
<gf:gain>
|
29
|
+
<gd:money amount='72.75' currencyCode='USD' />
|
30
|
+
</gf:gain>
|
31
|
+
<gf:marketValue>
|
32
|
+
<gd:money amount='687.75' currencyCode='USD' />
|
33
|
+
</gf:marketValue>
|
34
|
+
</gf:positionData>
|
35
|
+
<gf:symbol exchange='NASDAQ' fullName='Sun Microsystems, Inc.' symbol='JAVA' />
|
36
|
+
</entry>
|
37
|
+
<entry>
|
38
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG</id>
|
39
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
40
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
41
|
+
<title type='text'>Google Inc.</title>
|
42
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG' />
|
43
|
+
<gd:feedLink href='http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions' />
|
44
|
+
<gf:positionData gainPercentage='0.1788764045' return1w='-0.002048558422' return1y='0.1494506866' return3m='0.1494506866' return3y='0.1494506866' return4w='0.1494506866' return5y='0.1494506866' returnOverall='0.1494506866' returnYTD='0.1494506866'
|
45
|
+
shares='75.0'>
|
46
|
+
<gf:costBasis>
|
47
|
+
<gd:money amount='30037.5' currencyCode='USD' />
|
48
|
+
</gf:costBasis>
|
49
|
+
<gf:daysGain>
|
50
|
+
<gd:money amount='90.0009' currencyCode='USD' />
|
51
|
+
</gf:daysGain>
|
52
|
+
<gf:gain>
|
53
|
+
<gd:money amount='5373.0' currencyCode='USD' />
|
54
|
+
</gf:gain>
|
55
|
+
<gf:marketValue>
|
56
|
+
<gd:money amount='35410.5' currencyCode='USD' />
|
57
|
+
</gf:marketValue>
|
58
|
+
</gf:positionData>
|
59
|
+
<gf:symbol exchange='NASDAQ' fullName='Google Inc.' symbol='GOOG' />
|
60
|
+
</entry>
|
61
|
+
<entry>
|
62
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:AAPL</id>
|
63
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
64
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
65
|
+
<title type='text'>Apple Inc.</title>
|
66
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AAAPL' />
|
67
|
+
<gd:feedLink href='http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:AAPL/transactions' />
|
68
|
+
<gf:positionData gainPercentage='0.7216' return1w='0.01086254477' return1y='0.7216' return3m='0.7216' return3y='0.7216' return4w='0.7216' return5y='0.7216' returnOverall='0.7216' returnYTD='0.7216' shares='100.0'>
|
69
|
+
<gf:costBasis>
|
70
|
+
<gd:money amount='10000.0' currencyCode='USD' />
|
71
|
+
</gf:costBasis>
|
72
|
+
<gf:daysGain>
|
73
|
+
<gd:money amount='-39.9994' currencyCode='USD' />
|
74
|
+
</gf:daysGain>
|
75
|
+
<gf:gain>
|
76
|
+
<gd:money amount='7216.0' currencyCode='USD' />
|
77
|
+
</gf:gain>
|
78
|
+
<gf:marketValue>
|
79
|
+
<gd:money amount='17216.0' currencyCode='USD' />
|
80
|
+
</gf:marketValue>
|
81
|
+
</gf:positionData>
|
82
|
+
<gf:symbol exchange='NASDAQ' fullName='Apple Inc.' symbol='AAPL' />
|
83
|
+
</entry>
|
84
|
+
<entry>
|
85
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:ORCL</id>
|
86
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
87
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
88
|
+
<title type='text'>Oracle Corporation</title>
|
89
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AORCL' />
|
90
|
+
<gd:feedLink href='http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:ORCL/transactions' />
|
91
|
+
<gf:positionData gainPercentage='0.143' return1w='0.04050978607' return1y='0.143' return3m='0.143' return3y='0.143' return4w='0.143' return5y='0.143' returnOverall='0.143' returnYTD='0.143' shares='75.0'>
|
92
|
+
<gf:costBasis>
|
93
|
+
<gd:money amount='1500.0' currencyCode='USD' />
|
94
|
+
</gf:costBasis>
|
95
|
+
<gf:daysGain>
|
96
|
+
<gd:money amount='7.5' currencyCode='USD' />
|
97
|
+
</gf:daysGain>
|
98
|
+
<gf:gain>
|
99
|
+
<gd:money amount='214.5' currencyCode='USD' />
|
100
|
+
</gf:gain>
|
101
|
+
<gf:marketValue>
|
102
|
+
<gd:money amount='1714.5' currencyCode='USD' />
|
103
|
+
</gf:marketValue>
|
104
|
+
</gf:positionData>
|
105
|
+
<gf:symbol exchange='NASDAQ' fullName='Oracle Corporation' symbol='ORCL' />
|
106
|
+
</entry>
|
107
|
+
<entry>
|
108
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NYSE:IBM</id>
|
109
|
+
<updated>2009-09-12T16:20:13.000Z</updated>
|
110
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#position' />
|
111
|
+
<title type='text'>International Business Machines Corp.</title>
|
112
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NYSE%3AIBM' />
|
113
|
+
<gd:feedLink href='http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NYSE:IBM/transactions' />
|
114
|
+
<gf:positionData gainPercentage='0.1805' return1w='-0.07894176741' return1y='0.081875' return3m='0.081875' return3y='0.081875' return4w='0.081875' return5y='0.081875' returnOverall='0.081875' returnYTD='0.081875' shares='75.0'>
|
115
|
+
<gf:costBasis>
|
116
|
+
<gd:money amount='7500.0' currencyCode='USD' />
|
117
|
+
</gf:costBasis>
|
118
|
+
<gf:daysGain>
|
119
|
+
<gd:money amount='28.500375' currencyCode='USD' />
|
120
|
+
</gf:daysGain>
|
121
|
+
<gf:gain>
|
122
|
+
<gd:money amount='1353.75' currencyCode='USD' />
|
123
|
+
</gf:gain>
|
124
|
+
<gf:marketValue>
|
125
|
+
<gd:money amount='8853.75' currencyCode='USD' />
|
126
|
+
</gf:marketValue>
|
127
|
+
</gf:positionData>
|
128
|
+
<gf:symbol exchange='NYSE' fullName='International Business Machines Corp.' symbol='IBM' />
|
129
|
+
</entry>
|
130
|
+
</feed>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8'?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gf='http://schemas.google.com/finance/2007' xmlns:gd='http://schemas.google.com/g/2005'>
|
3
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions</id>
|
4
|
+
<updated>2009-09-12T18:22:44.000Z</updated>
|
5
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#transaction' />
|
6
|
+
<title type='text'>Google Inc.</title>
|
7
|
+
<link rel='alternate' type='text/html' href='http://finance.google.com/finance/portfolio?action=viewt&pid=9' />
|
8
|
+
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions' />
|
9
|
+
<link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions' />
|
10
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions' />
|
11
|
+
<openSearch:totalResults>4</openSearch:totalResults>
|
12
|
+
<openSearch:startIndex>1</openSearch:startIndex>
|
13
|
+
<openSearch:itemsPerPage>4</openSearch:itemsPerPage>
|
14
|
+
<entry>
|
15
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions/2</id>
|
16
|
+
<updated>2009-09-12T18:22:44.000Z</updated>
|
17
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#transaction' />
|
18
|
+
<title type='text'>2</title>
|
19
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/2' />
|
20
|
+
<link rel='edit' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/2' />
|
21
|
+
<gf:transactionData date='2009-09-01T00:00:00.000' shares='100.0' type='Buy'>
|
22
|
+
<gf:commission>
|
23
|
+
<gd:money amount='50.0' currencyCode='USD' />
|
24
|
+
</gf:commission>
|
25
|
+
<gf:price>
|
26
|
+
<gd:money amount='400.0' currencyCode='USD' />
|
27
|
+
</gf:price>
|
28
|
+
</gf:transactionData>
|
29
|
+
</entry>
|
30
|
+
<entry>
|
31
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions/10</id>
|
32
|
+
<updated>2009-09-12T18:22:44.000Z</updated>
|
33
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#transaction' />
|
34
|
+
<title type='text'>10</title>
|
35
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/10' />
|
36
|
+
<link rel='edit' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/10' />
|
37
|
+
<gf:transactionData date='2009-09-07T00:00:00.000' notes='Buy some more Google.' shares='100.0' type='Buy'>
|
38
|
+
<gf:commission>
|
39
|
+
<gd:money amount='12.75' currencyCode='USD' />
|
40
|
+
</gf:commission>
|
41
|
+
<gf:price>
|
42
|
+
<gd:money amount='425.0' currencyCode='USD' />
|
43
|
+
</gf:price>
|
44
|
+
</gf:transactionData>
|
45
|
+
</entry>
|
46
|
+
<entry>
|
47
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions/11</id>
|
48
|
+
<updated>2009-09-12T18:22:44.000Z</updated>
|
49
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#transaction' />
|
50
|
+
<title type='text'>11</title>
|
51
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/11' />
|
52
|
+
<link rel='edit' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/11' />
|
53
|
+
<gf:transactionData date='2009-09-08T00:00:00.000' shares='150.0' type='Buy'>
|
54
|
+
<gf:commission>
|
55
|
+
<gd:money amount='0.0' currencyCode='USD' />
|
56
|
+
</gf:commission>
|
57
|
+
<gf:price>
|
58
|
+
<gd:money amount='425.0' currencyCode='USD' />
|
59
|
+
</gf:price>
|
60
|
+
</gf:transactionData>
|
61
|
+
</entry>
|
62
|
+
<entry>
|
63
|
+
<id>http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAQ:GOOG/transactions/6</id>
|
64
|
+
<updated>2009-09-12T18:22:44.000Z</updated>
|
65
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/finance/2007#transaction' />
|
66
|
+
<title type='text'>6</title>
|
67
|
+
<link rel='self' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/6' />
|
68
|
+
<link rel='edit' type='application/atom+xml' href='http://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ%3AGOOG/transactions/6' />
|
69
|
+
<gf:transactionData date='2009-09-11T00:00:00.000' shares='25.0' type='Sell'>
|
70
|
+
<gf:commission>
|
71
|
+
<gd:money amount='50.0' currencyCode='USD' />
|
72
|
+
</gf:commission>
|
73
|
+
<gf:price>
|
74
|
+
<gd:money amount='427.0' currencyCode='USD' />
|
75
|
+
</gf:price>
|
76
|
+
</gf:transactionData>
|
77
|
+
</entry>
|
78
|
+
</feed>
|
data/spec/gmoney_spec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe GMoney::PortfolioFeedParser do
|
4
|
+
before(:all) do
|
5
|
+
feed = File.read('spec/fixtures/default_portfolios_feed.xml')
|
6
|
+
@portfolios = GMoney::PortfolioFeedParser.parse_portfolio_feed(feed)
|
7
|
+
|
8
|
+
empty_feed = File.read('spec/fixtures/empty_portfolio_feed.xml')
|
9
|
+
@default_portfolios = GMoney::PortfolioFeedParser.parse_portfolio_feed(empty_feed)
|
10
|
+
|
11
|
+
feed_with_returns = File.read('spec/fixtures/portfolio_feed_with_returns.xml')
|
12
|
+
@portfolios_with_returns = GMoney::PortfolioFeedParser.parse_portfolio_feed(feed_with_returns)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should create Portfolio objects out of portfolio feeds" do
|
16
|
+
@portfolios.each do |portfolio|
|
17
|
+
portfolio.should be_instance_of(GMoney::Portfolio)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return an Array of Portfolio objects equal to the size of Portfolio entries" do
|
22
|
+
@portfolios.size.should be_eql(3)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return a default portfolio if the user has not made any of her own" do
|
26
|
+
@default_portfolios.size.should be_eql(1)
|
27
|
+
@default_portfolios[0].title.should be_eql('My Portfolio')
|
28
|
+
@default_portfolios.size.should be_eql(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should create Portfolio objects with valid numeric data types for the returns" do
|
32
|
+
@portfolios_with_returns.each do |portfolio|
|
33
|
+
portfolio.public_methods(false).each do |pm|
|
34
|
+
if !(['id', 'feed_link', 'updated', 'title', 'currency_code', 'positions'].include? pm) && !(pm.include?('='))
|
35
|
+
return_val = portfolio.send(pm)
|
36
|
+
return_val.should be_instance_of(Float) if return_val
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe GMoney::Portfolio do
|
4
|
+
before(:all) do
|
5
|
+
@default_feed = File.read('spec/fixtures/default_portfolios_feed.xml')
|
6
|
+
@feed_with_returns = File.read('spec/fixtures/portfolio_feed_with_returns.xml')
|
7
|
+
@empty_feed = File.read('spec/fixtures/empty_portfolio_feed.xml')
|
8
|
+
@portfolio_9_feed = File.read('spec/fixtures/portfolio_9_feed.xml')
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@url = 'https://finance.google.com/finance/feeds/default/portfolios'
|
13
|
+
|
14
|
+
@gf_request = GMoney::GFRequest.new(@url)
|
15
|
+
@gf_request.method = :get
|
16
|
+
|
17
|
+
@gf_response = GMoney::GFResponse.new
|
18
|
+
@gf_response.status_code = 200
|
19
|
+
@gf_response.body = @default_feed
|
20
|
+
@positions = []
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return all Portfolios when status_code is 200" do
|
24
|
+
@gf_response.body = @default_feed
|
25
|
+
portfolios = portfolio_helper(@url)
|
26
|
+
|
27
|
+
portfolios.size.should be_eql(3)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return a portfolio with returns data is :with_returns == true" do
|
31
|
+
@url = 'https://finance.google.com/finance/feeds/default/portfolios?returns=true'
|
32
|
+
@gf_response.body = @feed_with_returns
|
33
|
+
|
34
|
+
portfolios = portfolio_helper(@url, {:with_returns => true})
|
35
|
+
|
36
|
+
portfolios.size.should be_eql(3)
|
37
|
+
portfolios[0].cost_basis.should be_eql(2500.00)
|
38
|
+
portfolios[0].gain_percentage.should be_eql(28.3636)
|
39
|
+
portfolios[0].return4w.should be_eql(-0.1670616114)
|
40
|
+
|
41
|
+
portfolios[2].cost_basis.should be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should raise an error if the portfolio request does not return an OK status code" do
|
45
|
+
@gf_response.status_code = 404
|
46
|
+
|
47
|
+
lambda { portfolio_helper(@url) }.should raise_error(GMoney::Portfolio::PortfolioRequestError)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return an Array with only the default 'My Portfolio' portfolio when a user does not define his own portfolios" do
|
51
|
+
@gf_response.body = @empty_feed
|
52
|
+
portfolios = portfolio_helper(@url)
|
53
|
+
|
54
|
+
portfolios.size.should be_eql(1)
|
55
|
+
portfolios[0].title.should be_eql('My Portfolio')
|
56
|
+
end
|
57
|
+
|
58
|
+
=begin TODO - create a method that retreives individual portfolios
|
59
|
+
it "should return a specific portfolio is the request a specific portfolio" do
|
60
|
+
@url += '/9'
|
61
|
+
@gf_request.url = @url
|
62
|
+
|
63
|
+
@gf_response.body = @portfolio_9_feed
|
64
|
+
portfolios = portfolio_helper(@url)
|
65
|
+
|
66
|
+
portfolios.size.should be_eql(1)
|
67
|
+
portfolios[0].title.should be_eql('GMoney Test')
|
68
|
+
end
|
69
|
+
=end
|
70
|
+
|
71
|
+
def portfolio_helper(url, options = {})
|
72
|
+
GMoney::GFSession.should_receive(:auth_token).and_return('toke')
|
73
|
+
|
74
|
+
GMoney::GFRequest.should_receive(:new).with(url, :headers => {"Authorization" => "GoogleLogin auth=toke"}).and_return(@gf_request)
|
75
|
+
|
76
|
+
GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
|
77
|
+
|
78
|
+
position_urls = get_position_urls(@gf_response.body)
|
79
|
+
|
80
|
+
position_urls.each do |position_url|
|
81
|
+
GMoney::Position.should_receive(:find_by_url).with(position_url, {:with_returns => options[:with_returns]}).any_number_of_times.and_return(@positions)
|
82
|
+
end
|
83
|
+
|
84
|
+
GMoney::Portfolio.all(options)
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_position_urls(feed)
|
88
|
+
doc = REXML::Document.new(feed)
|
89
|
+
feed_links = []
|
90
|
+
|
91
|
+
doc.elements.each('feed/entry') do |parsed_entry|
|
92
|
+
feed_links << parsed_entry.elements['gd:feedLink'].attributes['href']
|
93
|
+
end
|
94
|
+
feed_links
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe GMoney::PositionFeedParser do
|
4
|
+
before(:all) do
|
5
|
+
feed = File.read('spec/fixtures/positions_feed_for_portfolio_9.xml')
|
6
|
+
@positions = GMoney::PositionFeedParser.parse_position_feed(feed)
|
7
|
+
|
8
|
+
empty_feed = File.read('spec/fixtures/positions_feed_for_portfolio_14.xml')
|
9
|
+
@empty_positions = GMoney::PositionFeedParser.parse_position_feed(empty_feed)
|
10
|
+
|
11
|
+
feed_with_returns = File.read('spec/fixtures/positions_feed_for_portfolio_9r.xml')
|
12
|
+
@positions_with_returns = GMoney::PositionFeedParser.parse_position_feed(feed_with_returns)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should create Position objects out of position feeds" do
|
16
|
+
@positions.each do |position|
|
17
|
+
position.should be_instance_of(GMoney::Position)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return an Array of Position objects equal to the size of Position entries" do
|
22
|
+
@positions.size.should be_eql(5)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return an empty position if the user has not made any of her own" do
|
26
|
+
@default_positions.should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create Position objects with valid numeric data types for the returns" do
|
30
|
+
@positions_with_returns.each do |position|
|
31
|
+
position.public_methods(false).each do |pm|
|
32
|
+
if !(['id', 'feed_link', 'updated', 'title', 'exchange', 'symbol', 'full_name', 'transactions'].include? pm) && !(pm.include?('='))
|
33
|
+
return_val = position.send(pm)
|
34
|
+
return_val.should be_instance_of(Float) if return_val
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe GMoney::Position do
|
4
|
+
before(:all) do
|
5
|
+
@default_feed = File.read('spec/fixtures/positions_feed_for_portfolio_9.xml')
|
6
|
+
@feed_with_returns = File.read('spec/fixtures/positions_feed_for_portfolio_9r.xml')
|
7
|
+
@empty_feed = File.read('spec/fixtures/positions_feed_for_portfolio_14.xml')
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@url = 'https://finance.google.com/finance/feeds/default/portfolios/9/positions'
|
12
|
+
|
13
|
+
@gf_request = GMoney::GFRequest.new(@url)
|
14
|
+
@gf_request.method = :get
|
15
|
+
|
16
|
+
@gf_response = GMoney::GFResponse.new
|
17
|
+
@gf_response.status_code = 200
|
18
|
+
@gf_response.body = @defaul_feed
|
19
|
+
@transactions = []
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return all Positions when status_code is 200" do
|
23
|
+
@gf_response.body = @default_feed
|
24
|
+
positions = position_helper(@url)
|
25
|
+
|
26
|
+
positions.size.should be_eql(5)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return a position with returns data is :with_returns == true" do
|
30
|
+
@gf_response.body = @feed_with_returns
|
31
|
+
|
32
|
+
positions = position_helper(@url, {:with_returns => true})
|
33
|
+
|
34
|
+
positions.size.should be_eql(5)
|
35
|
+
positions[0].cost_basis.should be_eql(615.00)
|
36
|
+
positions[0].gain_percentage.should be_eql(0.1182926829)
|
37
|
+
positions[0].return4w.should be_eql(0.09390243902)
|
38
|
+
|
39
|
+
positions[4].days_gain.should be_eql(28.500375)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should raise an error if the position request does not return an OK status code" do
|
43
|
+
@gf_response.status_code = 404
|
44
|
+
|
45
|
+
lambda { position_helper(@url) }.should raise_error(GMoney::Position::PositionRequestError)
|
46
|
+
end
|
47
|
+
|
48
|
+
=begin TODO - create a method that retreives individual positions
|
49
|
+
it "should return a specific position is the request a specific position" do
|
50
|
+
end
|
51
|
+
=end
|
52
|
+
|
53
|
+
def position_helper(url, options = {})
|
54
|
+
GMoney::GFSession.should_receive(:auth_token).and_return('toke')
|
55
|
+
|
56
|
+
send_url = options[:with_returns] ? (url + '?returns=true') : url
|
57
|
+
|
58
|
+
GMoney::GFRequest.should_receive(:new).with(send_url, :headers => {"Authorization" => "GoogleLogin auth=toke"}).and_return(@gf_request)
|
59
|
+
|
60
|
+
GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
|
61
|
+
|
62
|
+
transaction_urls = get_transaction_urls(@gf_response.body)
|
63
|
+
|
64
|
+
transaction_urls.each do |transaction_url|
|
65
|
+
GMoney::Transaction.should_receive(:find_by_url).with(transaction_url).any_number_of_times.and_return(@transactions)
|
66
|
+
end
|
67
|
+
|
68
|
+
GMoney::Position.find_by_url(url, options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_transaction_urls(feed)
|
72
|
+
doc = REXML::Document.new(feed)
|
73
|
+
feed_links = []
|
74
|
+
|
75
|
+
doc.elements.each('feed/entry') do |parsed_entry|
|
76
|
+
feed_links << parsed_entry.elements['gd:feedLink'].attributes['href']
|
77
|
+
end
|
78
|
+
feed_links
|
79
|
+
end
|
80
|
+
end
|