ventureinkorea 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/ventureinkorea/client.rb +157 -0
- data/lib/ventureinkorea/errors.rb +20 -0
- data/lib/ventureinkorea/types.rb +147 -0
- data/lib/ventureinkorea/version.rb +5 -0
- data/lib/ventureinkorea.rb +6 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6ab3dad5ecde3a5cfab9883b03ff2664ab51f3c274ee41411d2e3b686e0071ca
|
|
4
|
+
data.tar.gz: 6b4ebfb2f4caa9b16e2e97a773317a97c733264e513b71b2ab119a61d1dbc853
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fd814374cfb6b84f60870b47f33e8c267bebfd979df93c1b45b46dd915c0eaf38eae4b330f6c669ff8ef0d01b722fff76cfc2fcb5c876c1eb281ec8d473ce2d2
|
|
7
|
+
data.tar.gz: d69f5ff5bb999a9d04664573f098da80f17def10a9a1f83a1a5618de7977f7eeef85e2f01c053d636329eddb6db5472f7d1ce5164dc099d572223db78ad6164b
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module VentureInKorea
|
|
8
|
+
# HTTP client for the VentureInKorea REST API.
|
|
9
|
+
#
|
|
10
|
+
# All methods return typed Ruby objects (GlossaryTerm, BlogPost, Company).
|
|
11
|
+
# Zero runtime dependencies — uses only Ruby stdlib (net/http, json, uri).
|
|
12
|
+
#
|
|
13
|
+
# client = VentureInKorea::Client.new
|
|
14
|
+
# terms = client.list_terms
|
|
15
|
+
# term = client.get_term("venture-certification")
|
|
16
|
+
# puts term.name
|
|
17
|
+
#
|
|
18
|
+
class Client
|
|
19
|
+
DEFAULT_BASE_URL = "https://ventureinkorea.com"
|
|
20
|
+
DEFAULT_TIMEOUT = 30
|
|
21
|
+
|
|
22
|
+
def initialize(base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT)
|
|
23
|
+
@base_url = base_url.chomp("/")
|
|
24
|
+
@timeout = timeout
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# List all glossary terms.
|
|
28
|
+
#
|
|
29
|
+
# @param params [Hash] optional query parameters
|
|
30
|
+
# @return [Array<GlossaryTerm>]
|
|
31
|
+
def list_terms(**params)
|
|
32
|
+
data = get("/api/v1/terms/", params)
|
|
33
|
+
results = data["results"] || []
|
|
34
|
+
results.map { |h| GlossaryTerm.from_hash(h) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Get a glossary term by slug.
|
|
38
|
+
#
|
|
39
|
+
# @param slug [String] term slug
|
|
40
|
+
# @return [GlossaryTerm]
|
|
41
|
+
# @raise [NotFoundError] if the term does not exist
|
|
42
|
+
def get_term(slug)
|
|
43
|
+
data = get("/api/v1/terms/#{slug}/")
|
|
44
|
+
GlossaryTerm.from_hash(data)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# List all blog posts.
|
|
48
|
+
#
|
|
49
|
+
# @param params [Hash] optional query parameters
|
|
50
|
+
# @return [Array<BlogPost>]
|
|
51
|
+
def list_posts(**params)
|
|
52
|
+
data = get("/api/v1/posts/", params)
|
|
53
|
+
results = data["results"] || []
|
|
54
|
+
results.map { |h| BlogPost.from_hash(h) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Get a blog post by slug.
|
|
58
|
+
#
|
|
59
|
+
# @param slug [String] post slug
|
|
60
|
+
# @return [BlogPost]
|
|
61
|
+
# @raise [NotFoundError] if the post does not exist
|
|
62
|
+
def get_post(slug)
|
|
63
|
+
data = get("/api/v1/posts/#{slug}/")
|
|
64
|
+
BlogPost.from_hash(data)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# List all venture-certified companies.
|
|
68
|
+
#
|
|
69
|
+
# @param params [Hash] optional query parameters
|
|
70
|
+
# @return [Array<Company>]
|
|
71
|
+
def list_companies(**params)
|
|
72
|
+
data = get("/api/v1/companies/", params)
|
|
73
|
+
results = data["results"] || []
|
|
74
|
+
results.map { |h| Company.from_hash(h) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Get a company by primary key.
|
|
78
|
+
#
|
|
79
|
+
# @param pk [Integer] company ID
|
|
80
|
+
# @return [Company]
|
|
81
|
+
# @raise [NotFoundError] if the company does not exist
|
|
82
|
+
def get_company(pk)
|
|
83
|
+
data = get("/api/v1/companies/#{pk}/")
|
|
84
|
+
Company.from_hash(data)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# List all post categories.
|
|
88
|
+
#
|
|
89
|
+
# @return [Array<PostCategory>]
|
|
90
|
+
def list_categories
|
|
91
|
+
data = get("/api/v1/categories/")
|
|
92
|
+
results = data["results"] || []
|
|
93
|
+
results.map { |h| PostCategory.from_hash(h) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# List aggregated FAQs.
|
|
97
|
+
#
|
|
98
|
+
# @param params [Hash] optional query parameters
|
|
99
|
+
# @return [Array<FAQ>]
|
|
100
|
+
def list_faqs(**params)
|
|
101
|
+
data = get("/api/v1/faq/", params)
|
|
102
|
+
results = data["results"] || []
|
|
103
|
+
results.map { |h| FAQ.from_hash(h) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Get platform-wide statistics.
|
|
107
|
+
#
|
|
108
|
+
# @return [PlatformStats]
|
|
109
|
+
def get_stats
|
|
110
|
+
data = get("/api/v1/stats/")
|
|
111
|
+
PlatformStats.from_hash(data)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Search across all content.
|
|
115
|
+
#
|
|
116
|
+
# @param query [String] search query
|
|
117
|
+
# @return [Hash] search results with :results, :query, :total
|
|
118
|
+
def search(query)
|
|
119
|
+
get("/api/v1/search/", q: query)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Autocomplete suggestions.
|
|
123
|
+
#
|
|
124
|
+
# @param query [String] partial query
|
|
125
|
+
# @return [Hash] autocomplete results
|
|
126
|
+
def autocomplete(query)
|
|
127
|
+
get("/api/v1/autocomplete/", q: query)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def get(path, params = {})
|
|
133
|
+
uri = URI("#{@base_url}#{path}")
|
|
134
|
+
uri.query = URI.encode_www_form(params.reject { |_, v| v.nil? || v.to_s.empty? }) unless params.empty?
|
|
135
|
+
|
|
136
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
137
|
+
http.use_ssl = uri.scheme == "https"
|
|
138
|
+
http.open_timeout = @timeout
|
|
139
|
+
http.read_timeout = @timeout
|
|
140
|
+
|
|
141
|
+
request = Net::HTTP::Get.new(uri)
|
|
142
|
+
response = http.request(request)
|
|
143
|
+
|
|
144
|
+
case response
|
|
145
|
+
when Net::HTTPSuccess
|
|
146
|
+
JSON.parse(response.body)
|
|
147
|
+
when Net::HTTPNotFound
|
|
148
|
+
raise NotFoundError, "Not found: #{path}"
|
|
149
|
+
when Net::HTTPTooManyRequests
|
|
150
|
+
retry_after = response["Retry-After"]&.to_i
|
|
151
|
+
raise RateLimitError.new("Rate limit exceeded", retry_after: retry_after)
|
|
152
|
+
else
|
|
153
|
+
raise Error, "API error (HTTP #{response.code}): #{response.body}"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module VentureInKorea
|
|
4
|
+
# General API error.
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Raised when the server returns HTTP 404.
|
|
8
|
+
class NotFoundError < Error; end
|
|
9
|
+
|
|
10
|
+
# Raised when the server returns HTTP 429.
|
|
11
|
+
# Exposes the Retry-After header value when present.
|
|
12
|
+
class RateLimitError < Error
|
|
13
|
+
attr_reader :retry_after
|
|
14
|
+
|
|
15
|
+
def initialize(message = "Rate limit exceeded", retry_after: nil)
|
|
16
|
+
@retry_after = retry_after
|
|
17
|
+
super(message)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module VentureInKorea
|
|
4
|
+
# A Korean venture/startup glossary term.
|
|
5
|
+
class GlossaryTerm
|
|
6
|
+
attr_reader :name, :slug, :definition, :category, :related_terms, :url
|
|
7
|
+
|
|
8
|
+
def initialize(name:, slug:, definition: "", category: "", related_terms: [], url: "")
|
|
9
|
+
@name = name
|
|
10
|
+
@slug = slug
|
|
11
|
+
@definition = definition
|
|
12
|
+
@category = category
|
|
13
|
+
@related_terms = related_terms
|
|
14
|
+
@url = url
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.from_hash(hash)
|
|
18
|
+
new(
|
|
19
|
+
name: hash["name"],
|
|
20
|
+
slug: hash["slug"],
|
|
21
|
+
definition: hash["definition"] || "",
|
|
22
|
+
category: hash["category"] || "",
|
|
23
|
+
related_terms: hash["related_terms"] || [],
|
|
24
|
+
url: hash["url"] || ""
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# A blog post about the Korean startup ecosystem.
|
|
30
|
+
class BlogPost
|
|
31
|
+
attr_reader :title, :slug, :excerpt, :content, :category, :published_at, :faqs, :url
|
|
32
|
+
|
|
33
|
+
def initialize(title:, slug:, excerpt: "", content: "", category: "",
|
|
34
|
+
published_at: "", faqs: [], url: "")
|
|
35
|
+
@title = title
|
|
36
|
+
@slug = slug
|
|
37
|
+
@excerpt = excerpt
|
|
38
|
+
@content = content
|
|
39
|
+
@category = category
|
|
40
|
+
@published_at = published_at
|
|
41
|
+
@faqs = faqs
|
|
42
|
+
@url = url
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.from_hash(hash)
|
|
46
|
+
new(
|
|
47
|
+
title: hash["title"],
|
|
48
|
+
slug: hash["slug"],
|
|
49
|
+
excerpt: hash["excerpt"] || "",
|
|
50
|
+
content: hash["content"] || "",
|
|
51
|
+
category: hash["category"] || "",
|
|
52
|
+
published_at: hash["published_at"] || "",
|
|
53
|
+
faqs: (hash["faqs"] || []).map { |f| FAQ.from_hash(f) },
|
|
54
|
+
url: hash["url"] || ""
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# A venture-certified company (벤처인증기업).
|
|
60
|
+
class Company
|
|
61
|
+
attr_reader :id, :name, :description, :industry, :certification_type, :founded_year, :url
|
|
62
|
+
|
|
63
|
+
def initialize(id:, name:, description: "", industry: "", certification_type: "",
|
|
64
|
+
founded_year: nil, url: "")
|
|
65
|
+
@id = id
|
|
66
|
+
@name = name
|
|
67
|
+
@description = description
|
|
68
|
+
@industry = industry
|
|
69
|
+
@certification_type = certification_type
|
|
70
|
+
@founded_year = founded_year
|
|
71
|
+
@url = url
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.from_hash(hash)
|
|
75
|
+
new(
|
|
76
|
+
id: hash["id"],
|
|
77
|
+
name: hash["name"],
|
|
78
|
+
description: hash["description"] || "",
|
|
79
|
+
industry: hash["industry"] || "",
|
|
80
|
+
certification_type: hash["certification_type"] || "",
|
|
81
|
+
founded_year: hash["founded_year"],
|
|
82
|
+
url: hash["url"] || ""
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# A frequently asked question.
|
|
88
|
+
class FAQ
|
|
89
|
+
attr_reader :question, :answer, :source_type, :source_slug
|
|
90
|
+
|
|
91
|
+
def initialize(question:, answer:, source_type: "", source_slug: "")
|
|
92
|
+
@question = question
|
|
93
|
+
@answer = answer
|
|
94
|
+
@source_type = source_type
|
|
95
|
+
@source_slug = source_slug
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.from_hash(hash)
|
|
99
|
+
new(
|
|
100
|
+
question: hash["question"],
|
|
101
|
+
answer: hash["answer"],
|
|
102
|
+
source_type: hash["source_type"] || "",
|
|
103
|
+
source_slug: hash["source_slug"] || ""
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# A post category.
|
|
109
|
+
class PostCategory
|
|
110
|
+
attr_reader :name, :slug, :post_count
|
|
111
|
+
|
|
112
|
+
def initialize(name:, slug:, post_count: 0)
|
|
113
|
+
@name = name
|
|
114
|
+
@slug = slug
|
|
115
|
+
@post_count = post_count
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.from_hash(hash)
|
|
119
|
+
new(
|
|
120
|
+
name: hash["name"],
|
|
121
|
+
slug: hash["slug"],
|
|
122
|
+
post_count: hash["post_count"] || 0
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Platform-wide statistics.
|
|
128
|
+
class PlatformStats
|
|
129
|
+
attr_reader :total_companies, :total_posts, :total_terms, :total_faqs
|
|
130
|
+
|
|
131
|
+
def initialize(total_companies: 0, total_posts: 0, total_terms: 0, total_faqs: 0)
|
|
132
|
+
@total_companies = total_companies
|
|
133
|
+
@total_posts = total_posts
|
|
134
|
+
@total_terms = total_terms
|
|
135
|
+
@total_faqs = total_faqs
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def self.from_hash(hash)
|
|
139
|
+
new(
|
|
140
|
+
total_companies: hash["total_companies"] || 0,
|
|
141
|
+
total_posts: hash["total_posts"] || 0,
|
|
142
|
+
total_terms: hash["total_terms"] || 0,
|
|
143
|
+
total_faqs: hash["total_faqs"] || 0
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ventureinkorea
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- dobestan
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-29 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '13.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '13.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: webmock
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description: API client for ventureinkorea.com. Search venture-certified companies,
|
|
56
|
+
startup glossary terms, and blog posts about Korea's innovation economy. Zero dependencies.
|
|
57
|
+
email:
|
|
58
|
+
- hello@ventureinkorea.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- lib/ventureinkorea.rb
|
|
64
|
+
- lib/ventureinkorea/client.rb
|
|
65
|
+
- lib/ventureinkorea/errors.rb
|
|
66
|
+
- lib/ventureinkorea/types.rb
|
|
67
|
+
- lib/ventureinkorea/version.rb
|
|
68
|
+
homepage: https://ventureinkorea.com
|
|
69
|
+
licenses:
|
|
70
|
+
- MIT
|
|
71
|
+
metadata:
|
|
72
|
+
homepage_uri: https://ventureinkorea.com
|
|
73
|
+
source_code_uri: https://github.com/dobestan/ventureinkorea-rb
|
|
74
|
+
changelog_uri: https://github.com/dobestan/ventureinkorea-rb/blob/main/CHANGELOG.md
|
|
75
|
+
documentation_uri: https://ventureinkorea.com/developers/
|
|
76
|
+
bug_tracker_uri: https://github.com/dobestan/ventureinkorea-rb/issues
|
|
77
|
+
post_install_message:
|
|
78
|
+
rdoc_options: []
|
|
79
|
+
require_paths:
|
|
80
|
+
- lib
|
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '3.0'
|
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
requirements: []
|
|
92
|
+
rubygems_version: 3.0.3.1
|
|
93
|
+
signing_key:
|
|
94
|
+
specification_version: 4
|
|
95
|
+
summary: Ruby client for the VentureInKorea Korean venture startup API
|
|
96
|
+
test_files: []
|