Accidental NilClass in my instance variables [closed] - ruby

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I am making a dating simulator. One of the first things I need is to keep track of the way characters feel about each other. In this sim, anyone can date anyone else, and there are two variables for relationship (one for love and one for friendship).
So I thought the easiest way to do this would be for each character to have a separate class that kept track of how they felt about everyone else. Below is one such sample class. I also thought that the easiest way to keep track of where points should be added was by giving each character a hash that pointed to their own variable, and then using a swap function to trade targets with the person they are speaking to.
However, I am getting an error message.
class HRelatStatus
def initialize
{#target=> #hrelat}
#krelat =[10, 10]
#arelat =[9, 4]
#srelat =[13, 11]
#jrelat =[12, 1]
#brelat =[5, 5]
#hrelat=[0, 0]
end
def dataaccess
attr_accessor :target, :krelat, :arelat, :srelat, :jrelat, :brelat, :hrelat
end
def makehappy
#target[0] = #target[0]+1
end
end
hfeels=HRelatStatus.new
puts #krelat.class
puts #krelat[1]
hfeels.makehappy
puts #target[0]
When I try to run this, #krelat comes back as a Nil class. And when I try to run the makehappy method (or any method, really) I get the error message undefined method '[]' for nil class.
How do I stop my instance variables from being nil classes? How can I sucessfully make methods that will add to one variable in the array for a specific character? And does anyone have a better idea for how I can specify who to target?

You are saying:
hfeels=HRelatStatus.new
puts #krelat.class
But there is no such thing as #krelat in this context. What you are after is the krelat instance variable inside your instance, i.e. hfeels.krelat.
(Of course, that won't work either because you've hidden your accessor generators inside an instance method.)

The first thing you actually need to do is learn how Ruby (or really, variable scope in any language) works.
#krelat outside of the class is totally unrelated to #krelat inside the class.
The makehappy method won't work because { #target => #hrelat } doesn't do anything in Ruby (well, it creates a hash with a nil key pointing to a nil value and then discards that hash. Ie. effectively nothing.
This code is a total mess, learn Ruby first. Buy "Programming Ruby" and read it.

Related

Specify Ruby method namespace for readability

This is a bit of a weird question, but I'm not quite sure how to look it up. In our project, we already have an existing concept of a "shift". There's a section of code that reads:
foo.shift
In this scenario, it's easy to read this as trying to access the shift variable of object foo. But it could also be Array#shift. Is there a way to specify which class we expect the method to belong to? I've tried variations such as:
foo.send(Array.shift)
Array.shift(foo)
to make it more obvious which method was being called, but I can't get it to work. Is there a way to be more explicit about which class the method you're trying to call belongs to to help in code readability?
On a fundamental level you shouldn't be concerned about this sort of thing and you absolutely can't tell the Array shift method to operate on anything but an Array object. Many of the core Ruby classes are implemented in C and have optimizations that often depend on specific internals being present. There's safety measures in place to prevent you from trying to do something too crazy, like rebinding and applying methods of that sort arbitrarily.
Here's an example of two "shifty" objects to help illustrate a real-world situation and how that applies:
class CharacterArray < Array
def initialize(*args)
super(args.flat_map(&:chars))
end
def inspect
join('').inspect
end
end
class CharacterList < String
def shift
slice!(0, 1)
end
end
You can smash Array#shift on to the first and it will work by pure chance because you're dealing with an Array. It won't work with the second one because that's not an Array, it's missing significant methods that the shift method likely depends on.
In practice it doesn't matter what you're using, they're both the same:
list_a = CharacterArray.new("test")
list_a.shift
# => "t"
list_a.shift
# => "e"
list_a << "y"
# => "sty"
list_b = CharacterList.new("test")
list_b.shift
# => "t"
list_b.shift
# => "e"
list_b << "y"
# => "sty"
These both implement the same interfaces, they both produce the same results, and as far as you're concerned, as the caller, that's good enough. This is the foundation of Duck Typing which is the philosophy Ruby has deeply embraced.
If you try the rebind trick on the CharacterList you're going to end up in trouble, it won't work, yet that class delivers on all your expectations as far as interface goes.
Edit: As Sergio points out, you can't use the rebind technique, Ruby abruptly explodes:
Array.instance_method(:shift).bind(list_b).call
# => Error: bind argument must be an instance of Array (TypeError)
If readability is the goal then that has 35 more characters than list_b.shift which is usually going dramatically in the wrong direction.
After some discussion in the comments, one solution is:
Array.instance_method(:shift).bind(foo).call
Super ugly, but gets across the idea that I wanted which was to completely specify which instance method was actually being called. Alternatives would be to rename the variable to something like foo_array or to call it as foo.to_a.shift.
The reason this is difficult is that Ruby is not strongly-typed, and this question is all about trying to bring stronger typing to it. That's why the solution is gross! Thanks to everybody for their input!

Issue with my Ruby Assignment [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I am new to learn Ruby, I got an assignment from my teacher which I am trying to understand.
Here is the question. Consider the following code:
ary = Array.new(7, "--day")
ary[2] = "Tuesday"
ary[4] = "Thursday"
ary[7] = "Sunday"
ary[-1] = "Saturday"
puts ary[7]
puts ary[-4]
puts ary[-6, 2]
puts ary[2] = ary[7][-3,3]
puts ary.length
Why does this code produce 6 lines of output? Where did the extra line come from?
What is the value of ary[2] at the end?
Why is the length (or size) of the array different than when we constructed it?
I won't answer these questions directly, since it sounds like it's a homework assignment, but I will try to point you in the right direction.
Take a look at the documentation for Ruby's Array#[]. More specifically, take a look at which usages in your example code match the usages in the examples, and you might get a better idea of what's happening. Keep in mind that with Ruby, you can index from the end of your array by using negative index numbers.
Open up irb in the terminal and run the first 5 lines (all the ary[]= lines). Then run each of the puts lines individually and see what the output is. Keep in mind that lines with => something are the return values, not what is being printed.
Take a look at String#[], and try out the different parts of line 9 individually. For example, see what ary[7] does. Then see what ary[7][-3, 3] does. See what happens if you do "Any Random String"[a_number, another_number].
After you first create the array, check ary.length. Then run each of the following lines, checking ary.length after each subsequent assignment.
Don't get discouraged, and don't listen to people telling you to give up. This stuff can be confusing when you first start out, but getting familiar with where to find documentation, how to use the command line tools, and how to experiment will make it much easier to explore and discover what your code is doing, when, and why.
If you ever need to try and figure out what is going on in your code, just open up irb in your terminal and start playing around with it, and you should be able to answer most of your questions through experimentation.

What does colon infront of a variable mean? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
class Library
attr_accessor :games
def initialize(games)
#games = games
end
end
How comes there is a colon infront of games?
Whenever I research what the : means I usually find articles where people say its a symbol, then give a very ambiguous definition of what a symbol is.
To keep it simple: symbols are nothing more than a name for a constant. The value is irrelevant, but only symbols with the same name share the same value:
Symbol objects represent names [...] inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods.
See Ruby docs on Symbol for more details.
The usual use cases for symbols include:
keys for hashes (hsh[:foo] 0 42; hsh[:foo] #=> 42)
method or variable names, since those types of objects are not first-class citizens of Ruby (there is a Method class representing a method, but that's something different)
Please note, that symbols won't be garbage collected, unlike strings. That means, you should avoid code like
key = :"oh-my-#{bar}" # like string interpolation
when bar is build from user (attacker) generated input.
In the case of attr_accessor, the parameter (:games in your case), creates an instance variable with the same name (#games) plus a setter and getter method (let l = Library.new, then the setter l.games=(val) and the getter l.games become available).
Instances of Symbol class. However it's mentioned and explained in all tutorials or beginner guides I've seen so far.
The colon indicates the variable is a symbol. Symbols are Strings, with one important difference, Symbols are immutable. Mutable objects can be changed after assignment while immutable objects can only be overwritten.

Ruby - Best way to check args in a new call when overriding a class? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a class called Polynomialthat is overriding Array. I need to check that the array being passed to it on Polynomial.new([]) has at least 2 args.
I was thinking something like the following, but it's causing weird behavior in my tests.
class Polynomial < Array
def initialize(coefficients)
if coefficients.size < 2
puts "you need to have more than 1 arg"
else
self = coefficients
end
end
If you insist on keeping Polynomial an Array (I agree with #matt that this is probably a bad idea) then you still should call #super in your initialize, at least if all is well. Given you would like to be given an array as the argument list you might resort to a splat argument which will always turn out to be an array. But since you asked I will include the check in my example code:
class Polynomial < Array
def initialize(*coeffs)
if coeffs.is_a? Array
coefficients=coeffs.flatten
if (coefficients.size < 2)
puts "you need to have more than 1 arg"
else
super(coefficients)
end
else
puts "you need to give me an array"
end
end
end
This checks if your argument is an array (which it always will be because of the splat). Ruby methods tend to be generous about the "things" you can throw at them, so this methods calls #flatten on your args list in order to allow both versions:
p1=Polynomial.new([1,2])
=> [1, 2]
p2=Polynomial.new(1,2)
=> [1, 2]
It checks your condition of at least 2 elements, but you would probably like to add additional conditions such as all of your arguments should be numerical (as it is you can have any Object in your coeffs, but you probably only want Numeric, another reason not to subclass Array). You may add more conditions as you see fit.
This is how a method can know how many arguments it received when called:
def meth(*args)
puts args.length
end
So you might like to design Polynomial to receive a variable number of arguments in its initializer, instead of an array of arguments, and then use *args to set the contents of the array. (I am not convinced, by the way, that Polynomial should be an array; one rather expects it to have an array...)

where is the documentation for Array()? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Browsing the ruleby source code, I noticed that they were calling Container(:and), which is something I rarely see. In fact, the only other place I've seen it is in the fabrication gem
A quick look showed that Container subclasses Array, and a quick hop into Pry showed that Array(:anything) #=> [:anything].
Another quick look at the ruby documentation for Array doesn't shed much light on to this question.
What method is being called by Array(), where is it documented, how can one define a method like this, and is it considered "bad form" in ruby?
For your first question, the answer is that it makes an array of its parameters.
For your second, I have no clue, but it's simple enough.
For your third, here it is: In Ruby, defining a global method with the same name as the class is considered good form only when used to construct or convert from object of that type of a more fundamental type. You should not define this method unless you are creating some sort of low type. You could define this for some class like BigInt128 but you shouldn't for ObscureOrSpecializedType678. There is also a design for these methods.
If the data that you are passed is of the returned type, return it. If the data is of a directly related type, perform obvious conversions (Fixnum to BigInt128). If the data passed in can be converted and is somewhat related (String to Fixnum) convert it (this conversion is usually only for String). If the data can not be converted, throw an exception. You should NEVER return a "magic value".
The other use of this method is to create a semi-literal syntax for non-literal types. The best examples of this are Rational() and Complex(). These functions, in addition to doing conversions, allow you to create rations and complex numbers in a more natural way (Rational(1, 2) vs. Rational.new(1, 2)). If there is a certain argument list that is simpler to the literal representation of a type, you would define a Classname() method.
For the most part, these methods are only part of the core language, and unless you are making a class like BigInt128 or FancyString or NaturalNumber, you should not define these methods.
From what I know the defined of these are:
Array(*args) -- Returns arguments as an array
Complex(real, complex) -- Create a complex number with given real and complex parts
Float(arg) -- Returns arg converted to a float (takes things like strings too)
Integer(arg) -- Same as Float(), but converts to an integer(floats are truncated)
Rational(numerator, denominator=1) -- Creates a Rational number with the given parts
String(arg) -- Converts argument to string by calling to_s
Also, some classes define [] as a class method, which is used for more complex initialization from basic data types (usual initialization only, not conversion) such as Hash[].
I don't know if it is really it, but made some tests with iurb and I guess it is only a helper funcion to create a new Array.
Given I have this class
class MyClass
def initialize(arg)
puts "Initialized with #{arg.to_s}"
end
end
then I can define a helper function like
def MyClass(arg)
MyClass.new(arg)
end
and here you go
irb(main):009:0> MyClass(1)
Initialized with 1
=> #<MyClass:0x4770e10>
uhhhh, since you're in Pry why not ask Pry to show you the documentation?!?!
[25] (pry) main: 0> show-doc Array
From: object.c in Ruby Core (C Method):
Number of lines: 4
Owner: Kernel
Visibility: private
Signature: Array(arg1)
Returns arg as an Array. First tries to call
arg.to_ary, then arg.to_a.
Array(1..5) #=> [1, 2, 3, 4, 5]
[26] (pry) main: 0> show-method Array
From: object.c in Ruby Core (C Method):
Number of lines: 5
Owner: Kernel
Visibility: private
static VALUE
rb_f_array(VALUE obj, VALUE arg)
{
return rb_Array(arg);
}
[27] (pry) main: 0>

Resources