kiyonori-matsumoto/tcl-ruby

View on GitHub
lib/tcl/ruby/commands/string.rb

Summary

Maintainability
A
2 hrs
Test Coverage
require 'strscan'

module Tcl
  module Ruby
    class Interpreter
      private

      def ___string(*arg)
        send("___string_#{arg[0]}", *arg[1..-1])
      rescue ArgumentError => e
        raise(TclArgumentError, "string #{arg[0]}: #{e.message}")
      end

      def ___string_length(str)
        str.length
      end

      def ___string_equal(*arg)
        opts = {}
        if arg.size != 2
          opts = OptionParser.parse(['nocase', 'length?'], arg)
          raise(TclArgumentError, 'string equal ?-nocase? ?-length int? string1 string2') unless arg.size == 2
        end
        __string_equal_body(*arg, opts)
      end

      def __string_equal_body(str1, str2, opts = {})
        if opts.key?('nocase')
          str1 = str1.upcase
          str2 = str2.upcase
        end
        if opts.key?('length')
          range = (0...opts['length'].to_i)
          (str1[range] == str2[range]) ? '1' : '0'
        else
          (str1 == str2) ? '1' : '0'
        end
      end

      def ___string_index(str, index)
        str[parse_index_format(index)]
      end

      def ___string_map(*arg)
        opts = {}
        if arg.size != 2
          opts = OptionParser.parse(['nocase'], arg)
          raise(TclArgumentError, 'string map ?-nocase? charMap string') unless arg.size == 2
        end
        __string_map_body(*arg, opts)
      end

      def __string_map_body(char_map, str, opts = {})
        h = parse(char_map, true).to_h
        scan = StringScanner.new str
        rstr = ''
        until scan.empty?
          r = h.each do |k, v|
            next unless (opts['nocase'] && scan.scan(/#{k}/i)) ||
                        scan.scan(/#{k}/)
            rstr << v
            break false
          end
          rstr << scan.scan(/./) if r
        end
        rstr
      end

      def ___string_range(str, first, last)
        first = parse_index_format first
        last = parse_index_format last
        str[first..last]
      end

      def ___string_repeat(str, count)
        str * count.to_i
      end

      def ___string_tolower(str, first = 0, last = nil)
        last ||= str.size
        __string_tosomething(str, first, last, :downcase)
      end

      def __string_tosomething(str, first, last, modifier)
        first = parse_index_format first
        last  = parse_index_format last
        str[first..last] = str[first..last].send(modifier)
        str
      end

      def ___string_totitle(str, first = 0, last = -1)
        __string_tosomething(str, first, last, :capitalize)
      end

      def ___string_toupper(str, first = 0, last = -1)
        __string_tosomething(str, first, last, :upcase)
      end

      def ___string_trim(str, chars = '\s')
        __string_trimmer(str, chars, 3)
      end

      def ___string_trimleft(str, chars = '\s')
        __string_trimmer(str, chars, 1)
      end

      def ___string_trimright(str, chars = '\s')
        __string_trimmer(str, chars, 2)
      end

      def __string_trimmer(str, chars, mode)
        str.sub!(/\A[#{chars}]+/, '') if mode & 1 != 0
        str.sub!(/[#{chars}]+\z/, '') if mode & 2 != 0
        str
      end
    end
  end
end