# Ruby - Methods with same structure in a DRY manner

Let's say that I have the following methods

def name(value)
if value
attribute['name'] = value
end

return attribute['name']
end

def surname(value)
if value
attribute['surname'] = value
end

return attribute['surname']
end

def age(value)
if value
attribute['age'] = value
end

return attribute['age']
end

def gender(value)
if value
attribute['gender'] = value
end

return attribute['gender']
end


As you see the structure is incredible similar. Im just defining getters and setters.

How could this be done in a more DRY manner?

• Yeah, I know I could create a different signature for the methods. But I would like to be able to implement the methods in this way as well. – Enrique Moreno Tent Nov 25 '16 at 11:27
• What is attribute, where is initialized? why is it singular? Please, show more code – tokland Nov 26 '16 at 15:04
• It is just some fake code I created. The point I am trying to make is how to create methods dynamically, that look very alike. – Enrique Moreno Tent Nov 26 '16 at 17:24
• Fix indentation (2 spaces), use attribute accessors, don't use explicit returns on last line of method. If you are looking for help on metaprogramming, why not try StackOverflow? You are not asking for a review, you are asking for a solution. Go to SO. – Damien Roche Nov 28 '16 at 17:14
• getters and setters are normally used for attributes of a class, these are already as DRY as it gets. there is nothing to be done better with these. – Malachi Nov 28 '16 at 18:42

In order to define accessors dynamically, I would use methods like #attribute_name for the getter and #attribute_name=(value) to be able to set values to nil or false (which your code prevents). Plus your API won't be confusing to other rubyists (typing foo_instance.name(nil) in order to get a value isn't really the Ruby Way).

class Foo
attr_accessor :foo, :bar, :baz
end


Now, if you need to do something else entirely and define multiple methods with the same body, I would recommend using Class#define_method

class Foo
def initialize(attributes = {})
@attributes = attributes
end

%w(foo bar baz).each do |name|
define_method name do
@attributes[name] # consider using Hash#fetch here
end

define_method "#{name}=" do |value|
@attributes[name] = value
end
end
end


For the sake of completeness, here's my answer without changing anything to the original code behavior :

%w(name surname age gender).each do |attribute_name|
define_method attribute_name do |value|
attribute[attribute_name] = value if value
attribute[attribute_name]
end
end

class Foo
[:foo, :bar, :baz].each do |method_name|
defin_method(method_name) do |value|
if value
attribute[method_name.to_s] = value
end

return attribute[method_name.to_s]
end
end
end


This is one way to define dynamic fields. Check that the array [:foo, :bar, :baz] can comes from some complex function, not just an static array.

Another way is using method_missing

class Foo
def get_methods
# some complex code here that returns an array like [:foo, :bar, :baz]
end

def method_missing(method, *args, &block)
if get_methods.include? method
else
super
end
end
end


The second way is more dynamic, because can changes after initialize the class. The first example only changes at beginning, but the second is on the fly.

Check this.

We can write function as follows

def attribute(key, value=nil)
value && (attribute[key] = value)
end


Using above method you can make structure DRY and dynamic. You can avoid if condition by using guard clause &&

• Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and how it improves upon the original) so that the author can learn from your thought process. – jacwah Nov 25 '16 at 12:28