mirror of
				https://github.com/red-data-tools/YouPlot.git
				synced 2025-11-04 11:38:10 +08:00 
			
		
		
		
	Add parser class
This commit is contained in:
		@@ -1,13 +1,14 @@
 | 
			
		||||
require 'optparse'
 | 
			
		||||
require_relative 'preprocessing'
 | 
			
		||||
require_relative 'command/params'
 | 
			
		||||
require_relative 'command/parser'
 | 
			
		||||
 | 
			
		||||
module Uplot
 | 
			
		||||
  Data = Struct.new(:headers, :series)
 | 
			
		||||
 | 
			
		||||
  class Command
 | 
			
		||||
    attr_accessor :params, :command
 | 
			
		||||
    attr_reader :main_parser, :sub_parsers, :raw_inputs, :data, :fmt
 | 
			
		||||
    attr_accessor :params
 | 
			
		||||
    attr_reader :raw_inputs, :data, :fmt, :parser
 | 
			
		||||
 | 
			
		||||
    def initialize
 | 
			
		||||
      @params = Params.new
 | 
			
		||||
@@ -22,224 +23,15 @@ module Uplot
 | 
			
		||||
 | 
			
		||||
      @raw_inputs = []
 | 
			
		||||
      @debug      = false
 | 
			
		||||
 | 
			
		||||
      @parser = Parser.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create_default_parser
 | 
			
		||||
      OptionParser.new do |opt|
 | 
			
		||||
        opt.program_name = 'uplot'
 | 
			
		||||
        opt.version = Uplot::VERSION
 | 
			
		||||
        opt.on('-O', '--output', TrueClass) do |v|
 | 
			
		||||
          @output = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-d', '--delimiter VAL', 'use DELIM instead of TAB for field delimiter', String) do |v|
 | 
			
		||||
          @delimiter = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-H', '--headers', 'specify that the input has header row', TrueClass) do |v|
 | 
			
		||||
          @headers = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-T', '--transpose', TrueClass) do |v|
 | 
			
		||||
          @transpose = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-t', '--title VAL', 'print string on the top of plot', String) do |v|
 | 
			
		||||
          params.title = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-x', '--xlabel VAL', 'print string on the bottom of the plot', String) do |v|
 | 
			
		||||
          params.xlabel = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-y', '--ylabel VAL', 'print string on the far left of the plot', String) do |v|
 | 
			
		||||
          params.ylabel = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-w', '--width VAL', 'number of characters per row', Integer) do |v|
 | 
			
		||||
          params.width = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-h', '--height VAL', 'number of rows', Numeric) do |v|
 | 
			
		||||
          params.height = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-b', '--border VAL', 'specify the style of the bounding box', String) do |v|
 | 
			
		||||
          params.border = v.to_sym
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-m', '--margin VAL', 'number of spaces to the left of the plot', Numeric) do |v|
 | 
			
		||||
          params.margin = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-p', '--padding VAL', 'space of the left and right of the plot', Numeric) do |v|
 | 
			
		||||
          params.padding = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('-c', '--color VAL', 'color of the drawing', String) do |v|
 | 
			
		||||
          params.color = v =~ /\A[0-9]+\z/ ? v.to_i : v.to_sym
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('--[no-]labels', 'hide the labels', TrueClass) do |v|
 | 
			
		||||
          params.labels = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('--fmt VAL', 'xyy, xyxy', String) do |v|
 | 
			
		||||
          @fmt = v
 | 
			
		||||
        end
 | 
			
		||||
        opt.on('--debug', TrueClass) do |v|
 | 
			
		||||
          @debug = v
 | 
			
		||||
        end
 | 
			
		||||
        yield opt if block_given?
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create_sub_parsers
 | 
			
		||||
      parsers = Hash.new do |h, k|
 | 
			
		||||
        h[k] = create_default_parser do |parser|
 | 
			
		||||
          parser.banner = <<~MSG
 | 
			
		||||
            Usage: uplot #{k} [options]
 | 
			
		||||
 | 
			
		||||
            Options:
 | 
			
		||||
          MSG
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      parsers[:barplot] = \
 | 
			
		||||
        parsers[:bar]
 | 
			
		||||
        .on('--symbol VAL', String) do |v|
 | 
			
		||||
          params.symbol = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--xscale VAL', String) do |v|
 | 
			
		||||
          params.xscale = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--count', TrueClass) do |v|
 | 
			
		||||
          @count = v
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:count] = \
 | 
			
		||||
        parsers[:c] # barplot -c
 | 
			
		||||
        .on('--symbol VAL', String) do |v|
 | 
			
		||||
          params.symbol = v
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:histogram] = \
 | 
			
		||||
        parsers[:hist]
 | 
			
		||||
        .on('-n', '--nbins VAL', Numeric) do |v|
 | 
			
		||||
          params.nbins = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--closed VAL', String) do |v|
 | 
			
		||||
          params.closed = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--symbol VAL', String) do |v|
 | 
			
		||||
          params.symbol = v
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:lineplot] = \
 | 
			
		||||
        parsers[:line]
 | 
			
		||||
        .on('--canvas VAL', String) do |v|
 | 
			
		||||
          params.canvas = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--xlim VAL', String) do |v|
 | 
			
		||||
          params.xlim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
        .on('--ylim VAL', String) do |v|
 | 
			
		||||
          params.ylim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:lineplots] = \
 | 
			
		||||
        parsers[:lines]
 | 
			
		||||
        .on('--canvas VAL', String) do |v|
 | 
			
		||||
          params.canvas = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--xlim VAL', String) do |v|
 | 
			
		||||
          params.xlim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
        .on('--ylim VAL', String) do |v|
 | 
			
		||||
          params.ylim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:scatter] = \
 | 
			
		||||
        parsers[:s]
 | 
			
		||||
        .on('--canvas VAL', String) do |v|
 | 
			
		||||
          params.canvas = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--xlim VAL', String) do |v|
 | 
			
		||||
          params.xlim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
        .on('--ylim VAL', String) do |v|
 | 
			
		||||
          params.ylim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:density] = \
 | 
			
		||||
        parsers[:d]
 | 
			
		||||
        .on('--grid', TrueClass) do |v|
 | 
			
		||||
          params.grid = v
 | 
			
		||||
        end
 | 
			
		||||
        .on('--xlim VAL', String) do |v|
 | 
			
		||||
          params.xlim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
        .on('--ylim VAL', String) do |v|
 | 
			
		||||
          params.ylim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:boxplot] = \
 | 
			
		||||
        parsers[:box]
 | 
			
		||||
        .on('--xlim VAL', String) do |v|
 | 
			
		||||
          params.xlim = get_lim(v)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      parsers[:colors]
 | 
			
		||||
        .on('-n', '--names', TrueClass) do |v|
 | 
			
		||||
          @color_names = v
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      # Preventing the generation of new sub-commands
 | 
			
		||||
      parsers.default = nil
 | 
			
		||||
      parsers
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create_main_parser
 | 
			
		||||
      create_default_parser do |main_parser|
 | 
			
		||||
        # Usage and help messages
 | 
			
		||||
        main_parser.banner = \
 | 
			
		||||
          <<~MSG
 | 
			
		||||
            Program: uplot (Tools for plotting on the terminal)
 | 
			
		||||
            Version: #{Uplot::VERSION} (using unicode_plot #{UnicodePlot::VERSION})
 | 
			
		||||
 | 
			
		||||
            Usage:   uplot <command> [options]
 | 
			
		||||
 | 
			
		||||
            Command:
 | 
			
		||||
                #{sub_parsers.keys.join("\n    ")}
 | 
			
		||||
 | 
			
		||||
            Options:
 | 
			
		||||
          MSG
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def parse_options(argv = ARGV)
 | 
			
		||||
      @sub_parsers = create_sub_parsers
 | 
			
		||||
      @main_parser = create_main_parser
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        main_parser.order!(argv)
 | 
			
		||||
      rescue OptionParser::ParseError => e
 | 
			
		||||
        warn "uplot: #{e.message}"
 | 
			
		||||
        exit 1
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      @command = argv.shift&.to_sym
 | 
			
		||||
 | 
			
		||||
      unless sub_parsers.has_key?(command)
 | 
			
		||||
        if command.nil?
 | 
			
		||||
          warn main_parser.help
 | 
			
		||||
        else
 | 
			
		||||
          warn "uplot: unrecognized command '#{command}'"
 | 
			
		||||
        end
 | 
			
		||||
        exit 1
 | 
			
		||||
      end
 | 
			
		||||
      parser = sub_parsers[command]
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        parser.parse!(argv) unless argv.empty?
 | 
			
		||||
      rescue OptionParser::ParseError => e
 | 
			
		||||
        warn "uplot: #{e.message}"
 | 
			
		||||
        exit 1
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def get_lim(str)
 | 
			
		||||
      str.split(/-|:|\.\./)[0..1].map(&:to_f)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def run
 | 
			
		||||
      parse_options
 | 
			
		||||
      parser.parse_options
 | 
			
		||||
      command = parser.command
 | 
			
		||||
      params = parser.params
 | 
			
		||||
 | 
			
		||||
      if command == :colors
 | 
			
		||||
        Plot.colors
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										225
									
								
								lib/uplot/command/parser.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								lib/uplot/command/parser.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
			
		||||
