hello ruby community I have a question (beginner) : I have a class with (as example) 3 attributes ,I want to convert the class's attribute to an array ,so I can store them into my csv file
class Human
attr_accessor :name,:Lname,:id
....
end
when I create :
human1=Human.new("nice","human",1)
I need a function that return ["nice","human",1]
is there a predefined one that I didn't find or I have to redefine to_a so it does the job
note: the class has more than 3 attribute
- is there a function to go through the object attribute or not
thanks for ur answers
CodePudding user response:
I need a function that return ["nice","human",1]
Creating such method is trivial. If it is specifically for CSV, I would name it accordingly, e.g.:
class Human
attr_accessor :name, :lname, :id
# ...
def to_csv
[name, lname, id]
end
end
To generate a CSV:
require 'csv'
human1 = Human.new("nice", "human", 1)
csv_string = CSV.generate do |csv|
csv << ['name', 'lname', 'id']
csv << human1.to_csv
end
puts csv_string
# name,lname,id
# nice,human,1
Note hat I've renamed Lname
to lname
in the above example. Uppercase is reserved for constants.
CodePudding user response:
is there a function to go through the object attribute or not?
No, there is no built in way to actually do what you want and you might be falling for a common beginner trap.
attr_accessor
does not "define attributes" since Ruby doesn't actually have properties/attributes/members like other langauges do. It defines a setter and getter method for an instance variable. Ruby doesn't keep track of which properties an object is presumed to have - only the actual instance variables which have been set.
But Ruby does provide the basic building blocks to make any kind of attributes system you want. This is very simplefied (and quite rubbish) example:
class Human
# this is a class instance variable
@attributes = []
# a class method that we use for "defining attributes"
def self.attribute(name)
attr_accessor name
@attributes << name
end
attribute(:name)
attribute(:l_name)
attribute(:id)
def initialize(**kwargs)
kwargs.each {|k,v| send("#{k}=", v) }
end
# the attributes that are defined for this class
def self.attributes
@attributes
end
# cast a human to an array
def to_a
self.class.attributes.map{ |attr| send(attr) }
end
# cast a human to an hash
def to_h
self.class.attributes.each_with_object({}) do |attr, hash|
hash[attr] = send(attr)
end
end
end
jd = Human.new(
name: 'John',
l_name: 'Doe',
id: 1
)
jd.to_a # ['John', Doe, 1]
jd.to_h # {:name=>"John", :l_name=>"Doe", :id=>1}
Here we are creating a class method attribute
that adds the names of the "attributes" to a class instance variable as they are declared. Thus the class "knows" what attributes it has. It then uses attr_accessor to create the setter and getter as usual.
When we are "extracting" the attributes (to_a
and to_h
) we use the list we have defined in the class to call each corresponding setter.
Usually this kind functionality would go into a module or a base class and not the actual classes that represent your buisness logic. For example Rails provides this kind of functionality through ActiveModel::Attributes
and ActiveRecord::Attributes
.