Reputation: 4867
Sorry if this is too simple. I'm looking for a way to make my ruby
code dry : I want to call a number of methods on the same instance variable @var = Model.new(param)
:
@var.method1
@var.method2
@var.method3
...
Is it possible to use the send
method to write one line of code ? Btw, is it possible to call a block on Model.new
to produce some more concise code ?
Upvotes: 3
Views: 139
Reputation: 37409
When I wrote my original answer, I missed the last sentence in your question:
Btw, is it possible to call a block on
Model.new
to produce some more concise code ?
And the answer to this question is YES. This pattern is a builder pattern, which is implemented in several gems in ruby (such as tire
).
The pattern states that the initialize
method receives a block, which is run in the context of the created object, using instance_eval
. If the block receives a parameter, the instance object is passed to it instead of changing the block's scope:
class Model
def initialize(name, &block)
@name = name
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
end
def method1
# something
end
def method2
# something
end
def method3
# something
end
end
And its usage will be something either like this:
@var = Model.new('model') do
method1
method2
method3
end
or, alternatively:
@var = Model.new('model') do |m|
m.method1
m.method2
m.method3
end
Upvotes: 0
Reputation: 37409
I believe that DRY should be used to make your code more maintainable, and more readable. I don't think it should be used to shorten the number of characters you type, or show-off your code acrobatics.
Both @Arup's and @p11y's solutions are great, within a context, but as a general rule (before knowing anything about your class or methods), I believe that writing
@var.method1
@var.method2
@var.method3
is more readable and maintainable than writing either
%i[method1 method2 method3].each(&@var.method(:send))
(you need to be fluent in advanced ruby to understand this)
or
@var.method1
.method2
.method3
(again the vanishing act is more confusing to the future reader than helpful)
Always think about who will read your code in 6 months, and what will be the clearest way for him to understand what's happening.
Upvotes: 6
Reputation: 118271
Do as below :
%i[method1 method2 method3].each { |m| @var.send(m) }
If you want to make it more short,use :
%i[method1 method2 method3].each(&@var.method(:send))
Upvotes: 3
Reputation: 54684
If you build method1
, method2
, etc. such that they return the instance itself using self
, you can build a chainable interface. For example:
class Foo
def method1
# do something
self
end
def method2
# do something
self
end
def method3
# do something
self
end
# more methods...
end
@var = Foo.new
@var.method1.method2.method3
# or if this gets too long
@var.method1
.method2
.method3
Upvotes: 5