Anki-Import

 view release on metacpan or  search on metacpan

lib/Anki/Import.pm  view on Meta::CPAN

arg parent_dir => (
  isa => 'Str',
  default => cwd,
  comment => 'optional directory to save output files, defaults to current directory',
);
opt quiet  => (
  isa => 'Bool',
  alias => 'q',
  default => 1,
  comment => 'On by default. Use --quiet to override this setting to suppress'
             . ' the success message after a successful execution of the command.'
);
opt verbose => (
  isa => 'Bool',
  alias => 'v',
  comment => 'provide details on progress of Anki::Import'
);
opt vverbose => (
  isa => 'Bool',
  alias => 'V',
  comment => 'verbose information plus debug info'
);

# start here
sub anki_import {
  my $args = optargs( @_ );

  my $file = $args->{file};
  if (!$file) {
    logf('Aborting: No file passed to Anki::Import.');
  }

  # set parent directory
  my $pd = $args->{parent_dir};

  # set log level as appropriate
  if ($args->{verbose}) {
    set_log_level('info');
  } elsif ($args->{vverbose}) {
    set_log_level('debug');
  } else {
    set_log_level('error');
  }
  logi('Log level set');

  # get and load the source file
  logi('Loading file');
  my $path  = File::Spec->catfile($file); logd($path);
  if (! -e $path) {
    logf("Aborting: Source file named '$path' does not exist.");
  };
  open (my $handle, "<:encoding(UTF-8)", $path) or logf("Could not open $path");;
  chomp(@lines = <$handle>);
  close $handle;
  logi('Source file loaded.');

  # pad data with a blank line to make it easier to process
  push @lines, '';

  # do the stuff we came here for
  validate_src_file(); logd(\@notes);
  generate_importable_files($pd);

  # print a success message
  unless ($args->{'quiet'}) {
    set_log_level('info');
    logi("Success! Your import files are in the $pd"
      . '/anki_import_files directory');
  }

  # fin
}

# functions for first pass parsing of source data
sub validate_src_file {
  logi('Validating source file');

  # throw error if file is empty
  logf('Source data file is empty.') if !$lines[0];

  # outer loop for parsing notes
  my %fields;  # keeps track of number of fields for each type of note
  while (next_line()) {

    # ignore blank lines
    next if ($cline =~ /^$|^\s+$/);

    if ($cline =~ /^#\s*(\S+)/) {
      $ntype = $1;
      logi("Found note type");
      logd($ntype);
      next;
    }

    logi('Processing new note');
    # get the note
    my $note = slurp_note();
    logd($note);

    logi('Checking number of note fields');
    # validaate that notes of the same type have the same number of fields
    if (my $number_of_fields = $fields{$ntype}) {
      if (scalar (@$note) != $number_of_fields) {
        my $field_count = scalar(@$note);
        logf("A(n) $ntype note ending on line $line_count"
        . " has $field_count fields, a different amount than previous '$ntype' note types."
        . " Notes of the same note type must have the same number of fields. One common reason"
        . " for this error is that you did not indicate that you wanted to leave a field blank. To leave a field blank,"
        . " place a single '`' (backtick) on the line by itself in the source file. You may also"
        . " have failed to separate notes with two or more blank lines."
        . " Check your source file to ensure it is properly formatted.\n\n\tRefer to the"
        . " Anki::Import documentation for more help with formatting your source file."
        );
      }
    } else {
      $fields{$ntype} = scalar @$note;
    }

    logi('Storing note');
    push @notes, {ntype => $ntype, note => $note};
  }

}

sub slurp_note {
  my @current_field;
  my @note;
  push @current_field, $cline;

  # loop over lines in the note
  while (next_line()) {
    logd($cline, 'cline');
    if ($cline =~ /^$|^\s+$/) {
      my @all_fields = @current_field;
      push (@note, \@all_fields) if @current_field;



( run in 0.593 second using v1.01-cache-2.11-cpan-140bd7fdf52 )