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
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
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
never mind re-read some more and figured it out.
On 6/5/06, Paul D. Kraus [email protected] 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.