bloomberg_quote 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bloomberg_quote.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 MATSUI Shinsuke
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # BloombergQuote
2
+
3
+ BloombergQuote is Ruby module which getting quotes form Bloomberg site
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'bloomberg_quote'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install bloomberg_quote
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ require 'bloomberg_quote'
23
+ # Fetching TOPIX Index quote
24
+ quote = BloombergQuote::Quote.new('TPX:IND')
25
+ quote.valid?
26
+ # => true
27
+ quote.data['Price']
28
+ # => 813.33
29
+ quote.data['Previous Close']
30
+ # => 819.27
31
+ quote.data['Open']
32
+ # => 814.37
33
+ # Fetching DUMMY currency
34
+ quote = BloombergQuote::Quote.new('DUMMY:CUR')
35
+ quote.valid?
36
+ # => false
37
+ ```
38
+
39
+ ## Supported fields
40
+
41
+ - Price
42
+ - Previous Close
43
+ - Open
44
+
45
+ ## FAQ
46
+
47
+ ### Where can I find ticker symbols?
48
+
49
+ You can search them at [Bloomberg](http://www.bloomberg.com/)
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
58
+
59
+ ## Acknowledgement
60
+
61
+ Code and APIs are inspired by [yahoo_quote](https://github.com/bcarreno/yahoo_quote).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "bloomberg_quote/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "bloomberg_quote"
7
+ s.version = BloombergQuote::VERSION
8
+ s.authors = ["MATSUI Shinsuke"]
9
+ s.email = ["poppen.jp@gmail.com"]
10
+ s.homepage = "https://github.com/poppen/bloomberg_quote"
11
+ s.summary = "getting quotes form Bloomberg site"
12
+ s.description = "BloombergQuote is a module which getting quotes form Bloomberg site"
13
+
14
+ s.rubyforge_project = "bloomberg_quote"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "fakeweb"
23
+ s.add_runtime_dependency "nokogiri"
24
+
25
+ # specify any dependencies here; for example:
26
+ # s.add_development_dependency "rspec"
27
+ # s.add_runtime_dependency "rest-client"
28
+ end
@@ -0,0 +1,3 @@
1
+ module BloombergQuote
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,95 @@
1
+ require "bloomberg_quote/version"
2
+ require "open-uri"
3
+ require "nokogiri"
4
+ require "json"
5
+
6
+ module BloombergQuote
7
+ class Quote
8
+ def initialize(symbol)
9
+ @symbol = symbol
10
+ pull_data
11
+ end
12
+
13
+ def valid?
14
+ return false unless @data
15
+ @data.size > 0
16
+ end
17
+
18
+ def data
19
+ @data.nil? ? {} : @data
20
+ end
21
+
22
+ private
23
+ def pull_data
24
+ return if @symbol.empty?
25
+
26
+ case @symbol
27
+ when /:IND\Z/
28
+ pull_index_data
29
+ when /:CUR\Z/
30
+ pull_currency_data
31
+ else
32
+ pull_stock
33
+ end
34
+ end
35
+
36
+ def pull_index_data
37
+ @data = {}
38
+
39
+ fetch_page
40
+ return unless @doc.css('div.ticker_header > span.price').text.
41
+ gsub(',','') =~ /(\d+\.?(?:\d+))/
42
+ @data["Price"] = $1.to_f
43
+
44
+ json = parse_json
45
+ @data["Previous Close"] = json["prev_close"].to_f
46
+ @data["Open"] = json["data_values"][0][1].to_f
47
+ end
48
+
49
+ def pull_currency_data
50
+ @data = {}
51
+
52
+ fetch_page
53
+ return unless @doc.css('div.ticker_header_currency > span.price').
54
+ text =~ /(\d+\.?(?:\d+))/
55
+ @data["Price"] = $1.to_f
56
+
57
+ json = parse_json
58
+ @data["Previous Close"] = json["prev_close"].to_f
59
+ @data["Open"] = json["data_values"][0][1].to_f
60
+ end
61
+
62
+ def pull_stock
63
+ @data = {}
64
+
65
+ fetch_page
66
+ return unless @doc.css('div.ticker_header > span.price').text.
67
+ gsub(',','') =~ /(\d+\.?(?:\d+))/
68
+ @data["Price"] = $1.to_f
69
+
70
+ json = parse_json
71
+ @data["Previous Close"] = json["prev_close"].to_f
72
+ @data["Open"] = json["data_values"][0][1].to_f
73
+ end
74
+
75
+ def parse_json
76
+ inline_scripts = @doc.xpath('//script[not(@src)]').map(&:text)
77
+ inline_scripts.find do |js|
78
+ js =~ /BLOOMBERG\.global_var\.chartData\s+?=\s+?(.+?);/
79
+ end
80
+ JSON.parse($1)
81
+ end
82
+
83
+ def fetch_page
84
+ @doc = Nokogiri::HTML(open_url)
85
+ end
86
+
87
+ def open_url
88
+ open(quote_url)
89
+ end
90
+
91
+ def quote_url
92
+ "http://www.bloomberg.com/quote/#{@symbol}"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+ require 'bloomberg_quote'
3
+ require 'fakeweb'
4
+
5
+ describe BloombergQuote do
6
+ describe 'Indexes' do
7
+ describe '#valid?' do
8
+ context 'when wrong symbol' do
9
+ it { BloombergQuote::Quote.new('DUMMY:IND').valid?.should be_false }
10
+ end
11
+
12
+ context 'when right symbol' do
13
+ it { BloombergQuote::Quote.new('TPX:IND').valid?.should be_true }
14
+ end
15
+ end
16
+
17
+ describe '#data' do
18
+ context 'when wrong symbol' do
19
+ it { BloombergQuote::Quote.new('DUMMY:IND').data.should be_empty }
20
+ end
21
+
22
+ shared_examples_for 'TPX:IND data' do |options|
23
+ subject { BloombergQuote::Quote.new('TPX:IND').data }
24
+ it { should_not be_empty }
25
+ it { should have_key('Price') }
26
+ it { should have_key('Previous Close') }
27
+ it { should have_key('Open') }
28
+ its(['Price']) { should be_instance_of(Float) }
29
+ its(['Previous Close']) { should be_instance_of(Float) }
30
+ its(['Open']) { should be_instance_of(Float) }
31
+
32
+ if options.has_key?(:use_fakeweb) && options[:use_fakeweb]
33
+ its(['Price']) { should == 813.33 }
34
+ its(['Previous Close']) { should == 819.27 }
35
+ its(['Open']) { should == 814.37 }
36
+ end
37
+ end
38
+
39
+ context 'when right symbol' do
40
+ it_should_behave_like 'TPX:IND data', {}
41
+
42
+ describe 'values' do
43
+ before(:all) do
44
+ FakeWeb.register_uri(
45
+ :get, "http://www.bloomberg.com/quote/TPX:IND",
46
+ :body => File.read('spec/fakeweb/tpx.html'))
47
+ end
48
+
49
+ after(:all) do
50
+ FakeWeb.clean_registry
51
+ end
52
+
53
+ it_should_behave_like 'TPX:IND data', :use_fakeweb => true
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ describe 'Currency' do
60
+ describe '#valid?' do
61
+ context 'when wrong symbol' do
62
+ it { BloombergQuote::Quote.new('DUMMY:CUR').valid?.should be_false }
63
+ end
64
+
65
+ context 'when right symbol' do
66
+ it { BloombergQuote::Quote.new('USDJPY:CUR').valid?.should be_true }
67
+ end
68
+ end
69
+
70
+ describe '#data' do
71
+ context 'when wrong symbol' do
72
+ it { BloombergQuote::Quote.new('DUMMY:CUR').data.should be_empty }
73
+ end
74
+
75
+ shared_examples_for 'USDJPY:CUR data' do |options|
76
+ subject { BloombergQuote::Quote.new('USDJPY:CUR').data }
77
+ it { should_not be_empty }
78
+ it { should have_key('Price') }
79
+ it { should have_key('Previous Close') }
80
+ it { should have_key('Open') }
81
+ its(['Price']) { should be_instance_of(Float) }
82
+ its(['Previous Close']) { should be_instance_of(Float) }
83
+ its(['Open']) { should be_instance_of(Float) }
84
+
85
+ if options.has_key?(:use_fakeweb) && options[:use_fakeweb]
86
+ its(['Price']) { should == 81.68 }
87
+ its(['Previous Close']) { should == 81.26 }
88
+ its(['Open']) { should == 81.26 }
89
+ end
90
+ end
91
+
92
+ context 'when right symbol' do
93
+ it_should_behave_like 'USDJPY:CUR data', {}
94
+
95
+ describe 'values' do
96
+ before(:all) do
97
+ FakeWeb.register_uri(
98
+ :get, "http://www.bloomberg.com/quote/USDJPY:CUR",
99
+ :body => File.read('spec/fakeweb/usdjpy.html'))
100
+ end
101
+
102
+ after(:all) do
103
+ FakeWeb.clean_registry
104
+ end
105
+
106
+ it_should_behave_like 'USDJPY:CUR data', :use_fakeweb => true
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe 'Stock' do
113
+ describe '#valid?' do
114
+ context 'when wrong symbol' do
115
+ it { BloombergQuote::Quote.new('DUMMY:JP').valid?.should be_false }
116
+ end
117
+
118
+ context 'when right symbol' do
119
+ it { BloombergQuote::Quote.new('9437:JP').valid?.should be_true }
120
+ it { BloombergQuote::Quote.new('1557:JP').valid?.should be_true }
121
+ end
122
+ end
123
+
124
+ describe '#data' do
125
+ context 'when wrong symbol' do
126
+ it { BloombergQuote::Quote.new('DUMMY:JP').data.should be_empty }
127
+ end
128
+
129
+ shared_examples_for 'stock data' do |symbol, data|
130
+ subject { BloombergQuote::Quote.new(symbol).data }
131
+ it { should_not be_empty }
132
+ it { should have_key('Price') }
133
+ it { should have_key('Previous Close') }
134
+ it { should have_key('Open') }
135
+ its(['Price']) { should be_instance_of(Float) }
136
+ its(['Previous Close']) { should be_instance_of(Float) }
137
+ its(['Open']) { should be_instance_of(Float) }
138
+
139
+ describe 'values' do
140
+ before(:all) do
141
+ FakeWeb.register_uri(
142
+ :get, "http://www.bloomberg.com/quote/#{symbol}",
143
+ :body => File.read("spec/fakeweb/#{symbol}.html"))
144
+ end
145
+
146
+ after(:all) do
147
+ FakeWeb.clean_registry
148
+ end
149
+
150
+ its(['Price']) { should == data[:price] }
151
+ its(['Previous Close']) { should == data[:previous_close] }
152
+ its(['Open']) { should == data[:open] }
153
+ end
154
+ end
155
+
156
+ context 'when right symbol' do
157
+ it_should_behave_like 'stock data', '9437:JP',
158
+ {:price => 136300, :previous_close => 136600, :open => 137100}
159
+
160
+ it_should_behave_like 'stock data', '1557:JP',
161
+ {:price => 11270, :previous_close => 11290, :open => 11420 }
162
+ end
163
+ end
164
+ end
165
+ end