Manipulating Ruby class default values - ruby

When there is more than one default value, how could I change only the second initialization variable without also calling the first?
For example, a Ruby class is created to return the value akin to the roll of a single die with default values for a six sided die ranging from 1 to 6:
class Die
def initialize(min=1, max=6)
#min = min
#max = max
end
def roll
rand(#min..#max)
end
end
If I wanted instead to use this code to simulate the return from rolling a 20 sided die, I could write the following:
p Die.new(min=1, max=20).roll
...but is there a way to argue only the second (max) value?
Of note - and this is where I am confused (I don't fully understand Ruby class attributes and variable scopes) - if I invoke:
p Die.new(max=20).roll
... I get nil printed. ?. (I understand that this is because rand(20..6) returns nil, but I thought that max= would retain the default min value for the first argument - instead max=20 gets ingested as the integer 20 binding to the min=... This seems weird to me.)
I suppose I could re-work the Die class to take a default value of the number of sides and also set the min (or max) value relative to the number of sides, but this is beside the point of my main question: How to override only the second default value without explicitly writing the first as well...
Presuming that most dice would normally have a minimum value of 1, I realize that I could reverse the order of min and max like so:
class Die2
def initialize(max=6, min=1)
#max = max
#min = min
end
def roll
rand(#min..#max)
end
end
...and then invoke whatever maximum number of sides like so:
p Die2.new(20).roll
...but given the syntax of class Die (and my inclination to write the minimum before the maximum) is there a way to only enter an argument for the second value? Or, perhaps I am approaching Ruby classes poorly? Any help or guidance is appreciated - thanks!

If you write
class Die
def initialize(min=1, max=6)
#min, #max = min, max
end
end
and create a new instance by passing a single argument, such as:
die = Die.new(3)
#=> #<Die:0x007fcc6902a700 #min=3, #max=6>
we can see from the return value that the argument 3 has been assigned to #min and #max gets its default value. In short, to pass a value to #max you must also pass one to #min (unless, of course, you reverse the order of the arguments).
You can do what you want by using named arguments (or named parameters), introduced in Ruby v2.0.
class Die
def initialize(min: 1, max: 6)
#min, #max = min, max
end
end
die = Die.new(max: 3)
#=> #<Die:0x007fcc698ccc00 #min=1, #max=3>
(or die = Die.new(:max=>3). As you see, #min equals its default value and #max equals the argument that is passed, 3.
Default values were required for keyword arguments in Ruby v2.0, but v2.1 extended their functionality to permit required named arguments as well. See, for example, this article.
Lastly, consider the following two cases (the second being the more interesting).
class Die
def initialize(min=1, max: 6)
#min, #max = min, max
end
end
die = Die.new(max: 3)
#=> #<Die:0x007fcc69954448 #min=1, #max=3>
class Die
def initialize(min, max: 6)
#min, #max = min, max
end
end
die = Die.new(max: 3)
#=> #<Die:0x007fa01b900930 #min={:max=>3}, #max=6>

In Ruby 2.0 and higher you can use keyword arguments to achieve the same effect:
class Die
def initialize(min: 1, max: 6) #<--declare arguments like this
#min = min
#max = max
end
def roll
rand(#min..#max)
end
end
p Die.new(max: 20).roll #<--and call like this
https://repl.it/Dyxn/0
you can read more about keyword arguments in this article

Related

Infinity is returned when calculating average in array

Why does the following method return infinity when trying to find the average volume of a stock:
class Statistics
def self.averageVolume(stocks)
values = Array.new
stocks.each do |stock|
values.push(stock.volume)
end
values.reduce(:+).to_f / values.size
end
end
class Stock
attr_reader :date, :open, :high, :low, :close, :adjusted_close, :volume
def initialize(date, open, high, low, close, adjusted_close, volume)
#date = date
#open = open
#high = high
#low = low
#close = close
#adjusted_close = adjusted_close
#volume = volume
end
def close
#close
end
def volume
#volume
end
end
CSV.foreach(fileName) do |stock|
entry = Stock.new(stock[0], stock[1], stock[2], stock[3], stock[4], stock[5], stock[6])
stocks.push(entry)
end
Here is how the method is called:
Statistics.averageVolume(stocks)
Output to console using a file that has 251 rows:
stock.rb:32: warning: Float 23624900242507002003... out of range
Infinity
Warning is called on the following line: values.reduce(:+).to_f / values.size
When writing average functions you'll want to pay close attention to the possibility of division by zero.
Here's a fixed and more Ruby-like implementation:
def self.average_volume(stocks)
# No data in means no data out, can't calculate.
return if (stocks.empty?)
# Pick out the `volume` value from each stock, then combine
# those with + using 0.0 as a default. This forces all of
# the subsequent values to be floating-point.
stocks.map(&:volume).reduce(0.0, &:+) / values.size
end
In Ruby it's strongly recommended to keep variable and method names in the x_y form, like average_volume here. Capitals have significant meaning and indicate constants like class, module and constant names.
You can test this method using a mock Stock:
require 'ostruct'
stocks = 10.times.map do |n|
OpenStruct.new(volume: n)
end
average_volume(stocks)
# => 4.5
average_volume([ ])
# => nil
If you're still getting infinity it's probably because you have a broken value somewhere in there for volume which is messing things up. You can try and filter those out:
stocks.map(&:value).reject(&:nan?)...
Where testing vs. nan? might be what you need to strip out junk data.

Ruby inject method

I'm doing some ruby exercises. In one of the solutions of my exercise, I found this code.
def make_change(amount)
{ H:50, Q:25, D:10, N:5, P:1 }.inject({}) do |res, (k,v)|
change, amount = amount.divmod(v)
res[k] = change unless change==0
res
end
end
This method takes an amount as parameter and associates coins to equal it. For example:
make_change(75)
#=> {H:1, Q:1}
(50 + 25 = 75)
But I don't understand where the change variable come from. How is the variable filled?
But i doesnt understand where does the "change" variable come from, how the variable is filled ?
change is defined and initialized in the first line of the block:
change, amount = amount.divmod(v)

Using Strings as Variable/Object Names in Ruby

I am dealing with fractals. You start with a rectangle, and that shape is decreased by a given decay rate. I have it set up to do the first 10 iterations of the given scenario, and each scenario looks like this:
y_1 = dec_y(y_1)
y_2 = dec_y(y_2)
a_y = [y_1, y_2]
rect_1 = TkcRectangle.new(canvas, [0,0], a_y)
where dec_y is defined as the following:
def dec_y(y)
to_ret = y / $rate
return to_ret
end
I want to turn the first snippet into a function/method (not exactly sure what the Ruby term is...), so that each iteration will just be a single line referencing a method, which makes the problem more extensible. But, I need each TkcRectangle to have a different name. The way I want to set it up, each TkcRectangle will have the same name. But, if I can set the name of the object to a string passed as an argument, then I should not have a problem.
How do I define the name of an object with a given string?
Edit : Code has not been tested, but will give you the idea.
Instead of naming each element, you can use an array and use the index instead
rectangles_array = Array.new
for each loop
rectangles_array << create_rectangle_object(y_1, y_2, canvas)
end for each loop
def dec_y(y)
to_ret = y / $rate
return to_ret
end
def create_rectangle_object(y_1, y_2, canvas)
return TkcRectangle.new(canvas, [0,0], [dec_y(y_1), dec_y(y_2)])
end
If you really want to name it read about structs.. Something like
MyRectangleStruct = Struct.new(:obj_name, :x1, :y1, :x2, :y2)
puts MyRectangleStruct.new(:obj_name => 'First_rec', .....)
define_method(method_name, &block)
with method_name being any string and &block being a block of ruby code; usually it looks something like this:
define_method(method_name) do
your code goes here
end

Some simple Ruby questions - iterators, blocks, and symbols

My background is in PHP and C#, but I'd really like to learn RoR. To that end, I've started reading the official documentation. I have some questions about some code examples.
The first is with iterators:
class Array
def inject(n)
each { |value| n = yield(n, value) }
n
end
def sum
inject(0) { |n, value| n + value }
end
def product
inject(1) { |n, value| n * value }
end
end
I understand that yield means "execute the associated block here." What's throwing me is the |value| n = part of the each. The other blocks make more sense to me as they seem to mimic C# style lambdas:
public int sum(int n, int value)
{
return Inject((n, value) => n + value);
}
But the first example is confusing to me.
The other is with symbols. When would I want to use them? And why can't I do something like:
class Example
attr_reader #member
# more code
end
In the inject or reduce method, n represents an accumulated value; this means the result of every iteration is accumulated in the n variable. This could be, as is in your example, the sum or product of the elements in the array.
yield returns the result of the block, which is stored in n and used in the next iterations. This is what makes the result "cumulative."
a = [ 1, 2, 3 ]
a.sum # inject(0) { |n, v| n + v }
# n == 0; n = 0 + 1
# n == 1; n = 1 + 2
# n == 3; n = 3 + 3
=> 6
Also, to compute the sum you could also have written a.reduce :+. This works for any binary operation. If your method is named symbol, writing a.reduce :symbol is the same as writing a.reduce { |n, v| n.symbol v }.
attr and company are actually methods. Under the hood, they dynamically define the methods for you. It uses the symbol you passed to work out the names of the instance variable and the methods. :member results in the #member instance variable and the member and member = methods.
The reason you can't write attr_reader #member is because #member isn't an object in itself, nor can it be converted to a symbol; it actually tells ruby to fetch the value of the instance variable #member of the self object, which, at class scope, is the class itself.
To illustrate:
class Example
#member = :member
attr_accessor #member
end
e = Example.new
e.member = :value
e.member
=> :value
Remember that accessing unset instance variables yields nil, and since the attr method family accepts only symbols, you get: TypeError: nil is not a symbol.
Regarding Symbol usage, you can sort of use them like strings. They make excellent hash keys because equal symbols always refer to the same object, unlike strings.
:a.object_id == :a.object_id
=> true
'a'.object_id == 'a'.object_id
=> false
They're also commonly used to refer to method names, and can actually be converted to Procs, which can be passed to methods. This is what allows us to write things like array.map &:to_s.
Check out this article for more interpretations of the symbol.
For the definition of inject, you're basically setting up chained blocks. Specifically, the variable n in {|value| n = yield(n, value)} is essentially an accumulator for the block passed to inject. So, for example, for the definition of product, inject(1) {|value| n * value}, let's assume you have an array my_array = [1, 2, 3, 4]. When you call my_array.product, you start by calling inject with n = 1. each yields to the block defined in inject, which in turns yields to the block passed to inject itself with n (1) and the first value in the array (1 as well, in this case). This block, {|n, value| n * value} returns 1 == 1 * 1, which is set it inject's n variable. Next, 2 is yielded from each, and the block defined in inject block yields as yield(1, 2), which returns 2 and assigns it to n. Next 3 is yielded from each, the block yields the values (2, 3) and returns 6, which is stored in n for the next value, and so forth. Essentially, tracking the overall value agnostic of the calculation being performed in the specialised routines (sum and product) allows for generalization. Without that, you'd have to declare e.g.
def sum
n = 0
each {|val| n += val}
end
def product
n = 1
each {|val| n *= val}
end
which is annoyingly repetitive.
For your second question, attr_reader and its family are themselves methods that are defining the appropriate accessor routines using define_method internally, in a process called metaprogramming; they are not language statements, but just plain old methods. These functions expect to passed a symbol (or, perhaps, a string) that gives the name of the accessors you're creating. You could, in theory, use instance variables such as #member here, though it would be the value to which #member points that would be passed in and used in define_method. For an example of how these are implemented, this page shows some examples of attr_* methods.
def inject(accumulator)
each { |value| accumulator = yield(accumulator, value) }
accumulator
end
This is just yielding the current value of accumulator and the array item to inject's block and then storing the result back into accumulator again.
class Example
attr_reader #member
end
attr_reader is just a method whose argument is the name of the accessor you want to setup. So, in a contrived way you could do
class Example
#ivar_name = 'foo'
attr_reader #ivar_name
end
to create an getter method called foo
Your confusion with the first example may be due to your reading |value| n as a single expression, but it isn't.
This reformatted version might be clearer to you:
def inject(n)
each do |value|
n = yield(n, value)
end
return n
end
value is an element in the array, and it is yielded with n to whatever block is passed to inject, the result of which is set to n. If that's not clear, read up on the each method, which takes a block and yields each item in the array to it. Then it should be clearer how the accumulation works.
attr_reader is less weird when you consider that it is a method for generating accessor methods. It's not an accessor in itself. It doesn't need to deal with the #member variable's value, just its name. :member is just the interned version of the string 'member', which is the name of the variable.
You can think of symbols as lighter weight strings, with the additional bonus that every equal label is the same object - :foo.object_id == :foo.object_id, whereas 'foo'.object_id != 'foo'.object_id, because each 'foo' is a new object. You can try that for yourself in irb. Think of them as labels, or primitive strings. They're surprisingly useful and come up a lot, e.g. for metaprogramming or as keys in hashes. As pointed out elsewhere, calling object.send :foo is the same as calling object.foo
It's probably worth reading some early chapters from the 'pickaxe' book to learn some more ruby, it will help you understand and appreciate the extra stuff rails adds.
First you need to understand where to use symbols and where its not..
Symbol is especially used to represent something. Ex: :name, :age like that. Here we are not going to perform any operations using this.
String are used only for data processing. Ex: 'a = name'. Here I gonna use this variable 'a' further for other string operations in ruby.
Moreover, symbol is more memory efficient than strings and it is immutable. That's why ruby developer's prefers symbols than string.
You can even use inject method to calculate sum as (1..5).to_a.inject(:+)

ruby and references. Working with fixnums

I know a bit about ruby way to handle objects and references. The replace stuff, ect ...
I know it d'ont work on fixnum, cause the var is the fixnum. But i wish to change the value of a fixnum inside a function, and that the value changed in the ouside var.
How can i do this ?
I guess i can use a string like this "1" but that's quite dirty.
Ruby will always pass-by-reference (because everything is an object) but Fixnum lacks any methods that allow you to mutate the value. See "void foo(int &x) -> Ruby? Passing integers by reference?" for more details.
You can either return a value that you then assign to your variable, like so:
a = 5
def do_something(value)
return 1 #this could be more complicated and depend on the value passed in
end
a = do_something(a)
or you could wrap your value in an object such as a Hash and have it updated that way.
a = {:value => 5}
def do_something(dict)
dict[:value] = 1
end
do_something(a) #now a[:value] is 1 outside the function
Hope this helps.
You could pass an array with a single number, like [1], or a hash like {value: 1}. Less ugly than a string, as your number itself remains a number, but less overhead than a new class...
When I was building a game I had the same problem you have. There was a numeric score that represented how many zombies you've killed and I needed to manually keep it in sync between Player (that incremented the score), ScoreBar and ScoreScreen (that displayed the score). The solution I've found was creating a separate class for the score that will wrap the value and mutate it:
class Score
def initialize(value = 0)
#value = value
end
def increment
#value += 1
end
def to_i
#value
end
def to_s
#value.to_s
end
end

Resources