Forum: Ruby can't figure out what's wrong

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E9a362fbd63ad45bb08716d19a8a20da?d=identicon&s=25 Erik Blas (dust)
on 2005-12-27 07:46
I'm reading the why's ruby guide, and i've retyped a class in the guide
to use through the metaprogramming chapter. when i try to use it with
irb i get this error:
nomethoderror: undefined method '[]=] for nil:class
 from path/dwemthy.rb:18:in 'life'
 from path/dwemthy.rb:16:in 'life'
 from path/rabbit.rb:4

here's the code for dwemthy.rb:
class Creature

	# get a metaclass for this class
	def self.metaclass; class << self; self; end; end

	# advanced metaprogramming cord for clean traits
	def self.traits( *arr )
		return @traits if arr.empty?

		# 1. setup accessors for each variable
		attr_accessor *arr

		# 2. add a new class method to each trait
		arr.each do |a|
			metaclass.instance_eval do
				define_method( a ) do |val|
					@triats ||= {}
					@traits[a] = val
				end
			end
		end

		# 3. for each monster, the 'initialize' method should use
		#     the default number for each trait
		class_eval do
			define_method( :initialize ) do
				self.class.traits.each do |k,v|
					instance_varable_set("@#{k}", v)
				end
			end
		end

	end

	# creature attributes are read only
	traits :life, :strength, :charisma, :weapon

	# this method applies a hit taken during a fight
	def hit( damage )
		p_up = rand( charisma )
		if p_up % 9 == 7
			@life += p_up / 4
			puts "[#{ self.class } magick powers up #{ p_up }!]"
		end

		# this method takes one turn in a fight
		def fight( enemy, weapon )
			if life <= 0
				puts "[#{ self.class } is too dead to fight!]"
				return
			end

			# attack opponent
			your_hit = rand( strength + weapon )
			puts "[You hit with #{ your_hit } points of damage!]"
			enemy.hit( your_hit )

			# retaliation
			p enemy
			if enemy.life > 0
				enemy_hit = rand( eneme.strenght + enemy.weapon )
				puts "[Your enemy hit with #{ enemy_hit } points \
				of damage!] "
				self.hit( enemy_hit )
			end
		end

	end
end

class DwemthysArray < Array
	alias _inspect inspect
	def inspect; "#<#{ self.class }#{ _inspect }>"; end
	def method_missing( meth, *args )
		answer = first.send( meth, *args )
		if first.life <= 0
			shift
			if empty?
				puts "[Whoa. You decimated Dwemty's Array!]"
			else
				puts "[Get ready. #{ first.class } has emerged.]"
			end
		end
		answer || 0
	end
end
E9a362fbd63ad45bb08716d19a8a20da?d=identicon&s=25 Erik Blas (dust)
on 2005-12-27 07:47
here is the code for rabbit.rb:
class Rabbit < Creature
	traits :bobs

	life 10
	strength 2
	charisma 44
	weapon 4
	bombs 3

	# little boomerang
	def ^( enemy )
		fight( enemy, 13 )
	end

	# the hero's sword is unlimited
	def /( enemy )
		fight( enemy, rand( 4+ ( ( enemy.life % 10 ) ** 2 ) ) )
	end

	# lettuce will build your strength and extra ruffage
	# will fly in the face of your opponent
	def %( enemy )
		lettuce = rand( chairsma )
		puts "[Healthy lettuce gives you#( lettuce ) life points!!]"
		@life += lettuce
		fight( enemy, 0 )
	end

	# bombs, but you have only threee
	def *( enemy )
		if @bombs.zero?
			puts '[Out of bombs!]'
			return
		end
		@bombs -= 1
		fight( enemy, 86 )
	end
end
93d566cc26b230c553c197c4cd8ac6e4?d=identicon&s=25 Pit Capitain (Guest)
on 2005-12-27 09:28
(Received via mailing list)
Erik, there are some typos in your code. See below.

erik blas schrieb:
> I'm reading the why's ruby guide, and i've retyped a class in the guide
> to use through the metaprogramming chapter. when i try to use it with
> irb i get this error:
> nomethoderror: undefined method '[]=] for nil:class
>  from path/dwemthy.rb:18:in 'life'

This means that in line 18, you tried to call method "[]=" on nil. Nil
doesn't have such a method, so the NoMethodError is raised.

> 	def self.traits( *arr )
> 					@traits[a] = val
This is line 18. It looks like an assignment, but it really is a method
call. It calls method "[]=" on the object @traits with arguments a and
val. The error message above means that @traits is nil. If you look at
the previous line (line 17), you notice the typo.

> 				end
> 			end
> 		end
>
> 		# 3. for each monster, the 'initialize' method should use
> 		#     the default number for each trait
> 		class_eval do
> 			define_method( :initialize ) do
> 				self.class.traits.each do |k,v|
> 					instance_varable_set("@#{k}", v)

This should be "instance_variable_set". Note the missing "i".

> 				end
> 			end
> 		end
> 	end

I haven't looked further. HTH.

Regards,
Pit
E9a362fbd63ad45bb08716d19a8a20da?d=identicon&s=25 Erik Blas (dust)
on 2005-12-27 10:52
Thank you for the help. Guess I'm just tired and didn't notice all the
typos. Was driving me up the wall.
A4327ebc799afb6896c5b224d76f9b9e?d=identicon&s=25 Ron Jeffries (Guest)
on 2005-12-28 03:59
(Received via mailing list)
On Tue, 27 Dec 2005 18:52:23 +0900, erik blas <ether.sa@gmail.com>
wrote:

>Thank you for the help. Guess I'm just tired and didn't notice all the
>typos. Was driving me up the wall.

When typing in a program that has been provided, typos in Ruby can be
irritating, as you've seen.

When building my own programs, I try to go in smaller bites in Ruby than
I might
in C# or Java, because syntax errors and typos are often hard to find.
This topic is locked and can not be replied to.