I am learning ruby and I am specifically playing with OOPS in it. I am trying to write equivalent of this PHP code in ruby
class Abc {
$a = 1;
$b = 4;
$c = 0;
function __constructor($cc) {
$this->c = $cc
}
function setA($v) {
$this->a = $v
}
function getSum() {
return ($this->a + $this->b + $this->c);
}
}
$m = new Abc(7);
$m->getSum(); // 12
$m->setA(10);
$m->getSum(); // 21
I am trying to write equivalent of above PHP to ruby.
Please note my goal is to have default values of soem of the class variable and if I want to override it, then I can do it by calling getter/setter method.
class Abc
attr_accessor :a
def initialize cc
#c = cc
end
def getSum
#???
end
end
I don't like to do
Abc.new(..and pass value of a, b and c)
My goal is to have default values, but they can be modified by instance, if required.
class Abc
attr_accessor :a, :b, :c
def initialize a = 1, b = 4, c = 0
#a = a
#b = b
#c = c
end
end
This will accept 1, 4, and 0 respectively as default values, but they can be overridden by passing in parameters.
So if you do example = Abc.new without paramaters it will have default values of 1,4,0 but you could do:
example2 = Abc.new 5, 5
without passing a value for c and you'd have values of a = 5 and b = 5 with by default c = 0 still.
More broadly, in your Ruby code examples above, you are using brackets where not needed. a def method_name begins a block, and a end will finish it. They serve in place of how brackets are traditionally used in other languages. So for your method getSum you can simply do
def get_sum
#your_code
end
Also, note def getSum (camelCase) would typically be def get_sum (snake_case) in Ruby. Also note in the examples I give above that parenthesis are dropped. They are not needed in Ruby.
Related
I'm new to programming, especially in Ruby so I've been making some basic projects. I have this code and as far as I know, it should work, but it gives results that I don't expect
The program takes a and B and returns a^b. I did this as a programming exercise, hence why I didn't just go a**b.
class Exponate
attr_accessor :args
def initialize args = {}
#args = args
#ans = nil
end
def index
#args[:b].times {
#ans = #args[:a] * #args[:a]
}
puts #ans
end
end
e = Exponate.new(:a => 32, :b => 6)
e.index
e.args[:a] = 5
e.index
Returns
1024 # Should be 1_073_741_824
25 # Should be 15_625
But they are definitely not that
You can write like this:
class Exponate
attr_accessor :args, :ans
def initialize args = {}
#args = args
end
def index
#ans = 1 # multiplication will start from 1
#args[:b].times {
#ans *= #args[:a] #same as #ans = #ans * #args[:a]
}
puts #ans
end
end
#ans = #args[:a] * #args[:a] will return the same value, no matter how many times called, you need to reference the accumulator variable in some way to make use of the cycle.
Using an instance variable for a local does not seem right - their lifetime is longer, so after method exits they cannot not be collected if the whole object is still referenced somewhere. Also the #s are more error-prone - if you make a typo (for example - #asn instead of #ans), you'll get nil instead of NameError, it may be harder to debug, so better to write this way:
def index
ans = 1
args[:b].times {
ans *= args[:a]
}
puts ans
end
For loops with an accumulator in ruby it's better to use Enumerable#inject:
#ans = #args[:b].times.inject(1){|acc,v| acc * #args[:a]}
this way it's less likely to forget initialisation.
In PHP, I can do this:
$a = 1;
$c = 'a';
$$c = 2;
//now $a == 2
Is there any equivalent in ruby? By which I mean, any simple way to have it dereference a variable during execution like this? I'd rather not use eval, because it looks messy - I've already determined that eval can't be called as a method of a string.
It is possible but it's a bit more complicated., and you actually have two possibilities:
Kernel#local_variables
Returns the names of the current local variables.
fred = 1
for i in 1..10
# ...
end
local_variables #=> [:fred, :i]
Binding#local_variable_get/set
Returns a value of local variable symbol.
def foo
a = 1
binding.local_variable_get(:a) #=> 1
binding.local_variable_get(:b) #=> NameError
end
This method is short version of the following code.
binding.eval("#{symbol}")
if you just need this you can do
a = 1
c = 'a'
eval("#{c} = 2")
a == 2 # => true
... but this is moron way to do this
if you need this for instance variables
class Foo
attr_reader :a
def initialize
#a = 1
end
end
foo = Foo.new
foo.instance_variable_get(:a) #=> 1
foo.a #=> 1
foo.instance_variable_set(:"#a", 2)
foo.a #=> 2
...you can also eval instance like this:
# ...
foo.instance_eval do
#a = 'b'
end
foo.a # => 'b'
class A
attr_accessor :rank
def change_rank
rank = rank + 1
end
end
a = A.new
a.rank = 5
p a.rank
a.change_rank
p a.rank
produces an error for rank = rank + 1 (undefined method + for nil:Nilclass). Shouldn't an implicit call to the "rank" method return the value of the instance variable #rank? For some reason, this code works if I change the 4th line to:
self.rank = self.rank + 1
Why does an explicit call to the rank method works while an implicit one doesn't?
def change_rank
rank = rank + 1
end
In this context name rank does not resolve to one of methods generated by attr_accessor. It is seen by ruby roughly as this:
def change_rank
rank = nil
rank = rank + 1
end
When ruby sees an assignment to a "naked" name, it creates a local variable with this name. It will shadow the outer method. And since local vars are initialized with nil, it explains the error you're getting.
You can do this to avoid the error (be explicit about what you're modifying):
def change_rank
self.rank += 1
end
Update:
Here's more code that illustrates this
defined?(x) # => nil # name x is unidentified yet
defined?(x = x) # => "assignment" # local var x is created by assignment
defined?(x) # => "local-variable" # now local var x exists
x # => nil # and its value is nil
I rewrite your code as following. You can see how Ruby treats rank= and rank with different ways.
class A
attr_accessor :rank
def change_rank
self.rank = rank + 1
end
end
a = A.new
a.rank = 5
p a.rank
a.change_rank
p a.rank
execution result:
5
6
In Ruby, I would like to select a default object for a block.
An example in Actionscript is:
with (board) {
length = 66;
width = 19;
fin_system = 'lockbox';
}
Which is equivalent to:
board.length = 66;
board.width = 19;
board.fin_system = 'lockbox';
Here is the documentation for this statement in Actionscript:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/statements.html#with
How can I accomplish this in Ruby?
Hash.new.tap do |h|
h[:name] = "Mike"
h[:language] = "Ruby"
end
#=> {:name=>"Mike", :language=>"Ruby"}
You could try Object#tap with Ruby 1.9.
So in your case:
board.tap do |b|
b.length = 66;
b.width = 19;
b.fin_system = "lockbox"
end
One way to implement it is with instance_eval, like that:
def with(obj, &blk)
obj.instance_eval(&blk)
end
a = "abc"
with a do
self << 'b'
gsub!('b', 'd')
upcase!
end
puts a #=> ADCD
with board do
self.length = 66
self.width = 19
self.fin_system = 'lockbox'
end
But in some cases you have to use self (with operators and setting methods).
You can't accomplish that exactly in Ruby because foo = bar will always set a foo local variable; it will never call a foo= method. You can use tap as suggested.
One solution to the larger design question would be to use a fluent interface:
board.length(66).width(20)
class Board
def length(amt)
#length = amt
self
end
def width(amt)
#width = amt
self
end
end
It's up to you to decide if this pattern suits your use case.
how can a write a class in ruby that has a procedures that i can call like this:
a = MyObj.new()
b = MyObj.new()
c = a * b
d = a / b
e = a - b
this is nicer than:
c = a.multiply(b)
...
thanks
class Foo
attr_accessor :value
def initialize( v )
self.value = v
end
def *(other)
self.class.new(value*other.value)
end
end
a = Foo.new(6)
#=> #<Foo:0x29c9920 #value=6>
b = Foo.new(7)
#=> #<Foo:0x29c9900 #value=7>
c = a*b
#=> #<Foo:0x29c98e0 #value=42>
You can find the list of operators that may be defined as methods here:
http://phrogz.net/ProgrammingRuby/language.html#operatorexpressions
You already got an answer on how to define the binary operators, so just as little addendum here's how you can define the unary - (like for negative numbers).
> class String
.. def -#
.. self.swapcase
.. end
.. end #=> nil
>> -"foo" #=> "FOO"
>> -"FOO" #=> "foo"
Just create methods whose name is the operator you want to overload, for example:
class MyObj
def / rhs
# do something and return the result
end
def * rhs
# do something and return the result
end
end
In Ruby, the * operator (and other such operators) are really just calling a method with the same name as the operator. So to override *, you could do something like this:
class MyObj
def *(obj)
# Do some multiplication stuff
true # Return whatever you want
end
end
You can use a similar technique for other operators, like / or +. (Note that you can't create your own operators in Ruby, though.)