leoniv/ass_launcher

View on GitHub
lib/ass_launcher/enterprise/web_client.rb

Summary

Maintainability
A
25 mins
Test Coverage
# encoding: utf-8

module AssLauncher
  module Enterprise
    # Abstract 1C:Enterprise client. Provides {#location} method as URI
    # generator for connection to
    # 1C information base via web browser.
    # @example (see #initialize)
    # @example (see #location)
    class WebClient
      require 'uri'
      require 'ass_launcher/enterprise/cli'
      DEFAULT_OPTIONS = { disable_startup_messages: true }
      DEFAULT_VERSION = '999'

      # @return [URI] base uri location
      attr_reader :uri
      # Version for 1C:Enterprise platform
      attr_reader :version
      # @return [WebClient]
      # @example
      #
      #  # Get webclient usin connection string:
      #  connection_string =\
      #  AssLauncher::Support::ConnectionString.new(
      #    'ws="http://host:port/infobase"')
      #  wc = AssLauncher::Enterprise::WebClient.new(cs.uri)
      #
      #  #or without connection_string
      #  wc = AssLauncher::Enterprise::WebClient.new('http://host/path')
      #
      # @param uri [String URI] base infobase location
      # @param version [String] version 1C:Enterprise platform.
      #  The {Enterprise::WebClient#cli_spec}
      #  depends on the {Enterprise::WebClient#version}.
      #  Default supposed max possable version.
      #  {Enterprise::WebClient::DEFAULT_VERSION}
      #
      def initialize(uri = '', version = DEFAULT_VERSION)
        @version = Gem::Version.new(version || DEFAULT_VERSION)
        @uri ||= URI(uri || '')
      end

      def uri=(uri)
        @uri = URI(uri)
      end

      # @return [Cli::CliSpec]
      def cli_spec
        @cli_spec ||= AssLauncher::Enterprise::Cli::CliSpec.for(self)
      end

      # Defined run modes fo client
      # @return (see Cli.defined_modes_for)
      def self.run_modes
        Cli.defined_modes_for(self)
      end

      # (see .run_modes)
      def run_modes
        self.class.run_modes
      end

      def build_args(&block)
        args_builder.build_args(&block)
      end
      private :build_args

      def args_builder
        Cli::ArgumentsBuilder.new(cli_spec, run_modes[0])
      end
      private :args_builder

      # Build URI location for connect to web infobase.
      #
      # We can use {Cli::ArgumentsBuilder} for
      # build connection string with validation parameters on defined in
      # {#cli_spec} specifications.
      #
      # Or we can pass parameters as +args+ array directly.
      # @example
      #  wc = AssLauncher::Enterprise::WebClient.new('http://host/path')
      #
      #  # Without ArgumentsBulder
      #  wc.location(['O', 'low', 'C', 'passed string',
      #    'N', '1cuser',
      #    'P', '1cpassw',
      #    'Authoff', '']) #=> URI
      #
      #  # With ArgumentsBulder
      #  wc.location do
      #    _O :Low
      #    _C 'passed string'
      #    _N '1cuser'
      #    _P '1cuser_password'
      #    wA :-
      #    oIDA :-
      #    authOff
      #    _L 'en'
      #    vL 'en'
      #    debuggerURL 'localhost'
      #    _UsePrivilegedMode
      #  end  #=> URI
      #
      # @param args [Arry]
      # @option options [bool] :disable_startup_messages adds or not
      #  '/DisableStartupMessages' flag parameter into +args+
      #
      def location(args = [], **options, &block)
        options = DEFAULT_OPTIONS.merge options
        args += ['DisableStartupMessages', '']\
          if options[:disable_startup_messages]
        args += build_args(&block) if block_given?
        add_to_query uri.dup, args_to_query(args)
      end

      def add_to_query(uri, q)
        if uri.query
          uri.query += escape "&#{q}" if q
        else
          uri.query = escape "#{q}" if q
        end
        uri
      end
      private :add_to_query

      def escape(s)
        self.class.escape(s)
      end
      private :escape

      # Fuckin 1C is bad understand of CGI.escape.
      # From escaping exclude: =&
      # and ' ' replaced on '%20'
      def self.escape(string)
        string.gsub(/([^ a-zA-Z0-9_.\-=&]+)/) do
          '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
        end.gsub(' ', '%20')
      end

      CLI_TO_WEB_PARAM_NAME = %r{^/}

      def args_to_query(args)
        r = to_query(args)
        r.gsub!(/&$/, '')
        return nil if r.empty?
        r
      end
      private :args_to_query

      def to_query(args)
        r = ''
        args.each_with_index do |v, i|
          next if (i + 1).even?
          r << "#{v.gsub(CLI_TO_WEB_PARAM_NAME, '')}"
          r << "=#{args[i + 1]}" unless args[i + 1].to_s.empty?
          r << '&'
        end
        r
      end
      private :to_query
    end
  end
end