Learn at least one new language every year. Andrew Hunt and David Thomas wrote down this recommendation in their book The Pragmatic Programmer . Last year I have been learning C, C++ and C# as it was part of my curriculum but this year I can choose a language on my own.
In 2009 I have already been experimenting with Python. I implemented the typical Game of Life using Qt but after that I kinda lost focus due to my studies. Recently I wanted to learn a new language and as in 2009 I ended up with Python.
This time I started by implementing a small command line tool that counts the number of lines of code. I know that the amount of code lines tells one nothing important about a code base or project but I still like to see how many lines have been written in the course of a project, i.e. projects that I participated in.
The following listing shows the code of the application.
#!usr/bin/env python3
#
# Copyright 2011 Ben Ripkens.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Count the number of lines for a given directory or file
"""
__author__ = '"Ben Ripkens" <bripkens.dev@gmail.com>'
import logging
import os
import glob
import sys
# Just the logger configuration which needs to be set up before the rest
# of the application
logger = logging . getLogger ( "linesofcode" )
class LineCounter :
"""Class that counts lines for a given path"""
def __init__ ( self ):
self . __paths = set ()
self . __lines_by_type = {}
def countpath ( self , path ):
"""
Analyse path an act differently based on the type of content.
Keyword arguments:
path -- The path which should be scanned.
Returns: LineCounter, The object on which you called the method
"""
path = os . path . normpath ( os . path . abspath ( path ))
if path in self . __paths :
logger . info ( """Path " % s" was already scanned""" , path )
return self
if not os . path . exists ( path ):
logger . info ( """Path " % s" does not seem to exist.""" , path )
return self
self . __paths . add ( path )
if os . path . isdir ( path ):
self . __countdir ( path )
elif os . path . isfile ( path ):
self . __addfile ( path )
return self
def print_statistics ( self ):
"""
A simple way of printing statistics to the console
Returns: LineCounter, The object on which you called the method
"""
longest_type_name = max ( len ( s ) for s in self . __lines_by_type . keys ())
for type in self . __lines_by_type . keys ():
print ( "{type:{padding}} {lines}" . format ( type = type ,
lines =
self . __lines_by_type [
type ],
padding = longest_type_name ))
total = sum ( i for i in self . __lines_by_type . values ())
print ( "Total: {}" . format ( total ))
return self
def __countdir ( self , dir ):
"""
Count the lines of a given directory
Keyword arguments:
directory -- The directory which should be scanned.
Returns: int, The number of lines of code of the directory
"""
directory_contents = glob . glob ( os . path . join ( dir , "*" ))
for path in directory_contents :
self . countpath ( path )
def __addfile ( self , file ):
"""
Add information about a file to the statistics
Keyword arguments:
file -- The file which should be scanned
Returns: LineCounter, The object on which you called the method
"""
lines = LineCounter . countfile ( file )
if lines == 0 :
return self
type = os . path . splitext ( file )[ 1 ]
if type not in self . __lines_by_type :
self . __lines_by_type [ type ] = lines
else :
self . __lines_by_type [ type ] = self . __lines_by_type [ type ] + lines
return self
@staticmethod
def countfile ( file ):
"""
Count the lines of a file
Keyword arguments:
file -- The file which should be scanned
Returns: int, The number of lines of code for the file
"""
if not LineCounter . is_text_file ( file ):
logger . debug ( """File " % s" is not a text file""" , file )
return 0
with open ( file ) as f :
return len ( f . readlines ())
return 0
@staticmethod
def is_text_file ( file ):
"""
Checks whether the given file is a text file.
Keyword arguments:
file -- File to be checked
Returns: boolean, true when the file is a text file, false otherwise
"""
with open ( file ) as f :
try :
return " \0 " not in f . read ()
except UnicodeDecodeError :
return False
return False
if __name__ == "__main__" :
folder = None
if len ( sys . argv ) < 2 :
LineCounter () . countpath ( os . getcwd ()) . print_statistics ()
else :
if os . path . exists ( sys . argv [ 1 ]):
LineCounter () . countpath (
os . path . abspath ( sys . argv [ 1 ])) . print_statistics ()
folder = os . path . abspath ( sys . argv [ 1 ])
else :
print ( "The path is invalid." )
Example usage and output.
python3 /home/ben/LinesOfCode/linesofcode.py .
.sh 11
.NavData 53
.java 35222
.default 32
.htm 567
.css 9457
.js 26010
.htc 3
.log 2526
.txt 160
.properties 2635
.xml 5806
.bat 6
.MF 8
.xhtml 10941
Total: 93437
Some websites that I used: