I've got a simple code for a class. It's:
def greeting
greeting = ARGV.shift
ARGV.each do |arg|
p "#{greeting}, #{arg}!"
end
end
My desire is for it to simply output "Hello, Charlie!" and "Hello, Sam!" based on the names stored in the array. However when I try to run the program in ruby it looks like I used a return statement.
address_bloc :> ls
address_bloc.rb greeting.rb ruby
argv_test.rb models spec
address_bloc :> greeting.rb Yo Tommy Bob Sally
-bash: greeting.rb: command not found
address_bloc :> ruby greeting.rb Yo Sam Sean Bill
address_bloc :> ruby greeting.rb Yo Sam Sean Bill
Remove the function definition logic and just include the contents at the top-level if this is all you want your script to do:
greeting = ARGV.shift
ARGV.each do |arg|
puts "#{greeting}, #{arg}!"
end
If you want to continue with defining a general-purpose function for greeting a list of names, you may also do so by calling greeting and passing it the contents of ARGV, as in the following:
def greeting(args)
greeting = args.shift
args.each do |arg|
puts "#{greeting}, #{arg}!"
end
end
greeting ARGV
But in general, it's a nicer function if its arguments are more meaningful, so consider doing something like this:
def greet_list(greeting, name_list)
name_list.each do |arg|
puts "#{greeting}, #{arg}!"
end
end
greet_list ARGV.shift, ARGV
Related
Is there a way to call multiple methods on the same instance without having to prefix each method call with the instance?
logger = Logger.new(STDERR)
table_name = ENV['ec2_information'].split('/')[1]
discovery = Ec2_ddb_discovery.new(logger:, table:)
discovery.scan_ddb_table
discovery.collect_stale_items.each { |item|
As max pleaner mentions in his comment, you can use instance_eval or if you need to pass arguments, you can use instance_exec.
These are typically used to create DSLs, but can be us like this as well.
class Foo
def bar_one
puts "hello from bar_one"
end
def bar_two
puts "hello from bar_two"
end
def bar_three(arg)
puts "hello from bar_three with #{arg}"
end
end
Foo.new.instance_eval do
bar_one
bar_two
bar_three("local_argument")
end
Foo.new.instance_exec("passed_argument") do |arg|
bar_one
bar_two
bar_three(arg)
end
How can I pass the results of a method to another method in ruby?
eg:
class D
def initialize(text)
#text = text
end
def a s
"hello #{s}"
end
def b s
"hi #{s}"
end
end
So, what I want to do is pass the output of method a to method b. So essentially(if the methods aren't inside a class) I can do the following the following:
puts b(a "Tom") #=>hi hello Tom
However, even if this isn't inside a class, it wouldn't look good if there are a lot of methods so there must be a more elegant way to do this. So what is the proper way to get the output hi hello Tom by applying the methods a and b to an instance of the class D?
UPDATE
I just wanted to make it a little bit more clear. Eg, in F# you can do something like this:
let a s = "hello " + s
let b s = "hi " + s
"Tom" |> a |> b #=> hello hi Tom
Here we defined functions a and b and then passed on the results to the next function.
I know that its a functional language so ways of doing things would be different there. But I am just wondering if there are any such tricks in Ruby?
You can leave the ()
def a s
"hello #{s}"
end
def b s
"hi #{s}"
end
puts b a "Tom"
If you have many methods :
puts [:a,:b].inject("Tom"){|result,method| self.send(method,result)}
If you want to use those methods with any object (including Classes) :
module Kernel
def chain_methods(start_value, *methods)
methods.inject(start_value){|result,method| self.send(method,result)}
end
end
class D
def a s
"hello #{s}"
end
def b s
"hi #{s}"
end
end
class E
class << self
def a s
"hello #{s}"
end
def b s
"hi #{s}"
end
end
end
# Example with instance methods
puts D.new.chain_methods("Tom", :a, :b)
# Example with class methods
puts E.chain_methods("Tom", :a, :b)
# Thanks mudasobwa :
E.chain_methods("Tom", :a, :b, :puts)
My functions are:
def hello(str)
puts "hello #{str}"
end
def hello_scope(scope, &block)
# ???
end
I would like to temporarily augment a function within a block of my method.
In hello_scope, I simply want to prepend the scope string to the str before passing it to the original hello method. Here's an example:
hello 'world' #=> hello world
hello_scope "welcome!" do
hello 'bob' #=> welcome!hello bob
hello 'alice' #=> welcome!hello alice
end
I'm kind of a noob when it comes to this kind of thing in Ruby. Can someone help me solve this in an elegant way?
Edit:
If it makes things easier, it's OK if we pass the method in as an argument to the block, such as:
hello_scope "welcome!" do |h|
h "bob" #=> welcome!hello bob
h "alice" #=> welcome!hello alice
end
One way is to create a "evaluation context object" on which the block is going to be instance-eval'd. This object has to provide all the methods that are specific to the block. In the example below, I did not use the same name as I don't remember how to explicitly referring to the global method "hello" (to avoid infinite recursion). In a proper library, "hello" would be defined as a class method somewhere, so that would not be an issue.
For instance
def hello(str)
puts "hello #{str}"
end
class HelloScope
def h(str)
print scope
hello(str)
end
end
def hello_scope(scope, &block)
HelloScope.new(scope).instance_eval(&block)
end
Just modify your "hello" method to take into account current scope:
class Greeter
def initialize
#scope = nil
end
def hello(str)
puts "#{#scope}hello #{str}"
end
def with_scope(scope)
#scope = scope
yield
#scope = nil
end
end
Greeter.new.instance_eval do
hello 'world' #=> hello world
with_scope "welcome!" do
hello 'bob' #=> welcome!hello bob
hello 'alice' #=> welcome!hello alice
end
end
I'm interesting how to pass method with arguments in ruby. I need to implement something like command pattern with flexible function setting. Example => lambda functions in C#.
Ruby lambda functions are defined as follows:
a.lambda{ puts "Hello"}
a.call #=> Hello
a = lambda{|str| puts str }
a.call("Hello world !!!") #=> Hello world !!!
a = lambda{|*args| puts args.join(' ')}
a.call("Hello", "World") #=> Hello World
You could do the command pattern the way you do most things in Ruby: with a block.
class Soldier
def initialize(&block)
#command = block
end
def action
#command.call if #command
end
end
s = Soldier.new do #the block
line = "We are drill machines, drill machines feel no pain"
2.times{ puts line }
puts line.upcase
end
puts "Action:"
s.action
You can dynamically invoke methods along with their argument lists. Below is only one of the ways
class Foo
def foo(what)
puts what
end
end
Foo.new.send(:what, "something") # ==> "something"
How do I pass the parameter name in the following case..the name is being is evaluated before being passed to class_eval
class Foo
end
Foo.class_eval %Q{
def hello(name)
p "hello #{name}"
end
}
Sorry about not giving the entire scenario...
I just wanted to add a instance method dynamically to a class and that method should be able to take arguments...
the above code would not compile complaining that the name is not defined as local variable when executing in irb..
Thanks
The other answers are the "right" answer, but you could also just skip interpolating inside the p call:
Foo.class_eval %Q{
def hello(name)
p "hello \#{name}"
end
}
I thought you wanted to change the actual parameter name (possibly useful for completion or when using Pry on dynamic methods), here assuming it's in a global, but could also be passed into a method doing the class_eval:
Foo.class_eval %Q{
def hello(#{$argname})
p "hello \#{$argname}"
end
}
Really simple:
Foo.class_eval do
def hello(name)
p "hello #{name}"
end
end
Try passing a block to class_eval instead of an array (from this link):
class Foo
end
Foo.class_eval {
def hello(name)
p "hello #{name}"
end
}
You then can call the instance method hello in the usual fashion:
boo = Foo.new
boo.hello("you")
which produces:
>> boo.hello("you")
"hello you"
=> nil
class Foo
end
Foo.class_eval do
define_method :hello do |name|
p "hello #{name}"
end
end
Foo.new.hello("coool") # => "hello coool"