I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
I have here the method
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
ArgumentError: wrong number of arguments (0 for 1)
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method to get the method and .call to call it:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
You want a proc object:
gaussian = Proc.new do |dist, *args|
sigma = args.first || 10.0
...
end
def weightedknn(data, vec1, k = 5, weightf = gaussian)
...
weight = weightf.call(dist)
...
end
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send with object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
def weightedknn(data, vec1, k = 5)
...
weight =
if block_given?
yield(dist)
else
gaussian.call(dist)
end
end
...
end
weightedknn(foo, bar) do |dist|
# square the dist
dist * dist
end
But it sounds like you would like more reusable chunks of code here.
You can pass a method as parameter with method(:function) way. Below is a very simple example:
def double(a)
return a * 2
end
=> nil
def method_with_function_as_param( callback, number)
callback.call(number)
end
=> nil
method_with_function_as_param( method(:double) , 10 )
=> 20
The normal Ruby way to do this is to use a block.
So it would be something like:
def weightedknn(data, vec1, k = 5)
foo
weight = yield(dist)
foo
end
And used like:
weightedknn(data, vec1) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
You can use the & operator on the Method instance of your method to convert the method to a block.
Example:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
You have to call the method "call" of the function object:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
# Returns a valid hash for html form select element, combined of all entities
# for the given +model+, where only id and name attributes are taken as
# values and keys correspondingly. Provide block returning boolean if you
# need to select only specific entities.
#
# * *Args* :
# - +model+ -> ORM interface for specific entities'
# - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
# * *Returns* :
# - hash of {entity.id => entity.name}
#
def make_select_list( model, &cond )
cond ||= proc { true } # cond defaults to proc { true }
# Entities filtered by cond, followed by filtration by (id, name)
model.all.map do |x|
cond.( x ) ? { x.id => x.name } : {}
end.reduce Hash.new do |memo, e| memo.merge( e ) end
end
Afterwerds, you can call this function like this:
#contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == #current_user
end
If you don't need to filter your selection, you simply omit the block:
#categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Similarly to a Proc or a method call, you can also pass a lambda as weightf parameter :
def main
gaussian = -> (params) {
...
}
weightedknn(data, vec1, k = 5, gaussian, params)
# Use symbol :gaussian if method exists instead
end
def weightedknn(data, vec1, k = 5, weightf, params)
...
weight = weightf.call(params)
...
end
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.
Related
I'm trying to learn Ruby. I want to pass an arbitrary function and an arbitrary list of arguments and keyword arguments into another function.
for example, I have this arbitrary function below
def dummy_func(a, b)
return a+b
end
And I have this wrapper function
def wrapper(func, *args, **kwargs)
func(args, kwargs))
end
I want it so I can pass my arguments in any of the following ways and still return the correct answer
wrapper(dummy_func, a=1, b=2)
wrapper(dummy_func, 1, b=2)
wrapper(dummy_func, a=1, b=2)
wrapper(dummy_func, 1, 2)
Is this possible in Ruby? What would be an idiomatic way of approaching it?
The idiomatic way is to instead yield to a block.
def dummy_func(a, b, key:)
return a+b+key
end
def wrapper
puts yield
end
a = 4
b = 5
c = 6
wrapper do
dummy_func(a ,b, key: c)
end
Since the block is closure it can see all the same variables that the call to wrapper can. Now there's no need to pass wrapper's arguments through.
If you really want to make your wrapper, you can do some introspection to determine what arguments the wrapped function takes.
def dummy_func(a, b=23, key: 42)
return a+b+key
end
def no_keys(a, b=23)
return a+b
end
def wrapper(func, *array, **hash)
method = self.method(func)
takes_array = method.parameters.any? { |p| [:req, :opt, :rest].include?(p[0]) }
takes_hash = method.parameters.any? { |p| [:keyreq, :key, :keyrest].include?(p[0]) }
if takes_array && takes_hash
self.send(func, *array, **hash)
elsif takes_array
self.send(func, *array)
elsif takes_hash
self.send(func, **hash)
else
self.send(func)
end
end
a = 4
b = 5
c = 6
puts wrapper(:dummy_func, a, b, key:c)
puts wrapper(:no_keys, a, b)
But this is quite a bit more complex and less flexible than yielding to a block. This also limits you to "functions" which are really methods on the main object (there are no function references in Ruby). That's why they're called with self.send. Blocks require no assumptions about what is being wrapped.
The closest you can get is keyword arguments:
https://www.justinweiss.com/articles/fun-with-keyword-arguments/
def hello_message(greeting, time_of_day, first_name:, last_name:)
"#{greeting} #{time_of_day}, #{first_name} #{last_name}!"
end
args = ["Morning"]
keyword_args = {last_name: "Weiss"}
hello_message("Good", *args, first_name: "Justin", **keyword_args)
=> "Good Morning, Justin Weiss!"
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
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(:+)
There has to be a built in way of doing this, right?
class Object
def send_chain(arr)
o=self
arr.each{|a| o=o.send(a) }
return o
end
end
I just ran across this and it really begs for inject:
def send_chain(arr)
arr.inject(self) {|o, a| o.send(a) }
end
Building upon previous answers, in case you need to pass arguments to each method, you can use this:
def send_chain(arr)
Array(arr).inject(self) { |o, a| o.send(*a) }
end
You can then use the method like this:
arr = [:to_i, [:+, 4], :to_s, [:*, 3]]
'1'.send_chain(arr) # => "555"
This method accepts single arguments as well.
No, there isn't a built in way to do this. What you did is simple and concise enough, not to mention dangerous. Be careful when using it.
On another thought, this can be extended to accept arguments as well:
class Object
def send_chain(*args)
o=self
args.each do |arg|
case arg
when Symbol, String
o = o.send arg # send single symbol or string without arguments
when Array
o = o.send *arg # smash the inner array into method name + arguments
else
raise ArgumentError
end
end
return o
end
end
this would let you pass a method name with its arguments in an array, like;
test = MyObject.new
test.send_chain :a_method, [:a_method_with_args, an_argument, another_argument], :another_method
How about this versatile solution without polluting the Object class:
def chain_try(arr)
[arr].flatten.inject(self_or_instance, :try)
end
or
def chain_send(arr)
[arr].flatten.inject(self_or_instance, :send)
end
This way it can take a Symbol, a String or an Array with a mix of both even.🤔
example usage:
chain_send([:method1, 'method2', :method3])
chain_send(:one_method)
chain_send('one_method')
In Ruby, is it possible to pass by reference a parameter with value-type semantics (e.g. a Fixnum)?
I'm looking for something similar to C#'s 'ref' keyword.
Example:
def func(x)
x += 1
end
a = 5
func(a) #this should be something like func(ref a)
puts a #should read '6'
Btw. I know I could just use:
a = func(a)
You can accomplish this by explicitly passing in the current binding:
def func(x, bdg)
eval "#{x} += 1", bdg
end
a = 5
func(:a, binding)
puts a # => 6
Ruby doesn't support "pass by reference" at all. Everything is an object and the references to those objects are always passed by value. Actually, in your example you are passing a copy of the reference to the Fixnum Object by value.
The problem with the your code is, that x += 1 doesn't modify the passed Fixnum Object but instead creates a completely new and independent object.
I think, Java programmers would call Fixnum objects immutable.
In Ruby you can't pass parameters by reference. For your example, you would have to return the new value and assign it to the variable a or create a new class that contains the value and pass an instance of this class around. Example:
class Container
attr_accessor :value
def initialize value
#value = value
end
end
def func(x)
x.value += 1
end
a = Container.new(5)
func(a)
puts a.value
You can try following trick:
def func(x)
x[0] += 1
end
a = [5]
func(a) #this should be something like func(ref a)
puts a[0] #should read '6'
http://ruby-doc.org/core-2.1.5/Fixnum.html
Fixnum objects have immediate value. This means that when they are assigned or
passed as parameters, the actual object is passed, rather than a reference to
that object.
Also Ruby is pass by value.
However, it seems that composite objects, like hashes, are passed by reference:
fp = {}
def changeit(par)
par[:abc] = 'cde'
end
changeit(fp)
p fp
gives
{:abc=>"cde"}