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 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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VentureInKorea
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ventureinkorea/version"
4
+ require_relative "ventureinkorea/errors"
5
+ require_relative "ventureinkorea/types"
6
+ require_relative "ventureinkorea/client"
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: []