I'm attempting to adjust a variable inside a Ruby/Rails function. Standard stuff for many other languages.
In c:
void change(int *io){
*io = 1;
}
Now we all know that Ruby is pass by reference (smiley face). This bit of code works perfectly:
def tester()
value = 'dave'
test_replace(value)
p value.to_s;
end
def test_replace(ioValue)
ioValue.replace 'test'
end
The output is 'test'.
So the problem is: fixed numbers don't have a replace method. They are not passed the same way as other values.
So my question is: how do I "io" an "int" in Ruby?
def tester()
value = 10
test_replace(value)
p value.to_s;
end
def test_replace(ioValue)
ioValue.replace 15
end
Which raises
undefined method `replace' for 10:Fixnum
#Linuxios is correct in his explanation about pass by value, but his work-arounds are pretty awkward. It's very easy to box a fixnum with a SimpleDelegator that supports a replace:
class NumberBox < SimpleDelegator
alias_method :replace, :__setobj__
class <<self; alias_method :[], :new; end
end
def tester()
value = NumberBox[10]
test_replace(value)
p value.to_s;
end
def test_replace(ioValue)
ioValue.replace 15
end
In the above value will behave exactly like the object it delegates to, established at initialization (with ::new or the NumberBox::[]) except it also supports the __setobj__ method and its alias replace which binds a new object as the delegatee.
There are really two ways to do this:
Wrap in an object
Wrap in an array
Create a mutable-int proxy object
Option two is easy, and I won't give an example. Option 1 would look like this:
class IntRef < BasicObject
def initialize(i)
#int = i
end
def replace(v)
#int = v
end
def method_missing(name, *args, &block)
#int.send(name, *args, &block)
end
end
Or option three: A proxy object!
class MutableInt < BasicObject
def initialize(i)
#int = i
end
def method_missing(name, *args, &block)
v = #int.send(name, *args, &block)
if(v.is_a?(::Fixnum))
#int = v
return self
end
v
end
end
WARNING: Anything, anything you do to this proxy sticks and changes the object. Beware.
Now we all know that Ruby is pass by reference
On the contrary, Ruby is pass by value only. No pass by reference. Same as Java, Python, etc.
Related
I would like to create an instance method that takes another instance method of its own class as a parameter, and then applies the passed method on the instance it's working on (known as self):
class MyClass
attr_reader :called_methods
def initialize
#called_methods = []
end
def my_first_method!
#called_methods << :my_first_method
self
end
def my_second_method!
#called_methods << :my_second_method
self
end
def my_strange_method!(secondary)
# Want to apply method whose name is given by secondary, to self
end
end
p MyClass.new.my_second_method!.my_strange_method!(:my_first_method!).called_methods
I suspect the unary & may be key, but all the web pages I can find on that operator involve calling methods on multiple objects, as when iterating over an Enumerable with #each or #map.
Use Object#public_send (or Object#send to apply protected/private method).
def my_strange_method!(secondary)
public_send(secondary)
self
end
p MyClass.new.
my_second_method!.
my_strange_method!(:my_first_method!).
called_methods
#⇒ [:my_second_method, :my_first_method]
There could be more defensive way to apply if and only the method is known:
def my_strange_method!(secondary)
raise ArgumentError.new("Unknown method #{secondary}") \
unless methods.include? secondary.to_s.to_sym
public_send(secondary)
end
p MyClass.new.
my_second_method!.
my_strange_method!(:my_first_method!).
called_methods
#⇒ [:my_second_method, :my_first_method]
p MyClass.new.
my_second_method!.
my_strange_method!(:inexisting_method!).
called_methods
#⇒ ArgumentError: Unknown method inexisting_method!
This is tagged with functional-programming so I'm going to offer a persistent (immutable) design -
class MyClass
attr_reader :called_methods
def initialize(m = [])
#called_methods = m
end
def my_first_method!
MyClass.new(called_methods + [ :first ])
end
def my_second_method!
MyClass.new(called_methods + [ :second ])
end
def my_strange_method!(secondary)
public_send secondary
end
end
MyClass.new.my_second_method!.my_strange_method!(:my_first_method!).called_methods
# [:second, :first]
I am working on a project of context-oriented programming in ruby. And I come to this problem:
Suppose that I have a class Klass:
class Klass
def my_method
proceed
end
end
I also have a proc stored inside a variable impl. And impl contains { puts "it works!" }.
From somewhere outside Klass, I would like to define a method called proceed inside the method my_method. So that if a call Klass.new.my_method, I get the result "it works".
So the final result should be something like that:
class Klass
def my_method
def proceed
puts "it works!"
end
proceed
end
end
Or if you have any other idea to make the call of proceed inside my_method working, it's also good. But the proceed of another method (let's say my_method_2) isn't the same as my_method.
In fact, the proceed of my_method represent an old version of my_method. And the proceed of my_method_2 represent an old version of my_method_2.
Thanks for your help
Disclaimer: you are doing it wrong!
There must be more robust, elegant and rubyish way to achieve what you want. If you still want to abuse metaprogramming, here you go:
class Klass
def self.proceeds
#proceeds ||= {}
end
def def_proceed
self.class.proceeds[caller.first[/`.*?'/]] = Proc.new
end
def proceed *args
self.class.proceeds[caller.first[/`.*?'/]].(*args)
end
def m_1
def_proceed { puts 1 }
proceed
end
def m_2
def_proceed { puts 2 }
proceed
end
end
inst = Klass.new
inst.m_1
#⇒ 1
inst.m_2
#⇒ 2
What you in fact need, is Module#prepend and call super from there.
One way of doing that is to construct a hash whose keys are the names of the methods calling proceed and whose values are procs that represent the implementations of proceed for each method calling it.
class Klass
singleton_class.send(:attr_reader, :proceeds)
#proceeds = {}
def my_method1(*args)
proceed(__method__,*args)
end
def my_method2(*args)
proceed(__method__,*args)
end
def proceed(m, *args)
self.class.proceeds[m].call(*args)
end
end
def define_proceed(m, &block)
Klass.proceeds[m] = Proc.new &block
end
define_proceed(:my_method1) { |*arr| arr.sum }
define_proceed(:my_method2) { |a,b| "%s-%s" % [a,b] }
k = Klass.new
k.my_method1(1,2,3) #=> 6
k.my_method2("cat", "dog") #=> "cat-dog"
It's possible to create a Complex number in Ruby using
c = Complex.new(1,2)
but, it can be shortened to
c = Complex(1,2)
Is it possible to achieve the same functionality without having to define a function outside the class, like in the example below?
class Bits
def initialize(bits)
#bits = bits
end
end
def Bits(list) # I would like to define this function inside the class
Bits.new list
end
b = Bits([0,1])
I think Ruby should allow at least one of the proposed constructors below
class Bits
def initialize(bits)
#bits = bits
end
def self.Bits(list) # version 1
new list
end
def Bits(list) # version 2
new list
end
def Bits.Bits(list) # version 3
new list
end
end
Have this snippet:
def make_light_constructor(klass)
eval("def #{klass}(*args) #{klass}.new(*args) end")
end
Now you can do this:
class Test
make_light_constructor(Test)
def initialize(x,y)
print x + y
end
end
t = Test(5,3)
Yes, I know you're still defining a function outside a class - but it is only one function, and now any class you want can make use of its implementation rather than making one function per class.
c = Complex(1,2)
is actually calling a method on Kernel
Basically you can't - the () operator cannot be overriden in Ruby (Complex class is written in C).
You could achieve something similar using []:
class Bits
def self.[](list)
Bits.new list
end
end
Which would allow something like:
b = Bits[[1,2]]
If you pack your classes into some module you can use 2 methods:
self.included - called when you include Mod
self.extend - called when you extend Mod
I have created very basic method using self.included.
Cons: It is hard to write. You can say it is complex; It may not contain all features.
Pros: It looks exactly like Complex(2,3) (it uses () instead of [] as in https://stackoverflow.com/a/24351316/2597260 answer); You create just initialize, self.included create the rest.
module M1
# some random classes
class A; end
class B
def initialize list
#list = list
end
attr_accessor :list
end
class C
def initialize var1
#var1 = var1
end
attr_accessor :var1
end
Answer = 42
# called on `include module_name`
def self.included mod
# classes are constants (in normal cases)
constants.each do |cons|
class_eval do
# I don't like hard-coded `::M1`
klass = ::M1.const_get cons
if klass.class==Class
define_method cons do |*args, &block|
klass.new *args, &block
end
end
end
end
end
end
include M1
p A()
b = B([1,2,3])
p b.list
c = C 42
p c.var1
puts Answer()
# NoMethodError: undefined method `Answer' for main:Object
# thats good, because Answer is not a class!
Here's another hack that you could (but shouldn't) use, inspired by this blog post:
def method_missing(sym, *args, **kwargs, &blk)
Object.const_get(sym).new(*args, **kwargs, &blk)
end
This simply expects any unknown method name to be the name of a class and calls :new on the class.
With rudimentary error handling:
alias sys_method_missing method_missing
def method_missing(sym, *args, **kwargs, &blk)
cls = Object.const_get(sym) if Object.constants.include? sym
if cls.is_a?(Class) then cls.new(*args, **kwargs, &blk)
else sys_method_missing(sym, *args, **kwargs, &blk) end
end
If an unknown method name is the name of a class, this calls :new on the class. Otherwise, it delegates the call to the original implementation of method_missing().
Usage:
class Foo
end
foo = Foo()
p foo
Result:
#<Foo:0x00007f8fe0877180>
This question already has answers here:
When to use `self.foo` instead of `foo` in Ruby methods
(3 answers)
Closed 9 years ago.
When do you use self.property_name in Ruby?
Use self when calling a class's mutator. For example, this won't work:
class Foo
attr_writer :bar
def do_something
bar = 2
end
end
The problem is that 'bar = 2' creates a local variable named 'bar', rather than calling the method 'bar=' which was created by attr_writer. However, a little self will fix it:
class Foo
attr_writer :bar
def do_something
self.bar = 2
end
end
self.bar = 2 calls the method bar=, as desired.
You may also use self to call a reader with the same name as a local variable:
class Foo
attr_reader :bar
def do_something
bar = 123
puts self.bar
end
end
But it's usually better to avoid giving a local variable the same name as an accessor.
self references the current object. This lends itself to many uses:
calling a method on the current object
class A
def initialize val
#val = val
end
def method1
1 + self.method2()
end
def method2
#val*2
end
end
Here running A.new(1).method1() will return 3. The use of self is optional here - the following code is equivalent:
class A
def initialize val
#val = val
end
def method1
1 + method2()
end
def method2
#val*2
end
end
self is not redundant for this purpose though - operator overloading makes it neccessary:
class A
def initialize val
#val = val
end
def [] x
#val + x
end
def method1 y
[y] #returns an array!
end
def method2 y
self.[y] #executes the [] method
end
end
This shows how self must be used if you want to call the current object's [] method.
referencing attributes
You can generate the methods to read and write to instance variables using attr_accessor and co.
class A
attr_accessor :val
def initialize val
#val = val
end
def increment!
self.val += 1
end
end
Using self is redundant here because you can just reference the variable directly, eg. #val.
Using the previous class, A.new(1).increment! would return 2.
method chaining
You can return self to provide a form of syntactical sugar known as chaining:
class A
attr_reader :val
def initialize val
#val = val
end
def increment!
#val += 1
self
end
end
Here, because we are returning the current object, methods can be chained:
A.new(1).increment!.increment!.increment!.val #returns 4
creating class methods
You can define class methods using self:
class A
def self.double x
x*2
end
def self.quadruple x
self.double(self.double(x))
end
end
This will enable you to call A.double(2) #= 4 and A.quadruple(2) #=8. Note that in a class method, self references that class because the class is the current object.
how the value of self is determined
The current value of self in a particular method is set to the object that that method was called upon. Normally this uses the '.' notation. When you run some_object.some_method(), self is bound to some_object for the duration of some_method, meaning that some_method can use self in one of the ways mentioned above.
Using self is used will reference the current object accessible within a program. Therefore, self.property is used when accessing a variable through a attr_accessor of some sort. In must cases, it can be used in place of #property from within an object.
How would I use the parameter value as the instance variable name of an object?
This is the object
Class MyClass
def initialize(ex,ey)
#myvar = ex
#myothervar = ey
end
end
I have the following method
def test(element)
instanceofMyClass.element #this obviously doesnt work
end
How can I have the test method return either myvar or myothervar value depending on the element parameter. I don't want to write an if condition though, I want to pass myvar or myother var via element to the object instance if possible.
def test(element)
instanceofMyClass.send(element.to_sym)
end
You'll get a missing method error if instanceofMyClass doesn't respond to element.
def test(element)
instanceofmyclass.instance_variable_get element
end
test :#myvar # => ex
test :#myothervar # => ey
I like the simplicity of send(), though one bad thing with it is that it can be used to access privates. The issue is still remains solution below, but at least then it's explicitly specified, and reader can see which methods are to be forwarded. The first one just uses delegation, while the second one uses more dynamic way to define methods on the fly.
require 'forwardable'
class A
extend Forwardable
def_delegators :#myinstance, :foo, :bar
class B
def foo
puts 'foo called'
end
def bar
puts 'bar called'
end
def quux
puts 'quux called'
end
def bif
puts 'bif called'
end
end
def initialize
#myinstance = B.new
end
%i(quux bif).each do |meth| # note that only A#quux and A#bif are defined dynamically
define_method meth do |*args_but_we_do_not_have_any|
#myinstance.send(meth)
end
end
end
a = A.new
a.foo
a.bar
a.quux
a.bif