Class: DBF::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/dbf/cli.rb

Defined Under Namespace

Classes: TerminalFilter

Constant Summary collapse

USAGE =
<<~HELP
  usage: dbf [-h|-s|-a|-c|-r] filename
    -h = print this message
    -v = print the DBF gem version
    -s = print summary information
    -a = create an ActiveRecord::Schema
    -r = create a Sequel migration
    -c = export as CSV
HELP
CONTROL_BYTES =

Bytes a terminal interprets as control or escape sequences. A crafted DBF can carry these in column names and record values, so they are replaced before file-derived text reaches an interactive terminal.

/[\x00-\x1F\x7F]/n
CONTROL_BYTES_KEEPING_NEWLINES =

The same, but keeping CR and LF so CSV row separators survive.

/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/n

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, stdout: $stdout, stderr: $stderr) ⇒ CLI

Returns a new instance of CLI.



65
66
67
68
69
# File 'lib/dbf/cli.rb', line 65

def initialize(argv, stdout: $stdout, stderr: $stderr)
  @argv = argv.dup
  @stdout = stdout
  @stderr = stderr
end

Class Method Details

.run(argv, stdout: $stdout, stderr: $stderr) ⇒ Object



61
62
63
# File 'lib/dbf/cli.rb', line 61

def self.run(argv, stdout: $stdout, stderr: $stderr)
  new(argv, stdout: stdout, stderr: stderr).run
end

.sanitize(value, pattern = CONTROL_BYTES) ⇒ String

Replaces terminal control bytes. Substitution happens on a byte copy so a value whose bytes are invalid in its encoding cannot raise here.

Parameters:

  • value (Object)
  • pattern (Regexp) (defaults to: CONTROL_BYTES)

Returns:

  • (String)


30
31
32
33
# File 'lib/dbf/cli.rb', line 30

def self.sanitize(value, pattern = CONTROL_BYTES)
  string = value.to_s
  string.b.gsub(pattern, '?').force_encoding(string.encoding)
end

Instance Method Details

#runObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/dbf/cli.rb', line 71

def run
  params = OptionParser.new.getopts(@argv, 'h', 's', 'a', 'c', 'r', 'v')

  if params['v']
    print_version
  elsif params['h']
    print_help
  else
    filename = @argv.shift
    return missing_filename unless filename

    action = %w[a r s c].find { |flag| params[flag] }
    case action
    when 'a' then print_ar_schema(filename)
    when 'r' then print_sequel_schema(filename)
    when 's' then print_summary(filename)
    when 'c' then print_csv(filename)
    end
  end
  0
rescue DBF::FileNotFoundError => e
  @stderr.puts "DBF::FileNotFoundError: #{e.message}"
  1
end