figa 0.0.1 → 0.1.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/README.md +107 -0
  4. data/lib/figa.rb +57 -38
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0730264f5ad57b4adcf105062fa9aa2396710067
4
- data.tar.gz: 882c6230a5d0b42cf50874f78904259f5ba5e820
3
+ metadata.gz: 6711826553277276616030f1bd03f3661fdb4f2d
4
+ data.tar.gz: 839c8010b513be67b475ddc66faab9e046d27b60
5
5
  SHA512:
6
- metadata.gz: ab01ea02cff6dc17a967b4b59e1ee1869b94b419df57ca0fb4090d9df7f3dc787bc66119a62c56726a536e4feec8b956a95388d26591f53345e06685b0ddad19
7
- data.tar.gz: 625d7b5399b4cdf8ee8cabac46990ad147532a634ef8773c4f470c82bd1352b1ff79ee3efde46c01a25ba429f0257e750f98b01fc02d0ce5ba679410bbcea655
6
+ metadata.gz: 7f5710c727d6a221f0d846574ae75d81fe0d51ad8b690480e9c163025b0cf17c61d6bc4c6519158bc1080dae98170555ee33a263bc3696ff4bb0ecc292936750
7
+ data.tar.gz: 1210ffc9cff8af805336b6ec2be04b2c5e2ab2067a1e9369816ed41b25e5720c9d9f1ac17f3c0d576b12a79188a89f2d4f5590aa531d11bf0b8f26f83eb84585
@@ -2,7 +2,14 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
- ## sentofu 0.0.1 released 2019-06-13
5
+ ## figa 0.1.0 released 2019-06-14
6
+
7
+ * Refine Figa::Client #map and #search
8
+ * Provide #next for #search results
9
+ * Use API key if provided to Figa::Client.new
10
+
11
+
12
+ ## figa 0.0.1 released 2019-06-13
6
13
 
7
14
  * Initial release
8
15
 
data/README.md CHANGED
@@ -1,11 +1,118 @@
1
1
 
