简体   繁体   中英

Undefined Method “+” for Numeric Class in Ruby

This is using tuple-space via Rinda and I have a bunch of "puts" in here to see each step happen in the console but I don't think that's very important. What IS important is when I run this section of code:

 while(true)

    ts.take(["empty"])

    tag, rear = ts.read( ["rear", Numeric])
    puts "11"

    value = 7
    puts "12"

    ts.write(["buf", rear, value])
    puts "13"

    puts "have some words"
    puts "14"

    tag, rear = ts.take( ["rear", Numeric])
    puts "15"

    (rear += 1) % n = rear

    puts "16"

    ts.write(["rear", Numeric])
    puts "17"

    ts.write(["full"])
    puts "18"

    end

I get the error:

"undefined method `+' for Numeric:Class (NoMethodError)"

Why? How do I fix this?

1st problem

(rear += 1) % n = rear

is a funny way of writing :

(rear = rear + 1) % (n = rear)

Which means :

  • increment rear by 1
  • set n to rear
  • return rear % rear , which is 0

You want :

rear = (rear + 1) % n

2nd problem

rear is defined as Numeric , the class , not as a Numeric (0, 1 or 3.1415...).

Where does it come from? There's an infinite loop, so the culprit could be after the line in which you get the error.

Between 16 and 17 , you use :

ts.write(["rear", Numeric])

and that's your problem. It should be :

ts.write(["rear", 3.14]) # or
ts.write(["rear", rear])

3 scripts to make it work

01_server.rb

require 'rinda/tuplespace'

URI = "druby://localhost:61676"
DRb.start_service(URI, Rinda::TupleSpace.new)
DRb.thread.join

02_your_script.rb

require 'rinda/rinda'

URI = "druby://localhost:61676"
DRb.start_service
ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, URI))

#######################################
# This needs to happen before your loop
ts.write(["rear", 0])
ts.write(["empty"])
n = 80
#######################################

loop do
  ts.take(["empty"])

  tag, rear = ts.read( ["rear", Numeric])
  puts "11"

  value = 7
  puts "12"

  ts.write(["buf", rear, value])
  puts "13"

  puts "have some words"
  puts "14"

  tag, rear = ts.take( ["rear", Numeric])
  puts "15"

  rear = (rear + 1) % n

  p "Rear is now : #{rear}"

  puts "16"

  # ts.write(["rear", Numeric]) # <- This was wrong. You don't want to write Numeric, the class.
  ts.write(["rear", rear])      # You want to write a Numeric, e.g. rear

  ts.write(["full"])
end

03_switch.rb

require 'rinda/rinda'

URI = "druby://localhost:61676"
DRb.start_service
ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, URI))

loop do
  ts.take(["full"])
  ts.write(["empty"])
end

Test

  • Lauch ruby 01_server.rb in a terminal
  • Launch ruby 02_your_script.rb in another terminal

It outputs :

11
12
13
have some words
14
15
"Rear is now : 1"
16

The loop stops, waiting for "empty" .

  • Launch 03_switch.rb in yet another terminal, and the loop repeats infinitely.

When you create a number, you create an instance of the Numeric class (or a class that inherits from Numeric ). The + method applies to instances of the Numeric class - it is an instance method. You are calling it on the class itself.

Numeric is an unusual class in that it doesn't use new to initialize new instances of the class. Instead numbers are created directly (you don't do n = Numeric.new(3) - you just n = 3 ). But the relationship between the class and the instance is the same in that the Class' class methods apply to the Class, and the instance methods (including + ) apply to the instances.

Ruby classes can be thought of as builders or factories for instances of that class. You have in effect called + on the thing that creates numbers rather than on a number

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM