4

Suppose I have a class Article, such that:

class Article

  attr_accessor :title, :author

  def initialize(title, author)
    @title = title
    @author= author
  end

end

Also, variable atrib is a String containing the name of an attribute. How could I turn this string into a variable to use as a getter?

a = Article.new
atrib='title'
puts a.eval(atrib)     # <---- I want to do this

EXTENDED

Suppose I now have an Array of articles, and I want to sort them by title. Is there a way to do the compact version using & as in:

col = Article[0..10]
sorted_one = col.sort_by{|a| a.try('title') }   #This works
sorted_two = col.sort_by(&:try('title'))   #This does not work
5
  • 6
    have you tried a.send(atrib.to_sym) Commented Oct 31, 2013 at 15:11
  • 1
    to_sym is not actually required a string is acceptable as well so you could call a.send(atrib) Commented Oct 31, 2013 at 15:18
  • why not a.title.. ? Commented Oct 31, 2013 at 15:19
  • @ArupRakshit I reduced it to a simple example. The tricky thing is that I've got the attribute name stored into a string. Commented Oct 31, 2013 at 15:20
  • is your class an ActiveRecord? Commented Oct 31, 2013 at 16:15

2 Answers 2

6

You can use either send or instance_variable_get:

a = Article.new 'Asdf', 'Coco'
a.pubic_send(:title) # (Recommended) Tries to call a public method named 'title'. Can raise NoMethodError
=> "Asdf"
# If at rails like your case:
a.try :title # Tries to call 'title' method, returns `nil` if the receiver is `nil` or it does not respond to method 'title'
=> "Asdf"
a.send(:title) # Same, but will work even if the method is private/protected
=> "Asdf"
a.instance_variable_get :@title # Looks for an instance variable, returns nil if one doesn't exist
=> "Asdf"

Shot answer to your extended question: no. The &:symbol shortcut for procs relies on Symbol#to_proc method. So to enable that behavior you'd need to redifine that method on the Symbol class:

class Symbol
  def to_proc  
    ->(x) { x.instance_eval(self.to_s) }    
  end  
end

[1,2,3].map(&:"to_s.to_i * 10")
=> [10, 20, 30]
Sign up to request clarification or add additional context in comments.

5 Comments

Or .try, which would be a more graceful way.
@pduersteler great insight! only applying to Rails though
@nicooga Please see updated post, for a subquestion of the initial question.
what is the difference of these three different methods?
@nicooga thanks for the answer to the extended part! I see why now
1

ActiveRecord instances have an attributes hash:

a = Article.new(title: 'foo')
#=> <#Article id: nil, title: "foo">

atrib = 'title'
a.attributes[atrib]
#=> "foo"

You can use order to get sorted objects from your database:

Article.order('title').first(10)
#=> array of first 10 articles ordered by title

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.