feat: develop the basic functions.

This commit is contained in:
jackfiled 2025-06-13 16:53:25 +08:00
parent 9ddcad2f08
commit 52d9629a5c
Signed by: jackfiled
GPG Key ID: DEF448811AE0286D
9 changed files with 179 additions and 36 deletions

View File

@ -110,8 +110,8 @@ IndentGotoLabels: false
# #endif # #endif
# #endif # #endif
IndentPPDirectives: BeforeHash IndentPPDirectives: BeforeHash
# IndentAccessModifiers: true
IndentWidth: 4 IndentWidth: 4
AccessModifierOffset: -4
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 3 MaxEmptyLinesToKeep: 3
NamespaceIndentation: None NamespaceIndentation: None

View File

@ -6,6 +6,9 @@ include_directories(include)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
find_package(GTest REQUIRED)
add_subdirectory(src)
add_executable(leetcode-fetcher main.cpp add_executable(leetcode-fetcher main.cpp
src/fetcher.cpp) src/fetcher.cpp)

View File

@ -59,25 +59,27 @@ struct CodeDefinition
struct ProblemContent struct ProblemContent
{ {
std::string title; std::string title;
std::string title_slug; std::string titleSlug;
std::string content; std::string content;
std::vector<CodeDefinition> codeDefinitions; std::vector<CodeDefinition> codeDefinitions;
int questionId; int questionId;
ProblemContent(std::string title, ProblemContent(std::string title,
std::string title_slug, std::string titleSlug,
std::string content, std::string content,
std::vector<CodeDefinition> codeDefinitions, std::vector<CodeDefinition> codeDefinitions,
int questionId) int questionId)
: title(std::move(title)) : title(std::move(title))
, title_slug(std::move(title_slug)) , titleSlug(std::move(titleSlug))
, content(std::move(content)) , content(std::move(content))
, codeDefinitions(std::move(codeDefinitions)) , codeDefinitions(std::move(codeDefinitions))
, questionId(questionId) , questionId(questionId)
{ {
} }
std::string formatTemplate(const std::string &templateContent) const; [[nodiscard]] std::string formatTemplate(const std::string &templateContent) const;
[[nodiscard]] std::string formatFilename() const;
}; };
struct Fetcher struct Fetcher
@ -104,6 +106,8 @@ private:
[[nodiscard]] std::vector<LeetCodeProblem> getProblems() const; [[nodiscard]] std::vector<LeetCodeProblem> getProblems() const;
[[nodiscard]] std::unique_ptr<ProblemContent> fetchProblemContent(const LeetCodeProblem &problem) const;
/// The callback function used by curl to write the http response content into a string. /// The callback function used by curl to write the http response content into a string.
static size_t httpWriteCallback(void *contents, const size_t size, size_t bufferLength, void *userData) static size_t httpWriteCallback(void *contents, const size_t size, size_t bufferLength, void *userData)
{ {
@ -121,6 +125,8 @@ private:
const LeetCodeProblem &problem); const LeetCodeProblem &problem);
static std::string readTemplateFile(); static std::string readTemplateFile();
static bool validateExistedProblem(const ProblemContent &problem);
}; };
#endif //FETCHER_H #endif //FETCHER_H

