Creating the Blog

This article is part of a series! You can find the other articles here:

1 | 2

Parker just told me "80.48" and said to ignore it. It will be immortalized on my blog.

Hello and welcome to my blog! Last week, my brother asked me if I wanted to join his webring. Wikipedia says "Webrings are mainly viewed as a relic of the... 1990s", so of course I had to say yes. I have never written anything in HTML though, so I have to figure out how to make a site in the first place!

I started by desiging the home page. I want the "Purp Corner" header on every page, a brief descrption, and then a list of all my personal projects. Some of the projects will only have one page, but I imagine future projects will have more than one article, and they all need to link to each other. Something I immediately notice is that every new page that gets added needs to be linked from the previous pages. My first task project that will be shared with the blog is... a program that makes the blog!

My plan is to have a header for each project that contains a list of text files. Each text file corresponds to a web page for the project. My program can create an in-memory map of the blog so it can substitute the correct address for links. I haven't quite decided on the format for these text files, but for now, let's call them "PML" (Purp Markup Language) files. Even though the PML parsing isn't finalized, let's start by creating the home page.

Home

The first thing I realize is that all of my web pages will have the same prefix and suffix. No problem, I can pull those out into some constants and slap them on the ends of any file I write.

          
HTMLHeader = "<html lang="en">\n  <body>\n    <main>\n..."
HTMLFooter = "\n    </main>\n    </body>\n  </html>"
          
        

Hmm... Those spaces on the beginning of each line will need to be tracked if I want to look at this later for debugging. My page content will always be wrapped inside an aptly-named HTML <div class="content">, plus the above <html>, <body>, and <main>, so it will be indented by 8 spaces at least! Python makes it pretty simple to expand a string some amount of times, so I'll simply track the nesting level:

          
nestdepth = 3
#Before any write...
file.write("  "*nestdepth)
nestdepth += 1
#And when we're done...
nestdepth -= 1
file.write("  "*nestdepth + "</div>")
          
        

I can already sense a problem with bookkeeping here... Before generating any page content in earnest, I have to remember to write the HTML header, and even after I know what strings to write to the web page, I have to manage the indentation levels. Don't forget to decrement it when you're done! Finally, write the HTML footer or your web page won't even work! It's simple enough to wrap some of these operations inside a function call, but without a "static" keyword, the user (that's me) would still need to carry around a copy of the current indent level. Needless to say, I didn't keep this around for very long. Let's wrap the data and its operations together in a class:

          
class HTMLPage:
	def __init__(self, filepath):
		self.file = open("./build/" + filepath + ".html", "w+")
		self.file.write(HTMLHeader)
		self.tagstack = ["html", "body", "main"]
		
	def __del__(self):
		self.file.write(HTMLFooter)
		self.file.close()
          
        

Now all files automatically have the header and footer written to them, and we have a way to access the current indentation (by tracking which tags are open). I'm putting a file object inside the class instead of subclassing "file" itself because Python 3's open function is now a factory that returns one of many file objects. A quick check in the interpreter says _io.TextIOWrapper, but the underscore is dissuading me from trying to access it directly. Anyway, from here it's not too challenging of a task to manage the opening/closing of HTML tags, which corresponds perfectly with the indentation:

          
#class HTMLPage:
	def Write(self, s):
		self.file.write("  "*len(self.tagstack))
		self.file.write(s)
		self.file.write("\n")
		
	def OpenTag(self, tag, style=None):
		if style:
			self.Write("<" + tag + " class=\"" + style + "\">")
		else:
			self.Write("<" + tag + ">")
		self.tagstack.append(tag)
	
	def CloseTag(self):
		tag = self.tagstack.pop()
		self.Write("</" + tag + ">")
          
        

First, a Write method to actually push the string through to the webpage. It handles the indentation and newline but otherwise does no processing. We can edit that indentation indirectly when using the Open- and CloseTag methods, which handle the tag's formatting for us automatically, too. Finally, I throw in one last method for convenience that ties everything together:

          
#class HTMLPage:
	def WriteTag(self, s, tag, style=None):
		self.OpenTag(tag, style)
		self.Write(s)
		self.CloseTag()
          
        

Okay, so now we can easily bang out paragraphs with different CSS classes, and all my program has to do is handle the string that the reader (hi!) will see. I can write those paragraphs in a text file, read them line by line, and then just call WriteTag repeatedly to convert them to an HTML form. If I end up needing to go to a new panel or component on the screen, I can fall back to the old behavior of tracking the tags manually and popping them off the stack when I'm done. As an example, let's go back and design the home page like we wanted to!

          
def CreateMainPage(filename, projects):
	file = HTMLPage(filename)
	
	file.OpenTag("div", "post")
	opening = ["Welcome to the purp corner! ...", "I've separated everything by project..."]
	for paragraph in opening:
		file.WriteTag(paragraph, "p")
	file.CloseTag()
	
	file.OpenTag("ul")
	ListArticles(file, projects)
	file.CloseTag()

def ListArticles(file, projects):
	for project in projects:
		file.OpenTag("li")
		file.OpenTag("div", "summary")
		
		file.WriteTag(HTMLPage.LinkLocal(project.title, project, project.pages[0]), "h2")
		file.WriteTag(project.desc, "p")
		
		file.CloseTag()
		file.CloseTag()
          
        

Open tag, write stuff, close tag. Easy! Obviously, it only looks so small because I've abstracted away how I'm getting a list of the projects (scanning for folders, opening each project file, reading their names and pages, etc.), but I feel like with not much code I already have a good framework for generating these blog posts. Now, let's address the issue of the PML formatting.

Every project I work on has its own folder with an "about" PML file (APML) and at least one other "body" PML file (BPMLs). Right now the APML must be named "about.pml", but I may change that in the future. about.pml contains the project name, description, and filepaths for the BPMLs, one per line. My program reads the APML, extracts all the information, and then will open each BPML in order to create the website. If there is more than one, it will add a small navigation blurb that links to each individual page. Hopefully, there is one of those on the screen right now!

So now what? In theory I just need to write a BPML parser and we're done! See you then.

This article is part of a series! You can find the other articles here:

1 | 2