pythonic 0.3.0

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

use {Argument, Block, Comment, Statement};

#[derive(Debug, Clone)]
pub struct Function {
    pub docstring: Option<Comment>,
    pub name: String,
    pub args: Vec<Argument>,
    block: Block,
}

#[cfg(test)]
mod tests {
    mod function {
        use {Function, FunctionCall};
        use {Argument, Block, Statement};
        #[test]
        fn it_outputs_a_function() {
            let mut function =
                Function::new("hello",
                              vec![Argument::new("name", Some("\"World\""), None, None)],
                              &Block::new());
            let arguments = vec![Statement::unnamed_variable("Hello"),
                                 Statement::variable("name")];
            let function_call = FunctionCall::new("print", arguments);
            function.add_statement(Statement::FunctionCall(function_call));
            let expected = r#"def hello(name="World"):
    print("Hello", name)
"#;
            let actual = format!("{}", function);
            println!("expected:");
            println!("{}", expected);
            println!("actual:");
            println!("{}", actual);

            assert_eq!(expected, actual);
        }

        #[test]
        fn it_outputs_a_function_with_a_comment() {
            let mut function = Function::new("hello",
                                             vec![Argument::new("name",
                                                                Some("\"World\""),
                                                                Some("str"),
                                                                Some("The name to say Hello to"))],
                                             &Block::new());
            let arguments = vec![Statement::unnamed_variable("Hello"),
                                 Statement::variable("name")];
            let function_call = FunctionCall::new("print", arguments);
            function.add_statement(Statement::FunctionCall(function_call));
            function.add_docstring("hello is a function that prints \"Hello\" with the given \
                                    name argument.");
            let expected = r#"def hello(name="World"):
    """
    hello is a function that prints "Hello" with the given name argument.

    :param name: The name to say Hello to
    :type name: str
    """
    print("Hello", name)
"#;
            let actual = format!("{}", function);
            println!("expected:");
            println!("{}", expected);
            println!("actual:");
            println!("{}", actual);

            assert_eq!(expected, actual);
        }
    }
    mod function_call {
        use FunctionCall;
        use {Statement};

        #[test]
        fn it_prints_a_function_call() {
            let arguments = vec![Statement::unnamed_variable("Hello"),
                                 Statement::variable("name")];
            let function_call = FunctionCall::new("print", arguments);

            let expected = "print(\"Hello\", name)";
            assert_eq!(expected, format!("{}", function_call));
        }
    }
}

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

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

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

impl Display for Function {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut s = String::new();
        let args_string =
            self.args.iter().map(|s| s.to_string()).collect::<Vec<String>>().join(", ");
        s.push_str(&format!("def {}({}):\n", self.name, args_string)[..]);

        let indent: String = self.block.indentation();
        let mut docstring = String::new();
        if let Some(ref doc) = self.docstring {
            docstring.push_str(&format!("{}{}", indent, doc)[..]);
        }
        let mut arg_help: Vec<String> = vec![];
        for arg in &self.args {
            if arg.has_help() {
                if let Some(help) = arg.help_string() {
                    arg_help.push(format!("{}{}", indent, help));
                }
            }
        }

        for arg in &self.args {
            if arg.has_help() {
                if let Some(type_str) = arg.type_string() {
                    arg_help.push(format!("{}{}", indent, type_str));
                }
            }
        }
        if arg_help.len() > 0 {
            docstring.push_str("\n\n");
            docstring.push_str(&arg_help.join("\n")[..]);
        }
        if docstring.len() > 0 {
            s.push_str(&format!(r#"{}"""
{}
{}"""
"#,
                                indent,
                                docstring,
                                indent)[..]);
        }
        s.push_str(&format!("{}", self.block)[..]);

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

#[derive(Debug, Clone)]
pub struct FunctionCall {
    pub name: String,
    pub arguments: Vec<Statement>,
}

impl FunctionCall {
    pub fn new<T: Display>(name: T, arguments: Vec<Statement>) -> FunctionCall {
        FunctionCall {
            name: name.to_string(),
            arguments: arguments,
        }
    }
}

impl Display for FunctionCall {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let args_string =
            self.arguments.iter().map(|s| s.to_string()).collect::<Vec<String>>().join(", ");
        write!(f, "{}({})", self.name, args_string)
    }
}