6fe6808d7705a77f61e77f24dcebde14

Is there a better way to do this?

I wish I could do something along the line of:
@x, @y = input.scan(/([0-9]).*([0-9])/)

class Position

  attr_accessor :x, :y

  #example of inputs: "12", "0 2", "1,1"
  def parse input
    coords = input.scan(/[0-9]/)    
    raise StandardError, "Invalid input! Please enter 2 coordinates. Example: 1 0" if coords.size != 2
    @x = coords[0].to_i
    @y = coords[1].to_i
  end
end

Refactorings

No refactoring yet !

A8d3f35baafdaea851914b17dae9e1fc

Adam

January 15, 2009, January 15, 2009 22:03, permalink

2 ratings. Login to rate!
class Position
  attr_reader :x, :y
  
  def self.parse(digits)
    new(*digits.scan(/(\d).*(\d)/).first)
  end
  
  def initialize(x, y)
    @x, @y = x.to_i, y.to_i
  end
  
  def inspect
    "<Position x:#{x}, y:#{y}>"
  end
end
6fe6808d7705a77f61e77f24dcebde14

Martin Carel

January 15, 2009, January 15, 2009 23:29, permalink

No rating. Login to rate!

I much prefer that. The regex reflects the intention. Plus, the whole thing is definitely more OO.
If I want to keep the error handling (e.g. if user enters "abc"), I'd suggest:

def self.parse(digits)
  new(*digits.scan(/(\d).*(\d)/).flatten)
rescue 
  raise StandardError, "invalid input! Please enter 2 coordinates. Example: 2 0" 
end
F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 23, 2009, January 23, 2009 20:39, permalink

1 rating. Login to rate!

My useless 2 cents. I like to have at least one base exception per class so developers can rescue it as needed (if at all)

class Position

  class Error < StandardError; end
  class ParseError < Error; end
  
  attr_reader :x, :y
  
  def self.parse digits
    new *digits.scan(/(\d).*(\d)/).first
  rescue
    raise ParseError, "Please pass a string containing 2 coordinates. Example: '2 0'", caller
  end
  
  def initialize x, y
    @x, @y = x.to_i, y.to_i
  end
  
  def inspect
    "<Position:#{__id__} x:#{x}, y:#{y}>"
  end
end
F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 23, 2009, January 23, 2009 20:54, permalink

No rating. Login to rate!

Also I should mention (although in this case it does not matter at all really) but generally something [^\d]* would be faster than .*

6fe6808d7705a77f61e77f24dcebde14

Martin Carel

January 23, 2009, January 23, 2009 21:07, permalink

No rating. Login to rate!

@ Tj Holowaychuk: it was not useless. I put StandardError for simplicity sake. See for yourself: http://tinyurl.com/cdq2dm :)

But I will improve with:
- defining my custom Error class inside Position class
- change the error message (like you subtlety did) to be more friendly

F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 23, 2009, January 23, 2009 21:31, permalink

No rating. Login to rate!

Sounds good. I like to have all other exception classes inherit from Error so it can be generically rescued like below but totally up to you. I find passing the callstack (caller) to raise helps a lot too as far as usability goes, it can be annoying when something blows up and its referencing far lower in the stack

... blah blah 
rescue Position::ParseError
  # Do something
rescue Position:Error
  # All other errors raised from Position
...
6fe6808d7705a77f61e77f24dcebde14

Martin Carel

January 23, 2009, January 23, 2009 21:58, permalink

No rating. Login to rate!

I like that!
Thanks for the trick.

Your refactoring





Format Copy from initial code

or Cancel