yahoo_quote 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -4,3 +4,4 @@
4
4
  Gemfile.lock
5
5
  extras/
6
6
  pkg/*
7
+ test/cache/
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Braulio Carreno
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,43 @@
1
+ # yahoo_quote
2
+
3
+ Easy interaction with Yahoo Finance API
4
+
5
+ ## Installation
6
+
7
+ gem install yahoo_quote
8
+
9
+ ## Usage
10
+
11
+ ```ruby
12
+ require 'yahoo_quote'
13
+ quote = YahooQuote::Quote.new('AAPL', ['Name', 'Last Trade (Price Only)', 'P/E Ratio'])
14
+ quote.valid?
15
+ # => true
16
+ quote.data['Name']
17
+ # => "Apple Inc."
18
+ quote.data['Last Trade (Price Only)']
19
+ # => 502.12
20
+ quote.data['P/E Ratio']
21
+ # => 14.29
22
+ quote = YahooQuote::Quote.new('ECOMMERCE', ['Name', 'Last Trade (Price Only)', 'P/E Ratio'])
23
+ quote.valid?
24
+ # => false
25
+ ```
26
+
27
+ To get list of supported fields:
28
+
29
+ ```ruby
30
+ puts quote.field_mappings.keys
31
+ ````
32
+
33
+ ## Configuration
34
+
35
+ Use /tmp to keep a simple cache:
36
+
37
+ ```ruby
38
+ YahooQuote::Configuration.cache_dir = "/tmp"
39
+ ```
40
+
41
+ ## Copyright
42
+
43
+ Copyright (c) 2012 Braulio Carreno. See LICENSE for details.
data/lib/yahoo_quote.rb CHANGED
@@ -23,9 +23,45 @@ module YahooQuote
23
23
  def initialize(symbol, fields)
24
24
  @symbol = symbol.gsub(".", '') # yahoo csv expects no periods
25
25
  @fields = fields
26
+ # used by validate method
27
+ @fields << "Market Capitalization" unless @fields.include? "Market Capitalization"
28
+ pull_data
26
29
  end
27
30
 
31
+ def valid?
32
+ return false unless @data
33
+ @data.size > 0
34
+ end
35
+
36
+ def data
37
+ @data.nil? ? {} : @data
38
+ end
39
+
40
+ def cache_response?
41
+ YahooQuote::Configuration.cache_dir
42
+ end
43
+
44
+ def filename_quote
45
+ YahooQuote::Configuration.cache_dir + "/#{@symbol}.csv"
46
+ end
47
+
48
+ def quote_url
49
+ tags = @fields.map{|x| field_mappings[x]}.join
50
+ "http://download.finance.yahoo.com/d/quotes.csv?s=#{@symbol}&f=#{tags}"
51
+ end
52
+
53
+ def graph_url
54
+ return nil unless valid?
55
+ "http://chart.finance.yahoo.com/z?s=#{@symbol}&t=1y&q=&l=&z=l&p=s&a=v&p=s&lang=en-US&region=US"
56
+ end
57
+
58
+ # Not working any longer
59
+ # def company_name_url
60
+ # "http://query.yahooapis.com/v1/public/yql?q=select%20CompanyName%20from%20yahoo.finance.stocks%20where%20symbol%3D%22#{@symbol}%22&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
61
+ # end
62
+
28
63
  def field_mappings
64
+ # From http://cliffngan.net/a/13
29
65
  {
30
66
  "1 yr Target Price" => "t8",
31
67
  "200-day Moving Average" => "m4",
@@ -115,36 +151,11 @@ module YahooQuote
115
151
  }
116
152
  end
117
153
 
118
- def parse_csv(csv)
119
- values = CSV.parse_line(csv)
120
- # TODO check result.size == fields.size
121
- response = {}
122
- values.each_with_index {|value, i| response[@fields[i]] = value}
123
- response
124
- end
154
+ private
125
155
 
126
- def validate(response)
127
- # Yahoo returns company name even if ticker symbol is invalid, other
128
- # fields are also populated.
129
- response["Market Capitalization"] == 'N/A' ? {} : response
130
- end
131
-
132
- # def company_name_url
133
- # "http://query.yahooapis.com/v1/public/yql?q=select%20CompanyName%20from%20yahoo.finance.stocks%20where%20symbol%3D%22#{@symbol}%22&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
134
- # end
135
-
136
- def quote_url
137
- tags = @fields.map{|x| field_mappings[x]}.join
138
- "http://download.finance.yahoo.com/d/quotes.csv?s=#{@symbol}&f=#{tags}"
139
- end
140
-
141
- def graph_url
142
- return nil unless valid?
143
- "http://chart.finance.yahoo.com/z?s=#{@symbol}&t=1y&q=&l=&z=l&p=s&a=v&p=s&lang=en-US&region=US"
144
- end
145
-
146
- def data
147
- return @data if @data
156
+ def pull_data
157
+ # abort if symbol has a weird character
158
+ return if @symbol.empty? || @symbol =~ /\W/
148
159
 
149
160
  io = URI.parse(quote_url)
150
161
  begin
@@ -153,24 +164,27 @@ module YahooQuote
153
164
  csv = ''
154
165
  end
155
166
  @data = validate(parse_csv(csv))
156
- if cache_response? && valid?
157
- File.open(filename_quote, 'w') {|f| CSV.dump([@data], f) }
158
- elsif cache_response? && File.file?(filename_quote)
159
- @data = (File.open(filename_quote, 'r') {|f| CSV.load(f)}).first
167
+ if cache_response?
168
+ if valid?
169
+ File.open(filename_quote, 'w') {|f| CSV.dump([@data], f) }
170
+ elsif File.file?(filename_quote)
171
+ @data = (File.open(filename_quote, 'r') {|f| CSV.load(f)}).first
172
+ end
160
173
  end
161
- @data
162
- end
163
-
164
- def filename_quote
165
- YahooQuote::Configuration.cache_dir + "/#{@symbol}.csv"
166
174
  end
167
175
 
168
- def valid?
169
- @data && @data.size > 0
176
+ def parse_csv(csv)
177
+ values = CSV.parse_line(csv, :converters => :numeric)
178
+ # TODO check result.size == fields.size
179
+ response = {}
180
+ values.each_with_index {|value, i| response[@fields[i]] = value}
181
+ response
170
182
  end
171
183
 
172
- def cache_response?
173
- YahooQuote::Configuration.cache_dir
184
+ def validate(response)
185
+ # Yahoo csv returns values even if ticker symbol is invalid,
186
+ # use this condition to make sure the response is ok.
187
+ response["Market Capitalization"] == 'N/A' ? {} : response
174
188
  end
175
189
  end
176
190
  end
@@ -3,7 +3,7 @@ module YahooQuote
3
3
 
4
4
  def self.cache_dir=(path)
5
5
  dir = path.to_s
6
- Dir.mkdir(dir) unless File.directory?(dir)
6
+ Dir.mkdir(dir) unless dir.empty? || File.directory?(dir)
7
7
  @@cache_dir = dir
8
8
  end
9
9
 
@@ -1,3 +1,3 @@
1
1
  module YahooQuote
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,9 +1,9 @@
1
1
  HTTP/1.1 200 OK
2
- Date: Mon, 06 Feb 2012 22:33:15 GMT
2
+ Date: Thu, 16 Feb 2012 20:40:05 GMT
3
3
  P3P: policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
4
4
  Cache-Control: private
5
5
  Connection: close
6
6
  Transfer-Encoding: chunked
7
7
  Content-Type: application/octet-stream
8
8
 
9
- "AAPL","Apple Inc.",463.97,432.6B
9
+ "Apple Inc.",503.65,14.16,469.6B
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Thu, 16 Feb 2012 20:51:23 GMT
3
+ P3P: policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
4
+ Cache-Control: private
5
+ Connection: close
6
+ Transfer-Encoding: chunked
7
+ Content-Type: application/octet-stream
8
+
9
+ "ECOMMERCE","ECOMMERCE",N/A
@@ -4,55 +4,65 @@ require 'yahoo_quote'
4
4
  require 'minitest/autorun'
5
5
  require 'fakeweb'
6
6
 
7
- # test error: YahooQuote::Configuration.cache_dir = "/etc/kk"
8
- #
7
+ # TODO test 2 things: make intermediate dirs for cache and permissions
8
+
9
9
  class TestYahooQuote < MiniTest::Unit::TestCase
10
10
  def setup
11
+ @url_regexp = %r(http://download\.finance\.yahoo\.com/d/quotes\.csv\?)
12
+ FakeWeb.allow_net_connect = false
13
+ FakeWeb.register_uri(:get, @url_regexp, :response => File.read("test/fakeweb/aapl_good.csv"))
14
+
11
15
  # TODO make gem method to clear the cache
12
16
  `rm -f /tmp/*csv`
13
17
  end
14
18
 
15
- def test_live_quote
16
- quote = YahooQuote::Quote.new('CSCO', ['Symbol', 'Name'])
17
- assert_equal "CSCO", quote.data["Symbol"]
18
- assert_equal "Cisco Systems, In", quote.data["Name"]
19
+ def test_empty_arguments
20
+ quote = YahooQuote::Quote.new('', [])
21
+ assert_equal false, quote.valid?
22
+ assert_nil quote.data["Symbol"]
23
+ assert_nil quote.data["Name"]
19
24
  end
20
25
 
21
- def test_invalid_ticker_symbol
22
- quote = YahooQuote::Quote.new('ECOMMERCE', ['Symbol', 'Name', 'Market Capitalization'])
26
+ def test_bad_symbol
27
+ quote = YahooQuote::Quote.new('C A', ['Symbol', 'Name'])
28
+ assert_equal false, quote.valid?
29
+ assert_nil quote.data["Symbol"]
23
30
  assert_nil quote.data["Name"]
31
+ end
32
+
33
+ def test_non_existing_company
34
+ FakeWeb.register_uri(:get, @url_regexp, :response => File.read("test/fakeweb/ecommerce.csv"))
35
+ quote = YahooQuote::Quote.new('ECOMMERCE', ['Symbol', 'Name'])
24
36
  assert_equal false, quote.valid?
25
- # TODO check no cached
37
+ assert_nil quote.data["Symbol"]
38
+ assert_nil quote.data["Name"]
26
39
  end
27
40
 
28
- def test_get_quote
29
- quote = YahooQuote::Quote.new('AAPL', ['Symbol', 'Name', 'Last Trade (Price Only)', 'Market Capitalization'])
30
- FakeWeb.register_uri(:get, quote.quote_url, :response => File.read('test/fakeweb/aapl.csv'))
41
+ def test_good_quote
42
+ quote = YahooQuote::Quote.new('AAPL', ['Name', 'Last Trade (Price Only)', 'P/E Ratio'])
31
43
  assert_equal "Apple Inc.", quote.data["Name"]
32
- assert_equal 463.97, quote.data["Last Trade (Price Only)"].to_f
33
- assert_equal '432.6B', quote.data["Market Capitalization"]
44
+ assert_equal 503.65, quote.data["Last Trade (Price Only)"]
45
+ assert_equal 14.16, quote.data["P/E Ratio"]
34
46
  end
35
47
 
36
48
  def test_graph_url
37
- quote = YahooQuote::Quote.new('AAPL', ['Symbol', 'Name', 'Last Trade (Price Only)', 'Market Capitalization'])
38
- FakeWeb.register_uri(:get, quote.quote_url, :response => File.read('test/fakeweb/aapl.csv'))
39
- # TODO this should not be necessary
40
- assert_equal "Apple Inc.", quote.data["Name"]
49
+ quote = YahooQuote::Quote.new('AAPL', [])
50
+ assert quote.valid?
41
51
  assert_match %r(^http://chart.finance.yahoo.com/z\?s=AAPL), quote.graph_url
42
52
  end
43
53
 
44
54
  def test_get_quote_from_cache
45
- YahooQuote::Configuration.cache_dir = "/tmp"
46
- quote = YahooQuote::Quote.new('AAPL', ['Symbol', 'Name', 'Last Trade (Price Only)'])
47
- FakeWeb.register_uri(:get, quote.quote_url, :response => File.read('test/fakeweb/aapl.csv'))
55
+ YahooQuote::Configuration.cache_dir = "test/cache"
56
+ quote = YahooQuote::Quote.new('AAPL', ['Name', 'Last Trade (Price Only)', 'P/E Ratio'])
57
+ assert File.file? "test/cache/AAPL.csv"
48
58
  assert_equal "Apple Inc.", quote.data["Name"]
49
- assert_equal 463.97, quote.data["Last Trade (Price Only)"].to_f
50
- # the quote should be cached now
51
- quote2 = YahooQuote::Quote.new('AAPL', ['Symbol', 'Name', 'Last Trade (Price Only)'])
52
- response = File.read('test/fakeweb/aapl_bad.csv')
53
- refute_match /Apple/i, response
54
- FakeWeb.register_uri(:get, quote2.quote_url, :response => response)
55
- assert_equal "Apple Inc.", quote2.data["Name"]
56
- assert_equal 463.97, quote2.data["Last Trade (Price Only)"].to_f
59
+ assert_equal 503.65, quote.data["Last Trade (Price Only)"]
60
+ bad_response = File.read('test/fakeweb/aapl_bad.csv')
61
+ refute_match /Apple/i, bad_response
62
+ FakeWeb.register_uri(:get, @url_regexp, :response => bad_response)
63
+ cached_quote = YahooQuote::Quote.new('AAPL', ['Name', 'Last Trade (Price Only)', 'P/E Ratio'])
64
+ assert_equal "Apple Inc.", cached_quote.data["Name"]
65
+ assert_equal 503.65, cached_quote.data["Last Trade (Price Only)"]
66
+ YahooQuote::Configuration.cache_dir = nil
57
67
  end
58
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yahoo_quote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-08 00:00:00.000000000Z
12
+ date: 2012-02-20 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fakeweb
16
- requirement: &2157063640 !ruby/object:Gem::Requirement
16
+ requirement: &2153635380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2157063640
24
+ version_requirements: *2153635380
25
25
  description: Facilitates querying Yahoo Finance stock API
26
26
  email:
27
27
  - bcarreno@yahoo.com
@@ -31,14 +31,15 @@ extra_rdoc_files: []
31
31
  files:
32
32
  - .gitignore
33
33
  - Gemfile
34
- - README
34
+ - LICENSE.txt
35
+ - README.markdown
35
36
  - Rakefile
36
- - lib/old_yahoo_quote.rb
37
37
  - lib/yahoo_quote.rb
38
38
  - lib/yahoo_quote/configuration.rb
39
39
  - lib/yahoo_quote/version.rb
40
- - test/fakeweb/aapl.csv
41
40
  - test/fakeweb/aapl_bad.csv
41
+ - test/fakeweb/aapl_good.csv
42
+ - test/fakeweb/ecommerce.csv
42
43
  - test/yahoo_quote_test.rb
43
44
  - yahoo_quote.gemspec
44
45
  homepage: https://github.com/bcarreno/yahoo_quote
@@ -66,6 +67,7 @@ signing_key:
66
67
  specification_version: 3
67
68
  summary: Yahoo Finance stock quotes
68
69
  test_files:
69
- - test/fakeweb/aapl.csv
70
70
  - test/fakeweb/aapl_bad.csv
71
+ - test/fakeweb/aapl_good.csv
72
+ - test/fakeweb/ecommerce.csv
71
73
  - test/yahoo_quote_test.rb
data/README DELETED
@@ -1 +0,0 @@
1
- Gem to interact with Yahoo Finance API
@@ -1,141 +0,0 @@
1
- require 'csv'
2
- require 'open-uri'
3
- require 'nokogiri'
4
-
5
- # Gets company name, quote and stock graph
6
- # See http://cliffngan.net/a/13
7
- #
8
- class YahooQuote
9
- attr_accessor :name, :data, :csv, :command
10
-
11
- def initialize(symbol)
12
- @symbol = symbol.gsub(".", '') # yahoo csv expects no periods
13
- parse_csv
14
- end
15
-
16
- def parse_csv
17
- # abort if symbol has a weird character
18
- if @symbol =~ /\W/
19
- return
20
- end
21
- keys = "snl1j1s1wvre7e8r6r7"
22
- @command = %Q|curl -sL "http://finance.yahoo.com/d/quotes.csv?s=#@symbol&f=#{keys}" |
23
- @csv ||= %x[ #{@command} ]
24
- @data = CSV.parse_line @csv
25
- @symbol, @name = *@data
26
- end
27
-
28
- def valid?
29
- return false unless @data
30
- @data[3] != "N/A"
31
- end
32
-
33
- def company_name_orig
34
- valid? ? name : nil
35
- end
36
-
37
- def company_name
38
- return unless valid?
39
- return @company_name if @company_name
40
- res = `curl -Ls "http://query.yahooapis.com/v1/public/yql?q=select%20CompanyName%20from%20yahoo.finance.stocks%20where%20symbol%3D%22#{@symbol}%22&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"`
41
- @company_name = Nokogiri::XML.parse(res).at("//CompanyName").inner_text
42
- rescue
43
- "No company name found"
44
- end
45
-
46
- def day_graph_url
47
- return nil unless valid?
48
- "http://ichart.finance.yahoo.com/t?s=#@symbol"
49
- end
50
-
51
- # the year graph
52
- def graph_url
53
- return nil unless valid?
54
- "http://chart.finance.yahoo.com/z?s=#{@symbol}&t=1y&q=&l=&z=l&p=s&a=v&p=s&lang=en-US&region=US"
55
- end
56
-
57
- def graph_header
58
- return nil unless valid?
59
- url = "http://ichart.finance.yahoo.com/t?s=#@symbol"
60
- url + "\n" + `curl -sI "#{url}"`
61
- end
62
- end
63
-
64
- if __FILE__ == $0
65
- puts ARGV.first
66
- y = YahooQuote.new ARGV.first
67
- puts y.name
68
- puts y.company_name
69
- puts y.csv.inspect
70
- puts y.data.inspect
71
-
72
- end
73
-
74
-
75
- __END__
76
-
77
-
78
- Usage
79
-
80
- y = YahooQuote.new("AMZN")
81
- puts y.name
82
- puts y.data.inspect
83
- puts y.valid?
84
-
85
- exit
86
-
87
- # try a nonexisting symbol
88
-
89
- y = YahooQuote.new("Alwkjlkwadj")
90
- puts y.name
91
- puts y.data.inspect
92
- puts y.valid?
93
-
94
-
95
-
96
-
97
-
98
-
99
- url = "http://finance.yahoo.com/d/quotes.csv?s=AMZN&f=snd1l1yr"
100
- puts `curl -sL '#{url}'`
101
-
102
- url = "http://finance.yahoo.com/d/quotes.csv?s=AMZN&f=snd1l1yr"
103
- puts `curl -sL '#{url}'`
104
-
105
- url = "http://ichart.finance.yahoo.com/t?s=%5AMZN"
106
- #puts `curl -sL '#{url}'` # => outputs a png file
107
-
108
-
109
-
110
- "XOM","Exxon Mobil Corpo","7/8/2011",82.42,2.17,11.73
111
- "BBD-B.TO","BOMBARDIER INC., ","7/8/2011",6.76,1.12,15.60
112
- "JNJ","Johnson & Johnson","7/8/2011",67.57,3.22,15.40
113
- "MSFT","Microsoft Corpora","7/8/2011",26.92,2.28,10.64
114
-
115
-
116
- 2nd query:
117
-
118
- "<img border=0 width=512 height=288
119
- src="http://chart.yahoo.com/c/AMZN/a/amzn.gif" alt="Chart"><br><table><tr><td width=512 align=center><font face=arial size=-1></font></td></tr></table>"
120
-
121
-
122
-
123
- "AMZN","Amazon.com, Inc.","7/8/2011",218.28,N/A,93.87
124
- "MSFT","Microsoft Corpora","7/8/2011",26.92,2.28,10.64
125
- "&nbsp;======&nbsp;"
126
-
127
-
128
- "AMZN","Amazon.com, Inc.","7/8/2011",218.28,N/A,93.87
129
- "MSFT","Microsoft Corpora","7/8/2011",26.92,2.28,10.64
130
-
131
- "AMZN","Amazon.com, Inc.","7/8/2011",218.28,N/A,93.87
132
- "MSFT","Microsoft Corpora","7/8/2011",26.92,2.28,10.64
133
- "<img border=0 width=512 height=288
134
- src="http://chart.yahoo.com/c//m/msft.gif" alt="Chart"><br><table><tr><td width=512 align=center><font face=arial size=-1></font></td></tr></table>","MSFT"
135
-
136
- http://ichart.finance.yahoo.com/t?s=%5EHSI
137
-
138
- "AMZN","Amazon.com, Inc.","7/8/2011",218.28,N/A,93.87
139
- "MSFT","Microsoft Corpora","7/8/2011",26.92,2.28,10.64
140
-
141
-