我创建了一个简单的静态网站生成器,名为pjen。GitHub存储库可以找到这里。
import os
class pjen:
def __init__(self, path=None):
"""
By default, the path will be set to the current working directory,
or the path can be specified using the 'path' keyword parameter.
"""
if path is None:
self.path = os.getcwd()
else:
self.path = path
self.path += "/website"
def create_project(self):
"""
Creates an initial file structure for a project at the specified path.
An exception is raised if a project already exists in the desired location.
Creates the following file structure:
website
|-> templates
|-> group1
|-> images
|-> scss
|-> css
|-> scripts
"""
if not os.path.exists(self.path):
#make the root directory
os.makedirs(self.path)
os.makedirs(self.path+"/templates")
os.makedirs(self.path+"/templates/group1")
os.makedirs(self.path+"/images")
os.makedirs(self.path+"/scss")
os.makedirs(self.path+"/css")
os.makedirs(self.path+"/scripts")
print("Created project in {}".format(self.path))
else:
raise IOError("A directory already exists at: {}".format(self.path))
def _count_indent(self, str, tab_equiv=4):
"""
Returns the number of leading spaces. A tab is counted as 'tab_equiv' spaces.
"""
i = 0
count = 0
while(str[i] == " " or str[i] == "\t"):
if str[i] == " ":
count += 1
if str[i] == "\t":
count += 4
i += 1
return count
def _sanatise_file_list(self, l, fname=None):
"""
Removes blacklisted files from the input list 'l'. In addition, a file with
the name 'fname' can also be removed.
"""
blacklist = [".DS_Store"]
if fname:
blacklist.append(fname)
for item in blacklist:
try:
l.pop(l.index(item))
except ValueError:
pass
def generate(self):
"""
Iterates through all the directories in the 'templates' directory, inserting all the
inputs into each template.
"""
#get a list of template groups
static_groups = os.listdir(self.path+"/templates")
self._sanatise_file_list(static_groups)
print("Found {} group(s)".format(len(static_groups)))
#iterate through each of the template groups
for group in static_groups:
#get each of the files in the group
files = os.listdir(self.path+"/templates/"+group)
#remove the template and hidden file
self._sanatise_file_list(files, "template.html")
#open the template
with open(self.path+"/templates/" + group + "/template.html", "r") as template:
#iterate though the files that need to be generated
for f in files:
#create a new static page
with open(self.path + "/" + f, "w") as page:
print("Generating file: {}".format(f))
#open up the input
with open(self.path + "/templates/" + group + "/" + f, "r") as my_input:
#iterate through the input and extract the various sections
css = ""
html = ""
scripts = ""
#flag to determine the section of the input file
in_section = None
#iterate through the input file and set the appropriate flag
for line in my_input.readlines():
if line.lstrip().startswith("{{ css }}"):
in_section = "css"
elif line.lstrip().startswith("{{ html }}"):
in_section = "html"
elif line.lstrip().startswith("{{ scripts }}"):
in_section = "scripts"
else:
if in_section == "css":
css += line
if in_section == "html":
html += line
if in_section == "scripts":
scripts += line
#reset the file pointer as the template can be read many times
template.seek(0)
#iterate through the template file
for line in template.readlines():
if line.lstrip().startswith("{{ css }}"):
indent = self._count_indent(line)
#if there is css in the input file then insert it
if css != "":
for insert_line in [x + "\n" for x in css.split("\n")]:
page.write(" "*indent + insert_line)
#if there is html in the input file then insert it
elif line.lstrip().startswith("{{ html }}"):
indent = self._count_indent(line)
if html != "":
for insert_line in [x + "\n" for x in html.split("\n")]:
page.write(" "*indent + insert_line)
#if there are script links in the input file then insert them
elif line.lstrip().startswith("{{ scripts }}"):
indent = self._count_indent(line)
if scripts != "":
for insert_line in [x + "\n" for x in scripts.split("\n")]:
page.write(" "*indent + insert_line)
#otherwise copy the template text
else:
page.write(line)
if __name__ == "__main__":
p = pjen()
p.generate()发布于 2015-12-16 15:05:43
create_project没有最好的名字。如果你想准确的话,它应该是create_project_folders。即使您不想长篇大论,您的print调用也应该更清楚它到底做了什么。我将翻转您的测试,并将if os.path.exists(self.path)用于raise IOError,这样函数的其余部分就不需要嵌套。请注意,它也更好地显示了流。伪码:
create_project function:
if project folder exists:
raise error
make folders说到创建文件夹,每次都会用新字符串重复调用相同的函数。这是使用for循环的最佳位置。此外,字符串实际上应该是常量。可能是类级别上的一组常量:
class pjen:
PROJECT_FOLDERS = (
"/templates",
"/templates/group1",
"/images",
"/scss",
"/css",
"/scripts",
)现在,您可以在这些文件夹中迭代,在create_project中创建它们:
def create_project(self):
if os.path.exists(self.path):
raise IOError("A directory already exists at: {}".format(self.path))
for folder in pjen.PROJECT_FOLDERS:
os.makedirs(self.path + folder)
print("Created project in {}".format(self.path))请注意,我没有包括os.makedirs(self.path)。这是因为Python使得所有目录都是必需的,而不仅仅是列表(事实上,这就是为什么makedirs而不是makedir)中的最后一个目录。同样,不需要调用os.makedirs(self.path + "/templates")和`os.makedirs(self.path +“/self.path/group1 1”),因为后者将创建两个文件夹。但是,我将其保持为常量,这样您就可以看到创建的文件夹的完整列表,因为这样可以提高可读性,并且您可能希望/需要在某个时候遍历所有项目文件夹。
不要使用str作为变量名,因为它会隐藏内置的str函数。使用string通常更好。我也不喜欢以下划线开头的_count_indent。这是一种惯例,用来表示函数是私有的,不应该在外部使用。我不明白为什么这里应该是这样的,除此之外,你不希望人们需要它。但我会亲自把下划线关掉。
对于输入列表来说,l是一个不好的名称,无论是input_list还是file_list都会更好。如果fname是None,那么就可以了,因为它不会对字符串列表产生任何影响。此外,与其将单个fname附加到blacklist中,还可以创建一个元组:
blacklist = (".DS_Store", fname)事实上,我会直接迭代,而不是把它分配给黑名单。
此外,您还使用pop来删除项,但您可以只使用remove。pop在删除该值后返回值,如果不需要该值,则不需要pop。
def _sanatise_file_list(self, l, fname=None):
"""
Removes blacklisted files from the input list 'l'. In addition, a file with
the name 'fname' can also be removed.
"""
for item in (".DS_Store", fname):
try:
l.pop(l.index(item))
except ValueError:
passgenerate作为一个函数太长了。你应该把它分解成更小的函数。理想情况下,每个函数只执行一项任务。这有助于可读性、清晰度和测试。
https://codereview.stackexchange.com/questions/114102
复制相似问题