aboutsummaryrefslogtreecommitdiff
path: root/generate
blob: 16d87d75226462dffa17d8bda185a5a04f92cd3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env python3

import json
import itertools
import textwrap
from pathlib import Path
from argparse import ArgumentParser

import requests
from bs4 import BeautifulSoup


ROOT_DIR = Path(__file__).resolve().parent
LANGUAGES_FILENAME = ROOT_DIR / 'languages.json'
URL_FORMAT = 'http://projecteuler.net/problem={index}'
LINE_WRAP = 89
PROBLEM_PADDING = 3


class Problem:
    def __init__(self, index: int, language: dict):
        self.index = index
        self.language = language

    def fetch(self):
        url = URL_FORMAT.format(index=self.index)
        print(f"Fetching problem {self.index} at {url}")
        data = requests.get(url)
        soup = BeautifulSoup(data.text, 'html.parser')
        data = soup.find('div', {'id': 'content'})
        self.title = data.h2.text
        self.sub_title = data.h3.text
        self.content = soup.find('div', {'class': 'problem_content'}).text
        print(self)
        return self

    def write(self):
        file_name = f'{self.index:03}-{self._slug}.{self.language["extension"]}'
        file_path = ROOT_DIR / self.language['name'] / file_name
        if file_path.exists():
            raise FileExistsError(f'{file_path} already exists')
        file_path.parent.mkdir(exist_ok=True)
        with open(file_path, 'w') as file:
            file.write(str(self))
        return self

    def __str__(self) -> str:
        title = self.title.strip()
        sub_title = self.sub_title.strip()
        content = self.content.strip()

        content_lines = []
        for line in content.splitlines():
            content_lines.extend(textwrap.wrap(line, width=LINE_WRAP))

        lines = [title, sub_title, "", *content_lines]
        lines = [self.language['comment']['prefix'] + line for line in lines]
        lines.insert(0, self.language['comment']['top'])
        lines.append(self.language['comment']['bottom'])
        lines.extend(itertools.repeat("", PROBLEM_PADDING))
        return '\n'.join(lines)

    @property
    def _slug(self) -> str:
        title = self.title.lower().replace(' ', '_')
        title = [c for c in title if c.isalnum() or c == '_']
        return ''.join(title)


def main():
    with open(LANGUAGES_FILENAME, 'r') as file:
        languages = json.load(file)
    parser = ArgumentParser(description='Project Euler problem file generator')
    parser.add_argument(
        '-p', '--preview',
        action='store_true',
        help='see a preview of the file without creating it',
    )
    parser.add_argument(
        'language',
        metavar='LANGUAGE',
        choices=languages,
        help='file programming language',
    )
    parser.add_argument(
        'indices',
        metavar='INDEX',
        nargs='+',
        type=int,
        help='Project Euler problems index',
    )
    args = parser.parse_args()
    for index in args.indices:
        language = languages[args.language]
        language['name'] = args.language
        problem = Problem(index, language)
        problem.fetch()
        if not args.preview:
            problem.write()


if __name__ == '__main__':
    main()