Is there any function or way to simulate this with in ruby?
It helps you to organize the code that acts over the same object, something like:
with(callDao) {
whenever(deleteAll()).thenComplete()
whenever(insertAll(any())).thenComplete()
}
vs
whenever(callDao.deleteAll()).thenComplete()
whenever(callDao.insertAll(any())).thenComplete()
Yes, you can build your own with using instance_eval.
def with(obj, &block)
obj.instance_eval(&block)
end
with(" banana ") {
puts strip
puts reverse
}
Output:
banana
ananab
Related
I'm learning Ruby and want to be able to do this:
Printer.hi there
and have Ruby output
"hi there"
So far I have the following implementation
class Printer
def method_missing(name, *args)
puts "#{name} #{args.join(',')}"
end
end
But this only lets me do
Printer.hi "there"
If I attempt
Printer.hi there
I get a
NameError: undefined local variable or method `there' for main:Object
which makes sense as I haven't ever defined 'there'. Is there a way to make this work though?
No, this is not possible in the form given (as far as I know).
You aren't looking for method missing, you are looking for the equivalent in the Ruby interpreter to capture when it cannot find a given symbol. So while you cannot intercept it there, you can do it inside of a block:
def hi(&block)
begin
yield
rescue NameError => e
e.message =~ /variable or method `(.+)'/
puts "hi #{$1}"
end
end
hi { there } # => hi there
Please note that I feel like a terrible world citizen for showing you this. Please don't use it anywhere, ever.
Yes, there is a way. When you write there without an explicit receiver, the receiver is the self object of that scope. In this case, it is main. Define methods_missing in the main context.
def method_missing(name, *args)
puts "#{name} was called with arguments: #{args.join(',')}"
end
But if you do so, that would mess up the rest of your code, perhaps. I see not point in doing this.
Since the return value of puts is nil, if you do Printer.hi there, it will evaluate to Printer.hi(nil). So in order for it to output "hi there", you need to define:
class Printer
def self.hi _; puts "hi there" end
end
No because strings need to be quoted, so they are not seen as variables.
Otherwise variables such as there would need some special sort of character to indicate that it is a string. However this still wouldn't work well as spaces would then need to be dealt with.
Use single or double quotes.
It's how the language works. accept this and move on to the next challenge :)
Interestingly you can do this in ruby 1.8.7 with just this code:
def method_missing(*args)
puts args.join ' '
end
I learned about this from Gary Bernhardt's talk, Wat. In 1.9 this gives you a stack level too deep error unless you do it inside a class. Google lead me to this post on Aurthur's tech blog thing, which claims you can do something similar in JRuby 1.9 mode:
def method_missing(*args)
puts [method.to_s, args].flatten.join ' '
end
However when I tried this on MRI 1.9.3 it did not work either. So in 1.9 you can't quite do what you want. Here is the closest I could come:
class Printer
def self.hi(message)
puts "hi #{message}"
end
def self.method_missing(m, *args)
[m.to_s, args].flatten.join ' '
end
def self.bare
hi there
end
end
Printer.bare
I want to pass a block to a block that is instance_eval-ed like this,
instance_eval(&block) { puts "test" }
where block is defined as containing something like:
puts "Incoming message:"
yield
Is this possible? I discovered a way of doing this with fibers, but I'm trying to use yield first. Looking at this question, it looks like this might not be possible, but I wanted to confirm.
It's weird, indeed. Why instance_eval ? It's usually used to change self, and evaluate in the context of the receiver.
cat = String.new('weird cat')
block1 = lambda do |obj, block|
puts "Incoming message for #{obj}:"
block.call
end
block2 = Proc.new { puts "test" }
block3 = lambda {|obj| block1.call(obj, block2)}
cat.instance_eval(&block3)
Execution (Ruby 1.9.2) :
$ ruby -w t2.rb
Incoming message for weird cat:
test
I want to store a "code block" in a variable to be reused, something like:
block = do
|test| puts test
end
3.upto(8) block
Can someone show me what am I doing so obviously wrong? (Or if it's just impossible)
There are many ways to do this in Ruby, one of which is to use a Proc:
foo = Proc.new do |test|
puts test
end
3.upto(8) { foo.call("hello world") }
Read more about Procs:
http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas
http://www.skorks.com/2010/05/ruby-procs-and-lambdas-and-the-difference-between-them/
Update, the above method could be rewritten as follows:
# using lower-case **proc** syntax, all on one line
foo = proc { |test| puts test }
3.upto(8) { foo.call("hello world") }
# using lambda, just switch the method name from proc to lambda
bar = lambda { |test| puts test }
3.upto(8) { bar.call("hello world") }
They're basically very similar methods, with subtle differences.
And finally, there are probably more elegant ways to do what I've outlined, be good to hear from anyone with a better way. Hope this helps.
I have two methods defined in my ruby file.
def is_mandatory(string)
puts xyz
end
def is_alphabets(string)
puts abc
end
An array containing the names of the methods.
methods = ["is_mandatory", "is_alphabets"]
When I do the following
methods.each do |method| puts method.concat("(\"abc\")") end
It just displays, is_mandatory("abc") is_alphabets("abc") rather than actually calling the method.
How can i convert the string to method name?
Any help is greatly appreciated.
Cheers!!
Best way is probably:
methods.each { |methodName| send(methodName, 'abc') }
See Object#send
Try using "send".
methods.each do |method|
self.send(method, "abc")
end
All previous solutions with send are fine but it is recommended to use public_send instead (otherwise you can be calling private methods).
Example:
'string'.public_send(:size)
=> 6
You can also add hash to send parameters to the method.
send("method_name", "abc", {add more parameters in this hash})
How can I overwrite the def method? But it's strange, cause I don't know from where the def method is defined. It's not Module, not Object, not BasicObject (of Ruby 1.9). And def.class don't say nothing ;)
I would like to use something like:
sub_def hello
puts "Hello!"
super
end
def hello
puts "cruel world."
end
# ...and maybe it could print:
# => "Hello!"
# => "cruel world."
Many thanks, for any ideas.
Who told you def is a method? It's not. It's a keyword, like class, if, end, etc. So you cannot overwrite it, unless you want to write your own ruby interpreter.
You could use alias_method.
alias_method :orig_hello, :hello
def hello
puts "Hello!"
orig_hello
end
You can use blocks to do some similar things like this:
def hello
puts "Hello"
yield if block_given?
end
hello do
puts "cruel world"
end
As others have said, def isn't a method, it's a keyword. You can't "override" it. You can, however, define a method called "def" via Ruby metaprogramming magic:
define_method :def do
puts "this is a bad idea"
end
This still won't override the def keyword, but you can call your new method with method(:def).call.
So, there you (sort of) have it.
Note: I have no idea why you'd ever want to define a method called def. Don't do it.