#1
  1. No Profile Picture
    Permanently Banned
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2013
    Posts
    2
    Rep Power
    0

    Beginner Ruby question


    I'm trying to learn ruby more in depth before I move on to rails dev, but I'm having some issues learning classes. I can't seem to understand why the following doesn't work.

    #point.rb
    class Point
    attr_accessor :x, :y

    def initialize(p = [0,0])
    @x = p[0]
    @y = p[1]
    end
    end

    #shape.rb
    require_relative 'point.rb'

    class Shape

    attr_accessor oints

    def initialize *the_points
    for p in the_points
    @points.append Point.new(p)
    end
    end

    end

    s = Shape.new([3,2])

    puts s.points

    When I call the function I get a no method error for NilClass, which I'm assuming is referring to @point.append.
  2. #2
  3. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Hi,

    next time, please create your own thread. This one is from last year and has absolutely nothing to do with your question. Also, please, please use [ CODE ] tags. It's really annoying to go through completely unformatted code with random smilies in it.

    As to the error messages:

    You haven't defined @points anywhere, which means it's nil. And nil doesn't have an append method. In fact, no Ruby core class has such a method.

    I guess you wanted to do something like this:

    ruby Code:
     
    class Point
      attr_accessor :x, :y
     
      def initialize(p = [0,0])
        @x = p[0]
        @y = p[1]
      end
    end
     
    class Shape
      attr_accessor <img src="http://images.devshed.com/fds/smilies/tongue.gif" border="0" alt="" title="Stick Out Tongue" class="inlineimg" />oints
     
      def initialize *the_points
        # initialize variable with an empty array
        @points = []
        for p in the_points
          @points << Point.new(p)
        end
      end
    end
     
    s = Shape.new([3,2])
     
    p s.points


    Note that this code still has several weaknesses and isn't really Ruby-like:
    • Don't use for ... in. It's ugly, inflexible and leaks the temporary variables created during the loop. I guess you're coming from a different language and though that's the Ruby equivalent of the standard for loop or something. But it's really not. Ruby uses each iterators to loop through collections.
    • Avoid low-level loops altogether. This is not Java or C#, where you have to go through an array, pick the elements one by one and move them to a new array. Ruby is more intelligent than that. In your case, you can simply use Array#map to create an array of Points.


    ruby Code:
    class Point
      attr_accessor :x, :y
     
      def initialize p = [0, 0]
        @x, @y = *p
      end
    end
     
    class Shape
      attr_accessor <img src="http://images.devshed.com/fds/smilies/tongue.gif" border="0" alt="" title="Stick Out Tongue" class="inlineimg" />oints
     
      def initialize *points
        # map the array of coordinates to an array of Points
        @points = points.map {|coords| Point.new coords}
      end
    end
     
    s = Shape.new [3, 2]
     
    p s.points


    In this particular case, you may find that nitpicking. But when it comes to actual projects, it does make a difference whether you have 5,000 lines of high-level code or 15,000 lines of low-level loops and whatnot.

    Comments on this post

    • sepp2k1 agrees
    Last edited by Jacques1; April 13th, 2013 at 09:42 AM.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2012
    Posts
    83
    Rep Power
    39
    If you don't set an instance variable to a value, its value will be nil. You can't do anything useful with nil, so generally you want to set a variable to a value before you start calling methods on it. You seem to want @points to be an array, so you should set it to be an array before you start calling array methods on it.

    That said, there actually is no append method in Ruby. To add an item to the end of an array, use push or <<.

    So a working version of your code would be:

    Code:
    @points = [] # Make @points an empty array
    for p in the_points
      @points.push Point.new(p)
      # Alternatively:
      # @points << Point.new(p)
    end
    That's not very idiomatic Ruby though.

    (If you haven't learned about blocks yet, you may want to stop reading here and make a mental note to learn about blocks soon.)

    When you want one array to contain the results of performing a given action on each element of another array, you can use the map method for this instead of a for loop. The map method is called on an array and takes a block, which it will then invoke once for every element in the array. It returns a new array containing the results of those calls. So the for loop can be replaced with map like this:

    Code:
    @points = the_points.map do |p|
      Point.new(p)
    end

    Comments on this post

    • Jacques1 agrees : Great minds think alike. :-D
  6. #4
  7. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,643
    Rep Power
    4248
    Thread split into a new thread. While some of the replies have been top notch, bullsforex is about to earn himself a permanent ban very soon, as a number of his posts are just cut/paste from stackoverflow and other sites on the web.
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  8. #5
  9. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    With all the spam and crossposts, looks like you gotta check every question before replying to it.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".

IMN logo majestic logo threadwatch logo seochat tools logo