Как преобразовать необработанную строку времени в Rails? - PullRequest
1 голос
/ 02 августа 2020

В Rails (> = 6), что было бы хорошим способом преобразовать необработанные строки, представляющие время, в объект ActiveSupport::Duration? Например, что-то вроде:

45 min
1 h

Я прочитал некоторые ответы в этом обсуждении , но проблема в том, что драгоценный камень chroni c больше не поддерживается .

1 Ответ

2 голосов
/ 02 августа 2020
module DurationParser
  class ParseError < StandardError; end
  # This is an example of how to extend it with aliases
  ALAISES = {
    hours: [:h, :hr],
    minutes: [:m, :min],
    seconds: [:s, :sec]
  }
  EXP = /^(?<value>[\d*|\.]*)\s*(?<token>\w*)?$/.freeze

  # Parses a human readable string into a duration
  # @example
  #   DurationParser.parse('2 hours, 1 minute')
  # @return [ActiveSupport::Duration]
  def self.parse(string)
    string.split(/and|,/).map(&:strip).map do |pair|
      matches = pair.match(EXP)
      method = token_to_method(matches[:token])
      raise ParseError unless method
      (matches[:value].to_i).send(method)
    end.reduce(&:+)
  end

  private
  def self.token_to_method(token)
    ActiveSupport::Duration::PARTS.find do |p|
      p == token.downcase.pluralize.to_sym
    end || ALAISES.find do |k,v|
      v.include?(token.downcase.to_sym)
    end&.first
  end
end

И проходящий spe c:

require 'rails_helper'

RSpec.describe DurationParser do
  describe '.parse' do
    it "handles hours" do
      expect(DurationParser.parse('1 h')).to eq 1.hour;
      expect(DurationParser.parse('1 hr')).to eq 1.hour;
      expect(DurationParser.parse('1 hour')).to eq 1.hour;
      expect(DurationParser.parse('3 hours')).to eq 3.hours;
    end
    it "handles minutes" do
      expect(DurationParser.parse('1 m')).to eq 1.minute;
      expect(DurationParser.parse('1 min')).to eq 1.minute;
      expect(DurationParser.parse('1 minute')).to eq 1.minute;
      expect(DurationParser.parse('2 minutes')).to eq 2.minutes;
    end
    it "handles seconds" do
      expect(DurationParser.parse('1 s')).to eq 1.second;
      expect(DurationParser.parse('1 sec')).to eq 1.second;
      expect(DurationParser.parse('1 second')).to eq 1.second;
      expect(DurationParser.parse('15 seconds')).to eq 15.seconds;
    end
    it "handles comma delimeted strings" do
      expect(DurationParser.parse('1 hour, 3 minutes, 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "handles 'and' delimeted strings" do
      expect(DurationParser.parse('1 hour and 3 minutes and 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "handles mixed delimeter strings" do
      expect(DurationParser.parse('1 hour and 3 minutes, 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "raises when a bad token is passed" do
      expect { DurationParser.parse('25 sols') }.to raise_error(DurationParser::ParseError) 
    end
  end
end

Конечно, если вы хотите что-то надежно машиночитаемое, вы хотите использовать ISO8601 длительности , а не странный синтаксический анализатор строк .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...