Added grass::Options and implemented options.load_paths

This commit is contained in:
Joe Ling - uni laptop 2020-07-15 12:37:19 +01:00
parent 5c20c00d6d
commit 50d1987af2
12 changed files with 121 additions and 65 deletions

View File

@ -10,7 +10,7 @@ Spec progress as of 2020-07-04:
## Use as library ## Use as library
``` ```
fn main() -> Result<(), Box<grass::Error>> { fn main() -> Result<(), Box<grass::Error>> {
let sass = grass::from_string("a { b { color: &; } }".to_string())?; let sass = grass::from_string("a { b { color: &; } }".to_string(), &grass::Options::default())?;
assert_eq!(sass, "a b {\n color: a b;\n}\n"); assert_eq!(sass, "a b {\n color: a b;\n}\n");
Ok(()) Ok(())
} }
@ -122,6 +122,77 @@ mod unit;
mod utils; mod utils;
mod value; mod value;
#[non_exhaustive]
#[derive(Debug)]
pub enum OutputStyle {
Expanded,
Compressed,
}
#[derive(Debug)]
pub struct Options<'a> {
pub style: OutputStyle,
pub load_paths: Vec<&'a Path>,
pub allows_charset: bool,
pub unicode_error_messages: bool,
pub quiet: bool,
}
///
/// `load_paths` - list of paths/files to check for imports for more information see the docs:
/// - <https://sass-lang.com/documentation/at-rules/import#finding-the-file>
/// - <https://sass-lang.com/documentation/at-rules/import#load-paths>
impl<'a> Default for Options<'a> {
fn default() -> Self {
Self {
style: OutputStyle::Expanded,
load_paths: Vec::new(),
allows_charset: true,
unicode_error_messages: true,
quiet: false,
}
}
}
impl<'a> Options<'a> {
/// `grass` currently offers 2 different output styles
///
/// - `OutputStyle::Expanded` writes each selector and declaration on its own line.
/// - `OutputStyle::Compressed` removes as many extra characters as possible, and writes the entire stylesheet on a single line.
///
/// By default, output is expanded.
pub fn style(mut self, style: OutputStyle) -> Self {
self.style = style;
self
}
pub fn quiet(mut self, quiet: bool) -> Self {
self.quiet = quiet;
self
}
pub fn load_path(mut self, path: &'a Path) -> Self {
self.load_paths.push(path);
self
}
/// adds on to the `load_path` vec, does not set the vec to paths
pub fn load_paths(mut self, paths: &'a [&'a Path]) -> Self {
self.load_paths.extend_from_slice(paths);
self
}
pub fn allows_charset(mut self, allows_charset: bool) -> Self {
self.allows_charset = allows_charset;
self
}
pub fn unicode_error_messages(mut self, unicode_error_messages: bool) -> Self {
self.unicode_error_messages = unicode_error_messages;
self
}
}
fn raw_to_parse_error(map: &CodeMap, err: Error) -> Box<Error> { fn raw_to_parse_error(map: &CodeMap, err: Error) -> Box<Error> {
let (message, span) = err.raw(); let (message, span) = err.raw();
Box::new(Error::from_loc(message, map.look_up_span(span))) Box::new(Error::from_loc(message, map.look_up_span(span)))
@ -131,7 +202,7 @@ fn raw_to_parse_error(map: &CodeMap, err: Error) -> Box<Error> {
/// ///
/// ``` /// ```
/// fn main() -> Result<(), Box<grass::Error>> { /// fn main() -> Result<(), Box<grass::Error>> {
/// let sass = grass::from_path("input.scss")?; /// let sass = grass::from_path("input.scss", &grass::Options::default())?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -139,24 +210,7 @@ fn raw_to_parse_error(map: &CodeMap, err: Error) -> Box<Error> {
#[cfg_attr(feature = "profiling", inline(never))] #[cfg_attr(feature = "profiling", inline(never))]
#[cfg_attr(not(feature = "profiling"), inline)] #[cfg_attr(not(feature = "profiling"), inline)]
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
pub fn from_path(p: &str) -> Result<String> { pub fn from_path(p: &str, options: &'_ Options<'_>) -> Result<String> {
from_paths(p, &Vec::new())
}
/// Compile CSS from a file and load in additional files through importing them
/// note: @use is currently unsupported
///
/// ```
/// fn main() -> Result<(), Box<grass::Error>> {
/// let sass = grass::from_paths("input.scss", &[std::path::Path::new("benches")])?;
/// Ok(())
/// }
/// ```
/// (grass does not currently allow files or paths that are not valid UTF-8)
#[cfg_attr(feature = "profiling", inline(never))]
#[cfg_attr(not(feature = "profiling"), inline)]
#[cfg(not(feature = "wasm"))]
pub fn from_paths(p: &str, loadpaths: &[&Path]) -> Result<String> {
let mut map = CodeMap::new(); let mut map = CodeMap::new();
let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?); let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?);
let empty_span = file.span.subspan(0, 0); let empty_span = file.span.subspan(0, 0);
@ -178,7 +232,7 @@ pub fn from_paths(p: &str, loadpaths: &[&Path]) -> Result<String> {
at_root_has_selector: false, at_root_has_selector: false,
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(), content_scopes: &mut Scopes::new(),
load_paths: loadpaths, options,
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e))?; .map_err(|e| raw_to_parse_error(&map, *e))?;
@ -188,11 +242,12 @@ pub fn from_paths(p: &str, loadpaths: &[&Path]) -> Result<String> {
.pretty_print(&map) .pretty_print(&map)
.map_err(|e| raw_to_parse_error(&map, *e)) .map_err(|e| raw_to_parse_error(&map, *e))
} }
/// Compile CSS from a string /// Compile CSS from a string
/// ///
/// ``` /// ```
/// fn main() -> Result<(), Box<grass::Error>> { /// fn main() -> Result<(), Box<grass::Error>> {
/// let sass = grass::from_string("a { b { color: &; } }".to_string())?; /// let sass = grass::from_string("a { b { color: &; } }".to_string(), &grass::Options::default())?;
/// assert_eq!(sass, "a b {\n color: a b;\n}\n"); /// assert_eq!(sass, "a b {\n color: a b;\n}\n");
/// Ok(()) /// Ok(())
/// } /// }
@ -200,7 +255,7 @@ pub fn from_paths(p: &str, loadpaths: &[&Path]) -> Result<String> {
#[cfg_attr(feature = "profiling", inline(never))] #[cfg_attr(feature = "profiling", inline(never))]
#[cfg_attr(not(feature = "profiling"), inline)] #[cfg_attr(not(feature = "profiling"), inline)]
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
pub fn from_string(p: String) -> Result<String> { pub fn from_string(p: String, options: &'_ Options<'_>) -> Result<String> {
let mut map = CodeMap::new(); let mut map = CodeMap::new();
let file = map.add_file("stdin".into(), p); let file = map.add_file("stdin".into(), p);
let empty_span = file.span.subspan(0, 0); let empty_span = file.span.subspan(0, 0);
@ -221,7 +276,7 @@ pub fn from_string(p: String) -> Result<String> {
at_root_has_selector: false, at_root_has_selector: false,
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(), content_scopes: &mut Scopes::new(),
load_paths: &Vec::new(), options,
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e))?; .map_err(|e| raw_to_parse_error(&map, *e))?;
@ -234,7 +289,7 @@ pub fn from_string(p: String) -> Result<String> {
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
#[wasm_bindgen] #[wasm_bindgen]
pub fn from_string(p: String) -> std::result::Result<String, JsValue> { pub fn from_string(p: String, options: &'_ Options<'_>) -> std::result::Result<String, JsValue> {
let mut map = CodeMap::new(); let mut map = CodeMap::new();
let file = map.add_file("stdin".into(), p); let file = map.add_file("stdin".into(), p);
let empty_span = file.span.subspan(0, 0); let empty_span = file.span.subspan(0, 0);

View File

@ -7,7 +7,7 @@ use std::{
use clap::{arg_enum, App, AppSettings, Arg}; use clap::{arg_enum, App, AppSettings, Arg};
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
use grass::from_paths; use grass::{from_path, Options};
arg_enum! { arg_enum! {
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
@ -189,11 +189,13 @@ fn main() -> std::io::Result<()> {
vals = Vec::new(); vals = Vec::new();
} }
let options = &Options::default().load_paths(&vals);
if let Some(name) = matches.value_of("INPUT") { if let Some(name) = matches.value_of("INPUT") {
if let Some(path) = matches.value_of("OUTPUT") { if let Some(path) = matches.value_of("OUTPUT") {
let mut buf = BufWriter::new(File::open(path).unwrap_or(File::create(path)?)); let mut buf = BufWriter::new(File::open(path).unwrap_or(File::create(path)?));
buf.write_all( buf.write_all(
from_paths(name, &vals) from_path(name, &options)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
eprintln!("{}", e); eprintln!("{}", e);
std::process::exit(1) std::process::exit(1)
@ -203,7 +205,7 @@ fn main() -> std::io::Result<()> {
} else { } else {
let mut stdout = BufWriter::new(stdout()); let mut stdout = BufWriter::new(stdout());
stdout.write_all( stdout.write_all(
from_paths(name, &vals) from_path(name, &options)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
eprintln!("{}", e); eprintln!("{}", e);
std::process::exit(1) std::process::exit(1)

View File

@ -52,7 +52,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt()?; .parse_stmt()?;
} else { } else {
@ -111,7 +111,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt()?; .parse_stmt()?;
} else { } else {
@ -139,7 +139,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt(); .parse_stmt();
} }
@ -319,7 +319,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -341,7 +341,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?, .parse()?,
); );
@ -391,7 +391,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -413,7 +413,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?, .parse()?,
); );
@ -516,7 +516,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -538,7 +538,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?, .parse()?,
); );

View File

@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?; .parse()?;

View File

@ -7,7 +7,7 @@ use crate::{common::QuoteKind, error::SassResult, lexer::Lexer, value::Value, To
use super::{Parser, Stmt}; use super::{Parser, Stmt};
/// Searches the current directory of the file then searches in load paths directories /// Searches the current directory of the file then searches in `load_paths` directories
/// if the import has not yet been found. /// if the import has not yet been found.
/// <https://sass-lang.com/documentation/at-rules/import#finding-the-file> /// <https://sass-lang.com/documentation/at-rules/import#finding-the-file>
/// <https://sass-lang.com/documentation/at-rules/import#load-paths> /// <https://sass-lang.com/documentation/at-rules/import#load-paths>
@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
let name = path_buf.file_name().unwrap_or_else(|| OsStr::new("..")); let name = path_buf.file_name().unwrap_or_else(|| OsStr::new(".."));
if let Some(name) = find_import(&path_buf, name, self.load_paths) { if let Some(name) = find_import(&path_buf, name, &self.options.load_paths) {
let file = self.map.add_file( let file = self.map.add_file(
name.to_string_lossy().into(), name.to_string_lossy().into(),
String::from_utf8(fs::read(&name)?)?, String::from_utf8(fs::read(&name)?)?,
@ -130,7 +130,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse(); .parse();
} }

View File

@ -165,7 +165,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
}) })
.parse_keyframes_selector()?; .parse_keyframes_selector()?;
@ -196,7 +196,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt()?; .parse_stmt()?;

View File

@ -154,7 +154,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()?; .parse()?;
@ -206,7 +206,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.scopes, content_scopes: self.scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()? .parse()?
} else { } else {

View File

@ -17,11 +17,10 @@ use crate::{
style::Style, style::Style,
utils::{read_until_closing_curly_brace, read_until_semicolon_or_closing_curly_brace}, utils::{read_until_closing_curly_brace, read_until_semicolon_or_closing_curly_brace},
value::Value, value::Value,
{Cow, Token}, Options, {Cow, Token},
}; };
use common::{Comment, ContextFlags, NeverEmptyVec, SelectorOrStyle}; use common::{Comment, ContextFlags, NeverEmptyVec, SelectorOrStyle};
pub(crate) use value::{HigherIntermediateValue, ValueVisitor}; pub(crate) use value::{HigherIntermediateValue, ValueVisitor};
mod args; mod args;
@ -83,7 +82,7 @@ pub(crate) struct Parser<'a> {
pub at_root_has_selector: bool, pub at_root_has_selector: bool,
pub extender: &'a mut Extender, pub extender: &'a mut Extender,
pub load_paths: &'a [&'a Path], pub options: &'a Options<'a>,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
@ -361,7 +360,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
}, },
allows_parent, allows_parent,
true, true,
@ -600,7 +599,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt()?; .parse_stmt()?;
@ -668,7 +667,7 @@ impl<'a> Parser<'a> {
at_root_has_selector, at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse()? .parse()?
.into_iter() .into_iter()
@ -709,7 +708,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_selector(false, true, String::new())?; .parse_selector(false, true, String::new())?;
@ -787,7 +786,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_stmt()?; .parse_stmt()?;

View File

@ -201,7 +201,7 @@ impl<'a> Parser<'a> {
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes, content_scopes: self.content_scopes,
load_paths: self.load_paths, options: self.options,
} }
.parse_value(in_paren) .parse_value(in_paren)
} }

View File

@ -476,7 +476,7 @@ impl Value {
at_root_has_selector: parser.at_root_has_selector, at_root_has_selector: parser.at_root_has_selector,
extender: parser.extender, extender: parser.extender,
content_scopes: parser.content_scopes, content_scopes: parser.content_scopes,
load_paths: parser.load_paths, options: parser.options,
} }
.parse_selector(allows_parent, true, String::new()) .parse_selector(allows_parent, true, String::new())
} }

