capital-iq 0.0.7 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzdhOGYzODE0MzU1YTdhZTcyNDNjZmMwYmRhZDhmMTIzZDg4MzU0MA==
4
+ ZTdhNTlhNjg1YTY2ZmY3ZjlmNmE1OTBlNjU5OTdjN2Y4YTUyYjdiNQ==
5
5
  data.tar.gz: !binary |-
6
- NjQyMTZhZmVmZjU4YzQ2YmMwMjdhMTAxZGE1NzNjNzgzNzA4ODRlYQ==
6
+ MmNlYjA5ZDI1YzBlODM4NTVkYjIxNzU1NGNhMTMwZGUxNmY5MzU1Mg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODYwYmJiODVkZTU0ZWFmMzM0NzJhNjFhN2ZkNTVkNDUxZDgyODA0ZTkzODJk
10
- YjU4ZWI1MzFmODJhOTUxYzYxNDkxZDQ3YmM0MTFkZGEyZGY0M2M2YzczMDQ3
11
- ZDY1MDVmOTE0NGJlZjIwMzE1Y2FlMWVmNDRiZWQ1ODk4YzBlMDg=
9
+ NDM4YzcxZTcwY2M5NjE3ZTExOTI5N2U0YjYwMTQxZGFjODY0NmVhZTcxNGY5
10
+ YjE0MjZiOTdhMmFkZjQzOGMwOWQ1MTNjOTNmZmQxOGM3OGUyYzQ5ZjM2MjY2
11
+ ZTg0MzEwYmYwOTZhM2FjYThkZWFiMGFkNzAwMDIwMjFhMWZiYzk=
12
12
  data.tar.gz: !binary |-
13
- ZmFkOTM0ODFhN2Y1YjcxZmZmNzNhN2Y0ZWIyNGI2YmRhZTNkMDJjZWI4ZTZl
14
- NmQ4YWY5YTA0MTk2ODQxOGY0Mjg4YTk4OThlMzM4MDNmNTI2OTYwZjNlOTRk
15
- MzA0NTNlNDM0ODY1YWY0MWY4NmU2NTY0MDA2Y2FjNDk5MDRjMDc=
13
+ ODQ3NWYwZmIzZTc4Zjk2ODY1ZjY3YWRiYTBjMjNmN2Y0ZjE0MzBmYmExMDcz
14
+ YzY1MjJiMjk2Zjk0OGQ2N2U2MGU4ZGE0OTZjYThjYjEwZjljOTdmOGMzZWI2
15
+ N2E4OWI3YjkwMGI5YzZhMmM4ZDJlMjcwOTA3ODJkMmNhNWRjZTk=
data/Gemfile CHANGED
@@ -1,16 +1,19 @@
1
1
  source "http://rubygems.org"
2
+ ruby "1.9.3"
2
3
 
3
4
  group :development do
4
- gem "rspec", "~> 2.8.0"
5
- gem "rdoc", "~> 3.12"
5
+ gem "rspec"
6
+ gem "rdoc"
6
7
  gem "bundler"
7
- gem "jeweler", "~> 1.8.3"
8
+ gem "jeweler"
8
9
  gem 'guard'
9
10
  gem 'guard-rspec'
10
11
  gem 'webmock'
12
+ gem 'dotenv'
11
13
  gem 'vcr'
14
+ gem 'redis'
12
15
  end
13
16
 
14
17
  gem 'httparty'
15
18
  gem 'json'
16
- gem 'hashie'
19
+ gem 'hashie'
data/Gemfile.lock CHANGED
@@ -9,6 +9,7 @@ GEM
9
9
  crack (0.4.2)
10
10
  safe_yaml (~> 1.0.0)
11
11
  diff-lcs (1.1.3)
12
+ dotenv (1.0.2)
12
13
  faraday (0.8.9)
13
14
  multipart-post (~> 1.2.0)
14
15
  ffi (1.9.3)
@@ -72,6 +73,7 @@ GEM
72
73
  ffi (>= 0.5.0)
73
74
  rdoc (3.12.2)
74
75
  json (~> 1.4)
76
+ redis (3.1.0)
75
77
  rspec (2.8.0)
76
78
  rspec-core (~> 2.8.0)
77
79
  rspec-expectations (~> 2.8.0)
@@ -94,13 +96,15 @@ PLATFORMS
94
96
 
95
97
  DEPENDENCIES
96
98
  bundler
99
+ dotenv
97
100
  guard
98
101
  guard-rspec
99
102
  hashie
100
103
  httparty
101
- jeweler (~> 1.8.3)
104
+ jeweler
102
105
  json
103
- rdoc (~> 3.12)
104
- rspec (~> 2.8.0)
106
+ rdoc
107
+ redis
108
+ rspec
105
109
  vcr
106
110
  webmock
data/README.rdoc CHANGED
@@ -2,22 +2,81 @@
2
2
 
3
3
  Ruby API wrapper to Capital IQ API.
4
4
 
