capital-iq 0.0.7 → 0.0.11

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