class RuboCop::Cop::Rails::TimeZone
This cop checks for the use of Time methods without zone.
Built on top of Ruby on Rails style guide (github.com/bbatsov/rails-style-guide#time) and the article danilenko.org/2012/7/6/rails_timezones/ .
Two styles are supported for this cop. When EnforcedStyle is 'strict' then only use of Time.zone is allowed.
When EnforcedStyle is 'flexible' then it's also allowed to use Time.in_time_zone.
@example
# always offense Time.now Time.parse('2015-03-02 19:05:37') # no offense Time.zone.now Time.zone.parse('2015-03-02 19:05:37') # no offense only if style is 'acceptable' Time.current DateTime.strptime(str, "%Y-%m-%d %H:%M %Z").in_time_zone Time.at(timestamp).in_time_zone
Constants
- ACCEPTED_METHODS
- DANGEROUS_METHODS
- MSG
- MSG_ACCEPTABLE
- MSG_CURRENT
- MSG_LOCALTIME
- TIMECLASS
Public Instance Methods
on_const(node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 52 def on_const(node) mod, klass = *node # we should only check core class # (`DateTime`/`Time` or `::Date`/`::DateTime`) return unless (mod.nil? || mod.cbase_type?) && method_send?(node) check_time_node(klass, node.parent) if TIMECLASS.include?(klass) end
Private Instance Methods
acceptable?()
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 151 def acceptable? style == :flexible end
acceptable_methods(klass, method_name, node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 159 def acceptable_methods(klass, method_name, node) acceptable = [ "`Time.zone.#{safe_method(method_name, node)}`", "`#{klass}.current`" ] ACCEPTED_METHODS.each do |am| acceptable << "`#{klass}.#{method_name}.#{am}`" end acceptable end
build_message(klass, method_name, node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 78 def build_message(klass, method_name, node) if acceptable? format(MSG_ACCEPTABLE, "#{klass}.#{method_name}", acceptable_methods(klass, method_name, node).join(', ') ) elsif method_name == 'current' format(MSG_CURRENT, "#{klass}.#{method_name}" ) else safe_method_name = safe_method(method_name, node) format(MSG, "#{klass}.#{method_name}", "Time.zone.#{safe_method_name}" ) end end
check_localtime(node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 132 def check_localtime(node) selector_node = node while !node.nil? && node.send_type? break if extract_method(node) == :localtime node = node.parent end _receiver, _method, args = *node add_offense(selector_node, :selector, MSG_LOCALTIME) if args.nil? end
check_time_node(klass, node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 63 def check_time_node(klass, node) chain = extract_method_chain(node) return if danger_chain?(chain) return check_localtime(node) if need_check_localtime?(chain) method_name = (chain & DANGEROUS_METHODS).join('.') return if offset_provided?(node) message = build_message(klass, method_name, node) add_offense(node, :selector, message) end
danger_chain?(chain)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 143 def danger_chain?(chain) (chain & DANGEROUS_METHODS).empty? || !(chain & good_methods).empty? end
extract_method(node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 106 def extract_method(node) _receiver, method_name, *_args = *node method_name end
extract_method_chain(node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 97 def extract_method_chain(node) chain = [] while !node.nil? && node.send_type? chain << extract_method(node) node = node.parent end chain end
good_methods()
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 155 def good_methods style == :strict ? [:zone] : [:zone, :current] + ACCEPTED_METHODS end
method_send?(node)
click to toggle source
checks that parent node of send_type and receiver is the given node
# File lib/rubocop/cop/rails/time_zone.rb, line 113 def method_send?(node) return false unless node.parent && node.parent.send_type? receiver, _method_name, *_args = *node.parent receiver == node end
need_check_localtime?(chain)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 147 def need_check_localtime?(chain) acceptable? && chain.include?(:localtime) end
offset_provided?(node)
click to toggle source
Time.new can be called with a time zone offset When it is, that should be considered safe Example: Time.new(1988, 3, 15, 3, 0, 0, “-05:00”)
# File lib/rubocop/cop/rails/time_zone.rb, line 176 def offset_provided?(node) _, _, *args = *node args.length >= 7 end
safe_method(method_name, node)
click to toggle source
# File lib/rubocop/cop/rails/time_zone.rb, line 121 def safe_method(method_name, node) _receiver, _method_name, *args = *node return method_name unless method_name == 'new' if args.empty? 'now' else 'local' end end