bloomberg_quote 0.0.1

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/.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