31
justfile Normal file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env just --justfile
update:
git pull
build: update
#!/usr/bin/env bash
set -euxo pipefail
mkdir -p cmake-build-debug-clang
cd cmake-build-debug-clang
cmake .. -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
ninja
fmt:
clang-format -i src/problems/*.cpp
test: fmt build
./cmake-build-debug-clang/src/problem-tests
commit: test
#!/usr/bin/env bash
set -euxo pipefail
time=$(date "+%Y%m%d")
message="$time finished."
git add -A
git commit -m "$message"
git push
pull id: build
./cmake-build-debug-clang/leetcode-fetcher {{ id }}

View File

@ -6,8 +6,7 @@ int main(int argc, char **argv)
if (argc != 2) if (argc != 2)
{ {
std::cout << "The fetcher expect the program id."; throw std::invalid_argument("The fetcher expect the program id.");
return -1;
} }
fetcher.fetchProblem(argv[1]); fetcher.fetchProblem(argv[1]);

7
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
enable_testing()
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/problems PROBLEMS_SRC)
add_executable(problem-tests ${PROBLEMS_SRC})
target_link_libraries(problem-tests GTest::gtest_main)

View File

@ -49,9 +49,40 @@ std::vector<LeetCodeProblem> Fetcher::getProblems() const
return problems; return problems;
} }
std::string replaceString(const std::string &original, std::unique_ptr<ProblemContent> Fetcher::fetchProblemContent(const LeetCodeProblem &problem) const
const std::string_view old_sub, {
const std::string_view new_sub) curl_easy_setopt(client.get(), CURLOPT_URL, kGraphQlUrl.c_str());
curl_easy_setopt(client.get(), CURLOPT_POST, 1L);
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(client.get(), CURLOPT_HTTPHEADER, headers);
std::string requestBody = formatQueryJson(problem.questionTitleSlug).dump();
curl_easy_setopt(client.get(), CURLOPT_POSTFIELDS, requestBody.c_str());
curl_easy_setopt(client.get(), CURLOPT_POSTFIELDSIZE, requestBody.size());
std::string responseBody;
curl_easy_setopt(client.get(), CURLOPT_WRITEFUNCTION, Fetcher::httpWriteCallback);
curl_easy_setopt(client.get(), CURLOPT_WRITEDATA, &responseBody);
CURLcode code = curl_easy_perform(client.get());
if (code != CURLE_OK)
{
throw std::runtime_error("Failed to fetch problem.");
}
const nlohmann::json jsonResponse = nlohmann::json::parse(responseBody);
return extractContentFromJson(jsonResponse, problem);
}
static std::string replaceString(const std::string &original,
const std::string_view old_sub,
const std::string_view new_sub)
{ {
if (old_sub.empty()) if (old_sub.empty())
return original; // 防止空字符串导致死循环 return original; // 防止空字符串导致死循环
@ -108,10 +139,21 @@ std::string ProblemContent::formatTemplate(const std::string &templateContent) c
std::string result = replaceString(templateContent, "__PROBLEM_ID__", std::to_string(questionId)); std::string result = replaceString(templateContent, "__PROBLEM_ID__", std::to_string(questionId));
result = replaceString(result, "__PROBLEM_TITLE__", title); result = replaceString(result, "__PROBLEM_TITLE__", title);
result = replaceString(result, "__PROBLEM_DEFAULT_CODE__", it->defaultCode); result = replaceString(result, "__PROBLEM_DEFAULT_CODE__", it->defaultCode);
std::string testCaseName = "P" + std::to_string(questionId);
result = replaceString(result, "__TEST_CASE_NAME__", testCaseName);
return result; return result;
} }
std::string ProblemContent::formatFilename() const
{
std::ostringstream stream("p");
stream << questionId;
stream << "-" << titleSlug << ".cpp";
return stream.str();
}
void Fetcher::fetchProblem(const std::string &idString) const void Fetcher::fetchProblem(const std::string &idString) const
{ {
std::vector<LeetCodeProblem> problems = getProblems(); std::vector<LeetCodeProblem> problems = getProblems();
@ -127,37 +169,21 @@ void Fetcher::fetchProblem(const std::string &idString) const
throw std::runtime_error("The target problem does not exist."); throw std::runtime_error("The target problem does not exist.");
} }
curl_easy_setopt(client.get(), CURLOPT_URL, kGraphQlUrl.c_str()); std::unique_ptr<ProblemContent> problemContent = fetchProblemContent(*it);
curl_easy_setopt(client.get(), CURLOPT_POST, 1L); const std::string templateFile = readTemplateFile();
std::string problemFileContent = problemContent->formatTemplate(templateFile);
std::string problemFilename = problemContent->formatFilename();
curl_slist *headers = nullptr; auto problemFile = std::ofstream("src/problems/" + problemFilename);
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(client.get(), CURLOPT_HTTPHEADER, headers); if (!problemFile.is_open())
std::string requestBody = formatQueryJson(it->questionTitleSlug).dump();
curl_easy_setopt(client.get(), CURLOPT_POSTFIELDS, requestBody.c_str());
curl_easy_setopt(client.get(), CURLOPT_POSTFIELDSIZE, requestBody.size());
std::string responseBody;
curl_easy_setopt(client.get(), CURLOPT_WRITEFUNCTION, Fetcher::httpWriteCallback);
curl_easy_setopt(client.get(), CURLOPT_WRITEDATA, &responseBody);
CURLcode code = curl_easy_perform(client.get());
if (code != CURLE_OK)
{ {
throw std::runtime_error("Failed to fetch problem."); throw std::runtime_error("Failed to open problem file.");
} }
const nlohmann::json jsonResponse = nlohmann::json::parse(responseBody); problemFile << problemFileContent;
const std::unique_ptr<ProblemContent> problemContent = extractContentFromJson(jsonResponse, *it);
std::string templateFile = readTemplateFile(); problemFile.close();
std::cout << problemContent->formatTemplate(templateFile) << std::endl;
} }
nlohmann::json Fetcher::formatQueryJson(const std::string &title) nlohmann::json Fetcher::formatQueryJson(const std::string &title)
@ -225,4 +251,26 @@ std::string Fetcher::readTemplateFile()
file.close(); file.close();
return buffer.str(); return buffer.str();
}
bool Fetcher::validateExistedProblem(const ProblemContent &problem)
{
std::filesystem::path problemDirectory = "src/problems";
std::string defaultFilename = problem.formatFilename();
if (!std::filesystem::exists(problemDirectory))
{
throw std::runtime_error("The problem directory is not exitsed.");
}
return std::ranges::any_of(std::filesystem::directory_iterator(problemDirectory),
[&](const std::filesystem::directory_entry &entry)
{
if (!entry.is_regular_file())
{
return false;
}
return entry.path().filename() == defaultFilename;
});
} }

View File

@ -0,0 +1,40 @@
/**
* [1] Two Sum
*/
#include <bits/stdc++.h>
#include <gtest/gtest.h>
using namespace std;
// submission codes start here
class Solution
{
public:
vector<int> twoSum(vector<int> &nums, int target)
{
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); ++i)
{
if (const auto &it = map.find(target - nums[i]); it != map.end())
{
return {it->second, i};
}
map.insert({nums[i], i});
}
return {};
}
};
// submission codes endo
TEST(P1, Test1)
{
Solution s;
vector nums = {2, 7, 11, 15};
vector result = {0, 1};
ASSERT_EQ(s.twoSum(nums, 9), result);
}

View File

@ -1,9 +1,18 @@
/** /**
* [__PROBLEM_ID__] __PROBLEM_TITLE__ * [__PROBLEM_ID__] __PROBLEM_TITLE__
*/ */
#include <bits/stdc++.h>
#include <gtest/gtest.h>
using namespace std;
// submission codes start here // submission codes start here
__PROBLEM_DEFAULT_CODE__ __PROBLEM_DEFAULT_CODE__
// submission codes end // submission codes endo
TEST(__TEST_CASE_NAME__, Test1)
{
}