Liquid error: undefined method `source' for nil:NilClass Liquid error: undefined method `url' for nil:NilClass

Is this your first visit? You may want to subscribe to the feed.

Articles tagged with range

Fixing Range#step

Update: This has been added to Rails’ active_support.

My last post got me thinking about my post a couple months ago about being annoyed that Range#step requires a block and returns itself.

Well, it’s Ruby. If you don’t like it, change it:

class Range
  alias_method :original_step, :step
  def step(value, &block)
    if block_given?
      original_step(value, &block)
    else
      returning [] do |array|
        original_step(value) {|step| array << step }
      end
    end
  end
end
(0..10).step(2)                 #=> [0, 2, 4, 6, 8, 10]
(0..10).setp(2) {|i| puts i }   #=> (0..10)

Now, before you start yelling at me for being an irresponsible programmer, may I remind you that this change and the ones in my previous post in no way change the original functionality of Range. step raises an error if no block is given, and include? simply returns false if a range is passed (you can’t have a Range of Ranges, so previously, a range would never include another Range).

I think I may submit a patch for ActiveSupport with these little nuggets.

update: test your code before you publish it. Code has been fixed so it really doesn’t have any adverse side-effects.

Code: range Feb 13, 2007 ● updated Oct 10, 2007 1 comment

Ranges include? or overlap? with Ranges

Update: This has been added to Rails’ active_support.

The past several days I’ve found myself repeatedly writing the following lines to check if two events are conflicting:

window = course.begin_at...course.end_at
window.include?(event.begin_at) || window.include?(event.end_at?)

It finally donned on me that all I’m really doing is checking if two ranges overlap. What I really wanted to be doing is:

  (course.begin_at...course.end_at).overlap?(event.begin_at...event.end_at)

While I was at it, I decided that it only made sense that Range#include? should be able to take a range:

class Range

  def overlap?(range)
    self.include?(range.first) || range.include?(self.first)
  end

  def include_with_range?(value)
    if value.is_a?(Range)
      last = value.exclude_end? ? value.last - 1 : value.last
      self.include?(value.first) && self.include?(last)
    else
      include_without_range?(value)
    end
  end
  alias_method_chain :include?, :range

end

update: thanks to Daniel Schierbeck for the better implementation of overlap?

So now, I can do things like:

(1..5).include?(2..3)    #=> true
(1..5).include?(4..8)    #=> false
(1..5).overlap?(4..8)    #=> true
(1...5).overlap?(5..10)  #=> false

I love this language!

Code: range Feb 13, 2007 ● updated Oct 10, 2007 9 comments

Why does #step return itself?

update: problem solved!

Today, I wanted to get an array of numbers from 5 to 250, incrementing by 5. You’d think this would be a perfect job for Range#step or Number#step, but strangely enough, both of them return self:

(5..250).step(5) { } #=> 5..250
5.step(250, 5) { } #=> 5

I cannot figure out why in the world step would return self. The other annoyance is that step must receive a block, but, given it’s return value, I understand why.

So, to accomplish my original goal, I could make use of #step by creating a temporary variable:

result = []
(5..250).step(5) {|n| result << n }

But, it feels unnatural in Ruby to create temporary variables, so I ended ditching #step:

(5..250).select {|n| n % 5 == 0 }
Code: range Dec 11, 2006 ● updated Feb 13, 2007 3 comments

Subscribe

Browse by Tag