module Uplot
 | 
			
		||||
  class Command
 | 
			
		||||
    class Parser
 | 
			
		||||
      attr_reader :command, :params, :main_parser, :sub_parsers
 | 
			
		||||
 | 
			
		||||
      def initialize
 | 
			
		||||
        @sub_parsers = create_sub_parsers
 | 
			
		||||
        @main_parser = create_main_parser
 | 
			
		||||
        @command = nil
 | 
			
		||||
        @params = Params.new
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def create_default_parser
 | 
			
		||||
        OptionParser.new do |opt|
 | 
			
		||||
          opt.program_name = 'uplot'
 | 
			
		||||
          opt.version = Uplot::VERSION
 | 
			
		||||
          opt.on('-O', '--output', TrueClass) do |v|
 | 
			
		||||
            @output = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-d', '--delimiter VAL', 'use DELIM instead of TAB for field delimiter', String) do |v|
 | 
			
		||||
            @delimiter = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-H', '--headers', 'specify that the input has header row', TrueClass) do |v|
 | 
			
		||||
            @headers = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-T', '--transpose', TrueClass) do |v|
 | 
			
		||||
            @transpose = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-t', '--title VAL', 'print string on the top of plot', String) do |v|
 | 
			
		||||
            params.title = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-x', '--xlabel VAL', 'print string on the bottom of the plot', String) do |v|
 | 
			
		||||
            params.xlabel = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-y', '--ylabel VAL', 'print string on the far left of the plot', String) do |v|
 | 
			
		||||
            params.ylabel = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-w', '--width VAL', 'number of characters per row', Integer) do |v|
 | 
			
		||||
            params.width = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-h', '--height VAL', 'number of rows', Numeric) do |v|
 | 
			
		||||
            params.height = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-b', '--border VAL', 'specify the style of the bounding box', String) do |v|
 | 
			
		||||
            params.border = v.to_sym
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-m', '--margin VAL', 'number of spaces to the left of the plot', Numeric) do |v|
 | 
			
		||||
            params.margin = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-p', '--padding VAL', 'space of the left and right of the plot', Numeric) do |v|
 | 
			
		||||
            params.padding = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('-c', '--color VAL', 'color of the drawing', String) do |v|
 | 
			
		||||
            params.color = v =~ /\A[0-9]+\z/ ? v.to_i : v.to_sym
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('--[no-]labels', 'hide the labels', TrueClass) do |v|
 | 
			
		||||
            params.labels = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('--fmt VAL', 'xyy, xyxy', String) do |v|
 | 
			
		||||
            @fmt = v
 | 
			
		||||
          end
 | 
			
		||||
          opt.on('--debug', TrueClass) do |v|
 | 
			
		||||
            @debug = v
 | 
			
		||||
          end
 | 
			
		||||
          yield opt if block_given?
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def create_sub_parsers
 | 
			
		||||
        parsers = Hash.new do |h, k|
 | 
			
		||||
          h[k] = create_default_parser do |parser|
 | 
			
		||||
            parser.banner = <<~MSG
 | 
			
		||||
              Usage: uplot #{k} [options]
 | 
			
		||||
 | 
			
		||||
              Options:
 | 
			
		||||
            MSG
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        parsers[:barplot] = \
 | 
			
		||||
          parsers[:bar]
 | 
			
		||||
          .on('--symbol VAL', String) do |v|
 | 
			
		||||
            params.symbol = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--xscale VAL', String) do |v|
 | 
			
		||||
            params.xscale = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--count', TrueClass) do |v|
 | 
			
		||||
            @count = v
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:count] = \
 | 
			
		||||
          parsers[:c] # barplot -c
 | 
			
		||||
          .on('--symbol VAL', String) do |v|
 | 
			
		||||
            params.symbol = v
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:histogram] = \
 | 
			
		||||
          parsers[:hist]
 | 
			
		||||
          .on('-n', '--nbins VAL', Numeric) do |v|
 | 
			
		||||
            params.nbins = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--closed VAL', String) do |v|
 | 
			
		||||
            params.closed = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--symbol VAL', String) do |v|
 | 
			
		||||
            params.symbol = v
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:lineplot] = \
 | 
			
		||||
          parsers[:line]
 | 
			
		||||
          .on('--canvas VAL', String) do |v|
 | 
			
		||||
            params.canvas = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--xlim VAL', String) do |v|
 | 
			
		||||
            params.xlim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
          .on('--ylim VAL', String) do |v|
 | 
			
		||||
            params.ylim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:lineplots] = \
 | 
			
		||||
          parsers[:lines]
 | 
			
		||||
          .on('--canvas VAL', String) do |v|
 | 
			
		||||
            params.canvas = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--xlim VAL', String) do |v|
 | 
			
		||||
            params.xlim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
          .on('--ylim VAL', String) do |v|
 | 
			
		||||
            params.ylim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:scatter] = \
 | 
			
		||||
          parsers[:s]
 | 
			
		||||
          .on('--canvas VAL', String) do |v|
 | 
			
		||||
            params.canvas = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--xlim VAL', String) do |v|
 | 
			
		||||
            params.xlim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
          .on('--ylim VAL', String) do |v|
 | 
			
		||||
            params.ylim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:density] = \
 | 
			
		||||
          parsers[:d]
 | 
			
		||||
          .on('--grid', TrueClass) do |v|
 | 
			
		||||
            params.grid = v
 | 
			
		||||
          end
 | 
			
		||||
          .on('--xlim VAL', String) do |v|
 | 
			
		||||
            params.xlim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
          .on('--ylim VAL', String) do |v|
 | 
			
		||||
            params.ylim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:boxplot] = \
 | 
			
		||||
          parsers[:box]
 | 
			
		||||
          .on('--xlim VAL', String) do |v|
 | 
			
		||||
            params.xlim = get_lim(v)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        parsers[:colors]
 | 
			
		||||
          .on('-n', '--names', TrueClass) do |v|
 | 
			
		||||
            @color_names = v
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        # Preventing the generation of new sub-commands
 | 
			
		||||
        parsers.default = nil
 | 
			
		||||
        parsers
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def create_main_parser
 | 
			
		||||
        create_default_parser do |main_parser|
 | 
			
		||||
          # Usage and help messages
 | 
			
		||||
          main_parser.banner = \
 | 
			
		||||
            <<~MSG
 | 
			
		||||
              Program: uplot (Tools for plotting on the terminal)
 | 
			
		||||
              Version: #{Uplot::VERSION} (using unicode_plot #{UnicodePlot::VERSION})
 | 
			
		||||
 | 
			
		||||
              Usage:   uplot <command> [options]
 | 
			
		||||
 | 
			
		||||
              Command:
 | 
			
		||||
                  #{sub_parsers.keys.join("\n    ")}
 | 
			
		||||
 | 
			
		||||
              Options:
 | 
			
		||||
            MSG
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def parse_options(argv = ARGV)
 | 
			
		||||
        begin
 | 
			
		||||
          main_parser.order!(argv)
 | 
			
		||||
        rescue OptionParser::ParseError => e
 | 
			
		||||
          warn "uplot: #{e.message}"
 | 
			
		||||
          exit 1
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        @command = argv.shift&.to_sym
 | 
			
		||||
 | 
			
		||||
        unless sub_parsers.has_key?(command)
 | 
			
		||||
          if command.nil?
 | 
			
		||||
            warn main_parser.help
 | 
			
		||||
          else
 | 
			
		||||
            warn "uplot: unrecognized command '#{command}'"
 | 
			
		||||
          end
 | 
			
		||||
          exit 1
 | 
			
		||||
        end
 | 
			
		||||
        parser = sub_parsers[command]
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          parser.parse!(argv) unless argv.empty?
 | 
			
		||||
        rescue OptionParser::ParseError => e
 | 
			
		||||
          warn "uplot: #{e.message}"
 | 
			
		||||
          exit 1
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def get_lim(str)
 | 
			
		||||
        str.split(/-|:|\.\./)[0..1].map(&:to_f)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user