4

Hey I am currently working on a project that integrates Spree and Refinery. Spree suggests that many modifications are done using what they call decorators:

Refinery::Page.class_eval do

  def autocomplete_label
    title
  end

  attr_accessible :spree_taxon_id
  has_one :spree_taxon

end

This works fine. But what is the difference between just opening up the class and adding the methods directly?

class Refinery::Page

  def autocomplete_label
    title
  end

  attr_accessible :spree_taxon_id
  has_one :spree_taxon

end

I can understand that the first can be used when the class is not known until runtime (which is not needed for this use case). Are there any other differences?

Nick
  • 2,715
  • 4
  • 24
  • 35
  • This might get you some idea : http://stackoverflow.com/questions/5391541/whats-the-difference-between-class-eval-and-class-classname – Subodh Dec 06 '12 at 09:13
  • Using `class_eval` allows you to access local variables of the enclosing scope - though that also doesn't seem necessary for this usage. – sepp2k Dec 06 '12 at 14:55

2 Answers2

2

The only difference I can think of is that the first version will cause it to autoload the existing Page class and then your code would get added after it had loaded. If the class hasn't yet been loaded, and you use the second version, it would likely interfere with the autoload behavior that Spree and Refinery are expecting, and the class may not get loaded correctly.

Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • So essentially the first will ensure that the standard class definition is loaded first. Whereas the other could be called before the standard class definition and would then be overridden by the 'original'. – Nick Dec 06 '12 at 13:25
  • Yup, at least that's the behavior I saw when playing with a Rails model in the console. – Peter Brown Dec 06 '12 at 13:40
  • @Nick I don't think there's a danger of it being overridden by the original so much as the original not being loaded at all (because there already is a class `Refinery::Page`, so the autoload system never sees a need to go looking for it somehwere else). – sepp2k Dec 06 '12 at 15:11
  • Yea sorry, @sepp2k is correct. I was only talking about the first part where it ensures the existing class was loaded first. It will not even load the existing one if you use `class Refinery::Page`. – Peter Brown Dec 06 '12 at 16:39
0

If you use the class decorator pattern suggested by Spree then your changes will live through an upgrade of the Gem. If you instead choose to add your methods directly to the class definition then they will be lost the moment you update your gems.

Simon Thordal
  • 893
  • 10
  • 28