2
2
  # figa
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/figa.svg)](http://badge.fury.io/rb/figa)
5
+
4
6
  A Ruby library to query [OpenFIGI](https://www.openfigi.com/) API v2.
5
7
 
6
8
 
7
9
  ## usage
8
10
 
11
+ Instantiate a Figa client:
12
+ ```ruby
13
+ client = Figa::Client.new
14
+ #
15
+ # instantiate a client without API key
16
+
17
+ client = Figa::Client.new('321456cd-af64-9932-bcbe-1a2345677999')
18
+ #
19
+ # instantiate a client with an API key
20
+ ```
21
+
22
+ Query for mappings ([/v2/mapping](https://www.openfigi.com/api#post-v2-mapping)):
23
+ ```ruby
24
+ client = Figa::Client.new
25
+
26
+ r = client.map(isin: 'US4592001014')
27
+
28
+ pp r
29
+ # ==>
30
+ # [{"data"=>
31
+ # [{"figi"=>"BBG000BLNNH6",
32
+ # "name"=>"INTL BUSINESS MACHINES CORP",
33
+ # "ticker"=>"IBM",
34
+ # "exchCode"=>"US",
35
+ # "compositeFIGI"=>"BBG000BLNNH6",
36
+ # "uniqueID"=>"EQ0010080100001000",
37
+ # "securityType"=>"Common Stock",
38
+ # "marketSector"=>"Equity",
39
+ # "shareClassFIGI"=>"BBG001S5S399",
40
+ # "uniqueIDFutOpt"=>nil,
41
+ # "securityType2"=>"Common Stock",
42
+ # "securityDescription"=>"IBM"},
43
+ # {"figi"=>"BBG000BLNNV0",
44
+ # "name"=>"INTL BUSINESS MACHINES CORP",
45
+ # "ticker"=>"IBM",
46
+ # "exchCode"=>"UA",
47
+ # "compositeFIGI"=>"BBG000BLNNH6",
48
+ # "uniqueID"=>"EQ0010080100001000",
49
+ # "securityType"=>"Common Stock",
50
+ # "marketSector"=>"Equity",
51
+ # "shareClassFIGI"=>"BBG001S5S399",
52
+ # "uniqueIDFutOpt"=>nil,
53
+ # "securityType2"=>"Common Stock",
54
+ # "securityDescription"=>"IBM"},
55
+ # ...
56
+
57
+ r = client.map(isin: 'US4592001014', exchCode: 'US')
58
+ r = client.map(idType: 'ID_ISIN', idValue: 'US4592001014', exchCode: 'US')
59
+
60
+ # one can query for multiple items
61
+ r = client.map([
62
+ { isin: 'US4592001014' },
63
+ { idType: 'ID_WERTPAPIER', idValue: '851399', exchCode: 'US' } ])
64
+ ```
65
+
66
+ Query for search ([/v2/search](https://www.openfigi.com/api#post-v2-search)):
67
+ ```ruby
68
+ r = client.search('ibm')
69
+ r = client.search(query: 'ibm')
70
+ r = client.search('ibm', exchCode: 'US')
71
+ r = client.search(query: 'ibm', exchCode: 'US')
72
+
73
+ pp r
74
+ # ==>
75
+ # {"data"=>
76
+ # [{"figi"=>"BBG00196W5Z9",
77
+ # "name"=>"Ibm",
78
+ # "ticker"=>"IBMD=4",
79
+ # "exchCode"=>"OC",
80
+ # "compositeFIGI"=>nil,
81
+ # "uniqueID"=>"EF12901854300074186897",
82
+ # "securityType"=>"DIVIDEND NEUTRAL STOCK FUTURE",
83
+ # "marketSector"=>"Equity",
84
+ # "shareClassFIGI"=>nil,
85
+ # "uniqueIDFutOpt"=>"IBMD=4 OC Equity",
86
+ # "securityType2"=>"Future",
87
+ # "securityDescription"=>"IBMD=4"},
88
+ # {"figi"=>"BBG00196W5Y0",
89
+ # "name"=>"Ibm",
90
+ # "ticker"=>"IBMD=3",
91
+ # "exchCode"=>"OC",
92
+ # "compositeFIGI"=>nil,
93
+ # "uniqueID"=>"EF12901854290074186860",
94
+ # "securityType"=>"DIVIDEND NEUTRAL STOCK FUTURE",
95
+ # "marketSector"=>"Equity",
96
+ # "shareClassFIGI"=>nil,
97
+ # "uniqueIDFutOpt"=>"IBMD=3 OC Equity",
98
+ # "securityType2"=>"Future",
99
+ # "securityDescription"=>"IBMD=3"},
100
+ # ...
101
+ ```
102
+
103
+ Search and `#next`:
104
+ ```ruby
105
+ r = client.search('ibm')
106
+ #
107
+ # grab the first "page" of results
108
+
109
+ r = r.next
110
+ #
111
+ # grab the next page of results
112
+
113
+ # ...
114
+ ```
115
+
9
116
 
10
117
  ## license
11
118
 
@@ -5,7 +5,7 @@ require 'net/http'
5
5
 
6
6
  module Figa
7
7
 
8
- VERSION = '0.0.1'
8
+ VERSION = '0.1.0'
9
9
 
10
10
  USER_AGENT = "Figa - https://github.com/jmettraux/figa - #{VERSION}"
11
11
  API_ROOT_URI = 'https://api.openfigi.com/v2'
@@ -18,28 +18,16 @@ module Figa
18
18
  @enum_values = {}
19
19
  end
20
20
 
21
- def map(h)
21
+ def map(array_or_hash)
22
22
 
23
- k0 = h.is_a?(Hash) ? h.keys.first.to_s : nil
23
+ a = to_mapping_parameter_array(array_or_hash)
24
24
 
25
- if k0 && h.size == 1 && enum_values('idType').include?(k0)
26
-
27
- h = { idType: h.keys.first, idValue: h.values.first }
28
- end
29
-
30
- validate(h)
31
-
32
- fail ArgumentError.new("parameter 'idType' is missing"
33
- ) unless h[:idType] || h['idType']
34
- fail ArgumentError.new("parameter 'idValue' is missing"
35
- ) unless h[:idValue] || h['idValue']
36
-
37
- post('/mapping', h)
25
+ post('/mapping', a)
38
26
  end
39
27
 
40
- def search(h)
28
+ def search(q, h={})
41
29
 
42
- h = { query: h } unless h.is_a?(Hash)
30
+ h = q.is_a?(String) ? h.merge(query: q) : q
43
31
 
44
32
  validate(h)
45
33
 
@@ -51,35 +39,56 @@ module Figa
51
39
 
52
40
  protected
53
41
 
54
- ENUM_KEYS = %w[
55
- idType exchCode micCode currency marketSecDes securityType securityType2 ]
42
+ def to_mapping_parameter_array(aoh)
43
+
44
+ a = aoh.is_a?(Array) ? aoh : [ aoh ]
45
+
46
+ id_types = enum_values('idType')
56
47
 
57
- def list_enum_values(key)
48
+ a.collect do |h|
58
49
 
59
- #fail ArgumentError.new(
60
- # "key #{key.inspect} not included in #{KEYS.inspect}"
61
- #) unless KEYS.include?(key)
50
+ oldk, itk =
51
+ h.keys.inject(nil) { |r, k|
52
+ next r if r
53
+ kk = k.upcase; next [ k, kk ] if id_types.include?(kk)
54
+ kk = "ID_#{kk}"; next [ k, kk ] if id_types.include?(kk)
55
+ nil }
56
+ if oldk
57
+ h[:idType] = itk
58
+ h[:idValue] = h.delete(oldk)
59
+ end
62
60
 
63
- get('/mapping/values/' + key)
61
+ validate(h)
62
+
63
+ fail ArgumentError.new("parameter 'idType' is missing"
64
+ ) unless h[:idType] || h['idType']
65
+ fail ArgumentError.new("parameter 'idValue' is missing"
66
+ ) unless h[:idValue] || h['idValue']
67
+
68
+ h
69
+ end
64
70
  end
65
71
 
72
+ ENUM_KEYS = %w[
73
+ idType exchCode micCode currency marketSecDes securityType securityType2 ]
74
+
66
75
  def enum_values(key)
67
76
 
68
- @enum_values[key] ||= list_enum_values(key)
77
+ @enum_values[key] ||= get('/mapping/values/' + key)['values']
69
78
  end
70
79
 
71
80
  def validate(h)
72
81
 
82
+ fail ArgumentError.new("#{h.inspect} is not a Hash") unless h.is_a?(Hash)
83
+
73
84
  h.each do |k, v|
74
85
 
75
86
  sk = k.to_s
76
87
  next unless ENUM_KEYS.include?(sk)
77
88
 
78
- vs = (@enum_values[sk] ||= list_enum_values(key))
79
-
80
89
  fail ArgumentError.new(
81
90
  "value #{v.inspect} is not a valid value for key #{k.inspect}"
82
- ) unless enum_values(keys).include?(v)
91
+ ) unless enum_values(sk).include?(v)
83
92
  end
84
93
  end
85
94
 
@@ -88,7 +97,7 @@ module Figa
88
97
 
89
98
  def request(method, uri, data=nil)
90
99
 
91
- uri = API_ROOT_URI + uri
100
+ uri = API_ROOT_URI + uri unless uri.match(/\Ahttps:\/\//)
92
101
 
93
102
  req = (method == :post ? Net::HTTP::Post : Net::HTTP::Get).new(uri)
94
103
  req.instance_eval { @header.clear }
@@ -101,7 +110,7 @@ module Figa
101
110
 
102
111
  req.set_header('User-Agent', USER_AGENT)
103
112
  req.set_header('Accept', 'application/json')
104
- # TODO api key
113
+ req.set_header('X-OPENFIGI-APIKEY', @api_key) if @api_key
105
114
 
106
115
  u = URI(uri)
107
116
 
@@ -110,17 +119,27 @@ module Figa
110
119
  t = Net::HTTP.new(u.host, u.port)
111
120
  t.use_ssl = (u.scheme == 'https')
112
121
  #t.set_debug_output($stdout)
113
- #t.set_debug_output($stdout) if u.to_s.match(/search/)
122
+ #t.set_debug_output($stdout) if uri.match(/search/)
114
123
 
115
124
  res = t.request(req)
116
125
 
117
- #class << res; attr_accessor :_elapsed; end
118
- #res._elapsed = monow - t0
119
-
120
126
  j = JSON.parse(res.body)
121
- def j._response; res; end
122
- j['_elapsed'] = monow - t0
123
- # TODO j['next']
127
+ #
128
+ class << j
129
+ attr_accessor :_response, :_client, :_elapsed, :_method, :_uri, :_form
130
+ end
131
+ #
132
+ j._response = res
133
+ j._client = self
134
+ j._elapsed = monow - t0
135
+ j._method = method
136
+ j._uri = uri
137
+ j._form = data
138
+ #
139
+ def j.next
140
+ n = self['next']; return nil unless n && n.is_a?(String)
141
+ _client.send(:request, _method, _uri, _form.merge(start: n))
142
+ end if j.is_a?(Hash)
124
143
 
125
144
  j
126
145
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: figa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-13 00:00:00.000000000 Z
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec