cufinder-ruby 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c9f06c87746a02b9f3ba1003f43e859f96549c67061db0d66465ce919324400f
4
+ data.tar.gz: e304713de973c2cfa7de842e9788a2d49a17383dc540a9c7520ff6205f50dfcd
5
+ SHA512:
6
+ metadata.gz: 65e625f7ac41c7b61af9b3f672d5a4c9cae6243a28a62c099feb13dc8bfecefd3c388790d355c5b6c7a47ec544676ccee0da857b89a23d7fc8de05ef745ab7d6
7
+ data.tar.gz: a35579b44987e8aa8c2bb5a8ecad07da0c6dc4585cf3c0a08626b2202253e77da1b60000e7d6481bac5c11e906c84e8bba3e61685fddc008efd90ca4555eeb5b
data/.gitignore ADDED
@@ -0,0 +1,59 @@
1
+ # Ruby
2
+ *.gem
3
+ *.rbc
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ # Bundler
15
+ /.bundle/
16
+ /vendor/bundle
17
+ /lib/bundler/man/
18
+
19
+ # Documentation
20
+ /.yardoc/
21
+ /_yardoc/
22
+ /doc/
23
+ /rdoc/
24
+
25
+ # Environment
26
+ /.env
27
+ /.env.local
28
+ /.env.development.local
29
+ /.env.test.local
30
+ /.env.production.local
31
+
32
+ # IDE
33
+ /.vscode/
34
+ /.idea/
35
+ *.swp
36
+ *.swo
37
+ *~
38
+
39
+ # OS
40
+ .DS_Store
41
+ .DS_Store?
42
+ ._*
43
+ .Spotlight-V100
44
+ .Trashes
45
+ ehthumbs.db
46
+ Thumbs.db
47
+
48
+ # Logs
49
+ *.log
50
+
51
+ # Coverage reports
52
+ /coverage/
53
+
54
+ # RSpec
55
+ .rspec_status
56
+
57
+ # Temporary files
58
+ *.tmp
59
+ *.temp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cufinder-ruby.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem "rspec", "~> 3.12"
8
+ gem "webmock", "~> 3.18"
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CUFinder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # CUFinder Ruby SDK
2
+
3
+ Official Ruby SDK for accessing CUFinder's comprehensive business intelligence and lead generation services.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'cufinder-ruby'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ gem install cufinder-ruby
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Basic Setup
28
+
29
+ ```ruby
30
+ require 'cufinder_ruby'
31
+
32
+ # Initialize the SDK with your API key
33
+ sdk = CufinderRuby::SDK.new(api_key: 'your-api-key-here')
34
+ ```
35
+
36
+ ### Available Services
37
+
38
+ The SDK provides access to all CUFinder API services:
39
+
40
+ #### 1. CUF - Company URL Finder
41
+ ```ruby
42
+ result = sdk.cuf(company_name: "Apple Inc", country_code: "US")
43
+ puts result.domain # => "apple.com"
44
+ ```
45
+
46
+ #### 2. LCUF - LinkedIn Company URL Finder
47
+ ```ruby
48
+ result = sdk.lcuf(company_name: "Apple Inc")
49
+ puts result.linkedin_url # => "linkedin.com/company/apple"
50
+ ```
51
+
52
+ #### 3. DTC - Domain to Company
53
+ ```ruby
54
+ result = sdk.dtc(company_website: "apple.com")
55
+ puts result.company_name # => "Apple Inc"
56
+ ```
57
+
58
+ #### 4. DTE - Domain to Emails
59
+ ```ruby
60
+ result = sdk.dte(company_website: "apple.com")
61
+ puts result.emails # => ["contact@apple.com", "info@apple.com"]
62
+ ```
63
+
64
+ #### 5. NTP - Name to Phones
65
+ ```ruby
66
+ result = sdk.ntp(company_name: "Apple Inc")
67
+ puts result.phones # => ["+1-408-996-1010"]
68
+ ```
69
+
70
+ #### 6. REL - Reverse Email Lookup
71
+ ```ruby
72
+ result = sdk.rel(email: "tim.cook@apple.com")
73
+ puts result.person.full_name # => "Tim Cook"
74
+ ```
75
+
76
+ #### 7. FCL - Find Company Lookalikes
77
+ ```ruby
78
+ result = sdk.fcl(query: "tech startup")
79
+ puts result.companies.length # => 10
80
+ ```
81
+
82
+ #### 8. ELF - Enrich LinkedIn Fundraising
83
+ ```ruby
84
+ result = sdk.elf(query: "tech company")
85
+ puts result.fundraising.funding_money_raised # => "$5M"
86
+ ```
87
+
88
+ #### 9. CAR - Company Annual Revenue
89
+ ```ruby
90
+ result = sdk.car(query: "Apple Inc")
91
+ puts result.revenue # => "$394.3B"
92
+ ```
93
+
94
+ #### 10. FCC - Find Company Children
95
+ ```ruby
96
+ result = sdk.fcc(query: "Apple Inc")
97
+ puts result.subsidiaries # => ["Beats Electronics", "Shazam"]
98
+ ```
99
+
100
+ #### 11. FTS - Find Tech Stack
101
+ ```ruby
102
+ result = sdk.fts(query: "web development")
103
+ puts result.technologies # => ["React", "Node.js", "Python"]
104
+ ```
105
+
106
+ #### 12. EPP - Enrich Person Profile
107
+ ```ruby
108
+ result = sdk.epp(linkedin_url: "linkedin.com/in/tim-cook")
109
+ puts result.person.full_name # => "Tim Cook"
110
+ ```
111
+
112
+ #### 13. FWE - Find Work Email
113
+ ```ruby
114
+ result = sdk.fwe(linkedin_url: "linkedin.com/in/tim-cook")
115
+ puts result.email # => "tim.cook@apple.com"
116
+ ```
117
+
118
+ #### 14. TEP - Title Email Phone
119
+ ```ruby
120
+ result = sdk.tep(full_name: "Tim Cook", company: "Apple Inc")
121
+ puts result.person.email # => "tim.cook@apple.com"
122
+ puts result.person.phone # => "+1-408-996-1010"
123
+ ```
124
+
125
+ #### 15. ENC - Enrich Company
126
+ ```ruby
127
+ result = sdk.enc(query: "Apple Inc")
128
+ puts result.company.employee_count # => 164000
129
+ ```
130
+
131
+ #### 16. CEC - Company Employee Count
132
+ ```ruby
133
+ result = sdk.cec(query: "Apple Inc")
134
+ puts result.countries # => {"US" => 100000, "CA" => 5000}
135
+ ```
136
+
137
+ #### 17. CLO - Company Locations
138
+ ```ruby
139
+ result = sdk.clo(query: "Apple Inc")
140
+ puts result.locations.first.city # => "Cupertino"
141
+ ```
142
+
143
+ #### 18. CSE - Company Search Engine
144
+ ```ruby
145
+ result = sdk.cse(name: "tech", country: "US", industry: "software")
146
+ puts result.companies.length # => 50
147
+ ```
148
+
149
+ #### 19. PSE - Person Search Engine
150
+ ```ruby
151
+ result = sdk.pse(full_name: "John", country: "US", company_name: "Apple")
152
+ puts result.peoples.length # => 25
153
+ ```
154
+
155
+ #### 20. LBS - Local Business Search
156
+ ```ruby
157
+ result = sdk.lbs(name: "restaurant", city: "New York")
158
+ puts result.companies.length # => 100
159
+ ```
160
+
161
+ ### Error Handling
162
+
163
+ The SDK provides comprehensive error handling:
164
+
165
+ ```ruby
166
+ begin
167
+ result = sdk.cuf(company_name: "Apple Inc", country_code: "US")
168
+ rescue CufinderRuby::AuthenticationError => e
169
+ puts "Authentication failed: #{e.message}"
170
+ rescue CufinderRuby::RateLimitError => e
171
+ puts "Rate limit exceeded: #{e.message}"
172
+ rescue CufinderRuby::CreditLimitError => e
173
+ puts "Credit limit exceeded: #{e.message}"
174
+ rescue CufinderRuby::ApiError => e
175
+ puts "API error #{e.status}: #{e.message}"
176
+ rescue CufinderRuby::ValidationError => e
177
+ puts "Validation error: #{e.message}"
178
+ end
179
+ ```
180
+
181
+ ### Configuration
182
+
183
+ You can configure the SDK with custom settings:
184
+
185
+ ```ruby
186
+ sdk = CufinderRuby::SDK.new(
187
+ api_key: 'your-api-key',
188
+ base_url: 'https://api.cufinder.io/v2', # Default
189
+ timeout: 30, # Default
190
+ max_retries: 3 # Default
191
+ )
192
+ ```
193
+
194
+ ## Development
195
+
196
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
197
+
198
+ To install this gem onto your local machine, run `bundle exec rake install`.
199
+
200
+ ## Contributing
201
+
202
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cufinder/cufinder-ruby.
203
+
204
+ ## License
205
+
206
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "cufinder-ruby"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["CUFinder Team"]
5
+ spec.email = ["support@cufinder.io"]
6
+
7
+ spec.summary = "Ruby SDK for the CUFinder API"
8
+ spec.description = "Official Ruby SDK for accessing CUFinder's services"
9
+ spec.homepage = "https://github.com/cufinder/cufinder-ruby"
10
+ spec.license = "MIT"
11
+
12
+ spec.metadata["homepage_uri"] = spec.homepage
13
+ spec.metadata["source_code_uri"] = "https://github.com/cufinder/cufinder-ruby"
14
+ spec.metadata["changelog_uri"] = "https://github.com/cufinder/cufinder-ruby/blob/main/CHANGELOG.md"
15
+
16
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "httparty", "~> 0.21"
24
+ spec.add_dependency "json", "~> 2.6"
25
+
26
+ spec.add_development_dependency "rspec", "~> 3.12"
27
+ spec.add_development_dependency "webmock", "~> 3.18"
28
+ spec.add_development_dependency "rake", "~> 13.0"
29
+ end
@@ -0,0 +1,84 @@
1
+ require "httparty"
2
+ require "json"
3
+ require "cufinder_ruby/errors"
4
+
5
+ module CufinderRuby
6
+ class Client
7
+ include HTTParty
8
+
9
+ attr_reader :api_key, :base_url, :timeout, :max_retries
10
+
11
+ def initialize(api_key:, base_url: "https://api.cufinder.io/v2", timeout: 30, max_retries: 3)
12
+ @api_key = api_key
13
+ @base_url = base_url
14
+ @timeout = timeout
15
+ @max_retries = max_retries
16
+
17
+ self.class.base_uri base_url
18
+ self.class.timeout timeout
19
+ self.class.headers "User-Agent" => "cufinder-ruby/#{CufinderRuby::VERSION}"
20
+ end
21
+
22
+ def post(endpoint, data)
23
+ response = self.class.post(
24
+ endpoint,
25
+ body: form_encode(data),
26
+ headers: {
27
+ "x-api-key" => api_key,
28
+ "Content-Type" => "application/x-www-form-urlencoded"
29
+ }
30
+ )
31
+
32
+ handle_response(response)
33
+ end
34
+
35
+ private
36
+
37
+ def form_encode(data)
38
+ return "" if data.nil? || data.empty?
39
+
40
+ data.map do |key, value|
41
+ next if value.nil?
42
+
43
+ if value.is_a?(Array)
44
+ value.map { |v| "#{key}=#{CGI.escape(v.to_s)}" }.join("&")
45
+ else
46
+ "#{key}=#{CGI.escape(value.to_s)}"
47
+ end
48
+ end.compact.join("&")
49
+ end
50
+
51
+ def handle_response(response)
52
+ case response.code
53
+ when 200..299
54
+ extract_data(response.parsed_response)
55
+ when 401
56
+ raise AuthenticationError, response.body
57
+ when 402
58
+ raise CreditLimitError, response.body
59
+ when 429
60
+ raise RateLimitError, response.body
61
+ else
62
+ raise ApiError.new(response.code, response.body)
63
+ end
64
+ rescue JSON::ParserError => e
65
+ raise HttpError, "Failed to parse response: #{e.message}"
66
+ rescue HTTParty::Error => e
67
+ raise HttpError, "HTTP request failed: #{e.message}"
68
+ end
69
+
70
+ def extract_data(response_data)
71
+ # Extract data from wrapper if present (similar to Go SDK's mapToStruct)
72
+ if response_data.is_a?(Hash) && response_data.key?("data")
73
+ data = response_data["data"]
74
+ # Add meta_data if it exists in the outer response
75
+ if response_data.key?("meta_data")
76
+ data["meta_data"] = response_data["meta_data"]
77
+ end
78
+ data
79
+ else
80
+ response_data
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ module CufinderRuby
2
+ class Error < StandardError; end
3
+
4
+ class AuthenticationError < Error; end
5
+ class RateLimitError < Error; end
6
+ class CreditLimitError < Error; end
7
+ class ApiError < Error
8
+ attr_reader :status, :message
9
+
10
+ def initialize(status, message)
11
+ @status = status
12
+ @message = message
13
+ super("API Error #{status}: #{message}")
14
+ end
15
+ end
16
+
17
+ class HttpError < Error; end
18
+ class ValidationError < Error; end
19
+ end
@@ -0,0 +1,99 @@
1
+ require "cufinder_ruby/client"
2
+ require "cufinder_ruby/services"
3
+
4
+ module CufinderRuby
5
+ class SDK
6
+ attr_reader :client, :services
7
+
8
+ def initialize(api_key:, base_url: "https://api.cufinder.io/v2", timeout: 30, max_retries: 3)
9
+ @client = Client.new(
10
+ api_key: api_key,
11
+ base_url: base_url,
12
+ timeout: timeout,
13
+ max_retries: max_retries
14
+ )
15
+ @services = Services.new(@client)
16
+ end
17
+
18
+ # Convenience methods for each service
19
+ def cuf(company_name:, country_code:)
20
+ @services.get_domain(company_name: company_name, country_code: country_code)
21
+ end
22
+
23
+ def lcuf(company_name:)
24
+ @services.get_linkedin_url(company_name: company_name)
25
+ end
26
+
27
+ def dtc(company_website:)
28
+ @services.get_company_name(company_website: company_website)
29
+ end
30
+
31
+ def dte(company_website:)
32
+ @services.get_emails(company_website: company_website)
33
+ end
34
+
35
+ def ntp(company_name:)
36
+ @services.get_phones(company_name: company_name)
37
+ end
38
+
39
+ def rel(email:)
40
+ @services.get_person_by_email(email: email)
41
+ end
42
+
43
+ def fcl(query:)
44
+ @services.find_company_lookalikes(query: query)
45
+ end
46
+
47
+ def elf(query:)
48
+ @services.enrich_linkedin_fundraising(query: query)
49
+ end
50
+
51
+ def car(query:)
52
+ @services.get_annual_revenue(query: query)
53
+ end
54
+
55
+ def fcc(query:)
56
+ @services.find_company_children(query: query)
57
+ end
58
+
59
+ def fts(query:)
60
+ @services.find_tech_stack(query: query)
61
+ end
62
+
63
+ def epp(linkedin_url:)
64
+ @services.enrich_person_profile(linkedin_url: linkedin_url)
65
+ end
66
+
67
+ def fwe(linkedin_url:)
68
+ @services.find_work_email(linkedin_url: linkedin_url)
69
+ end
70
+
71
+ def tep(full_name:, company:)
72
+ @services.get_title_email_phone(full_name: full_name, company: company)
73
+ end
74
+
75
+ def enc(query:)
76
+ @services.enrich_company(query: query)
77
+ end
78
+
79
+ def cec(query:)
80
+ @services.get_company_employee_count(query: query)
81
+ end
82
+
83
+ def clo(query:)
84
+ @services.get_company_locations(query: query)
85
+ end
86
+
87
+ def cse(**params)
88
+ @services.search_companies(params)
89
+ end
90
+
91
+ def pse(**params)
92
+ @services.search_people(params)
93
+ end
94
+
95
+ def lbs(**params)
96
+ @services.search_local_businesses(params)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,178 @@
1
+ require "cufinder_ruby/client"
2
+ require "cufinder_ruby/types"
3
+ require "cufinder_ruby/errors"
4
+
5
+ module CufinderRuby
6
+ class Services
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ # CUF Service - Company URL Finder
12
+ def get_domain(params)
13
+ validate_required(params, [:company_name, :country_code])
14
+
15
+ response = @client.post("/cuf", params)
16
+ CufResponse.new(response)
17
+ end
18
+
19
+ # LCUF Service - LinkedIn Company URL Finder
20
+ def get_linkedin_url(params)
21
+ validate_required(params, [:company_name])
22
+
23
+ response = @client.post("/lcuf", params)
24
+ LcufResponse.new(response)
25
+ end
26
+
27
+ # DTC Service - Domain to Company
28
+ def get_company_name(params)
29
+ validate_required(params, [:company_website])
30
+
31
+ response = @client.post("/dtc", params)
32
+ DtcResponse.new(response)
33
+ end
34
+
35
+ # DTE Service - Domain to Emails
36
+ def get_emails(params)
37
+ validate_required(params, [:company_website])
38
+
39
+ response = @client.post("/dte", params)
40
+ DteResponse.new(response)
41
+ end
42
+
43
+ # NTP Service - Name to Phones
44
+ def get_phones(params)
45
+ validate_required(params, [:company_name])
46
+
47
+ response = @client.post("/ntp", params)
48
+ NtpResponse.new(response)
49
+ end
50
+
51
+ # REL Service - Reverse Email Lookup
52
+ def get_person_by_email(params)
53
+ validate_required(params, [:email])
54
+
55
+ response = @client.post("/rel", params)
56
+ RelResponse.new(response)
57
+ end
58
+
59
+ # FCL Service - Find Company Lookalikes
60
+ def find_company_lookalikes(params)
61
+ validate_required(params, [:query])
62
+
63
+ response = @client.post("/fcl", params)
64
+ FclResponse.new(response)
65
+ end
66
+
67
+ # ELF Service - Enrich LinkedIn Fundraising
68
+ def enrich_linkedin_fundraising(params)
69
+ validate_required(params, [:query])
70
+
71
+ response = @client.post("/elf", params)
72
+ ElfResponse.new(response)
73
+ end
74
+
75
+ # CAR Service - Company Annual Revenue
76
+ def get_annual_revenue(params)
77
+ validate_required(params, [:query])
78
+
79
+ response = @client.post("/car", params)
80
+ CarResponse.new(response)
81
+ end
82
+
83
+ # FCC Service - Find Company Children
84
+ def find_company_children(params)
85
+ validate_required(params, [:query])
86
+
87
+ response = @client.post("/fcc", params)
88
+ FccResponse.new(response)
89
+ end
90
+
91
+ # FTS Service - Find Tech Stack
92
+ def find_tech_stack(params)
93
+ validate_required(params, [:query])
94
+
95
+ response = @client.post("/fts", params)
96
+ FtsResponse.new(response)
97
+ end
98
+
99
+ # EPP Service - Enrich Person Profile
100
+ def enrich_person_profile(params)
101
+ validate_required(params, [:linkedin_url])
102
+
103
+ response = @client.post("/epp", params)
104
+ EppResponse.new(response)
105
+ end
106
+
107
+ # FWE Service - Find Work Email
108
+ def find_work_email(params)
109
+ validate_required(params, [:linkedin_url])
110
+
111
+ response = @client.post("/fwe", params)
112
+ FweResponse.new(response)
113
+ end
114
+
115
+ # TEP Service - Title Email Phone
116
+ def get_title_email_phone(params)
117
+ validate_required(params, [:full_name, :company])
118
+
119
+ response = @client.post("/tep", params)
120
+ TepResponse.new(response)
121
+ end
122
+
123
+ # ENC Service - Enrich Company
124
+ def enrich_company(params)
125
+ validate_required(params, [:query])
126
+
127
+ response = @client.post("/enc", params)
128
+ EncResponse.new(response)
129
+ end
130
+
131
+ # CEC Service - Company Employee Count
132
+ def get_company_employee_count(params)
133
+ validate_required(params, [:query])
134
+
135
+ response = @client.post("/cec", params)
136
+ CecResponse.new(response)
137
+ end
138
+
139
+ # CLO Service - Company Locations
140
+ def get_company_locations(params)
141
+ validate_required(params, [:query])
142
+
143
+ response = @client.post("/clo", params)
144
+ CloResponse.new(response)
145
+ end
146
+
147
+ # CSE Service - Company Search Engine
148
+ def search_companies(params)
149
+ # All parameters are optional for CSE
150
+ response = @client.post("/cse", params)
151
+ CseResponse.new(response)
152
+ end
153
+
154
+ # PSE Service - Person Search Engine
155
+ def search_people(params)
156
+ # All parameters are optional for PSE
157
+ response = @client.post("/pse", params)
158
+ PseResponse.new(response)
159
+ end
160
+
161
+ # LBS Service - Local Business Search
162
+ def search_local_businesses(params)
163
+ # All parameters are optional for LBS
164
+ response = @client.post("/lbs", params)
165
+ LbsResponse.new(response)
166
+ end
167
+
168
+ private
169
+
170
+ def validate_required(params, required_fields)
171
+ missing_fields = required_fields.select { |field| params[field].nil? || params[field].to_s.strip.empty? }
172
+
173
+ unless missing_fields.empty?
174
+ raise ValidationError, "Missing required fields: #{missing_fields.join(', ')}"
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,521 @@
1
+ module CufinderRuby
2
+ # Base response structure for all CUFinder API responses
3
+ class BaseResponse
4
+ attr_accessor :query, :credit_count, :meta_data, :confidence_level
5
+
6
+ def initialize(data = {})
7
+ @query = data["query"]
8
+ @credit_count = data["credit_count"]
9
+ @meta_data = data["meta_data"]
10
+ @confidence_level = data["confidence_level"]
11
+ end
12
+ end
13
+
14
+ # Company main location
15
+ class MainLocation
16
+ attr_accessor :geo, :country, :state, :city, :address, :continent, :postal_code
17
+
18
+ def initialize(data = {})
19
+ @geo = data["geo"]
20
+ @country = data["country"]
21
+ @state = data["state"]
22
+ @city = data["city"]
23
+ @address = data["address"]
24
+ @continent = data["continent"]
25
+ @postal_code = data["postal_code"]
26
+ end
27
+ end
28
+
29
+ # Company social media information
30
+ class CompanySocial
31
+ attr_accessor :facebook, :linkedin, :twitter, :youtube, :instagram
32
+
33
+ def initialize(data = {})
34
+ @facebook = data["facebook"]
35
+ @linkedin = data["linkedin"]
36
+ @twitter = data["twitter"]
37
+ @youtube = data["youtube"]
38
+ @instagram = data["instagram"]
39
+ end
40
+ end
41
+
42
+ # Company employee information
43
+ class CompanyEmployees
44
+ attr_accessor :range, :count
45
+
46
+ def initialize(data = {})
47
+ @range = data["range"]
48
+ @count = data["count"]
49
+ end
50
+ end
51
+
52
+ # Company information model
53
+ class Company
54
+ attr_accessor :name, :domain, :linkedin_url, :industry, :overview, :type, :size,
55
+ :main_location, :location, :description, :founded, :revenue,
56
+ :employees, :website, :phone, :email, :social, :technologies,
57
+ :subsidiaries, :headquarters, :country, :state, :city, :zip_code, :address
58
+
59
+ def initialize(data = {})
60
+ @name = data["name"]
61
+ @domain = data["domain"]
62
+ @linkedin_url = data["linkedin_url"]
63
+ @industry = data["industry"]
64
+ @overview = data["overview"]
65
+ @type = data["type"]
66
+ @size = data["size"]
67
+ @main_location = data["main_location"] ? MainLocation.new(data["main_location"]) : nil
68
+ @location = data["location"]
69
+ @description = data["description"]
70
+ @founded = data["founded"]
71
+ @revenue = data["revenue"]
72
+ @employees = data["employees"] ? CompanyEmployees.new(data["employees"]) : nil
73
+ @website = data["website"]
74
+ @phone = data["phone"]
75
+ @email = data["email"]
76
+ @social = data["social"] ? CompanySocial.new(data["social"]) : nil
77
+ @technologies = data["technologies"]
78
+ @subsidiaries = data["subsidiaries"]
79
+ @headquarters = data["headquarters"]
80
+ @country = data["country"]
81
+ @state = data["state"]
82
+ @city = data["city"]
83
+ @zip_code = data["zip_code"]
84
+ @address = data["address"]
85
+ end
86
+ end
87
+
88
+ # Person location information
89
+ class PersonLocation
90
+ attr_accessor :country, :state, :city
91
+
92
+ def initialize(data = {})
93
+ @country = data["country"]
94
+ @state = data["state"]
95
+ @city = data["city"]
96
+ end
97
+ end
98
+
99
+ # Person social media information
100
+ class PersonSocial
101
+ attr_accessor :linkedin_username, :linkedin_connections, :linkedin, :twitter, :facebook, :github
102
+
103
+ def initialize(data = {})
104
+ @linkedin_username = data["linkedin_username"]
105
+ @linkedin_connections = data["linkedin_connections"]
106
+ @linkedin = data["linkedin"]
107
+ @twitter = data["twitter"]
108
+ @facebook = data["facebook"]
109
+ @github = data["github"]
110
+ end
111
+ end
112
+
113
+ # Current job information
114
+ class CurrentJob
115
+ attr_accessor :title, :role, :level
116
+
117
+ def initialize(data = {})
118
+ @title = data["title"]
119
+ @role = data["role"]
120
+ @level = data["level"]
121
+ end
122
+ end
123
+
124
+ # Person information model
125
+ class Person
126
+ attr_accessor :first_name, :last_name, :full_name, :logo, :overview, :experience,
127
+ :connections, :interests, :skills, :educations, :experiences,
128
+ :certifications, :company, :location, :current_job, :social
129
+
130
+ def initialize(data = {})
131
+ @first_name = data["first_name"]
132
+ @last_name = data["last_name"]
133
+ @full_name = data["full_name"]
134
+ @logo = data["logo"]
135
+ @overview = data["overview"]
136
+ @experience = data["experience"]
137
+ @connections = data["connections"]
138
+ @interests = data["interests"]
139
+ @skills = data["skills"]
140
+ @educations = data["educations"]
141
+ @experiences = data["experiences"]
142
+ @certifications = data["certifications"]
143
+ @company = data["company"] ? Company.new(data["company"]) : nil
144
+ @location = data["location"] ? PersonLocation.new(data["location"]) : nil
145
+ @current_job = data["current_job"] ? CurrentJob.new(data["current_job"]) : nil
146
+ @social = data["social"] ? PersonSocial.new(data["social"]) : nil
147
+ end
148
+ end
149
+
150
+ # Response types for each service
151
+ class CufResponse < BaseResponse
152
+ attr_accessor :domain
153
+
154
+ def initialize(data = {})
155
+ super(data)
156
+ @domain = data["domain"]
157
+ end
158
+ end
159
+
160
+ class LcufResponse < BaseResponse
161
+ attr_accessor :linkedin_url
162
+
163
+ def initialize(data = {})
164
+ super(data)
165
+ @linkedin_url = data["linkedin_url"]
166
+ end
167
+ end
168
+
169
+ class DtcResponse < BaseResponse
170
+ attr_accessor :company_name
171
+
172
+ def initialize(data = {})
173
+ super(data)
174
+ @company_name = data["company_name"]
175
+ end
176
+ end
177
+
178
+ class DteResponse < BaseResponse
179
+ attr_accessor :emails
180
+
181
+ def initialize(data = {})
182
+ super(data)
183
+ @emails = data["emails"] || []
184
+ end
185
+ end
186
+
187
+ class NtpResponse < BaseResponse
188
+ attr_accessor :phones
189
+
190
+ def initialize(data = {})
191
+ super(data)
192
+ @phones = data["phones"] || []
193
+ end
194
+ end
195
+
196
+ # REL Person
197
+ class RelPerson
198
+ attr_accessor :full_name, :first_name, :last_name, :linkedin_url, :summary,
199
+ :linkedin_followers, :facebook, :twitter, :avatar, :country,
200
+ :state, :city, :job_title, :job_title_categories, :company_name,
201
+ :company_linkedin, :company_website, :company_size, :company_industry,
202
+ :company_facebook, :company_twitter, :company_country, :company_state, :company_city
203
+
204
+ def initialize(data = {})
205
+ @full_name = data["full_name"]
206
+ @first_name = data["first_name"]
207
+ @last_name = data["last_name"]
208
+ @linkedin_url = data["linkedin_url"]
209
+ @summary = data["summary"]
210
+ @linkedin_followers = data["linkedin_followers"]
211
+ @facebook = data["facebook"]
212
+ @twitter = data["twitter"]
213
+ @avatar = data["avatar"]
214
+ @country = data["country"]
215
+ @state = data["state"]
216
+ @city = data["city"]
217
+ @job_title = data["job_title"]
218
+ @job_title_categories = data["job_title_categories"]
219
+ @company_name = data["company_name"]
220
+ @company_linkedin = data["company_linkedin"]
221
+ @company_website = data["company_website"]
222
+ @company_size = data["company_size"]
223
+ @company_industry = data["company_industry"]
224
+ @company_facebook = data["company_facebook"]
225
+ @company_twitter = data["company_twitter"]
226
+ @company_country = data["company_country"]
227
+ @company_state = data["company_state"]
228
+ @company_city = data["company_city"]
229
+ end
230
+ end
231
+
232
+ class RelResponse < BaseResponse
233
+ attr_accessor :person
234
+
235
+ def initialize(data = {})
236
+ super(data)
237
+ @person = data["person"] ? RelPerson.new(data["person"]) : nil
238
+ end
239
+ end
240
+
241
+ # FCL Company
242
+ class FclCompany
243
+ attr_accessor :name, :website, :employee_count, :size, :industry, :description,
244
+ :linkedin_url, :domain, :country, :state, :city, :address,
245
+ :founded_year, :logo_url, :followers_count
246
+
247
+ def initialize(data = {})
248
+ @name = data["name"]
249
+ @website = data["website"]
250
+ @employee_count = data["employee_count"]
251
+ @size = data["size"]
252
+ @industry = data["industry"]
253
+ @description = data["description"]
254
+ @linkedin_url = data["linkedin_url"]
255
+ @domain = data["domain"]
256
+ @country = data["country"]
257
+ @state = data["state"]
258
+ @city = data["city"]
259
+ @address = data["address"]
260
+ @founded_year = data["founded_year"]
261
+ @logo_url = data["logo_url"]
262
+ @followers_count = data["followers_count"]
263
+ end
264
+ end
265
+
266
+ class FclResponse < BaseResponse
267
+ attr_accessor :companies
268
+
269
+ def initialize(data = {})
270
+ super(data)
271
+ @companies = (data["companies"] || []).map { |c| FclCompany.new(c) }
272
+ end
273
+ end
274
+
275
+ # ELF Fundraising
276
+ class ElfFundraising
277
+ attr_accessor :funding_last_round_type, :funding_ammount_currency_code,
278
+ :funding_money_raised, :funding_last_round_investors_url
279
+
280
+ def initialize(data = {})
281
+ @funding_last_round_type = data["funding_last_round_type"]
282
+ @funding_ammount_currency_code = data["funding_ammount_currency_code"]
283
+ @funding_money_raised = data["funding_money_raised"]
284
+ @funding_last_round_investors_url = data["funding_last_round_investors_url"]
285
+ end
286
+ end
287
+
288
+ class ElfResponse < BaseResponse
289
+ attr_accessor :fundraising
290
+
291
+ def initialize(data = {})
292
+ super(data)
293
+ @fundraising = data["fundraising_info"] ? ElfFundraising.new(data["fundraising_info"]) : nil
294
+ end
295
+ end
296
+
297
+ class CarResponse < BaseResponse
298
+ attr_accessor :revenue
299
+
300
+ def initialize(data = {})
301
+ super(data)
302
+ @revenue = data["annual_revenue"]
303
+ end
304
+ end
305
+
306
+ class FccResponse < BaseResponse
307
+ attr_accessor :subsidiaries
308
+
309
+ def initialize(data = {})
310
+ super(data)
311
+ @subsidiaries = data["subsidiaries"] || []
312
+ end
313
+ end
314
+
315
+ class FtsResponse < BaseResponse
316
+ attr_accessor :technologies
317
+
318
+ def initialize(data = {})
319
+ super(data)
320
+ @technologies = data["technologies"] || []
321
+ end
322
+ end
323
+
324
+ # EPP Person
325
+ class EppPerson
326
+ attr_accessor :full_name, :first_name, :last_name, :linkedin_url, :summary,
327
+ :linkedin_followers, :facebook, :twitter, :avatar, :country,
328
+ :state, :city, :job_title, :job_title_categories, :company_name,
329
+ :company_linkedin, :company_website, :company_size, :company_industry,
330
+ :company_facebook, :company_twitter, :company_country, :company_state, :company_city
331
+
332
+ def initialize(data = {})
333
+ @full_name = data["full_name"]
334
+ @first_name = data["first_name"]
335
+ @last_name = data["last_name"]
336
+ @linkedin_url = data["linkedin_url"]
337
+ @summary = data["summary"]
338
+ @linkedin_followers = data["linkedin_followers"]
339
+ @facebook = data["facebook"]
340
+ @twitter = data["twitter"]
341
+ @avatar = data["avatar"]
342
+ @country = data["country"]
343
+ @state = data["state"]
344
+ @city = data["city"]
345
+ @job_title = data["job_title"]
346
+ @job_title_categories = data["job_title_categories"]
347
+ @company_name = data["company_name"]
348
+ @company_linkedin = data["company_linkedin"]
349
+ @company_website = data["company_website"]
350
+ @company_size = data["company_size"]
351
+ @company_industry = data["company_industry"]
352
+ @company_facebook = data["company_facebook"]
353
+ @company_twitter = data["company_twitter"]
354
+ @company_country = data["company_country"]
355
+ @company_state = data["company_state"]
356
+ @company_city = data["company_city"]
357
+ end
358
+ end
359
+
360
+ class EppResponse < BaseResponse
361
+ attr_accessor :person
362
+
363
+ def initialize(data = {})
364
+ super(data)
365
+ @person = data["person"] ? EppPerson.new(data["person"]) : nil
366
+ end
367
+ end
368
+
369
+ class FweResponse < BaseResponse
370
+ attr_accessor :email
371
+
372
+ def initialize(data = {})
373
+ super(data)
374
+ @email = data["work_email"]
375
+ end
376
+ end
377
+
378
+ # TEP Person
379
+ class TepPerson
380
+ attr_accessor :full_name, :first_name, :last_name, :linkedin_url, :summary,
381
+ :linkedin_followers, :facebook, :twitter, :avatar, :country,
382
+ :state, :city, :job_title, :job_title_categories, :company_name,
383
+ :company_linkedin, :company_website, :company_size, :company_industry,
384
+ :company_facebook, :company_twitter, :company_country, :company_state,
385
+ :company_city, :email, :phone
386
+
387
+ def initialize(data = {})
388
+ @full_name = data["full_name"]
389
+ @first_name = data["first_name"]
390
+ @last_name = data["last_name"]
391
+ @linkedin_url = data["linkedin_url"]
392
+ @summary = data["summary"]
393
+ @linkedin_followers = data["linkedin_followers"]
394
+ @facebook = data["facebook"]
395
+ @twitter = data["twitter"]
396
+ @avatar = data["avatar"]
397
+ @country = data["country"]
398
+ @state = data["state"]
399
+ @city = data["city"]
400
+ @job_title = data["job_title"]
401
+ @job_title_categories = data["job_title_categories"]
402
+ @company_name = data["company_name"]
403
+ @company_linkedin = data["company_linkedin"]
404
+ @company_website = data["company_website"]
405
+ @company_size = data["company_size"]
406
+ @company_industry = data["company_industry"]
407
+ @company_facebook = data["company_facebook"]
408
+ @company_twitter = data["company_twitter"]
409
+ @company_country = data["company_country"]
410
+ @company_state = data["company_state"]
411
+ @company_city = data["company_city"]
412
+ @email = data["email"]
413
+ @phone = data["phone"]
414
+ end
415
+ end
416
+
417
+ class TepResponse < BaseResponse
418
+ attr_accessor :person
419
+
420
+ def initialize(data = {})
421
+ super(data)
422
+ @person = data["person"] ? TepPerson.new(data["person"]) : nil
423
+ end
424
+ end
425
+
426
+ # ENC Company
427
+ class EncCompany
428
+ attr_accessor :name, :website, :employee_count, :industry, :size, :description,
429
+ :linkedin_url, :type, :domain, :country, :state, :city, :address,
430
+ :founded_year, :logo_url, :followers_count
431
+
432
+ def initialize(data = {})
433
+ @name = data["name"]
434
+ @website = data["website"]
435
+ @employee_count = data["employee_count"]
436
+ @industry = data["industry"]
437
+ @size = data["size"]
438
+ @description = data["description"]
439
+ @linkedin_url = data["linkedin_url"]
440
+ @type = data["type"]
441
+ @domain = data["domain"]
442
+ @country = data["country"]
443
+ @state = data["state"]
444
+ @city = data["city"]
445
+ @address = data["address"]
446
+ @founded_year = data["founded_year"]
447
+ @logo_url = data["logo_url"]
448
+ @followers_count = data["followers_count"]
449
+ end
450
+ end
451
+
452
+ class EncResponse < BaseResponse
453
+ attr_accessor :company
454
+
455
+ def initialize(data = {})
456
+ super(data)
457
+ @company = data["company"] ? EncCompany.new(data["company"]) : nil
458
+ end
459
+ end
460
+
461
+ class CecResponse < BaseResponse
462
+ attr_accessor :countries
463
+
464
+ def initialize(data = {})
465
+ super(data)
466
+ @countries = data["countries"]
467
+ end
468
+ end
469
+
470
+ # CLO Location
471
+ class CloLocation
472
+ attr_accessor :country, :state, :city, :postal_code, :line1, :line2, :latitude, :longitude
473
+
474
+ def initialize(data = {})
475
+ @country = data["country"]
476
+ @state = data["state"]
477
+ @city = data["city"]
478
+ @postal_code = data["postal_code"]
479
+ @line1 = data["line1"]
480
+ @line2 = data["line2"]
481
+ @latitude = data["latitude"]
482
+ @longitude = data["longitude"]
483
+ end
484
+ end
485
+
486
+ class CloResponse < BaseResponse
487
+ attr_accessor :locations
488
+
489
+ def initialize(data = {})
490
+ super(data)
491
+ @locations = (data["locations"] || []).map { |l| CloLocation.new(l) }
492
+ end
493
+ end
494
+
495
+ class CseResponse < BaseResponse
496
+ attr_accessor :companies
497
+
498
+ def initialize(data = {})
499
+ super(data)
500
+ @companies = (data["companies"] || []).map { |c| Company.new(c) }
501
+ end
502
+ end
503
+
504
+ class PseResponse < BaseResponse
505
+ attr_accessor :peoples
506
+
507
+ def initialize(data = {})
508
+ super(data)
509
+ @peoples = (data["peoples"] || []).map { |p| Person.new(p) }
510
+ end
511
+ end
512
+
513
+ class LbsResponse < BaseResponse
514
+ attr_accessor :companies
515
+
516
+ def initialize(data = {})
517
+ super(data)
518
+ @companies = (data["companies"] || []).map { |c| Company.new(c) }
519
+ end
520
+ end
521
+ end
@@ -0,0 +1,3 @@
1
+ module CufinderRuby
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "cufinder_ruby/version"
2
+ require "cufinder_ruby/client"
3
+ require "cufinder_ruby/sdk"
4
+ require "cufinder_ruby/errors"
5
+
6
+ module CufinderRuby
7
+ class Error < StandardError; end
8
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cufinder-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - CUFinder Team
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-10-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.21'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.21'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.18'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.18'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ description: Official Ruby SDK for accessing CUFinder's services
84
+ email:
85
+ - support@cufinder.io
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - cufinder-ruby.gemspec
97
+ - lib/cufinder_ruby.rb
98
+ - lib/cufinder_ruby/client.rb
99
+ - lib/cufinder_ruby/errors.rb
100
+ - lib/cufinder_ruby/sdk.rb
101
+ - lib/cufinder_ruby/services.rb
102
+ - lib/cufinder_ruby/types.rb
103
+ - lib/cufinder_ruby/version.rb
104
+ homepage: https://github.com/cufinder/cufinder-ruby
105
+ licenses:
106
+ - MIT
107
+ metadata:
108
+ homepage_uri: https://github.com/cufinder/cufinder-ruby
109
+ source_code_uri: https://github.com/cufinder/cufinder-ruby
110
+ changelog_uri: https://github.com/cufinder/cufinder-ruby/blob/main/CHANGELOG.md
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubygems_version: 3.4.20
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Ruby SDK for the CUFinder API
130
+ test_files: []