I'm new to ruby and just testing out how to define a method with two variable inputs from the user. Currently, it takes the values but it returns nothing.
Is there something I missing here?
puts "Tell me what you want to print."
word = gets.chomp
puts "How many times do you want it printed?"
number = gets.to_i
def print_x_times(word)
i = 0
while i < number
puts(word)
i += 1
end
end
A few nits here:
You've defined a new method, but you haven't invoked it. You're likely using something like IRB to interactively play around, but the fact remains that you've only defined that method.
You're going to confuse yourself if you use word and number as variables inside of that method, since they're not guaranteed to be the same as the ones you've defined outside of it.
If you want to pass two values to the method, then you have to specify two parameters:
def print_x_times(word, number)
# code
end
...then, you actually go about calling it with your variables.
print_x_times(word, number)
You should pass number as an argument to the function print_x_times as you do for word
moreover, this code defines a function but doesn't call it, you should call it too
You have two issues here...
You need to define the method to take two parameters, word and number.
Then you need to call that method with the two arguments you derived from user input.
Related
I am new to Ruby and to Rails, and am trying to understand fully what I'm reading.
I am looking at some of the Rails source code, in this case action_controller/metal/instrumentation.rb.
def render(*args)
render_output = nil
self.view_runtime = cleanup_view_runtime do
Benchmark.ms { render_output = super }
end
render_output
end
I understand that *args is using the splat operator to collect the arguments together into an array. But after that, it stops making much sense to me.
I can't fathom why render_output is set to nil before being reassigned to equal super and then called with no arguments. I gather that some speedtest is being done, but coming from other languages I'd expect this to just be something more like Benchmark.ms(render_output) or perhaps Benchmark.start followed by render_output followed by Benchmark.end. I'm having a hard time following the way it works here.
But more importantly, I don't really follow why args isn't used again. Why bother defining a param that isn't used? And I mean, clearly it is getting used-- I just don't see how. There's some hidden mechanism here that I haven't learned about yet.
In this context, it is important to note how super works, because in some cases it passes implicitly arguments and you might not expect that.
When you have method like
def method(argument)
super
end
then super is calling the overridden implementation of method implicitly with the exact same arguments as the current method was called. That means in this example super will actually call super(argument).
Of course, you can still define a method call that explicitly sends other arguments to the original implementation, like in this example:
def method(argument)
super(argument + 1)
end
Another important edge-case is when you want to explicitly call super without any arguments although the current method was called with arguments then you need to be very explicit like this
def method(argument)
super() # note the empty parentheses
end
Let me try to describe you what I think this code does.
*args*
is using the splat operator to collect the arguments together into an array
that is totally correct, however they don't use it, and if you will go to master branch, they just changed it to *. Asking why it is defined and not used, I think that's question about bad design. They should have called it _args or at least like it is now just single splat *.
render_output is set to nil because of scopes, it has to be explicitly defined out block, lambda, proc in order to store value in it, otherwise its visibility will be locked only to those lambda, proc, block execution. Refer to this article
Benchmark.start. Blocks are great ruby construction. You are totally correct that speedtest is done, we can see it is just decorator for benchmark library.
source.
You are wondering why we cannot just pass it as Benchmark.ms(render_output), that's because what will be given to benchmark ms function? It will be given result, like <div> my html </div. And how we can measure this string result - no how. That's why we calling super right in this block, we want to access parent class function and wrap it inside block, so we are not calling it, we just construct it, and it will be called inside benchmark lib, and measured execution like
class Benchmark
...
def realtime # :yield:
r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end
...
end
So here we can count realtime of function execution, this is the code from original library
I am try to write a function that will find the items in an array which match the string passed to the function. See code below.
class Island
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}</i>
How i keep getting "undefined method 'filer' for #
I'm not sure what i'm doing wrong.
First let me object against the solution posted by #Sravan :
While it is true - and sometimes even a good solution - to monkey-patch a class, you have to be careful how to do it, because it may become a time bomb:
Ruby evolves, and new versions often add methods to existing classes. This means that if you add a method Array#search, and a new version of Ruby will also add a method of the same name, your new method will SILENTLY override the one in Ruby. You likely won't notice it for long time, until you are using a feature which is supposed to use Rubys Array#search - maybe by using something new in stdlib - and you get weird results. To track down this type of error can be a nightmare. This is exactly the case when you use search as a method name.
Now, how to do it then? Three possibilities:
(1) If you monkey-patch, use at least a method name which is unlikely to become part of the official interface. It might have your project's name as a prefix, or plenty of underscore characters, and so on. Note that this is not 100% foolproof: A later version of Ruby might add under the hood a private method with exactly the same name than the one you were choosing, but of course the odder your name, the less likely this will happen.
(2) If you don't like this idea of using "clumsy" names, you could at least test before defining the new method, whether it already exists, and throw an exception if it doesn't:
class Array
if self.method_defined?(:search)
raise "#{self.class}::search already defined"
else
def search(...)
...
end
end
end
(3) The third possibility is to avoid monkey-patching and keep the method in your Island class. In this case, the method definition would be different:
class Island
def self.filter(array, string)
...
end
end
and it would be called by
Island.filter(myarray, mystring)
UPDATE: Forgot a forth possibility:
(4) You can make Island a subclass of Array. I don't know what else you want to do with your islands, but maybe this is an option worth considering:
class Island < Array
def filter(string)
...
end
end
Of course, when invoking filter, you need to turn your array into an island, before you can use it:
list = Island.new([....])
Following ruby's convention over configuration, you can add/overwrite any method in any class
So, adding a function to array class makes it accessible to all the arrays. So, in this solution.
1) First thing is you have taken the filter function in Island class, instead, you need to take inside Array class since the list is an array.
class Array
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}
O/P:
anthony
andre
antoinette
2) Since Filter is a keyword as suggested by other answer, take another name for it. Eg: search
class Array
def search(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list.search("an"){|i| puts i}
I’m using Rails 4.2.7 on Ubuntu 14.04. According to this — Why doesn't ruby support method overloading? , I should be able to overload methods in my service class if each method has a different number of arguments. So I have created …
def create_my_object_time_obj(data_hash)
create_my_object_time_obj(data_hash, nil)
end
def create_my_object_time_obj(data_hash, my_object_id)
…
Yet, when I try and invoke the call that only takes a single argument
my_object_time = service.create_my_object_time_obj(data_hash)
I get the error
Error during processing: wrong number of arguments (given 1, expected 2)
/Users/login/Documents/workspace/myproject/app/services/text_table_to_my_object_time_converter_service.rb:82:in `create_my_object_time_obj'
What’s the right way to overload my methods from my service class?
Ruby allows one and only one method for a given unique name, regardless of the method signature. The Ruby interpreter only looks at the names of methods, as opposed to the Java interpreter, which considers parameters as well as method names.
You can only override methods, with the latest version of a method of a given name taking precedence over all previous methods which share that name.
You can, however, get around the inability to overload by taking advantage of the splat (*) operator to pass a variable number of arguments to your method in an array, and then branching based on the number of passed parameters.
def foo(*args)
if args.length == 1
# logic for a single argument
elsif args.length == 2
# logic for two arguments
else
# logic for other conditions
end
end
Just simple define your method as per below:
def create_my_object_time_obj(data_hash, my_object_id = nil)
create_my_object_time_obj(data_hash, my_object_id)
end
now you can call this method by single argument:
my_object_time = service.create_my_object_time_obj(data_hash)
this will work file. try this :)
This question already has answers here:
Blocks and yields in Ruby
(10 answers)
Closed 9 years ago.
I keep writing the same pattern of code in Ruby, which seems like it would benefit from a 'do' style bit of code but I'm not sure how to write the method.
I keep doing this pattern of code, which starts and ends with the same lines of code...
x.increment!(:step_count) # same each time
# ...then some different code each
x.update_column(:step_description, "blerg message") # same each time
I feel it would benefit from a 'do' something that would look like this...
update_steps "blerg message" do
# ...then some different code each
end
And then inside the 'do' each time it does the common code.
How would I go about making a method where I can use a 'do'.
Thanks!
Edit: I think it's important to not close this because I didn't know to search for 'block' or 'yield'. People who may no know these terms may end up searching for 'do' instead.
Creating methods that accept a block is one of Ruby's most powerful features.
The common way to define such a method would be:
def foo(*args, &block)
# your code here
yield
# some more code
end
foo do
# This code runs when yield is called
end
There are a few things you should know about the above:
The &block parameter is not required. You can just use yield anyway. But there are a few reasons why you should add it to your method definition:
It makes it clear that your method accepts a block
The & basically transforms the block to a proc object. This could be handy since that way you can actually pass it around as a parameter to another method that accepts a block. You just need to re-apply the & to make it again a block.
Handling a proc object can be more powerful since you can also set its binding.
You can pass arguments to yield. The arguments you pass are the block local variables. For example in:
[1,2,3].each {|x| puts x}
yield is called with one of the array elements on every iteration. Calling yield with an argument is the same as block.call(a) where a is an argument.
If your method encounters a yield and there is no block given it will raise an exception. This might be correct in some cases. But if you want to have a different behavior if no block is given you can use the block_given? method to check it.
&block must be the last parameter in your method definition.
Pass it a block as an argument
def my_method(&block)
do_something_the_same
yield # calls whatever is inbetween "do" and "end"
end
Or you can also do this by calling block.call
def update_steps(&block)
block.call()
end
For example
func(#param) do |f|
some code here
end
and
#param.each do |sth|
some code here
end
What does the absolute value sign do here? I don't understand these two pieces of code.
It's the local variable within the block, so for the line:
#param.each do |sth|
you're iterating over #param right, well each item in #param is referred to singularly as sth.
So if #param refers to an array containing the numbers
[1,3,5,4]
During the first iteration sth will be 1, then 3, then 5, then 4.
Same goes for :
func(#param) do |f|
except now the local variable is called f! You could call it anything you want, even |ihavenoideawhatimdoing|
It's a local variable, it is saying that for the block of code between do...end, the variable f is defined.
It is a parameter to a block. The block is the part of the code between the do and the end. That block of code can use f or sth, which in your examples would probably have been set by func or each.
A tutorial on Ruby blocks will probably be helpful.
Labmda calculus - more abstract, but it was the context in which I first saw these things.
It signifies instance variables. You often see it interchanged if people are using attr_* methods like attr_accessor, which makes #someattr and self.some_attr equivalent in instance methods.