yahoo_stock 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ module YahooStock
2
+ class Result
3
+
4
+ def initialize(context)
5
+ @context = context
6
+ end
7
+
8
+ def output
9
+ return @context if @context.is_a?(String)
10
+ @context.output
11
+ end
12
+
13
+ def store(filename)
14
+ File.open(filename, 'a') do |f|
15
+ f.write(output)
16
+ f.write("\n")
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module YahooStock
2
+
3
+ # == DESCRIPTION:
4
+ # Parse results to show in an array form
5
+ #
6
+ # == USAGE
7
+ # YahooStock::Result::ArrayFormat.new("data as commma separated values").output
8
+ #
9
+ # Mostly will be used as a separate strategy for formatting results
10
+ class Result::ArrayFormat < Result
11
+
12
+ def initialize(data)
13
+ @data = data
14
+ super(self)
15
+ end
16
+
17
+ def output
18
+ # Some inconsistency happens hence remove quotes
19
+ val = @data.gsub(/\"/,'').split(/\r\n|\n/)
20
+ new_val = []
21
+ val.each {|v| new_val << v.split(',')}
22
+ return new_val
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,37 @@
1
+ module YahooStock
2
+ # == DESCRIPTION:
3
+ # Convert results as an array of key value pairs
4
+ #
5
+ # == USAGE
6
+ # YahooStock::Result::HashFormat.new("data as string"){['array', 'of', 'keys']}.output
7
+ # The number of keys in the block array must be equal to the values expected to be returned
8
+ #
9
+ # Mostly will be used as a separate strategy for formatting results
10
+ class Result::HashFormat < Result
11
+
12
+ def initialize(data, &block)
13
+ @data = YahooStock::Result::ArrayFormat.new(data).output
14
+ @keys = yield
15
+ super(self)
16
+ end
17
+
18
+ def output
19
+ data = []
20
+ @data.each do |datum|
21
+ row_values = {}
22
+ datum.each_with_index do |item, i|
23
+ row_values[keys[i]] = item
24
+ end
25
+ data << row_values
26
+ end
27
+ data
28
+ end
29
+
30
+ def keys
31
+ @keys.collect{|key| key.to_s.gsub(/\s/,'_').downcase.to_sym}
32
+ end
33
+
34
+ end
35
+
36
+
37
+ end
@@ -0,0 +1,61 @@
1
+ module YahooStock
2
+ # == DESCRIPTION:
3
+ #
4
+ # This class provides the ability to find out the stock /scrip symbols for a company used in stock exchanges.
5
+ #
6
+ # It uses Yahoo http://finance.yahoo.com/lookup page to find, screen scrape / parse the returned results.
7
+ #
8
+ # == USAGE:
9
+ #
10
+ # * If you want to use the symbols in your existing code then:
11
+ #
12
+ # symbol = YahooStock::ScripSymbol.new('company name')
13
+ #
14
+ # symbol.find #will return a string
15
+ #
16
+ # symbol.results :to_array, #will return an array of values instead of a string
17
+ #
18
+ # will give you an array of arrays where each outer array is the different option for the company name
19
+ # you provided and the inner array includes stock symbol, full company name, stock price, exchange symbol
20
+ # so that you can decide easily what symbol you can use.
21
+ #
22
+ # * If you just want to print the results on your console screen
23
+ #
24
+ # YahooStock::ScripSymbol.print_options('company name')
25
+ #
26
+ # * If you just want to store the results in file to use it later
27
+ #
28
+ # You can pass in any number of companies in the parameter
29
+ #
30
+ # YahooStock::ScripSymbol.save_options_to_file('path/to/filename','company1', 'company2')
31
+ #
32
+ class ScripSymbol < Base
33
+ # Initialize with the name of the company as parameter for which stock symbol is needed
34
+ #
35
+ # symbol = YahooStock::ScripSymbol.new('company name')
36
+ #
37
+ # symbol.find
38
+
39
+ attr_reader :company
40
+
41
+ def initialize(company_name)
42
+ @company = company_name
43
+ @interface = YahooStock::Interface::ScripSymbol.new(@company)
44
+ end
45
+
46
+ def company=(company)
47
+ @company = @interface.company = company
48
+ end
49
+
50
+ def data_attributes
51
+ ['Symbol', 'Name', 'Last Trade', 'Type', 'Industry Category', 'Exchange']
52
+ end
53
+
54
+ # get stock symbols for multilple companies
55
+ def self.results(*companies)
56
+ res = companies.inject('') { |options, company| options + new(company).results.output + "\n" }
57
+ YahooStock::Result.new(res)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+ require 'spec'
3
+ require 'yahoo_stock'
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe YahooStock::Base do
4
+ before(:each) do
5
+ @interface = stub!('Base')
6
+ @base = YahooStock::Base.new(@interface)
7
+ end
8
+
9
+ describe "find" do
10
+
11
+ it "should get the values from interface" do
12
+ @interface.should_receive(:values)
13
+ @base.find
14
+ end
15
+ end
16
+
17
+ describe "results" do
18
+
19
+ it "should return the results using find" do
20
+ @base.should_receive(:find)
21
+ @base.results
22
+ end
23
+
24
+ it "should yield the block if a block is given" do
25
+ @base.results {"Block to pass, probably, a class with result output method"
26
+ }.should eql('Block to pass, probably, a class with result output method')
27
+ end
28
+
29
+ it "should use the ArrayFormat class for results when :to_array is passed to the results param" do
30
+ @base.stub!(:find)
31
+ YahooStock::Result::ArrayFormat.should_receive(:new)
32
+ @base.results(:to_array)
33
+ end
34
+
35
+ it "should create the YahooStock::Result object when no formatting option is provided" do
36
+ find = stub('find')
37
+ @base.stub!(:find).and_return(find)
38
+ YahooStock::Result.should_receive(:new).with(find)
39
+ @base.results
40
+ end
41
+
42
+ end
43
+ describe "data_attributes" do
44
+ it "should raise an error if the data_attributes is called as this is an abstract method" do
45
+ lambda { @base.data_attributes }.should raise_error(RuntimeError, 'Abstract method called. Use the subclass data_attributes method')
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe YahooStock::History do
4
+
5
+ describe ".new" do
6
+
7
+ it "should raise error when no parameter is passed during object initialization" do
8
+ lambda { YahooStock::History.new
9
+ }.should raise_error(ArgumentError)
10
+ end
11
+
12
+ it "should raise error when the parameter is not a hash" do
13
+ lambda { YahooStock::History.new(nil)
14
+ }.should raise_error(YahooStock::History::HistoryError, 'A hash of start_date, end_date and stock_symbol is expected as parameters')
15
+ end
16
+
17
+ it "should inititalize the history interface" do
18
+ options = {}
19
+ YahooStock::Interface::History.should_receive(:new).with(options)
20
+ YahooStock::History.new({})
21
+ end
22
+
23
+ end
24
+
25
+ describe "find" do
26
+ before(:each) do
27
+ @interface = stub('YahooStock::Interface::History')
28
+ YahooStock::Interface::History.stub!(:new).and_return(@interface)
29
+ @interface.stub!(:values)
30
+ @history = YahooStock::History.new(:stock_symbol => 'a symbol', :start_date => Date.today-3, :end_date => Date.today-1)
31
+ end
32
+
33
+ it "should find values using interface" do
34
+ @interface.should_receive(:values).and_return('data')
35
+ @history.find
36
+ end
37
+
38
+ it "should remove the first line from the data as it is just the headings" do
39
+ data = 'data returned'
40
+ @interface.stub!(:values).and_return(data)
41
+ data.should_receive(:sub).with(/Date.*\s/,'')
42
+ @history.find
43
+ end
44
+ end
45
+
46
+ describe "data_attributes" do
47
+ before(:each) do
48
+ @history = YahooStock::History.new(:stock_symbol => 'a symbol', :start_date => Date.today-3, :end_date => Date.today-1)
49
+ @data = "Date, price, etc \n23, 34, 44\n\n222,234,2"
50
+ @history.stub!(:values_with_header).and_return(@data)
51
+ end
52
+
53
+ it "should return nil if history values are not present" do
54
+ @history.stub!(:values_with_header)
55
+ @history.data_attributes.should eql(nil)
56
+ end
57
+
58
+ it "should return only header values if history values are present" do
59
+ @history.data_attributes.should eql(["Date","price","etc"])
60
+ end
61
+
62
+ end
63
+
64
+ describe "values_with_header" do
65
+
66
+ it "should get values from the interface" do
67
+ @interface = stub('YahooStock::Interface::History')
68
+ YahooStock::Interface::History.stub!(:new).and_return(@interface)
69
+ @history = YahooStock::History.new(:stock_symbol => 'a symbol', :start_date => Date.today-3, :end_date => Date.today-1)
70
+ @interface.should_receive(:values)
71
+ @history.values_with_header
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,317 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe YahooStock::Interface::History do
4
+
5
+ describe ".new" do
6
+
7
+ it "should raise error when no parameter is passed during object initialization" do
8
+ lambda { YahooStock::Interface::History.new
9
+ }.should raise_error(ArgumentError)
10
+ end
11
+
12
+ it "should raise an error if stock symbol key is not present in parameter hash" do
13
+ lambda { YahooStock::Interface::History.new(:start_date => Date.today-7)
14
+ }.should raise_error(YahooStock::Interface::History::HistoryError, ':stock_symbol key is not present in the parameter hash')
15
+ end
16
+
17
+ it "should raise error when stock_symbol value in hash is nil" do
18
+ lambda { YahooStock::Interface::History.new(:stock_symbol => nil)
19
+ }.should raise_error(YahooStock::Interface::History::HistoryError, ':stock_symbol value cannot be nil or blank')
20
+ end
21
+
22
+ it "should raise error when stock_symbol value in hash is blank" do
23
+ lambda { YahooStock::Interface::History.new(:stock_symbol => '')
24
+ }.should raise_error(YahooStock::Interface::History::HistoryError, ':stock_symbol value cannot be nil or blank')
25
+ end
26
+
27
+ it "should raise error when start date key is not present in parameter hash" do
28
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd') }.should raise_error(YahooStock::Interface::History::HistoryError, ':start_date key is not present in the parameter hash')
29
+ end
30
+
31
+ it "should raise error when start_date value is nil" do
32
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd', :start_date => nil) }.should raise_error(YahooStock::Interface::History::HistoryError, ':start_date value cannot be blank')
33
+ end
34
+
35
+ it "should raise error when start_date value is blank" do
36
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd', :start_date => '') }.should raise_error(YahooStock::Interface::History::HistoryError, ':start_date value cannot be blank')
37
+ end
38
+
39
+ it "should raise error when start date value is not of type date" do
40
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd', :start_date => '23/3/2009') }.should raise_error(YahooStock::Interface::History::HistoryError, 'Start date must be of type Date')
41
+ end
42
+
43
+ it "should raise error when end date key is not present in parameter hash" do
44
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd', :start_date => Date.today-1) }.should raise_error(YahooStock::Interface::History::HistoryError, ':end_date key is not present in the parameter hash')
45
+ end
46
+
47
+ it "should raise error when end_date value is nil" do
48
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
49
+ :start_date => Date.today-1,
50
+ :end_date => nil) }.should raise_error(YahooStock::Interface::History::HistoryError, ':end_date value cannot be blank')
51
+ end
52
+
53
+ it "should raise error when end_date value is blank" do
54
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
55
+ :start_date => Date.today-1,
56
+ :end_date => '') }.should raise_error(YahooStock::Interface::History::HistoryError, ':end_date value cannot be blank')
57
+ end
58
+
59
+ it "should raise error when end date value is not of type date" do
60
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
61
+ :start_date => Date.today-1,
62
+ :end_date => 'sds') }.should raise_error(YahooStock::Interface::History::HistoryError, 'End date must be of type Date')
63
+ end
64
+
65
+ it "should raise error when start date is not less than today" do
66
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
67
+ :start_date => Date.today,
68
+ :end_date => Date.today)
69
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'Start date must be in the past')
70
+ end
71
+
72
+ it "should raise error when start date is greater than end date" do
73
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
74
+ :start_date => Date.today-7,
75
+ :end_date => Date.today-8)
76
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'End date must be greater than the start date')
77
+ end
78
+
79
+ it "should not raise error when start date is in the past, end date is greater than start date and all relevant keys are present with right type" do
80
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
81
+ :start_date => Date.today-7,
82
+ :end_date => Date.today-1)
83
+ }.should_not raise_error
84
+
85
+ end
86
+
87
+ it "should by default set interval to daily if no value provided for it" do
88
+ @history = YahooStock::Interface::History.new(:stock_symbol => 'd',
89
+ :start_date => Date.today-7,
90
+ :end_date => Date.today-1)
91
+ @history.interval.should eql(:daily)
92
+ end
93
+
94
+ it "should raise invalid keys error when an invalid key is passed in the parameter" do
95
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
96
+ :start_date => Date.today-7,
97
+ :end_date => Date.today-1, :boom => 1) }.should raise_error(YahooStock::Interface::History::HistoryError, "An invalid key 'boom' is passed in the parameters. Allowed keys are stock_symbol, start_date, end_date, interval")
98
+ end
99
+
100
+ it "should raise error when interval is neither :daily, :weekly or :monthly" do
101
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
102
+ :start_date => Date.today-7,
103
+ :end_date => Date.today-1,
104
+ :interval => :yearly)
105
+ }.should raise_error(YahooStock::Interface::History::HistoryError, "Allowed values for interval are daily, weekly, monthly")
106
+
107
+ end
108
+
109
+ it "should not raise error when interval is :daily" do
110
+ lambda { YahooStock::Interface::History.new(:stock_symbol => 'd',
111
+ :start_date => Date.today-7,
112
+ :end_date => Date.today-1,
113
+ :interval => :daily)
114
+ }.should_not raise_error
115
+
116
+ end
117
+ end
118
+
119
+ describe "setters" do
120
+ before(:each) do
121
+ @history = YahooStock::Interface::History.new(:stock_symbol => 'd',
122
+ :start_date => Date.today-7,
123
+ :end_date => Date.today-1)
124
+ end
125
+
126
+ it "should raise error when stock symbol is being set to nil" do
127
+ lambda { @history.stock_symbol = nil
128
+ }.should raise_error(YahooStock::Interface::History::HistoryError, ':stock_symbol value cannot be nil or blank')
129
+ end
130
+
131
+ it "should raise error when stock symbol is being set to an empty string" do
132
+ lambda { @history.stock_symbol = ''
133
+ }.should raise_error(YahooStock::Interface::History::HistoryError, ':stock_symbol value cannot be nil or blank')
134
+ end
135
+
136
+ it "should set the new stock symbol value when it is valid" do
137
+ @history.stock_symbol = 'new_val'
138
+ @history.stock_symbol.should eql('new_val')
139
+ end
140
+
141
+ it "should raise error when start date type is not a date" do
142
+ lambda { @history.start_date = '21/3/2009'
143
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'Start date must be of type Date')
144
+ end
145
+
146
+ it "should raise error when start date is not in the past" do
147
+ lambda { @history.start_date = Date.today
148
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'Start date must be in the past')
149
+ end
150
+
151
+ it "should set the start date when start date is valid" do
152
+ s_date = Date.today-1
153
+ @history.start_date = s_date
154
+ @history.start_date.should eql(s_date)
155
+ end
156
+
157
+ it "should raise error when end date type is not a date" do
158
+ lambda { @history.end_date = '21/3/2009'
159
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'End date must be of type Date')
160
+ end
161
+
162
+ it "should raise error when end date type is not in the past" do
163
+ lambda { @history.end_date = Date.today
164
+ }.should raise_error(YahooStock::Interface::History::HistoryError, 'End date must be in the past')
165
+ end
166
+
167
+ it "should raise error when end date type is not in the past" do
168
+ e_date = Date.today-1
169
+ @history.end_date = e_date
170
+ @history.end_date.should eql(e_date)
171
+ end
172
+
173
+ it "should raise error when settin interval other than :daily, :monthly or :weekly" do
174
+ lambda { @history.interval = :yearly }.should raise_error(YahooStock::Interface::History::HistoryError)
175
+ end
176
+
177
+ it "should set the interval" do
178
+ @history.interval = :daily
179
+ @history.interval.should eql(:daily)
180
+ end
181
+
182
+ it "should set the interval default to daily if not set" do
183
+ @history.interval.should eql(:daily)
184
+ end
185
+ end
186
+
187
+ describe "uri" do
188
+ before(:each) do
189
+ @history = YahooStock::Interface::History.new(:stock_symbol => 'symbol',
190
+ :start_date => Date.today-7,
191
+ :end_date => Date.today-1)
192
+ end
193
+
194
+ it "should get the interval to generate url" do
195
+ @history.should_receive(:interval)
196
+ @history.uri
197
+ end
198
+
199
+ it "should get the day of the start date" do
200
+ @history.start_date.should_receive(:day)
201
+ @history.uri
202
+ end
203
+
204
+ it "should get the day of the end date" do
205
+ @history.end_date.should_receive(:day)
206
+ @history.uri
207
+ end
208
+
209
+ it "should get the year of the start date" do
210
+ @history.start_date.should_receive(:year)
211
+ @history.uri
212
+ end
213
+
214
+ it "should get the day of the end date" do
215
+ @history.start_date.should_receive(:year)
216
+ @history.uri
217
+ end
218
+
219
+ it "should get the month of the start and end date" do
220
+ @history.should_receive(:sprintf).exactly(2)
221
+ @history.uri
222
+ end
223
+
224
+ it "should have the base url" do
225
+ @history.uri.should =~ /http:\/\/ichart.finance.yahoo.com\/table.csv?/
226
+ end
227
+
228
+ it "should have parameter 'a' with month -1 " do
229
+ month = sprintf("%02d", @history.start_date.month-1)
230
+ @history.uri.should =~ /a=#{month}/
231
+ end
232
+
233
+ it "should have parameter 'b' with start date day " do
234
+ @history.uri.should =~ /b=#{@history.start_date.day}/
235
+ end
236
+
237
+ it "should have parameter 'c' with start date year " do
238
+ @history.uri.should =~ /c=#{@history.start_date.year}/
239
+ end
240
+
241
+ it "should have parameter 'd' with end date month -1 " do
242
+ month = sprintf("%02d", @history.end_date.month-1)
243
+ @history.uri.should =~ /d=#{month}/
244
+ end
245
+
246
+ it "should have parameter 'e' with end date day " do
247
+ @history.uri.should =~ /e=#{@history.end_date.day}/
248
+ end
249
+
250
+ it "should have parameter 'f' with end date year " do
251
+ @history.uri.should =~ /c=#{@history.end_date.year}/
252
+ end
253
+
254
+ it "should have parameter 'g' with interval" do
255
+ @history.uri.should =~ /g=d/
256
+ end
257
+
258
+ it "should have the parameter 's' with stock symbol" do
259
+ @history.uri.should =~ /s=symbol/
260
+ end
261
+
262
+ end
263
+
264
+ describe "get" do
265
+ before(:each) do
266
+ @history = YahooStock::Interface::History.new(:stock_symbol => 'd',
267
+ :start_date => Date.today-7,
268
+ :end_date => Date.today-1)
269
+ response = stub('HTTP')
270
+ Net::HTTP.stub!(:get_response).and_return(response)
271
+ response.stub!(:code).and_return('200')
272
+ response.stub!(:body)
273
+ end
274
+
275
+ it "should check the stock symbol" do
276
+ @history.should_receive(:stock_symbol).times.at_least(2).and_return('symbol')
277
+ @history.get
278
+ end
279
+
280
+ it "should check the end date" do
281
+ @history.should_receive(:end_date).times.at_least(1).and_return(Date.today-1)
282
+ @history.get
283
+ end
284
+
285
+ it "should check the start date" do
286
+ @history.should_receive(:start_date).times.at_least(1).and_return(Date.today-7)
287
+ @history.get
288
+ end
289
+
290
+ it "should raise error if start date is not present" do
291
+ @history.stub!(:start_date)
292
+ lambda { @history.get }.should raise_error('Cannot send request unless all parameters, ie stock_symbol, start and end date are present')
293
+ end
294
+
295
+ it "should raise error if end date is not present" do
296
+ @history.stub!(:end_date)
297
+ lambda { @history.get }.should raise_error('Cannot send request unless all parameters, ie stock_symbol, start and end date are present')
298
+ end
299
+
300
+ it "should raise error if stock symbol is not present" do
301
+ @history.stub!(:stock_symbol)
302
+ lambda { @history.get }.should raise_error('Cannot send request unless all parameters, ie stock_symbol, start and end date are present')
303
+ end
304
+
305
+ it "should send the http request to yahoo" do
306
+ Net::HTTP.should_receive(:get_response)
307
+ @history.get
308
+ end
309
+
310
+ it "should parse the url" do
311
+ URI.should_receive(:parse)
312
+ @history.get
313
+ end
314
+
315
+ end
316
+
317
+ end