View File

@ -44,7 +44,7 @@ fn imports_variable() {
tempfile!("imports_variable", "$a: red;"); tempfile!("imports_variable", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }
@ -59,7 +59,7 @@ fn import_no_semicolon() {
fn import_no_quotes() { fn import_no_quotes() {
let input = "@import import_no_quotes"; let input = "@import import_no_quotes";
tempfile!("import_no_quotes", "$a: red;"); tempfile!("import_no_quotes", "$a: red;");
match grass::from_string(input.to_string()) { match grass::from_string(input.to_string(), &grass::Options::default()) {
Ok(..) => panic!("did not fail"), Ok(..) => panic!("did not fail"),
Err(e) => assert_eq!( Err(e) => assert_eq!(
"Error: Expected string.", "Error: Expected string.",
@ -78,7 +78,7 @@ fn single_quotes_import() {
tempfile!("single_quotes_import", "$a: red;"); tempfile!("single_quotes_import", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }
@ -88,7 +88,7 @@ fn finds_name_scss() {
tempfile!("finds_name_scss.scss", "$a: red;"); tempfile!("finds_name_scss.scss", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }
@ -98,7 +98,7 @@ fn finds_underscore_name_scss() {
tempfile!("_finds_underscore_name_scss.scss", "$a: red;"); tempfile!("_finds_underscore_name_scss.scss", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }
@ -110,7 +110,7 @@ fn chained_imports() {
tempfile!("chained_imports__c.scss", "$a: red;"); tempfile!("chained_imports__c.scss", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }
@ -129,7 +129,7 @@ fn chained_imports_in_directory() {
tempfile!("chained_imports_in_directory__c.scss", "$a: red;"); tempfile!("chained_imports_in_directory__c.scss", "$a: red;");
assert_eq!( assert_eq!(
"a {\n color: red;\n}\n", "a {\n color: red;\n}\n",
&grass::from_string(input.to_string()).expect(input) &grass::from_string(input.to_string(), &grass::Options::default()).expect(input)
); );
} }

View File

@ -7,7 +7,7 @@ macro_rules! test {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $func() { fn $func() {
let sass = grass::from_string($input.to_string()) let sass = grass::from_string($input.to_string(), &grass::Options::default())
.expect(concat!("failed to parse on ", $input)); .expect(concat!("failed to parse on ", $input));
assert_eq!( assert_eq!(
String::from($input), String::from($input),
@ -20,7 +20,7 @@ macro_rules! test {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $func() { fn $func() {
let sass = grass::from_string($input.to_string()) let sass = grass::from_string($input.to_string(), &grass::Options::default())
.expect(concat!("failed to parse on ", $input)); .expect(concat!("failed to parse on ", $input));
assert_eq!( assert_eq!(
String::from($output), String::from($output),
@ -39,7 +39,7 @@ macro_rules! error {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $func() { fn $func() {
match grass::from_string($input.to_string()) { match grass::from_string($input.to_string(), &grass::Options::default()) {
Ok(..) => panic!("did not fail"), Ok(..) => panic!("did not fail"),
Err(e) => assert_eq!($err, e.to_string() Err(e) => assert_eq!($err, e.to_string()
.chars() .chars()