How to make callable attribute in Ruby - ruby

I do not know how to google it, but i know what i want.
i want to make something like this
class SchedulingManager
attr_accessor :on_start
def call
on_start
end
end
scheduling = SchedulingManager.new
scheduling.on_start do
puts "hello"
end
so i want my on_start here to be initiate by do block style. and save it so i can call in method call and print hello (or do whatever code in the block).
i do not know what the name of it, i also do not know how to google it.
Kindly need your help guys, thanks

I would do it like this and store the block in a variable.
class SchedulingManager
def on_start(&block)
#block = block
end
def call
#block&.call
end
end
scheduling = SchedulingManager.new
scheduling.on_start do
puts "hello"
end
scheduling.call
#=> hello

Related

caller_method returns not the value, that i expected

I want to know, what method calls another method (I'm just trying to create simple expect("string").to eq("string") model (just like in RSpect, but more easier).
But i get "main", what is that? (I see that "main" for first time)
public
def expect(message)
message.to_s
end
def to
caller_method = caller_locations.first.label
puts caller_method
end
expect("test").to #=> <main>
#what output i expected:
expect("test").to #=> expect
My goal:
#first i need to do something like that:
expect("test").to eq("test") #=> true
#final must look like this:
expect(expect("test").to eq("test")).to eq(true) #=> true
I would recommend against using caller_method in this case. Rather, make a class whose methods return self - that way they will be chainable:
module Expectation
attr_accessor :caller_method
def expect(arg)
self.caller_method = "expect"
self
end
def to
caller_method
end
end
include Expectation
expect("foo").to
# => "expect"
Obviously this is only a starting point, and this doesn't actually do any comparisons / validations yet. But hopefully you can understand this pattern. The key thing is returning self to make a chainable API, and storing internal state using something like attr_accessor

Make methods dynamic in ruby

Define a class as follows. I want to call one_method dynamically. By default, wow.one_method calls the first one_method. If I want to change the behavior of the method, just call redefine.
I can implement the method as a function type property, but that is not what I want.
If I use the following code directly, it would report errors. Could you modify it slightly.
class Wow
def one_method
puts "hello Ruby"
end
def redefine(what="none")
define_method :one_method do
puts what
end
end
end
wow = Wow.new
wow.redefine("Whatever I want.")
You can achieve that via class_eval or instance_eval:
class Wow
def one_method
puts "hello Ruby"
end
def redefine(what="none")
self.class.class_eval do
define_method :one_method do
puts what
end
end
end
end
wow = Wow.new
wow.one_method #=> hello Ruby
wow.redefine("Whatever I want.")
wow.one_method #=> Whatever I want.
Reason is that define_method defines instance method on the receiver and is a class's instance method so you'll have to call it on the eigen class of the object that you want to redefine a method on.
I would recommend achieving your goal in a more canonical way, just redefine the method on the instance itself:
class Wow
def one
:one
end
end
w = Wow.new
w.one
#=> :one
def w.one
:two
end
w.one
#=> :two
Drawbacks are:
your methods lookup table caches will be dropped
the code is becoming more obscure and hard to debug
Alternatives:
I don't know your real problem, but for your particular question it is better to parameterize your one_method method just to receive an argument for puts. Also, you can pass a block, so you will receive more grained control over the behavior.

error during wrapping the ruby code into a class

I am an RoR newbie. I have created a small application in ruby which has small functions to execute the code.
e.g.
def abc(xyz)
some code
end
def ghi(xyz)
some code
end
def jkl(output)
some code
end
xyz = abc[ARGV(0)]
output = ghi(xyz)
puts jkl(output)
Now, when I run this code in command prompt using ruby .rb, it executes nicely and returns the desired results. But when I try to create a class and add this whole code to it e.g.
class Foo
def abc(xyz)
some code
end
def ghi(xyz)
some code
end
def jkl(output)
some code
end
xyz = abc[ARGV(0)]
output = ghi(xyz)
puts jkl(output)
end
It generates the error like "undefined method 'abc' for Foo:Class (NoMethodError)"
All I want to ask is that how shall I add this code to a class so that it can become more pluggable and get the desired results.
Thanks in advance.
As this is written, these are all instance methods. You need to make them class methods like these two examples, or you could leave them as is and create an instance of the class. Either way, you should probably move the last three statements outside the class definition.
class Foo
class << self
def abc(xyz)
some code
end
def ghi(xyz)
some code
end
def jkl(output)
some code
end
end
end
xyz = Foo.abc('something')
output = Foo.ghi(xyz)
puts Foo.jkl(output)
OR....
class Foo
def self.abc(xyz)
some code
end
def self.ghi(xyz)
some code
end
def self.jkl(output)
some code
end
end
xyz = Foo.abc('something')
output = Foo.ghi(xyz)
puts Foo.jkl(output)
EDIT: To answer your question in the comments, this is how you would instantiate the class and call using instance methods.
class Foo
def abc(xyz)
some code
end
def ghi(xyz)
some code
end
def jkl(output)
some code
end
end
bar = Foo.new
xyz = bar.abc('something')
output = bar.ghi(xyz)
puts bar.jkl(output)
If you don't have any Ruby learning materials yet, you might want to check out Chris Pine's tutorial, which includes a section on classes and how they work. As for books, here is a great book for Ruby in general and here is a question regarding books for Rails. I would suggest getting a decent grasp of Ruby before getting too deep into Rails.

Accessing variables using overloading brackets [] in Ruby

Hi i want to do the following. I simply want to overload the [] method in order to access the instance variables... I know, it doesn't make great sense at all, but i want to do this for some strange reason :P
It will be something like this...
class Wata
attr_accessor :nombre, :edad
def initialize(n,e)
#nombre = n
#edad = e
end
def [](iv)
self.iv
end
end
juan = Wata.new('juan',123)
puts juan['nombre']
But this throw the following error:
overload.rb:11:in `[]': undefined method 'iv' for # (NoMethodError)
How can i do that?
EDIT
I have found also this solution:
def [](iv)
eval("self."+iv)
end
Variables and messages live in a different namespace. In order to send the variable as a message, you'd need to define it as either:
def [](iv)
send iv
end
(if you want to get it through an accessor)
or
def [](iv)
instance_variable_get "##{iv}"
end
(if you want to access the ivar directly)
try instance_variable_get instead:
def [](iv)
instance_variable_get("##{iv}")
end

Ruby access to symbol "invoked by"

I want to (efficiently) get the symbol an aliased method is called with at runtime. A direct efficient access to a stack frame object of some sort to get it would be the fantasy.
ie:
class Foo
def generic_call(*args)
puts("generic_call() was called by using #{???}")
end
alias :specific_call1 :generic_call
alias :specific_call2 :generic_call
end
Foo.new.specific_call1
Foo.new.specific_call2
the result I'd want
generic_call() was called by using specific_call1()
generic_call() was called by using specific_call2()
class Foo
def generic_call()
puts "generic call was called by #{caller[0][/in `([^']+)'/, 1]}"
end
def specific_call1() generic_call end
def specific_call2() generic_call end
end
Foo.new.specific_call2 # Prints: generic call was called by specific_call2
This will however not work if you use alias to create specific_callN from generic_call because methods created by alias are actually a copy of the original method - they don't actually call the original method (which is why you can freely redefine the original without affecting the alias).
A code snippet to get the current method name:
module Kernel
private
# Defined in ruby 1.9
unless defined?(__method__)
def __method__
caller[0] =~ /`([^']*)'/ and $1
end
end
end
There's no built-in way to do this. You can kind of hack it like:
def current_method_name
caller[0].split('`').last.split('\'')[0]
end
Maybe, you want something like this?
class Object
def named_alias(name, generic_name)
([Class, Module].include?(self.class) ? self : self.class).class_eval do
define_method(name) { |*args| send(generic_name, name, *args) }
end
end
end
class Foo
def generic_call(f, *args)
puts("generic_call() was called by using #{f} with #{args}")
end
# def specific_call1(*args)
# generic_call(:specific_call1, *args)
# end
named_alias(:specific_call1, :generic_call)
named_alias(:specific_call2, :generic_call)
end
Foo.new.specific_call1
Foo.new.specific_call2
Disclaimer: I don't know Ruby, I've just Googled how one performs currying there, then adapted the code a bit.

Resources