securities 1.0.0 → 2.0.0
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/.DS_Store +0 -0
- data/.travis.yml +0 -2
- data/Gemfile +4 -0
- data/Guardfile +10 -0
- data/README.md +46 -59
- data/lib/securities.rb +1 -0
- data/lib/securities/lookup.rb +29 -0
- data/lib/securities/scraper.rb +45 -35
- data/lib/securities/stock.rb +96 -136
- data/lib/securities/version.rb +1 -1
- data/securities.gemspec +1 -0
- data/spec/.DS_Store +0 -0
- data/spec/lookup_spec.rb +22 -0
- data/spec/stock_spec.rb +69 -6
- metadata +27 -4
data/.DS_Store
ADDED
Binary file
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -23,83 +23,70 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
You can get stock information with commands:
|
25
25
|
|
26
|
-
|
27
|
-
my_stocks = Securities::Stock.new('aapl', 'yhoo')
|
28
|
-
|
29
|
-
or
|
30
|
-
|
31
|
-
# Symbol array
|
32
|
-
my_stocks = Securities::Stock.new(["aapl", "yhoo"])
|
33
|
-
|
34
|
-
my_data = my_stocks.history(:start_date => '2012-01-01', :end_date => '2012-02-01', :periods => :weekly)
|
26
|
+
my_stocks = Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-01', :end_date => '2012-02-01', :type => :weekly)
|
35
27
|
|
36
|
-
Optional parameter :
|
28
|
+
Optional parameter :type accepts :daily, :weekly, :monthly, :dividend. If not specified, it defaults to :daily.
|
37
29
|
|
38
30
|
:end_date defaults to Date.today if not specified.
|
39
31
|
|
40
32
|
You can access hash for a single stock with:
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
|
34
|
+
my_stocks.output
|
35
|
+
my_stocks.symbol
|
36
|
+
my_stocks.start_date
|
37
|
+
my_stocks.end_date
|
38
|
+
my_stocks.type
|
45
39
|
|
46
40
|
Output is returned in a hash:
|
47
41
|
|
48
|
-
|
49
|
-
[{:date=>"2012-01-04",
|
50
|
-
:open=>"410.00",
|
51
|
-
:high=>"414.68",
|
52
|
-
:low=>"409.28",
|
53
|
-
:close=>"413.44",
|
54
|
-
:volume=>"9286500",
|
55
|
-
:adj_close=>"411.67"},
|
56
|
-
{:date=>"2012-01-03",
|
42
|
+
[{:date=>"2012-01-03",
|
57
43
|
:open=>"409.40",
|
58
44
|
:high=>"412.50",
|
59
45
|
:low=>"409.00",
|
60
46
|
:close=>"411.23",
|
61
47
|
:volume=>"10793600",
|
62
|
-
:adj_close=>"409.47"}
|
63
|
-
|
64
|
-
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:
|
68
|
-
:
|
69
|
-
:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
48
|
+
:adj_close=>"409.47"},
|
49
|
+
{:date=>"2012-01-04",
|
50
|
+
:open=>"410.00",
|
51
|
+
:high=>"414.68",
|
52
|
+
:low=>"409.28",
|
53
|
+
:close=>"413.44",
|
54
|
+
:volume=>"9286500",
|
55
|
+
:adj_close=>"411.67"}]
|
56
|
+
|
57
|
+
Stock symbol lookup:
|
58
|
+
|
59
|
+
my_lookup = Securities::Lookup.new('Google')
|
60
|
+
|
61
|
+
Returns a hash with matched symbol, name, last trade, type, industry/category, exchange.
|
62
|
+
|
63
|
+
my_lookup.output
|
64
|
+
|
65
|
+
[{:symbol=>"GOOG",
|
66
|
+
:name=>"Google Inc.",
|
67
|
+
:last_trade=>"726.31",
|
68
|
+
:type=>"Stock",
|
69
|
+
:industry_category=>"Internet Information Providers",
|
70
|
+
:exchange=>"NMS"},
|
71
|
+
{:symbol=>"GOOG.MX",
|
72
|
+
:name=>"Google Inc.",
|
73
|
+
:last_trade=>"9,306.00",
|
74
|
+
:type=>"Stock",
|
75
|
+
:industry_category=>"Internet Information Providers",
|
76
|
+
:exchange=>"MEX"},
|
77
|
+
...]
|
78
|
+
|
79
|
+
my_lookup.input returns 'Google'
|
80
|
+
|
81
|
+
# Version 2.0.0
|
82
|
+
|
83
|
+
* Adds support for stock symbol lookup.
|
84
|
+
|
85
|
+
* Removes support for multiple stock input cause it complects the gem code and its implementation without adding much to it.
|
97
86
|
|
98
87
|
## To do:
|
99
88
|
|
100
|
-
* Write specs.
|
101
89
|
* Add quote info (P/E, P/S, etc.)
|
102
|
-
* Add symbol from name lookup.
|
103
90
|
* Add options support.
|
104
91
|
|
105
92
|
## Contributing
|
data/lib/securities.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Securities
|
2
|
+
#
|
3
|
+
# Symbol lookup with Securities::Lookup.new('apple')
|
4
|
+
#
|
5
|
+
class Lookup
|
6
|
+
|
7
|
+
attr_accessor :input, :output
|
8
|
+
# Error handling
|
9
|
+
class LookupException < StandardError ; end
|
10
|
+
|
11
|
+
def initialize parameters
|
12
|
+
@input = parameters.delete(' ')
|
13
|
+
if @input.empty?
|
14
|
+
raise LookupException, 'The lookup input was empty.'
|
15
|
+
end
|
16
|
+
url = generate_lookup_url
|
17
|
+
request = :lookup
|
18
|
+
@output = Securities::Scraper.get(request, url)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def generate_lookup_url
|
24
|
+
url = 'http://finance.yahoo.com/lookup?s=' + @input
|
25
|
+
return url
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/securities/scraper.rb
CHANGED
@@ -2,6 +2,7 @@ require 'active_support/core_ext'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'net/http'
|
4
4
|
require 'csv'
|
5
|
+
require 'nokogiri'
|
5
6
|
|
6
7
|
module Securities
|
7
8
|
#
|
@@ -10,64 +11,73 @@ module Securities
|
|
10
11
|
class Scraper
|
11
12
|
|
12
13
|
# Error handling
|
13
|
-
class ScraperException < StandardError
|
14
|
-
end
|
14
|
+
class ScraperException < StandardError ; end
|
15
15
|
|
16
|
-
def self.get type,
|
16
|
+
def self.get type, url
|
17
|
+
results = Array.new
|
18
|
+
|
19
|
+
# Encoding for bad characters in index names.
|
20
|
+
clean_url = URI::encode(url)
|
21
|
+
uri = URI.parse(clean_url)
|
17
22
|
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
# Check connection.
|
24
|
+
begin
|
25
|
+
get = Net::HTTP.get(uri)
|
26
|
+
rescue => error
|
27
|
+
raise ScraperException, "Connection error: #{error.message}"
|
22
28
|
end
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
parameters.each do |symbol, url|
|
30
|
+
case type
|
31
|
+
#
|
32
|
+
# Scraping for lookup.
|
33
|
+
when :lookup
|
34
|
+
doc = Nokogiri::HTML(get)
|
30
35
|
|
31
|
-
|
36
|
+
table = doc.at('div#yfi_sym_results tbody')
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
get = Net::HTTP.get(uri)
|
36
|
-
rescue => error
|
37
|
-
raise ScraperException, "Connection error: #{error.message}"
|
38
|
+
if table.nil?
|
39
|
+
raise ScraperException, 'There were no results for this lookup.'
|
38
40
|
end
|
39
41
|
|
40
|
-
#
|
42
|
+
# Symbol Name Last Trade Type Industry/Category Exchange
|
43
|
+
table.xpath('tr').each do |tr|
|
44
|
+
row = tr.xpath('td')
|
45
|
+
results << {:symbol => row[0].text,
|
46
|
+
:name => row[1].text,
|
47
|
+
:last_trade => row[2].text,
|
48
|
+
:type => row[3].text,
|
49
|
+
:industry_category => row[4].text,
|
50
|
+
:exchange => row[5].text}
|
51
|
+
end
|
52
|
+
#
|
53
|
+
# Scraping for history
|
54
|
+
when :history
|
55
|
+
# Skip first line because it contains headers with Date,Open,High,Low,Close,Volume,Adj Close.
|
41
56
|
# Check for errors during CSV parsing.
|
42
57
|
begin
|
43
58
|
csv = CSV.parse(get, :headers => true)
|
44
59
|
rescue => error
|
45
|
-
#
|
46
|
-
|
47
|
-
# bug => if exception occurs in one symbol, it will not give any results for any other.
|
48
|
-
# raise ScraperException, "Invalid symbol '#{symbol}' specified."
|
49
|
-
results[symbol] = []
|
50
|
-
next
|
60
|
+
# Probably an invalid symbol specified or there was some other way the parser couldn't read a CSV.
|
61
|
+
raise ScraperException, 'Stock symbol does not exist.'
|
51
62
|
end
|
52
63
|
|
53
|
-
data = Array.new
|
54
64
|
csv.each_with_index do |row, index|
|
55
65
|
line = Hash.new
|
56
66
|
csv.headers.each_with_index do |header, i|
|
57
|
-
# Set headers as keys for data hash.
|
67
|
+
# Set headers as keys for the data hash.
|
58
68
|
line[header.parameterize.underscore.to_sym] = row[i]
|
59
|
-
|
69
|
+
results[index] = line
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
# raise ScraperException, "There were no results for #{symbol}."
|
67
|
-
# end
|
73
|
+
if results.empty?
|
74
|
+
raise ScraperException, 'There were no results for this symbol.'
|
75
|
+
end
|
68
76
|
|
69
|
-
results
|
77
|
+
# Reversing results to return from the oldest to the newest.
|
78
|
+
results = results.reverse
|
70
79
|
end
|
80
|
+
|
71
81
|
return results
|
72
82
|
end
|
73
83
|
|
data/lib/securities/stock.rb
CHANGED
@@ -1,160 +1,120 @@
|
|
1
1
|
module Securities
|
2
2
|
|
3
|
-
# Usage: my_stocks = Securities::Stock.new('aapl', 'yhoo').history(:start_date => '2012-01-01', :end_date => '2012-02-01', :periods => :weekly)
|
4
|
-
# :periods accepts :daily, :weekly, :monthly, :dividend. If not specified, it defaults to :daily.
|
5
|
-
#
|
6
|
-
# You can access hash for a single stock with:
|
7
|
-
# my_stocks["yhoo"]
|
8
|
-
|
9
3
|
class Stock
|
10
4
|
|
11
|
-
attr_accessor :
|
5
|
+
attr_accessor :symbol, :output, :start_date, :end_date, :type
|
12
6
|
# REGEX for YYYY-MM-DD
|
13
7
|
DATE_REGEX = /^[0-9]{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])/
|
14
|
-
|
8
|
+
TYPE_CODES_ARRAY = {:daily => 'd', :weekly => 'w', :monthly => 'm', :dividends => 'v'}
|
15
9
|
|
16
10
|
# Error handling
|
17
|
-
class StockException < StandardError
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize *parameters
|
21
|
-
validate_symbols(parameters)
|
22
|
-
end
|
11
|
+
class StockException < StandardError ; end
|
23
12
|
|
24
|
-
def
|
25
|
-
|
26
|
-
parameters[:
|
27
|
-
validate_history(parameters)
|
28
|
-
urls = generate_history_url(parameters)
|
13
|
+
def initialize parameters
|
14
|
+
validate_input(parameters)
|
15
|
+
@symbol = parameters[:symbol]
|
29
16
|
@start_date = parameters[:start_date]
|
30
17
|
@end_date = parameters[:end_date]
|
31
|
-
@
|
32
|
-
|
18
|
+
@type = parameters[:type]
|
19
|
+
url = generate_history_url
|
20
|
+
request = :history
|
21
|
+
@output = Securities::Scraper.get(request, url)
|
33
22
|
end
|
34
23
|
|
35
24
|
private
|
36
25
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
start_date = parameters[:start_date].to_date
|
63
|
-
end_date = parameters[:end_date].to_date
|
64
|
-
|
65
|
-
periods = case parameters[:periods]
|
66
|
-
when :daily then 'd'
|
67
|
-
when :weekly then 'w'
|
68
|
-
when :monthly then 'm'
|
69
|
-
when :dividends then 'v'
|
70
|
-
end
|
71
|
-
|
72
|
-
results = Hash.new
|
73
|
-
@symbols.each do |symbol|
|
26
|
+
#
|
27
|
+
# History URL generator
|
28
|
+
#
|
29
|
+
# Generating URL for various types of requests within stocks.
|
30
|
+
#
|
31
|
+
# Using Yahoo Finance
|
32
|
+
# http://ichart.finance.yahoo.com/table.csv?s=%s&a=%s&b=%s&c=%s&d=%s&e=%s&f=%s&g=%s&ignore=.csv
|
33
|
+
#
|
34
|
+
# s = stock symbol
|
35
|
+
#
|
36
|
+
# Period start date
|
37
|
+
# a = start month
|
38
|
+
# b = start day
|
39
|
+
# c = start year
|
40
|
+
#
|
41
|
+
# Period end date
|
42
|
+
# d = end month
|
43
|
+
# e = end day
|
44
|
+
# f = end year
|
45
|
+
#
|
46
|
+
# g = type
|
47
|
+
# Type values allowed: 'd' for daily (the default), 'w' for weekly, 'm' for monthly and 'v' for dividends.
|
48
|
+
def generate_history_url
|
49
|
+
|
74
50
|
url = 'http://ichart.finance.yahoo.com/table.csv?s=%s&a=%s&b=%s&c=%s&d=%s&e=%s&f=%s&g=%s&ignore=.csv' % [
|
75
|
-
symbol,
|
76
|
-
start_date.month - 1,
|
77
|
-
start_date.day,
|
78
|
-
start_date.year,
|
79
|
-
end_date.month - 1,
|
80
|
-
end_date.day,
|
81
|
-
end_date.year,
|
82
|
-
|
51
|
+
@symbol,
|
52
|
+
@start_date.to_date.month - 1,
|
53
|
+
@start_date.to_date.day,
|
54
|
+
@start_date.to_date.year,
|
55
|
+
@end_date.to_date.month - 1,
|
56
|
+
@end_date.to_date.day,
|
57
|
+
@end_date.to_date.year,
|
58
|
+
TYPE_CODES_ARRAY[@type]
|
83
59
|
]
|
84
|
-
results[symbol] = url
|
85
|
-
end
|
86
|
-
|
87
|
-
# Returns a hash {'symbol' => 'url'}
|
88
|
-
return results
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
# Input parameters validation
|
93
|
-
#
|
94
|
-
def validate_symbols parameters
|
95
|
-
|
96
|
-
# Reject empty symbol hashes.
|
97
|
-
@symbols = parameters.reject(&:empty?)
|
98
|
-
|
99
|
-
if @symbols.nil?
|
100
|
-
raise StockException, 'You must specify at least one stock symbol.'
|
101
|
-
end
|
102
|
-
|
103
|
-
# FIXME: A kinda hacky way to check if parameters are a nested array (when accepting an array as a symbols argument).
|
104
|
-
# Unnesting an array.
|
105
|
-
@symbols[0].is_a?(Array) ? @symbols = @symbols[0] : nil
|
106
|
-
|
107
|
-
unless @symbols.uniq.length == @symbols.length
|
108
|
-
raise StockException, 'Duplicate stock symbols given.'
|
109
|
-
end
|
110
|
-
end
|
111
60
|
|
112
|
-
|
113
|
-
unless parameters.is_a?(Hash)
|
114
|
-
raise StockException, 'Given parameters have to be a hash.'
|
61
|
+
return url
|
115
62
|
end
|
116
63
|
|
117
|
-
|
118
|
-
|
64
|
+
#
|
65
|
+
# Input parameters validation
|
66
|
+
#
|
67
|
+
|
68
|
+
def validate_input parameters
|
69
|
+
unless parameters.is_a?(Hash)
|
70
|
+
raise StockException, 'Given parameters have to be a hash.'
|
71
|
+
end
|
72
|
+
|
73
|
+
# Check if stock symbol is specified.
|
74
|
+
unless parameters.has_key?(:symbol)
|
75
|
+
raise StockException, 'No stock symbol specified.'
|
76
|
+
end
|
77
|
+
# Check if stock symbol is a string.
|
78
|
+
unless parameters[:symbol].is_a?(String)
|
79
|
+
raise StockException, 'Stock symbol must be a string.'
|
80
|
+
end
|
81
|
+
# Check if stock symbol is valid.
|
82
|
+
unless parameters[:symbol].match('^[a-zA-Z0-9]+$')
|
83
|
+
raise StockException, 'Invalid stock symbol specified.'
|
84
|
+
end
|
85
|
+
|
86
|
+
# Use today date if :end_date is not specified.
|
87
|
+
unless parameters.has_key?(:end_date)
|
88
|
+
parameters[:end_date] = Date.today.strftime("%Y-%m-%d")
|
89
|
+
end
|
90
|
+
|
91
|
+
unless parameters.has_key?(:start_date)
|
92
|
+
raise StockException, 'Start date must be specified.'
|
93
|
+
end
|
94
|
+
|
95
|
+
unless DATE_REGEX.match(parameters[:start_date])
|
96
|
+
raise StockException, 'Invalid start date specified. Format YYYY-MM-DD.'
|
97
|
+
end
|
98
|
+
|
99
|
+
unless DATE_REGEX.match(parameters[:end_date])
|
100
|
+
raise StockException, 'Invalid end date specified. Format YYYY-MM-DD.'
|
101
|
+
end
|
102
|
+
|
103
|
+
unless parameters[:start_date].to_date < parameters[:end_date].to_date
|
104
|
+
raise StockException, 'End date must be greater than the start date.'
|
105
|
+
end
|
106
|
+
|
107
|
+
unless parameters[:start_date].to_date < Date.today
|
108
|
+
raise StockException, 'Start date must not be in the future.'
|
109
|
+
end
|
110
|
+
|
111
|
+
# Set to default :type if key isn't specified.
|
112
|
+
parameters[:type] = :daily if !parameters.has_key?(:type)
|
113
|
+
|
114
|
+
unless TYPE_CODES_ARRAY.has_key?(parameters[:type])
|
115
|
+
raise StockException, 'Invalid type specified.'
|
116
|
+
end
|
119
117
|
end
|
120
118
|
|
121
|
-
unless parameters.has_key?(:start_date)
|
122
|
-
raise StockException, 'Start date must be specified.'
|
123
|
-
end
|
124
|
-
|
125
|
-
unless DATE_REGEX.match(parameters[:start_date])
|
126
|
-
raise StockException, 'Invalid start date specified. Format YYYY-MM-DD.'
|
127
|
-
end
|
128
|
-
|
129
|
-
unless DATE_REGEX.match(parameters[:end_date])
|
130
|
-
raise StockException, 'Invalid end date specified. Format YYYY-MM-DD.'
|
131
|
-
end
|
132
|
-
|
133
|
-
unless parameters[:start_date].to_date < parameters[:end_date].to_date
|
134
|
-
raise StockException, 'End date must be greater than the start date.'
|
135
|
-
end
|
136
|
-
|
137
|
-
unless parameters[:start_date].to_date < Date.today
|
138
|
-
raise StockException, 'Start date must not be in the future.'
|
139
|
-
end
|
140
|
-
|
141
|
-
# Set to default :periods if key isn't specified.
|
142
|
-
parameters[:periods] = :daily if !parameters.has_key?(:periods)
|
143
|
-
|
144
|
-
unless PERIODS_ARRAY.include?(parameters[:periods])
|
145
|
-
raise StockException, 'Invalid periods value specified.'
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
#
|
153
|
-
# The missing hash function
|
154
|
-
# Returns true if all keys are present in hash.
|
155
|
-
#
|
156
|
-
class Hash
|
157
|
-
def has_keys?(*_keys)
|
158
|
-
(_keys - self.keys).empty?
|
159
119
|
end
|
160
120
|
end
|
data/lib/securities/version.rb
CHANGED
data/securities.gemspec
CHANGED
data/spec/.DS_Store
ADDED
Binary file
|
data/spec/lookup_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Securities::Lookup do
|
4
|
+
describe "Lookup" do
|
5
|
+
|
6
|
+
context "should raise an exception if parameter" do
|
7
|
+
it "is empty" do
|
8
|
+
expect { Securities::Lookup.new(' ') }.to raise_error('The lookup input was empty.')
|
9
|
+
end
|
10
|
+
it "got no results" do
|
11
|
+
expect { Securities::Lookup.new('some invalid lookup string') }.to raise_error('There were no results for this lookup.')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "should not raise an exception if parameter" do
|
16
|
+
it "is not empty" do
|
17
|
+
expect { Securities::Lookup.new('Apple') }.not_to raise_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/spec/stock_spec.rb
CHANGED
@@ -1,11 +1,74 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Securities::Stock do
|
4
|
-
describe "
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
describe "Stock" do
|
5
|
+
context "should raise an exception if parameter" do
|
6
|
+
|
7
|
+
it "is a not a hash" do
|
8
|
+
expect { Securities::Stock.new('some values') }.to raise_error('Given parameters have to be a hash.')
|
9
|
+
end
|
10
|
+
|
11
|
+
context "Symbol" do
|
12
|
+
it "is not passed" do
|
13
|
+
expect { Securities::Stock.new(:start_date => '2012-01-01', :end_date => '2012-01-04') }.to raise_error('No stock symbol specified.')
|
14
|
+
end
|
15
|
+
it "is not a string" do
|
16
|
+
expect { Securities::Stock.new(:symbol => ["AAPL", "GOOG"], :start_date => '2012-01-01', :end_date => '2012-01-04') }.to raise_error('Stock symbol must be a string.')
|
17
|
+
end
|
18
|
+
it "is an invalid string" do
|
19
|
+
expect { Securities::Stock.new(:symbol => 'AAPL company', :start_date => '2012-01-01', :end_date => '2012-01-04') }.to raise_error('Invalid stock symbol specified.')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "History" do
|
24
|
+
|
25
|
+
it ":start_date not specified" do
|
26
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :end_date => '2012-01-01', :type => :weekly) }.to raise_error('Start date must be specified.')
|
27
|
+
end
|
28
|
+
it ":start_date or :end_date is invalid" do
|
29
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-50', :end_date => '2012-02-10', :type => :weekly) }.to raise_error('Invalid start date specified. Format YYYY-MM-DD.')
|
30
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-10', :end_date => '2012-02-50', :type => :weekly) }.to raise_error('Invalid end date specified. Format YYYY-MM-DD.')
|
31
|
+
end
|
32
|
+
it ":start_date greater than :end_date" do
|
33
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-10', :end_date => '2012-01-01', :type => :weekly) }.to raise_error('End date must be greater than the start date.')
|
34
|
+
end
|
35
|
+
it ":start_date is in the future" do
|
36
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => (Date.today+1).strftime("%Y-%m-%d"), :type => :weekly) }.to raise_error('End date must be greater than the start date.')
|
37
|
+
end
|
38
|
+
it ":type value is invalid" do
|
39
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-01', :type => :some_invalid_value) }.to raise_error('Invalid type specified.')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "should not raise an exception if parameter" do
|
46
|
+
|
47
|
+
it "is a string" do
|
48
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-01-01', :end_date => '2012-01-04') }.not_to raise_error
|
49
|
+
end
|
50
|
+
it ":end_date is not specified (should default to today)" do
|
51
|
+
expect { @my_stocks = Securities::Stock.new(:symbol => 'AAPL', :start_date => (Date.today-8).strftime("%Y-%m-%d"), :type => :weekly) }.not_to raise_error
|
52
|
+
@my_stocks.end_date.to_date.should eq(Date.today)
|
53
|
+
end
|
54
|
+
it ":type is not specified (defaults to :daily)" do
|
55
|
+
expect { @my_stocks = Securities::Stock.new(:symbol => 'AAPL', :start_date => (Date.today-8).strftime("%Y-%m-%d")) }.not_to raise_error
|
56
|
+
@my_stocks.type.should eq(:daily)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "Scraper" do
|
63
|
+
context "should raise an exception if" do
|
64
|
+
|
65
|
+
it "symbol is invalid" do
|
66
|
+
expect { Securities::Stock.new(:symbol => 'invalidsymbol', :start_date => (Date.today-8).strftime("%Y-%m-%d")) }.to raise_error('Stock symbol does not exist.')
|
67
|
+
end
|
68
|
+
it "there are no results" do
|
69
|
+
expect { Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-01', :end_date => '2012-08-05', :type => :dividends) }.to raise_error('There were no results for this symbol.')
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
10
73
|
end
|
11
74
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: securities
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: rspec
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,18 +66,23 @@ executables: []
|
|
50
66
|
extensions: []
|
51
67
|
extra_rdoc_files: []
|
52
68
|
files:
|
69
|
+
- .DS_Store
|
53
70
|
- .gitignore
|
54
71
|
- .rspec
|
55
72
|
- .travis.yml
|
56
73
|
- Gemfile
|
74
|
+
- Guardfile
|
57
75
|
- LICENSE
|
58
76
|
- README.md
|
59
77
|
- Rakefile
|
60
78
|
- lib/securities.rb
|
79
|
+
- lib/securities/lookup.rb
|
61
80
|
- lib/securities/scraper.rb
|
62
81
|
- lib/securities/stock.rb
|
63
82
|
- lib/securities/version.rb
|
64
83
|
- securities.gemspec
|
84
|
+
- spec/.DS_Store
|
85
|
+
- spec/lookup_spec.rb
|
65
86
|
- spec/spec_helper.rb
|
66
87
|
- spec/stock_spec.rb
|
67
88
|
homepage: https://github.com/Nedomas/securities
|
@@ -78,7 +99,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
99
|
version: '0'
|
79
100
|
segments:
|
80
101
|
- 0
|
81
|
-
hash: -
|
102
|
+
hash: -994639684959431574
|
82
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
104
|
none: false
|
84
105
|
requirements:
|
@@ -87,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
108
|
version: '0'
|
88
109
|
segments:
|
89
110
|
- 0
|
90
|
-
hash: -
|
111
|
+
hash: -994639684959431574
|
91
112
|
requirements: []
|
92
113
|
rubyforge_project:
|
93
114
|
rubygems_version: 1.8.24
|
@@ -95,5 +116,7 @@ signing_key:
|
|
95
116
|
specification_version: 3
|
96
117
|
summary: Financial information scraper gem. Uses Yahoo Finance API.
|
97
118
|
test_files:
|
119
|
+
- spec/.DS_Store
|
120
|
+
- spec/lookup_spec.rb
|
98
121
|
- spec/spec_helper.rb
|
99
122
|
- spec/stock_spec.rb
|