yahoo_stock 1.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.
@@ -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