5
+ == Compatibility Warning
6
+
7
+ Breaking changes were introduced in versions following v0.0.7. This was necessary to provide support for new features such as multi-identifier/multi-mnemonic calls.
8
+
9
+ v0.0.7 design is no longer maintained and can be found here: https://github.com/exitround/capital-iq/tree/v0.0.7
5
10
 
6
11
  == Installation
7
12
 
8
13
  gem install capital-iq
9
-
10
14
 
11
- == Usage
15
+ == Capital IQ API Basics
12
16
 
13
- client = CapitalIQ::Base.new('user@host.com', 'sfd98j429ds')
14
- => #<CapitalIQ::Base:0x007fd81d41ac38 @auth={:username=>"user@host.com", :password=>"sfd98j429ds"}>
15
-
16
- client.quick_match('exitround')
17
- => "IQ231729634"
18
-
19
- client.gdsp_request('IQ231729634', 'IQ_CITY')
20
- => "San Francisco"
17
+ Each request to Capital IQ API contains three required parameters: function, identifier, mnemonic, and one optional parameter: properties. The corresponding result will contain a rowset with "headers" and "rows". For single-value mnemonics the result would usually consist of a single header and a single row. The header name would usually match the name of the input mnemonic. Multi-value mnemonics, however, often contain additional headers (such as "change date" etc) and multiple rows.
18
+
19
+ Please refer to Capital IQ support and documentation for specific function/mnemonic instructions and data retrieval pricing information.
20
+
21
+ == Gem Usage
22
+
23
+ To start, initialize the client object with the user name and password. This example assumes that they are stored in the environment variables:
24
+ client = CapitalIQ::Client.new(ENV['CAPIQ_USER'], ENV['CAPIQ_PWD'])
25
+
26
+ === API Calls Based on Request Objects
27
+
28
+ This is the most basic way of using the gem. Create a request, call the api, get the result. Here, the function is GDSHE, the identifier is 'microsoft' and the mnemonic is IQ_COMPANY_ID_QUICK_MATCH:
29
+
30
+ req = CapitalIQ::Request.new(CapitalIQ::Functions::GDSHE, 'microsoft', 'IQ_COMPANY_ID_QUICK_MATCH')
31
+ res = client.base_request(req)
32
+
33
+
34
+ You have an option of passing multiple requst objects into a call. They are all executed in one round trip. Beware of the API limits however.
35
+
36
+ req1 = CapitalIQ::Request.new(CapitalIQ::Functions::GDSHE, 'microsoft', 'IQ_COMPANY_ID_QUICK_MATCH')
37
+ req2 = CapitalIQ::Request.new(CapitalIQ::Functions::GDSHE, 'google', 'IQ_COMPANY_ID_QUICK_MATCH')
38
+ res = client.base_request([req1, req2])
39
+
40
+ === Convenience Methods - request_xxxxx
41
+
42
+ You may choose to use the convenience methods provided by the +Client+ class - +request_xxxxx+, where xxxxx - is the name of Capital IQ API function). They allow to forgo creating the request objects explicity, (the requsts objects do get created underneath though):
43
+
44
+ res = client.request_gdshe('microsoft', 'IQ_COMPANY_ID_QUICK_MATCH', {startRank:1, endRank:20})
45
+
46
+ The returned values are accessed by the identifier and the header name:
47
+
48
+ res_val = res['microsoft']['IQ_COMPANY_ID_QUICK_MATCH']
49
+
50
+ When using GDSHE or GDSHV functions, the result is represented by an array. Therefore +res_val+ above is an array. We'll use +first+ method to get the actual value:
51
+
52
+ ms_id = res_val.first
53
+
54
+ You can use the +scalar+ method when querying on a single identifier, so the above example can be shortened to:
55
+
56
+ ms_id = res.scalar['IQ_COMPANY_ID_QUICK_MATCH'].first
57
+
58
+ === Multiple identifier / single mnemonic requests
59
+
60
+ This example generates two requests:
61
+
62
+ res = client.request_gdshe(['microsoft', 'google'], 'IQ_COMPANY_ID_QUICK_MATCH', {startRank:1, endRank:20})
63
+ ms_id = res['microsoft']['IQ_COMPANY_ID_QUICK_MATCH'].first
64
+ google_id = res['google']['IQ_COMPANY_ID_QUICK_MATCH'].first
65
+
66
+ === Multiple identifier / multiple mnemonic queries
67
+
68
+ This call generates (2 identifiers times 3 mnemonics) = 6 requests (they're still executed in a batch)
69
+
70
+ res = client.request_gdsp([ms_id, google_id], %w(IQ_COMPANY_WEBSITE IQ_COMPANY_NAME IQ_BUSINESS_DESCRIPTION))
71
+
72
+ You can use the +to_hash+ method to retrieve all values for a given identifier
73
+
74
+ # All values for +ms_id+
75
+ ms_data = res[ms_id].to_hash
76
+
77
+ Or you can retrieve all values for all identifiers:
78
+
79
+ all_data = res.to_hash
21
80
 
22
81
 
23
82
  == Contributing to capital-iq
data/Rakefile CHANGED
@@ -15,12 +15,12 @@ require 'jeweler'
15
15
  Jeweler::Tasks.new do |gem|
16
16
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
17
  gem.name = "capital-iq"
18
- gem.homepage = "http://github.com/seeingidog/capital-iq"
18
+ gem.homepage = "http://github.com/exitround/capital-iq"
19
19
  gem.license = "MIT"
20
20
  gem.summary = %Q{Ruby wrapper for the CapIQ API}
21
21
  gem.description = %Q{Ruby wrapper for the CapIQ API}
22
- gem.email = "ian@ruby-code.com"
23
- gem.authors = ["Ian Morgan"]
22
+ gem.email = "dev@exitround.com"
23
+ gem.authors = ["Val Savvateev", "Greg Dean"]
24
24
  # dependencies defined in Gemfile
25
25
  end
26
26
  Jeweler::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.7
1
+ 0.0.11
data/capital-iq.gemspec CHANGED
@@ -2,17 +2,18 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: capital-iq 0.0.7 ruby lib
5
+ # stub: capital-iq 0.0.11 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "capital-iq"
9
- s.version = "0.0.7"
9
+ s.version = "0.0.11"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
- s.authors = ["Ian Morgan"]
13
- s.date = "2014-10-10"
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Val Savvateev", "Greg Dean"]
14
+ s.date = "2015-02-24"
14
15
  s.description = "Ruby wrapper for the CapIQ API"
15
- s.email = "ian@ruby-code.com"
16
+ s.email = "dev@exitround.com"
16
17
  s.extra_rdoc_files = [
17
18
  "LICENSE.txt",
18
19
  "README.rdoc"
@@ -27,19 +28,18 @@ Gem::Specification.new do |s|
27
28
  "VERSION",
28
29
  "capital-iq.gemspec",
29
30
  "lib/capital-iq.rb",
30
- "lib/capital-iq/api-error.rb",
31
- "lib/capital-iq/base.rb",
31
+ "lib/capital-iq/api_error.rb",
32
+ "lib/capital-iq/api_response.rb",
33
+ "lib/capital-iq/cache.rb",
34
+ "lib/capital-iq/client.rb",
35
+ "lib/capital-iq/functions.rb",
32
36
  "lib/capital-iq/request.rb",
33
- "lib/capital-iq/transaction.rb",
34
- "spec/capital-iq_spec.rb",
35
- "spec/request_spec.rb",
36
- "spec/responses/capiq_ibm.json",
37
- "spec/spec_helper.rb"
37
+ "lib/capital-iq/request_result.rb",
38
+ "spec/capital-iq_spec.rb"
38
39
  ]
39
- s.homepage = "http://github.com/seeingidog/capital-iq"
40
+ s.homepage = "http://github.com/exitround/capital-iq"
40
41
  s.licenses = ["MIT"]
41
- s.require_paths = ["lib"]
42
- s.rubygems_version = "2.1.11"
42
+ s.rubygems_version = "2.4.5"
43
43
  s.summary = "Ruby wrapper for the CapIQ API"
44
44
 
45
45
  if s.respond_to? :specification_version then
@@ -49,39 +49,45 @@ Gem::Specification.new do |s|
49
49
  s.add_runtime_dependency(%q<httparty>, [">= 0"])
50
50
  s.add_runtime_dependency(%q<json>, [">= 0"])
51
51
  s.add_runtime_dependency(%q<hashie>, [">= 0"])
52
- s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
53
- s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
52
+ s.add_development_dependency(%q<rspec>, [">= 0"])
53
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
54
54
  s.add_development_dependency(%q<bundler>, [">= 0"])
55
- s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
55
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
56
56
  s.add_development_dependency(%q<guard>, [">= 0"])
57
57
  s.add_development_dependency(%q<guard-rspec>, [">= 0"])
58
58
  s.add_development_dependency(%q<webmock>, [">= 0"])
59
+ s.add_development_dependency(%q<dotenv>, [">= 0"])
59
60
  s.add_development_dependency(%q<vcr>, [">= 0"])
61
+ s.add_development_dependency(%q<redis>, [">= 0"])
60
62
  else
61
63
  s.add_dependency(%q<httparty>, [">= 0"])
62
64
  s.add_dependency(%q<json>, [">= 0"])
63
65
  s.add_dependency(%q<hashie>, [">= 0"])
64
- s.add_dependency(%q<rspec>, ["~> 2.8.0"])
65
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
66
+ s.add_dependency(%q<rspec>, [">= 0"])
67
+ s.add_dependency(%q<rdoc>, [">= 0"])
66
68
  s.add_dependency(%q<bundler>, [">= 0"])
67
- s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
69
+ s.add_dependency(%q<jeweler>, [">= 0"])
68
70
  s.add_dependency(%q<guard>, [">= 0"])
69
71
  s.add_dependency(%q<guard-rspec>, [">= 0"])
70
72
  s.add_dependency(%q<webmock>, [">= 0"])
73
+ s.add_dependency(%q<dotenv>, [">= 0"])
71
74
  s.add_dependency(%q<vcr>, [">= 0"])
75
+ s.add_dependency(%q<redis>, [">= 0"])
72
76
  end
73
77
  else
74
78
  s.add_dependency(%q<httparty>, [">= 0"])
75
79
  s.add_dependency(%q<json>, [">= 0"])
76
80
  s.add_dependency(%q<hashie>, [">= 0"])
77
- s.add_dependency(%q<rspec>, ["~> 2.8.0"])
78
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
81
+ s.add_dependency(%q<rspec>, [">= 0"])
82
+ s.add_dependency(%q<rdoc>, [">= 0"])
79
83
  s.add_dependency(%q<bundler>, [">= 0"])
80
- s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
84
+ s.add_dependency(%q<jeweler>, [">= 0"])
81
85
  s.add_dependency(%q<guard>, [">= 0"])
82
86
  s.add_dependency(%q<guard-rspec>, [">= 0"])
83
87
  s.add_dependency(%q<webmock>, [">= 0"])
88
+ s.add_dependency(%q<dotenv>, [">= 0"])
84
89
  s.add_dependency(%q<vcr>, [">= 0"])
90
+ s.add_dependency(%q<redis>, [">= 0"])
85
91
  end
86
92
  end
87
93
 
data/lib/capital-iq.rb CHANGED
@@ -1,9 +1,17 @@
1
+ require 'set'
2
+ require 'ostruct'
1
3
  require 'httparty'
2
4
  require 'json'
3
- require_relative 'capital-iq/base'
4
- require_relative 'capital-iq/request'
5
- require_relative 'capital-iq/api-error'
6
- require_relative 'capital-iq/transaction'
5
+ require 'digest'
6
+ require 'zlib'
7
7
 
8
8
  module CapitalIQ
9
9
  end
10
+
11
+ require_relative 'capital-iq/cache'
12
+ require_relative 'capital-iq/functions'
13
+ require_relative 'capital-iq/api_error'
14
+ require_relative 'capital-iq/request'
15
+ require_relative 'capital-iq/request_result'
16
+ require_relative 'capital-iq/api_response'
17
+ require_relative 'capital-iq/client'
@@ -0,0 +1,4 @@
1
+ module CapitalIQ
2
+ class ApiError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,73 @@
1
+ module CapitalIQ
2
+ class ApiResponse
3
+ class IdentifierResultGroup
4
+ attr_reader :identifier
5
+ def initialize(identifier)
6
+ @identifier = identifier
7
+ @header_map = {}
8
+ @results = []
9
+ end
10
+ def <<(result)
11
+ raise "Result contains wrong identifier" if result.Identifier != self.identifier
12
+ @results << result
13
+ (result.Headers || []).each { |h| @header_map[h] = result }
14
+ end
15
+ def headers
16
+ @header_map.keys
17
+ end
18
+
19
+ def [](header)
20
+ @header_map[header][header]
21
+ end
22
+
23
+ def to_hash
24
+ Hash[self.headers.collect { |h| [h, self[h]] }]
25
+ end
26
+
27
+ def to_s
28
+ to_hash().to_s()
29
+ end
30
+ end
31
+
32
+ def initialize(response_data)
33
+ @response_data = response_data
34
+
35
+ @results = []
36
+ @identifier_results = Hash.new {|hash, key| hash[key] = IdentifierResultGroup.new(key)}
37
+ raw_results = response_data["GDSSDKResponse"]
38
+ return if !raw_results.is_a?(Array)
39
+
40
+ # create wrappers for each response
41
+ @results = raw_results.collect { |r| RequestResult.new(r) }
42
+ # build a map from header to corresponding result wrappers
43
+ @results.each { |r| @identifier_results[r.Identifier] << r }
44
+ end
45
+
46
+ def has_errors?(header=nil)
47
+ return true if @response_data.include?("Errors")
48
+ @results.find { |r| r.has_errors?(header)}
49
+ end
50
+
51
+ def [](identifier)
52
+ return nil unless @identifier_results.has_key?(identifier)
53
+ @identifier_results[identifier]
54
+ end
55
+
56
+ def scalar
57
+ return nil if @identifier_results.length == 0
58
+ @identifier_results.first[1]
59
+ end
60
+
61
+ def identifiers
62
+ @identifier_results.keys
63
+ end
64
+
65
+ def to_hash
66
+ Hash[self.identifiers.collect { |id| [id, self[id]] }]
67
+ end
68
+
69
+ def to_s
70
+ to_hash().to_s()
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,89 @@
1
+ module CapitalIQ
2
+ class Cache
3
+
4
+ def initialize(store, prefix)
5
+ @store = store
6
+ @prefix = prefix
7
+ end
8
+
9
+ ##
10
+ # Read from the Cache.
11
+ #
12
+ def [](url)
13
+ interpret case
14
+ when store.respond_to?(:[])
15
+ store[key_for(url)]
16
+ when store.respond_to?(:get)
17
+ store.get key_for(url)
18
+ when store.respond_to?(:read)
19
+ store.read key_for(url)
20
+ end
21
+ end
22
+
23
+ ##
24
+ # Write to the Cache.
25
+ #
26
+ def []=(url, value)
27
+ case
28
+ when store.respond_to?(:[]=)
29
+ store[key_for(url)] = value
30
+ when store.respond_to?(:set)
31
+ store.set key_for(url), value
32
+ when store.respond_to?(:write)
33
+ store.write key_for(url), value
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Delete cache entry for given URL,
39
+ # or pass <tt>:all</tt> to clear all URLs.
40
+ #
41
+ def expire(url)
42
+ if url == :all
43
+ urls.each{ |u| expire(u) }
44
+ else
45
+ expire_single_url(url)
46
+ end
47
+ end
48
+
49
+
50
+ private # ----------------------------------------------------------------
51
+
52
+ attr_reader :prefix, :store
53
+
54
+ ##
55
+ # Cache key for a given URL.
56
+ #
57
+ def key_for(url)
58
+ [prefix, url].join
59
+ end
60
+
61
+ ##
62
+ # Array of keys with the currently configured prefix
63
+ # that have non-nil values.
64
+ #
65
+ def keys
66
+ store.keys.select{ |k| k.match /^#{prefix}/ and interpret(store[k]) }
67
+ end
68
+
69
+ ##
70
+ # Array of cached URLs.
71
+ #
72
+ def urls
73
+ keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
74
+ end
75
+
76
+ ##
77
+ # Clean up value before returning. Namely, convert empty string to nil.
78
+ # (Some key/value stores return empty string instead of nil.)
79
+ #
80
+ def interpret(value)
81
+ value == "" ? nil : value
82
+ end
83
+
84
+ def expire_single_url(url)
85
+ key = key_for(url)
86
+ store.respond_to?(:del) ? store.del(key) : store.delete(key)
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,78 @@
1
+ module CapitalIQ
2
+ class Client
3
+ attr_reader :cache
4
+
5
+ ENDPOINT = 'https://sdk.gds.standardandpoors.com/gdssdk/rest/v2/clientservice.json'
6
+ include HTTParty
7
+ format :json
8
+
9
+ def initialize(username, password, cache_store=nil, cache_prefix="CAPIQ_")
10
+ @auth = {username: username, password: password}
11
+ @cache = Cache.new(cache_store, cache_prefix)
12
+ end
13
+
14
+ def base_request(requests)
15
+ # build request
16
+ requests = [requests] unless requests.class == Array
17
+ request_array = requests.collect { |r| r.to_hash }
18
+ request_body = {inputRequests: {inputRequests: request_array}.to_json}
19
+
20
+ # send request
21
+ response_data = from_cache(request_body) || self.class.post(
22
+ ENDPOINT, body: request_body, basic_auth: @auth, ssl_version: :SSLv3
23
+ ).parsed_response
24
+
25
+ # analyze response
26
+ response = ApiResponse.new(response_data)
27
+ raise ApiError if response.has_errors?
28
+ to_cache(request_body, response_data)
29
+ response
30
+ end
31
+
32
+ def request(function, identifiers, mnemonics, properties=nil)
33
+ mnemonics = [mnemonics] unless mnemonics.is_a? Enumerable
34
+ identifiers = [identifiers] unless identifiers.is_a? Enumerable
35
+ requests = []
36
+ identifiers.each do |identifier|
37
+ requests.unshift(*mnemonics.collect {|m| CapitalIQ::Request.new(function, identifier, m, properties)})
38
+ end
39
+ base_request(requests)
40
+ end
41
+
42
+ def method_missing(meth, *args, &block)
43
+ if meth.to_s =~ /^request_(.+)$/
44
+ function = $1.upcase
45
+ if Functions.all.include?(function)
46
+ request(*([function]+args))
47
+ else
48
+ super
49
+ end
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def to_cache(request_body, response_data)
58
+ return if @cache.nil?
59
+ @cache[cache_key(request_body)] = Zlib::Deflate.deflate(response_data.to_json)
60
+ end
61
+
62
+ def from_cache(request_body)
63
+ return nil if @cache.nil?
64
+ result = @cache[cache_key(request_body)]
65
+ return nil if result.nil?
66
+ JSON.parse(Zlib::Inflate.inflate(result))
67
+ end
68
+
69
+ def cache_key(request_body)
70
+ Digest::MD5.hexdigest(request_body.to_s)
71
+ end
72
+
73
+ end
74
+
75
+ # b/w compatibility with 0.07
76
+
77
+ Base = Client
78
+ end
@@ -0,0 +1,21 @@
1
+ module CapitalIQ
2
+ class Functions
3
+ GDSP ||= 'GDSP'
4
+ GDSPV ||= 'GDSPV'
5
+ GDSG ||= 'GDSG'
6
+ GDSHE ||= 'GDSHE'
7
+ GDSHV ||= 'GDSHV'
8
+ GDST ||= 'GDST'
9
+
10
+ @all ||= Set.new([GDSP,GDSPV,GDSG,GDSHE,GDSHV,GDST])
11
+
12
+ class << self
13
+
14
+ attr_reader :all
15
+
16
+ def is_array_function(function)
17
+ function == GDSHE || function == GDSHV
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,14 +1,24 @@
1
1
  module CapitalIQ
2
2
  class Request
3
- attr_reader :request
4
-
5
- def initialize(function, identifier, mnemonic, properties)
6
- request_hash = {inputRequests:[
7
- {function:function, identifier: identifier, mnemonic: mnemonic}
8
- ]}
9
- request_hash.merge!({properties: properties}) if properties
10
- @request = "inputRequests=" + request_hash.to_json
3
+ attr_reader :function, :identifier, :mnemonic, :properties
4
+
5
+ def initialize(function, identifier, mnemonic, properties = nil)
6
+ @function = function
7
+ @identifier = identifier
8
+ @mnemonic = mnemonic
9
+ @properties = properties
10
+
11
+ @hash = {
12
+ function: self.function,
13
+ identifier: self.identifier,
14
+ mnemonic: self.mnemonic
15
+ }
16
+ @hash[:properties] = properties unless properties.nil?
11
17
  end
12
-
18
+
19
+ def to_hash
20
+ @hash
21
+ end
22
+
13
23
  end
14
24
  end
@@ -0,0 +1,28 @@
1
+ module CapitalIQ
2
+ class RequestResult < OpenStruct
3
+ def initialize(raw_result)
4
+ @raw_result = raw_result
5
+ super raw_result
6
+ end
7
+
8
+ def has_errors?(header=nil)
9
+ !self.ErrMsg.nil? && (header.nil? || header.in?(self.Headers))
10
+ end
11
+
12
+ def [](header)
13
+ result = value_array(header)
14
+ return result if Functions.is_array_function(self.Function)
15
+ result.first
16
+ end
17
+
18
+ private
19
+ def value_array(header)
20
+ header_idx = self.Headers.index(header)
21
+ raise ArgumentError, "Unknown header '#{header}'" if header_idx.nil?
22
+ self.Rows.collect do |row|
23
+ v = row["Row"][header_idx]
24
+ v == 'Data Unavailable' ? nil : v
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,50 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'webmock/rspec'
2
+ require 'vcr'
3
+ require 'dotenv'
4
+
5
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/capital-iq.rb')
6
+
7
+ Dotenv.load
8
+
9
+ VCR.configure do |c|
10
+ c.cassette_library_dir = 'spec/vcr_cassettes'
11
+ c.hook_into :webmock
12
+ end
2
13
 
3
14
  describe "CapitalIq" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
15
+ VCR.use_cassette("spec") do
16
+ client = CapitalIQ::Client.new(ENV['CAPIQ_USER'], ENV['CAPIQ_PWD'])
17
+
18
+ # Call based on a request object
19
+ # All requests passed to the base_request method are executed withing one roundtrip
20
+ req1 = CapitalIQ::Request.new(CapitalIQ::Functions::GDSHE, 'microsoft', 'IQ_COMPANY_ID_QUICK_MATCH')
21
+ req2 = CapitalIQ::Request.new(CapitalIQ::Functions::GDSHE, 'google', 'IQ_COMPANY_ID_QUICK_MATCH')
22
+ res = client.base_request([req1, req2])
23
+
24
+ # Shortened form - no need to create request objects explicitly, although they do get created underneath:
25
+ res = client.request_gdshe('microsoft', 'IQ_COMPANY_ID_QUICK_MATCH', {startRank:1, endRank:20})
26
+
27
+ # Returned values are accessed by identifier and mnemonic:
28
+ res_val = res['microsoft']['IQ_COMPANY_ID_QUICK_MATCH']
29
+
30
+ # When using GDSHE or GDSHV, the result is represented by an array (so we'll use 'first' here)
31
+ ms_id = res_val.first
32
+
33
+ # You can use 'scalar' when querying on a single identifier, so we can shorten the whole thing to:
34
+ ms_id = res.scalar['IQ_COMPANY_ID_QUICK_MATCH'].first
35
+
36
+ # Multiple identifier / single mnemonic requests
37
+ # This example generates two requests
38
+ res = client.request_gdshe(['microsoft', 'google'], 'IQ_COMPANY_ID_QUICK_MATCH', {startRank:1, endRank:20})
39
+ ms_id = res['microsoft']['IQ_COMPANY_ID_QUICK_MATCH'].first
40
+ google_id = res['google']['IQ_COMPANY_ID_QUICK_MATCH'].first
41
+
42
+ # Multiple identifier / multiple mnemonic queries
43
+ # This call generates (2 identifiers times 3 mnemonics) = 6 requests (they're still executed in a batch)
44
+ res = client.request_gdsp([ms_id, google_id], %w(IQ_COMPANY_WEBSITE IQ_COMPANY_NAME IQ_BUSINESS_DESCRIPTION))
45
+ # You can use the 'to_hash' method to retrieve all mnemonic values for a given identifier
46
+ ms_data = res[ms_id].to_hash # all mnemonics for ms_id
47
+ # Or you can retrieve all values for all identifiers
48
+ google_data = res[google_id].to_hash # all mnemonics for google_id
6
49
  end
7
50
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capital-iq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
- - Ian Morgan
7
+ - Val Savvateev
8
+ - Greg Dean
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-10-10 00:00:00.000000000 Z
12
+ date: 2015-02-24 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: httparty
@@ -56,30 +57,30 @@ dependencies:
56
57
  name: rspec
57
58
  requirement: !ruby/object:Gem::Requirement
58
59
  requirements:
59
- - - ~>
60
+ - - ! '>='
60
61
  - !ruby/object:Gem::Version
61
- version: 2.8.0
62
+ version: '0'
62
63
  type: :development
63
64
  prerelease: false
64
65
  version_requirements: !ruby/object:Gem::Requirement
65
66
  requirements:
66
- - - ~>
67
+ - - ! '>='
67
68
  - !ruby/object:Gem::Version
68
- version: 2.8.0
69
+ version: '0'
69
70
  - !ruby/object:Gem::Dependency
70
71
  name: rdoc
71
72
  requirement: !ruby/object:Gem::Requirement
72
73
  requirements:
73
- - - ~>
74
+ - - ! '>='
74
75
  - !ruby/object:Gem::Version
75
- version: '3.12'
76
+ version: '0'
76
77
  type: :development
77
78
  prerelease: false
78
79
  version_requirements: !ruby/object:Gem::Requirement
79
80
  requirements:
80
- - - ~>
81
+ - - ! '>='
81
82
  - !ruby/object:Gem::Version
82
- version: '3.12'
83
+ version: '0'
83
84
  - !ruby/object:Gem::Dependency
84
85
  name: bundler
85
86
  requirement: !ruby/object:Gem::Requirement
@@ -98,16 +99,16 @@ dependencies:
98
99
  name: jeweler
99
100
  requirement: !ruby/object:Gem::Requirement
100
101
  requirements:
101
- - - ~>
102
+ - - ! '>='
102
103
  - !ruby/object:Gem::Version
103
- version: 1.8.3
104
+ version: '0'
104
105
  type: :development
105
106
  prerelease: false
106
107
  version_requirements: !ruby/object:Gem::Requirement
107
108
  requirements:
108
- - - ~>
109
+ - - ! '>='
109
110
  - !ruby/object:Gem::Version
110
- version: 1.8.3
111
+ version: '0'
111
112
  - !ruby/object:Gem::Dependency
112
113
  name: guard
113
114
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +151,20 @@ dependencies:
150
151
  - - ! '>='
151
152
  - !ruby/object:Gem::Version
152
153
  version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: dotenv
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
153
168
  - !ruby/object:Gem::Dependency
154
169
  name: vcr
155
170
  requirement: !ruby/object:Gem::Requirement
@@ -164,8 +179,22 @@ dependencies:
164
179
  - - ! '>='
165
180
  - !ruby/object:Gem::Version
166
181
  version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: redis
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ! '>='
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
167
196
  description: Ruby wrapper for the CapIQ API
168
- email: ian@ruby-code.com
197
+ email: dev@exitround.com
169
198
  executables: []
170
199
  extensions: []
171
200
  extra_rdoc_files:
@@ -181,15 +210,15 @@ files:
181
210
  - VERSION
182
211
  - capital-iq.gemspec
183
212
  - lib/capital-iq.rb
184
- - lib/capital-iq/api-error.rb
185
- - lib/capital-iq/base.rb
213
+ - lib/capital-iq/api_error.rb
214
+ - lib/capital-iq/api_response.rb
215
+ - lib/capital-iq/cache.rb
216
+ - lib/capital-iq/client.rb
217
+ - lib/capital-iq/functions.rb
186
218
  - lib/capital-iq/request.rb
187
- - lib/capital-iq/transaction.rb
219
+ - lib/capital-iq/request_result.rb
188
220
  - spec/capital-iq_spec.rb
189
- - spec/request_spec.rb
190
- - spec/responses/capiq_ibm.json
191
- - spec/spec_helper.rb
192
- homepage: http://github.com/seeingidog/capital-iq
221
+ homepage: http://github.com/exitround/capital-iq
193
222
  licenses:
194
223
  - MIT
195
224
  metadata: {}
@@ -209,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
238
  version: '0'
210
239
  requirements: []
211
240
  rubyforge_project:
212
- rubygems_version: 2.1.11
241
+ rubygems_version: 2.4.5
213
242
  signing_key:
214
243
  specification_version: 4
215
244
  summary: Ruby wrapper for the CapIQ API
@@ -1,4 +0,0 @@
1
- module CapitalIQ
2
- class APIError < StandardError
3
- end
4
- end
@@ -1,77 +0,0 @@
1
- module CapitalIQ
2
- class Base
3
- ENDPOINT = 'https://sdk.gds.standardandpoors.com/gdssdk/rest/v2/clientservice.json'
4
- include HTTParty
5
- format :json
6
-
7
- def initialize(username, password)
8
- @auth = {username: username, password: password}
9
- end
10
-
11
- def request(function, identifier, mnemonic, properties)
12
- request_body = Request.new(function, identifier, mnemonic, properties).request
13
- response_data = self.class.post(ENDPOINT, body: request_body, basic_auth: @auth, ssl_version: :SSLv3).parsed_response
14
- response = response_data[response_data.keys.first]
15
- raise CapitalIQ::APIError if response == "Error Processing the Request"
16
- raise CapitalIQ::APIError, response.first['ErrMsg'] if response.first['ErrMsg']
17
- response.first
18
- end
19
-
20
- def gdst_request(identifier, mnemonic)
21
- response = request('GDST', identifier, mnemonic, {PERIODTYPE: "IQ_FQ"})
22
- response['Rows'].first['Row'].first
23
- end
24
-
25
- def gdsp_request(identifier, mnemonic)
26
- response = request('GDSP', identifier, mnemonic, nil)
27
- response['Rows'].first['Row'].first
28
- end
29
-
30
- def gdshe_request(identifier, mnemonic, properties)
31
- response = request('GDSHE', identifier, mnemonic, properties)
32
- response['Rows'].first['Row'].first
33
- end
34
-
35
- def quick_match(name)
36
- gdshe_request(name, 'IQ_COMPANY_ID_QUICK_MATCH', {startRank:"1", endRank:"5"})
37
- end
38
-
39
- def match_and_request(name, mnemonic)
40
- identifier = quick_match(name)
41
- gdsp_request(identifier, mnemonic)
42
- end
43
-
44
- def transaction_list(identifier)
45
- transaction_items = ['IQ_TR_CURRENCY', 'IQ_TR_TARGET_ID', 'IQ_TR_BUYER_ID', 'IQ_TR_SELLER_ID', 'IQ_TR_STATUS', 'IQ_TR_CLOSED_DATE', 'IQ_TR_IMPLIED_EV_FINAL']
46
- walk_transactions(identifier, 'IQ_TRANSACTION_LIST_MA', transaction_items)
47
- end
48
-
49
- def pe_transactions(identifier)
50
- transaction_items = ['IQ_PRIMARY_SIC_CODE', 'IQ_EMPLOYEES']
51
- walk_transactions(identifier, 'IQ_INVESTMENTS_ALL_ID', transaction_items)
52
- end
53
-
54
- private
55
- def walk_transactions(identifier, list_identifier, transaction_items)
56
- acquisitions = {}
57
- transaction_list = request('GDSHE', identifier, list_identifier, {startRank:"1", endRank:"20"})
58
- return nil if transaction_list['Rows'].first["Row"].first == 'Data Unavailable'
59
- transaction_list['Rows'].each do |transaction|
60
- acquisitions[transaction['Row'].first] = transaction_items.map {|transaction_item|
61
- Hash[transaction_item, request('GDSP', transaction['Row'].first, transaction_item, nil)['Rows'].map {|a|
62
- next if a['Row'].first == 'Data Unavailable'
63
- if a['Row'].first.include?(',')
64
- a['Row'].first.split(', ')
65
- else
66
- a['Row'].first
67
- end
68
- }.first
69
- ]
70
- }.reduce({}, :merge)
71
- end
72
- acquisitions
73
-
74
- end
75
-
76
- end
77
- end
@@ -1,8 +0,0 @@
1
- module CapitalIQ
2
- class Transaction
3
-
4
- def initialize
5
- end
6
-
7
- end
8
- end
data/spec/request_spec.rb DELETED
@@ -1,7 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "CapitalIQ Request" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
6
- end
7
- end
File without changes
data/spec/spec_helper.rb DELETED
@@ -1,22 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- $LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'rspec'
4
- require 'capital-iq'
5
- require 'webmock/rspec'
6
- require 'vcr'
7
-
8
- # Requires supporting files with custom matchers and macros, etc,
9
- # in ./support/ and its subdirectories.
10
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
-
12
- RSpec.configure do |config|
13
-
14
- end
15
-
16
- WebMock.disable_net_connect!
17
- WebMock.stub_request(:post. "https://sdk.gds.standardandpoors.com/gdssdk/rest/v2/clientservice.json").to_return(:status => 200, :body => File.new(File.dirname(__FILE__) + '/responses/capiq_ibm.json'), :headers => {})
18
-
19
- VCR.config do |c|
20
- c.cassette_library_dir = 'spec/fixtures/dish_cassettes'
21
- c.stub_with :webmock
22
- end