pythonic 0.3.0

pythonic is a Rust AST builder that generates Python
Documentation
use std::fmt::{Display, Formatter, Result};

use {Block, Comment, Statement};

#[cfg(test)]
mod tests {
    use {Argument, Assignment, Block, Class, Function, FunctionCall, KeywordArgument, Statement};
    #[test]
    fn it_makes_a_class() {
        let mut program = Block::new();
        let mut class = Class::new("Greeter", &program);
        class.inherit_from("Exception");
        class.add_docstring("Greeter is a class to say Hello!");
        let arguments = vec![
          Argument::new("self", None, None, None),
          Argument::new("name", Some("\"World\""), Some("str"), Some("The name to greet")),
        ];
        let mut init = Function::new("__init__", arguments, &class.block);
        init.add_docstring("Set up name variable for the Greeter");
        init.add_statement(
          Statement::Assignment(
            Assignment::new(
              Argument::variable("self.name"), Statement::variable("name"))));
        class.add_statement(Statement::Function(init));
        let arguments = vec![
          Argument::new("self", None, None, None),
        ];
        let mut hello = Function::new("hello", arguments, &class.block);
        hello.add_docstring("Say hello to self.name");
        let print = FunctionCall::new("print",
                                      vec![
            Statement::unnamed_variable("Hello"),
            Statement::variable("self.name"),
            Statement::unnamed_variable("!"),
          ]);
        hello.add_statement(Statement::FunctionCall(print));
        class.add_statement(Statement::Function(hello));
        program.add_statement(Statement::Class(class));
        program.add_statement(
            Statement::Assignment(Assignment::new(
            Argument::variable("g"),
            Statement::FunctionCall(FunctionCall::new(
                "Greeter",
                vec![
                    Statement::KeywordArgument(KeywordArgument::new("name", "\"Chris\""))
                ]
            ))
        )));
        let function_call = FunctionCall::new("g.hello", vec![]);
        program.add_statement(Statement::FunctionCall(function_call));
        let expected = r#"class Greeter(Exception):
    """
    Greeter is a class to say Hello!
    """

    def __init__(self, name="World"):
        """
        Set up name variable for the Greeter

        :param name: The name to greet
        :type name: str
        """
        self.name = name

    def hello(self):
        """
        Say hello to self.name
        """
        print("Hello", self.name, "!")


g = Greeter(name="Chris")
g.hello()
"#;
        let actual = format!("{}", program);

        println!("expected:");
        println!("\"{}\"", expected);
        println!("actual:");
        println!("\"{}\"", actual);
        assert_eq!(expected, actual);
    }
}

#[derive(Debug, Clone)]
pub struct Class {
    pub docstring: Option<Comment>,
    pub name: String,
    pub block: Block,
    pub inherit_from: Option<String>,
}

impl Class {
    pub fn new<T: Display>(name: T, parent: &Block) -> Class {
        Class {
            docstring: None,
            name: name.to_string(),
            block: Block::new_with_parent(parent),
            inherit_from: None,
        }
    }

    pub fn inherit_from<T: Display>(&mut self, inherit: T) {
        self.inherit_from = Some(inherit.to_string());
    }

    pub fn add_statement(&mut self, statement: Statement) {
        self.block.add_statement(statement);
    }


    pub fn add_docstring<T: Display>(&mut self, doc: T) {
        self.docstring = Some(Comment::docstring(doc))
    }
}

impl Display for Class {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(write!(f, "class {}", self.name));
        if let Some(ref inherit) = self.inherit_from {
            try!(write!(f, "({})", inherit));
        }
        try!(write!(f, ":\n"));
        let indent: String = self.block.indentation();
        if let Some(ref docstring) = self.docstring {
            let mut s = String::new();
            s.push_str(&format!(r#"{}"""
{}{}
{}"""

"#,
                                indent,
                                indent,
                                docstring,
                                indent)[..]);

            try!(write!(f, "{}", s));
        }

        write!(f, "{}", self.block)
    }
}