

Reading the Ruby Source to Understand Rails Idiosyncrasies - cmdrcoriander
http://pivotallabs.com/reading-the-ruby-source/

======
Denzel
Well, first of all, you aren't reading the Ruby source to understand _Rails '_
idiosyncrasies, you're reading the Ruby source to understand _Ruby 's_
idiosyncrasies applied to Rails.

Secondly, this article is far more verbose than necessary when compared to the
succinct 5-paragraph explanation provided by David Flanagan in "The Ruby
Programming Language" p. 69-70 [1]

It's great that you took a chance to dive into the source of Ruby.
Nonetheless, it's times like these when I wish people would understand that
the best way to learn a programming language is by example AND by
documentation (whether official docs or books). Those that ONLY learn by
example fail to understand or unlock the true power of a language until it's
too late.

[1] [http://www.amazon.com/Ruby-Programming-Language-David-
Flanag...](http://www.amazon.com/Ruby-Programming-Language-David-
Flanagan/dp/0596516177)

------
norswap
I was going to write that this was a failing of the Ruby documentation. But
actually, it's pretty well documented if you take the time to read it
([http://ruby-doc.org/core-2.0/Range.html](http://ruby-
doc.org/core-2.0/Range.html)).

There's absolutely no need to go hitchhiking in the C source in this case.

~~~
stormbrew
While I agree that it's documented well enough that once you hit the situation
and read the doc you should be able to figure out why without diving into the
C, I think the documentation still fails in the sense that it doesn't give you
any guidance as to why or when you would choose which one.

That said, I really don't consider this magic as another subthread suggests.
include? just has an optimization for numeric ranges, but otherwise behaves
exactly as Enumerable#include? should.

------
RyanZAG
If there's only one thing I've learnt from trying different languages out: the
less magic, the better.

~~~
tptacek
This is an easy and thus superficial bit of insight to add. A more reliable
truism would be that "unnecessary magic is bad", but that brings us no closer
to evaluating Rails. Ultimately, you have to be able to point to specific
magical behaviors and make a case for what makes them gratuitous.

~~~
majormajor
Without turning this into a debate about particular bits of magic, my general
conclusion from using Rails (especially when projects are in maintenance mode)
is that it frequently makes it overly complicated to do things differently
than how the framework wants you to, making you resort to monkey patching and
other magical strategies of your own.

It's wonderful for prototyping but I'm becoming increasingly wary of it for
production systems that are going to have a long life (at which point the
whole perf/scaling thing comes into play too).

Which is all a very roundabout way of saying "use the right tool for the right
job," I suppose.

~~~
matthewmacleod
> my general conclusion from using Rails is that it frequently makes it overly
> complicated to do things differently than how the framework wants you to

I can't agree with this at all.

Rails has default and reasonably sensible idioms for expressing common
concepts. They work in most cases, but there are of course situations where
you want to implement something in a way that results in an impedance mismatch
with the framework.

In these cases, it's embarrassingly easy to compose different behaviours, or
indeed to write entirely custom ones, in order to achieve the functionality
you require. At the end of the day, it's Ruby with some helper libraries, and
developers are free to use as much or as little of these as is required.

If there's a problem in this vein with Rails, it's that the magic makes it
almost too tempting to twist apps into the "Rails way", even when it's not
appropriate. Good developers will be aware of this, and use the correct
approach.

------
zhoutong
I wonder if looking up the source is really necessary. I did some tests with
Rails console just now. It seems that Ruby and Rails are handling the case
quite logically.

"3.days.ago" at least by default is a TimeWithZone object in Rails.

    
    
      3.days.ago.class
       => ActiveSupport::TimeWithZone
    

And then the way Ruby iterates Range is through the "succ" method. So even
this will give you a wall of errors:

    
    
      (3.days.ago..2.days.ago).to_a
    

Sending "succ" to a TimeWithZone object will print a warning because the
method is deprecated. So basically a warning will show for every second in the
range.

Calling .include? should be equivalent to .to_a.include? in effect.

------
ahawkins
One uses a loop and one doesn't? Not sure if there's so much to get out of
this post.

~~~
norswap
`cover?` uses the comparison operators to check if the value is within the
range. `include?`, on the other hand, will behave like `cover?` only if the
range values are "numeric". If they aren't, it will iterate through the range
to see if it contains the value. This is possible because range values are
required to implement the `succ` method which gives the next value.

------
danso
Well, I learned about the cover? Method, so that's a big plus for a typical
Saturday...but I'm confused as to why include? for ranges doesn't just act as
an alias for cover?

I can't think of a Range that is _not_ meant to be continuous...I would test
out some cases right now if my computer weren't grinding away at a database
insertion process...

edit: OK, tried it out....as I suspected, Ranges that consists of Strings will
have different behavior:

    
    
        [16] pry(main)> ('aa'..'zz').include?('c')
        => false
        [17] pry(main)> ('aa'..'zz').cover?('c')
        => true
        [18] pry(main)> ('aa'..'zz').include?('cc')
        => true
        [19] pry(main)> ('aa'..'zz').cover?('cc')
        => true
        [20] pry(main)> ('aa'..'zz').cover?('cccccc')

~~~
norswap
Ranges are always continuous, but `cover?` uses the comparison operators,
while `include?` iterates over the items in the range in some cases.
`include?` is practical in cases where you don't want to implement the
comparison operators.

See
[https://news.ycombinator.com/item?id=6076608](https://news.ycombinator.com/item?id=6076608)

