Object Troubles - undefined method `+'


#1

I am parsing a text file that is 3 fields per line deliminted by pipes
‘|’
Each line contains a customer code, shipmethod, and customer name.
Each line represents an invoice that was cut.

I need to count all invoices and then count all invoices that went out
next
day air saver.
From working with the pick axe it seems to me that you have a class with
two
attributes invoice, and nda invoice.
You then store your objects in a hash for easy lookup.

When i run the below program I get this error…
./parse.rb:14:in incndainvoice': undefined method+’ for nil:NilClass
(NoMethodError)
from ./parse.rb:31
from ./parse.rb:20

TIA,
Paul

Here is my class and program …

#!/usr/bin/env ruby

class Customer
attr_reader :invoices, :ndainvoices
attr_writer :invoices, :ndainvoices
def initialize
@invoices = 1
@ndainvoices = 0
end
def increment_invoice
invoices = invoices + 1
end
def increment_ndainvoice
ndainvoice = ndainvoice + 1
end
end

customers = Hash.new

open(‘NdaInvoiceCount.txt’,‘r’).each_line do |line|
(customer_code, ship_method, customer_name) =
line.chomp.split(’|’)
if customers[ customer_code ]
customers[ customer_code ].increment_invoice
else
customers[ customer_code ] = Customer.new
end
customers[ customer_code ].increment_ndainvoice if ship_method

‘SAVGRD’
end

here is some sample data…
0000016324|SAVGRD|Dupage Prosthetics
0000038955|SAVGRD|TRUDELL ORTH & PROS SERVICES
0000019155|UPS |Scott Orthotic Labs
0000061674|UPS |COMPREHENSIVE BRACE & LIMB CTR LLC
0000008593|U02G |Huron Valley Assoc
0000039954|SAVGRD|Island Coast Orthopedics
0000028719|UPS |Paul Richelson’s Feet First
0000003455|FEDGND|CLARK ORTH
0000019297|UPS |J. Slawner LTD.
0000061508|UPS |LEVY & RAPPEL


#2

class Customer
attr_reader :invoices, :ndainvoices
attr_writer :invoices, :ndainvoices
def initialize
@invoices = 1
@ndainvoices = 0

Here you initialize 2 instance variables, @invoices and @ndainvoices

end

def increment_invoice
invoices = invoices + 1

The local variable ‘invoices’ does exist yet, so ‘nil + 1’ raises the
error.
You probably intended:

@invoices = @invoices + 1

end

def increment_ndainvoice
ndainvoice = ndainvoice + 1

same here

end


#3

On Jun 5, 2006, at 10:00 PM, Paul D. Kraus wrote:

def increment_ndainvoice
ndainvoice = ndainvoice + 1
end

You are trying to set local variables. Instance variables are
prefixed with @. If you were trying to call your attr_writer method,
you need to prefix it with self:

self.invoices += 1

Here is a more idiomatic way of writing what you would like:

class Customer
attr_accessor :invoices, :ndainvoices
def initialize
@invoices = 0
@ndainvoices = 0
end
end

customers = Hash.new { |h, k| h[k] = Customer.new }
IO.foreach(‘NdaInvoiceCount.txt’) do |line|
(customer_code, ship_method, customer_name) = line.chomp.split(’|’)
customers[customer_code].invoices += 1
customers[ customer_code ].ndainvoices += 1 if ship_method ==
‘SAVGRD’
end

– Daniel


#4

never mind re-read some more and figured it out.


#5

On 6/5/06, Paul D. Kraus removed_email_address@domain.invalid wrote:

./parse.rb:14:in incndainvoice': undefined method+’ for nil:NilClass
(NoMethodError)
from ./parse.rb:31
from ./parse.rb:20

    invoices = invoices + 1
end
def increment_ndainvoice
    ndainvoice = ndainvoice + 1 # this is line 14
end

end

You’re problem here is that on line 14, you are actually using a local
variable. This is a little tricky, since it’s actually your assignment
that is changing the context of the right hand side. What happens is
that the parser sees “ndainvoice =” and assumes you’re creating a new
local variable called “ndainvoice”; this new local variable then masks
the “ndainvoice” method. Since it’s value is nil (the default value of
an unassigned-to variable), the effect of the line is:

ndainvoice = nil + 1 # ndainvoice is a local variable here

In order to get ruby to recognize the assignment as a method call,
rather than an assignment to a new local variable, you need to prefix
“self.”:

self.ndainvoice = ndainvoice + 1

The reference to ndainvoice on the right hand side is correctly
interpreted as a method call since there is no local variable of the
same name to mask it. Alternatively, you can use the instance variable
directly by prefixing an “@” (as you do in initialize):

@ndainvoice = @ndainvoice + 1

As a final step, you can also use += to shorten the “a = a + b” pattern:

self.ndainvoice += 1

or

@ndainvoice += 1

Incidentally, you have the same problem on line 11.

Jacob F.