Is there any way Ruby can remove template code in initializers?

I write a lot of initialize code that sets parameter attributes similar to this:

  class SiteClient attr_reader :login, :password, :domain def initialize(login, password, domain='somedefaultsite.com') @login = login @password = password @domain = domain end end 

Is there another Ruby way to do this? It seems to me that I am writing the same template customization code again and again.

+5
source share
4 answers

You can use Ruby Struct :

 class MyClass < Struct.new(:login, :password, :domain) end 

Or you can try some gems for this, i.e. Virtus :

 class MyClass include Virtus.model attribute :login, String attribute :password, String attribute :domain, String end 

And then (in both cases):

 MyClass.new(login: 'a', password: 'b', domain: 'c') 
+8
source

You can do a little better:

 def initialize(login, password, site = 'somedefaultsite.com') @login, @password, @domain = login, password, domain end 

and if you don't have an optional argument, you can be a little more lazy:

 def initialize(*a) @login, @password, @domain = a end 
+2
source

There is a gem of fattr that you can include in your Ruby or gem application to do just that.

 require 'fattr' class SiteClient fattr :login fattr :password fattr :domain => 'somedefaultsite.com' def initialize(**attributes) attributes.each do |k, v| public_send k, v end end end client = SiteClient.new client.username = 'susan' client.password = 'anything' another_client = SiteClient.new username: 'bob', password: ' p@ssword1 ' 

In this example, the fattr method fattr define read and write methods for each attribute. In addition, it can assign a default value to each attribute. The initializer is configured to accept a hash of the key pairs that it will iterate over to fill in the attributes by calling the attribute method with the value to be assigned.

Something to be aware of is an example that generates both read and write methods for your attributes. In your question you are only using attr_reader , so this may not be exactly what you need if you want your class data to be immutable. There may be a way to configure fattr , but I haven't played with that yet, that's not all.

Special thanks to Avdi Grimm and episode 276 of RubyTapas , in which I learned about this.

+2
source

In this DAS screencast , Gary Bernhardt looks at several metaprogramming tricks that can shorten the syntax of common class constructs, one of which is the type of initialization method that you describe. He linked it to a stone that will make your code look something like this:

 class SiteClient extend Cls takes :login, :password, :domain attr_reader :login, :password, :domain end 

If you like the little monkey fixes, you can also implement the takes method, as you did in screencast

 class Module def takes(*names) define_method(:initialize) do |*values| names.zip(values).each do |name, value| instance_variable_set(:"@#{name}", value) end end end end 

Retrieves the need for an extend Cls string from the above example.

0
source

Source: https://habr.com/ru/post/1212484/


All Articles