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)
}
}