【问题标题】:How to convert raw string of time in Rails?如何在 Rails 中转换原始时间字符串?
【发布时间】:2020-08-02 14:53:49
【问题描述】:

在 Rails (>= 6) 中,将表示时间的原始字符串转换为 ActiveSupport::Duration 对象的好方法是什么?例如,类似:

45 min
1 h

我在this discussion 中阅读了一些答案,但问题是chronic gem 不再维护。

【问题讨论】:

标签: ruby-on-rails ruby


【解决方案1】:
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

还有一个合格的规范:

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 durations,而不是一个不稳定的字符串解析器。

【讨论】:

  • 正则表达式不是我的强项,所以这可能很简单。
  • 谢谢!确实 ISO8601 会很棒,但我没有掌握数据
猜你喜欢
  • 2021-05-21
  • 2014-08-06
  • 2018-01-23
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多