Is there a ruby equivalent to the php __invoke magic method? - ruby

Is there an equivalent to the php __invoke method in ruby?
e.g
class Test {
public function __invoke() {
echo "invoked";
}
}
$test = new Test();
$test(); // prints invoked

Not the same exact thing but it should do the job
class Test
def self.call
puts "invoked self.call"
return new
end
def call
puts "invoked call"
end
end
t = Test.()
t.()
You can use the .() syntax on both classes and objects, since classes are objects. .() is just a shorthand for .call

Related

Difference between "def" and "static def" in Gradle

As the title, what is exactly the difference of these two defs in Groovy?
Maybe it's a documentation problem, I can't find anything...
A method declaration without static marks a method as an instance method. Whereas a declaration with static will make this method static - can be called without creating an instance of that class - see https://www.geeksforgeeks.org/static-methods-vs-instance-methods-java/
def in groovy defines a value as duck typed. The capabilities of the value are not determined by its type, they are checked at runtime. The question if you can call a method on that value is answered at runtime - see optional typing.
static def means that the method will return a duck typed value and can be called without having instance of the class.
Example:
Suppose you have these two classes:
class StaticMethodClass {
static def test(def aValue) {
if (aValue) {
return 1
}
return "0"
}
}
class InstanceMethodClass {
def test(def aValue) {
if (aValue) {
return 1
}
return "0"
}
}
You are allowed to call StaticMethodClass.test("1"), but you have to create an instance of InstanceMethodClass before you can call test - like new InstanceMethodClass().test(true).

Unit testing a method in which I am doing a dependency injection

I have a terminal app with two classes: Todo and TodoApp. The method below lives in TodoApp, I would like to unit test this method and keep it isolated in my test. Since I am doing a dependency injection within the method, how could I mock that? (#todos is an empty array in TodoApp initialize)
def add(task, day, todo = Todo)
#todos.push(todo.new(task, day))
return "#{task} was added to your todos"
end
Thanks in advance for your help.
I imagine your code looks like this.
class TodoApp
def initialize
#todos = []
end
def add(task, day, todo = Todo)
#todos.push(todo.new(task, day))
return "#{task} was added to your todos"
end
end
This is NOT injecting the empty array into the TodoApp. And, therefore you are going to have difficulty accessing it from the tests.
But, if your TodoApp object looked like this:
class TodoApp
def initialize(todos = [])
#todos = todos
end
def add(task, day, todo = Todo)
#todos.push(todo.new(task, day))
return "#{task} was added to your todos"
end
end
Now you are injecting something into TodoApp that can be mocked, or even just evaluated:
describe TodoApp do
subject(:app) { described_class.new(todos) }
let(:todos) { [] }
describe '#add' do
subject(:add) { app.add(task, day) }
let(:task) { 'task' }
let(:day) { 'day' }
it 'pushes the item on the list of todos' do
expect { add }.to change { todos.length }.by(1)
end
end
end

Ruby send a method call to a block

I was wondering if you could yield a method call in Ruby. What I would like to do is the following:
do_in_thread { send_http_request(result) }
def do_in_thread
Thread.new { yield }
end
I basically want that method to be called in a Thread if the method is inside the block of the method do_in_thread().
Isn't it already doing so?
def do_in_thread
Thread.new { yield }
end
puts Thread.current.id
# 70059539355960
do_in_thread { puts Thread.current.id }
# 70059432631980

Having trouble with send and define_method

I'm trying to create a custom attr_accessor, but can't seem to get it to work. Instead of returning the value assigned to the writer, it returns the instance variable. Any ideas?
class Object
def custom_attr_accessor(klass, attribute)
ivar = "##{attribute}".to_sym
writer_body = lambda { |arg| instance_variable_set(ivar, arg) }
reader_body = lambda { ivar }
klass.send(:define_method, "#{attribute}=".to_sym, &writer_body)
klass.send(:define_method, "#{attribute}".to_sym, &reader_body)
end
end
class Person
end
custom_attr_accessor(Person, :age)
me = Person.new
me.age = 100
puts me.age
=> #age
Just like you did a instance_variable_set, you need instance_variable_get:
reader_body = lambda { instance_variable_get(ivar) }
BTW, extending Object and passing a class is not very pretty. Try to make it Persion. custom_attr_accessor(:age), that would be much more OOP.

How can I assert on initialize behaviour with RSpec?

I have a message class, which can be initialized by passing arguments into the constructor, or by passing no arguments and then setting the attributes later with accessors. There is some pre-processing going on in the setter methods of the attributes.
I've got tests which ensure the setter methods do what they're supposed to, but I can't seem to figure out a good way of testing that the initialize method actually calls the setters.
class Message
attr_accessor :body
attr_accessor :recipients
attr_accessor :options
def initialize(message=nil, recipients=nil, options=nil)
self.body = message if message
self.recipients = recipients if recipients
self.options = options if options
end
def body=(body)
#body = body.strip_html
end
def recipients=(recipients)
#recipients = []
[*recipients].each do |recipient|
self.add_recipient(recipient)
end
end
end
I would tend to test the behaviour of the initializer,
i.e. that its setup the variables how you would expect.
Not getting caught up in the actuality of how you do it, assume that the underlying accessors work, or alternatively you could set the instance variables if you wanted. Its almost a good old fashioned unit test.
e.g.
describe "initialize" do
let(:body) { "some text" }
let(:people) { ["Mr Bob","Mr Man"] }
let(:my_options) { { :opts => "are here" } }
subject { Message.new body, people, my_options }
its(:message) { should == body }
its(:recipients) { should == people }
its(:options) { should == my_options }
end

Resources