Forum: Ruby Custom Exceptions

37ee5fa90f5eaeef62553629382497f7?d=identicon&s=25 Leslie Viljoen (leslieviljoen)
on 2010-04-06 16:45
(Received via mailing list)
Hi everyone

I want to make a custom exception like so:

class BillRowError < StandardError
    def initialize(field, index)
        @field = field
        @index = index
    end
end

I'll call this like so:
raise(BillRowError.new(:roamingcalls, @index), "Roaming Calls field
missing") if n.length == 0

But now I'd like to be able to modify the string that Ruby prints when
the
exception is not rescue'd. I thought I could add this method to the
BillRowError class:

    def message
        @message + " field: #{@field}, row: #{@index}"
    end

That almost works but I get a "instance variable @message not
initialized"
warning, which means Ruby is not setting @message in my object like I
expected. Making my own message= method doesn't help.

Can an exception object access and modify the message that gets passed
in
the "raise"?
1e5769440be526b44d90f0bb0665faac?d=identicon&s=25 Mario Antonetti (Guest)
on 2010-04-06 17:23
(Received via mailing list)
On Tue, Apr 6, 2010 at 9:44 AM, Leslie Viljoen
<leslieviljoen@gmail.com>wrote:

>
>    end
>
> That almost works but I get a "instance variable @message not initialized"
> warning, which means Ruby is not setting @message in my object like I
> expected. Making my own message= method doesn't help.
>
> Can an exception object access and modify the message that gets passed in
> the "raise"?
>

You could try rewriting the to_s method and take advantage of the
inheritance:

def to_s
  super + " field: #{@field}, row: #{@index}"
end

That worked for me.  I'm not sure if this is the recommended solution.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2010-04-06 17:24
Judging by the C source, Exception uses hidden(*) instance variables
"mesg" and "bt" for message and backtrace respectively. However, the
accessor #message internally calls #to_s, which you can override.

class BillRowError < StandardError
  def initialize(field, index)
    @field = field
    @index = index
  end

  alias :orig_to_s :to_s
  def to_s
    "#{orig_to_s} field: #{@field}, row: #{@index}"
  end
end

begin
  raise BillRowError.new(5, 7), "bar"
rescue BillRowError => e
  p e
  p e.instance_variables
  p e.message
  p e.backtrace
end

Produces:

#<BillRowError: bar field: 5, row: 7>
["@index", "@field"]
"bar field: 5, row: 7"
["ert.rb:14"]

Admittedly this behaviour doesn't seem to be well documented, so may be
fragile. Use at your own risk.

HTH,

Brian.

(*) It uses instance variables whose names don't begin with '@' and so
cannot be accessed by normal code
23172b6630dc631a134c9bad2fec2a39?d=identicon&s=25 Chris Hulan (Guest)
on 2010-04-06 17:26
(Received via mailing list)
On Apr 6, 10:44 am, Leslie Viljoen <leslievilj...@gmail.com> wrote:
>     end
>     def message
>         @message + " field: #{@field}, row: #{@index}"
>     end
>
> That almost works but I get a "instance variable @message not initialized"
> warning, which means Ruby is not setting @message in my object like I
> expected. Making my own message= method doesn't help.
>
> Can an exception object access and modify the message that gets passed in
> the "raise"?

The default Exception:initialize is defined to take 1 parameter, a
string containing the error message
You define different initialize parameters so @message is not getting
set as expected

Maybe something like:
class BillRowError < StandardError
    def initialize(msg, field, index)
        super(msg)
        @field = field
        @index = index
    end

    def message
        @message + " field: #{@field}, row: #{@index}"
    end

end
...
raise(BillRowError.new("Roaming Calls field missing",:roamingcalls,
@index), ) if n.length == 0

cheers
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2010-04-06 17:56
Chris Hulan wrote:
> The default Exception:initialize is defined to take 1 parameter, a
> string containing the error message

But 'raise' also lets you pass an error message, in addition to the
exception instance.

Note that even the default constructor doesn't create an instance
variable called @message.

class Foo < StandardError
end

begin
  raise Foo, "bar"
rescue Foo => e
  p e
  p e.instance_variables
  p e.instance_variable_get(:@message)
  p e.message
  p e.backtrace
end

#<Foo: bar>
[]              # << No instance variables!
nil             # << No @message!
"bar"
["ert.rb:5"]
23172b6630dc631a134c9bad2fec2a39?d=identicon&s=25 Chris Hulan (Guest)
on 2010-04-06 19:10
(Received via mailing list)
On Apr 6, 11:56 am, Brian Candler <b.cand...@pobox.com> wrote:
> class Foo < StandardError
> end
>
> #<Foo: bar>
> []              # << No instance variables!
> nil             # << No @message!
> "bar"
> ["ert.rb:5"]
> --
> Posted viahttp://www.ruby-forum.com/.

I should stop answering questions based on reading the docs at ruby-
docs.org, they are just not very clear...plus sloppy reading on my
part doesn't help ;)
So message is not an attribute so using @message is wrong.
It looks like overriding to_s, or maybe using super in the override of
message to get the parents input.

cheers
37ee5fa90f5eaeef62553629382497f7?d=identicon&s=25 Leslie Viljoen (leslieviljoen)
on 2010-04-06 23:53
(Received via mailing list)
On Tue, Apr 6, 2010 at 7:10 PM, Chris Hulan <chris.hulan@gmail.com>
wrote:

>
> I should stop answering questions based on reading the docs at ruby-
> docs.org, they are just not very clear...plus sloppy reading on my
> part doesn't help ;)
> So message is not an attribute so using @message is wrong.
> It looks like overriding to_s, or maybe using super in the override of
> message to get the parents input.
>
>
Yip, these surprising revelations were the reason for my post!
37ee5fa90f5eaeef62553629382497f7?d=identicon&s=25 Leslie Viljoen (leslieviljoen)
on 2010-04-06 23:58
(Received via mailing list)
On Tue, Apr 6, 2010 at 5:24 PM, Brian Candler <b.candler@pobox.com>
wrote:

>   alias :orig_to_s :to_s
>  p e.message
> Admittedly this behaviour doesn't seem to be well documented, so may be
> fragile. Use at your own risk.
>
>
Wow thanks for this, I didn't think of aliasing the old to_s. I find it
strange that exceptions don't just use a plain old @message instance
variable but I suppose there's some good reason for it.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.