Jengamon / ruwren

A Rustified binding for Wren
Other
40 stars 9 forks source link

Default module loader? #7

Closed KHN190 closed 3 years ago

KHN190 commented 3 years ago

Besides the module loader always returns None, I'm thinking something like:

pub struct DefaultLoader {
    source_dir: &str,
}
impl DefaultLoader {
    pub fn new() -> DefaultLoader {
        DefaultLoader { source_dir: "." }
    }
    pub fn source_dir(&mut self, source_dir: &str) -> &mut Self {
        self.source = source_dir;
        self
    }
}
impl ModuleScriptLoader for DefaultLoader {
    fn load_script(&mut self, module: String) -> Option<String> {
        use std::fs::File;
        use std::io::Read;
        use std::path::Path;

        // Look for a file named [module].wren.
        let mut name_path = Path::new(self.source_dir).join(&module);
        name_path.set_extension("wren");

        let mut buffer = String::new();

        let result = File::open(&name_path).map(|mut f| f.read_to_string(&mut buffer));
        if result.is_ok() {
            return Some(buffer);
        } else {
            None
        }
    }
}

It loads wren scripts from source_dir in hierarchy. So you can do:

main.wren
a.wren
    - lib/
      b.wren

in main.wren:

import "a"
import "lib/b"

Except the part whether using relative current working directory as default. Or more useful, it should load from multiple source directories. Is it good to add in, or we prefer not?

Jengamon commented 3 years ago

We could add this loader as one beside the null loader. The null loader is a useful default in that it forces the user to provide logic for loading modules if they want to load any modules, which could be unique to their use case, but a generic file loader does sound useful, and I would write: (not sure this builds)

use std::path::{PathBuf, Path};
use std::fs::File;
use ruwren::ModuleScriptLoader;

pub struct BasicFileLoader {
  base_dir: PathBuf
}

impl BasicFileLoader {
  pub fn new() -> BasicFileLoader {
    BasicFileLoader { base_dir: ".".into() }
  }

  pub fn base_dir<P: AsRef<Path>>(self, base_dir: P) -> Self {
    self.base_dir = base_dir.as_ref().into();
    self
  }
}

impl ModuleScriptLoader for BasicFileLoader {
  fn load_script(&mut self, module: String) -> Option<String> {

    let module_path = self.base_dir.join(module).with_extension("wren");

    let mut contents = String::new();

    match File::open(module_path) {
      Ok(mut file) => {
        use std::io::Read;
        file.read_to_string(&mut contents);
        Some(contents)
      },
      Err(_) => {
        // TODO Error reporting? We hardly know 'er.
        None
      }
    }
  }
}