Monkey patch to return the current time when an empty string is specified in Ruby's Time.parse

Background

When upgrading ruby from 1.8.7 to 1.9.3, if an empty string is specified in the argument of Time.parse, an exception will occur.

[EXCEPTION] ArgumentError: Occurs when date is given an empty string. Prior to 1.9.2, no exception was raised and an instance of Time representing the current time was returned.

Ruby 1.9.2 Reference Manual Time.parse

Since there were too many empty strings specified in Time.parse and it was difficult to fix, I decided to apply a monkey patch to Time.parse to solve it.

Conclusion

If an empty string is specified, Time.now is returned, and other than that, it is an override-like process that calls the parse method of the built-in class.

class Time
  class << self
    alias_method :__parse__, :parse
    private :__parse__

    def parse(time)
      if time.empty?
        #Returns the current time
        Time.now
      else
        #Built-in class Time.Call parse
        __parse__(time)
      end
    end
  end
end

It is also possible to define it with self.parse.

class Time
  class << self
    alias_method :__parse__, :parse
    private :__parse__
  end

  def self.parse(time)
    if time.empty?
      #Returns the current time
      Time.now
    else
      #Built-in class Time.Call parse
      __parse__(time)
    end
  end
end

To the conclusion

Time override

I wanted to check the empty string while making use of the built-in class Time, so I thought that I should inherit Time and override it. However, when inheriting, you need to make the class name an alias and change all the places where Time.parse (arg) is used to the new class name. I gave up because this was the end of the story.

Time.parse monkey patch

Next, I considered a monkey patch. Cookpad also supported monkey patches, so I referred to this. (It was written that you should not do it as much as possible.) How to apply monkey patches in Ruby on Rails applications

I prepared an extension class of Time and defined it as follows.


class Time
  def self.parse(time)
    if time.empty?
      Time.now
    else
      Time.parse(time)
    end
  end
end

However, this is an error. This is also NG because the extension class Time.parse has been called all the time and it has become an infinite loop situation.


irb(main):002:0> Time.parse('2020-01-01 12:34:56')
SystemStackError: stack level too deep
	from /usr/local/lib/ruby/1.9.1/irb/workspace.rb:80
Maybe IRB bug!

Applying Time.parse monkey patch & alias_method

I investigated if there is a way to call the extension class Time.parse from the previous code and referred to the following article. Override existing method ](https://qiita.com/umanoda/items/33613b94ccabf7b1f851)

By using ʻalias_method and changing the method name of parseof the extension class Time toparse, it seemed that the infinite loop could be avoided. Just in case, it is defined as private` so that it will not be called from the outside.


class Time

  alias_method :__parse__, :parse
  private :__parse__

  def self.parse(time)
    if time.empty?
      Time.now
    else
      Time.parse(time)
    end
  end
end

Then I get an error if there is no parse method. alias_medhod could not be applied because parse is a class method.

bundle exec rails c
`alias_method': undefined method `parse' for class `Time' (NameError)

Applying Time.parse monkey patch & alias_method (class method)

I have referred to the following about how to alias_method a class method. Add alias to class method

It could be applied by defining ʻalias_method` in class << self. The final form is here.

class Time
  class << self
    alias_method :__parse__, :parse
    private :__parse__
  end

  def self.parse(time)
    if time.empty?
      Time.now
    else
      __parse__(time)
    end
  end
end

It is also possible to define the parse method in class << self as shown below. In that case, self is not necessary.

class Time
  class << self
    alias_method :__parse__, :parse
    private :__parse__

    def parse(time)
      if time.empty?
        Time.now
      else
        __parse__(time)
      end
    end
  end
end

Finally

I think that there are few environments that use ruby 1.8.7 now, but I hope that it will be useful for upgrading the legacy code. Also, I think that it will be helpful for the method of monkey patch of the built-in class, so I hope it helps.

reference

Ruby 1.9.2 Reference Manual Time.parse

How to apply monkey patches in Ruby on Rails applications

Override existing method ](https://qiita.com/umanoda/items/33613b94ccabf7b1f851)

Add alias to class method

Class Extension

Recommended Posts

Monkey patch to return the current time when an empty string is specified in Ruby's Time.parse
How to output the value when there is an array in the array
How to set when "The constructor Empty () is not visible" occurs in junit
How to set chrony when the time shifts in CentOS7
Throw an exception and catch when there is no handler corresponding to the path in spring
When the character string passed to C ++ by JNA is garbled
Countermeasures for forgetting to specify the font when titleTextAttributes is specified
How to write the view when Vue is introduced in Rails?
How to get the current date as a string in yyyyMMdd format
I want to display an error message when registering in the database
[Ruby] How to prevent errors when nil is included in the operation
When reassigning to an argument in a Ruby method and then calling `super` → The reassigned one is used
Possibility when deploying to EC2 but nothing is displayed in the error log
Corresponds to a property whose type is an array when empty using JsonDeserializer
If the parameter is an array, how to include it in Stopara's params.permit
[Comma (,) is strictly prohibited in the address! ] Things to keep in mind when applying for an exam at Pearson VUE
[Java] When putting a character string in the case of a switch statement, it is necessary to make it a constant expression