class_eval and open classes
Asked Answered
J

3

12

I am using Spree, and Spree has a class called Order that looks like:

module Spree
  class Order
    # class definition.
  end
end

In my own app, I have been customising Order like so:

Spree::Order.class_eval do
  # customisations
end

My question is, can I simply just do this:

module Spree
  class Order
    # My own customisations.
  end
end

Any downsides to this? Essentially, I want to avoid using class_eval.

Johnsen answered 10/3, 2014 at 2:42 Comment(3)
hey.. did you find a solution to this? I'm now just getting started with spree, and need to add a constant to the Spree::Order class. using class_eval somehow isn't working for constants, and without class_eval, I can't figure out how to access other methods in the class that I am reopening.Recreant
Try using @@some_constant. Not a Spree issue, but a general Ruby weirdness.Johnsen
yep.. that's what I did and it worked. One note though, I had to require the module/class that I was opening prior to opening it. This ensured that the original class file was loaded before I opened it again to change it to avoid getting class not found errors.Recreant
C
6

Benjamin, reopen class will not inform you (but class_eval will raise error) if the existing class does not exist or not loaded.

But if you have test coverage, reopen class should be safe I guess?

See https://mcmap.net/q/295150/-how-to-understand-the-difference-between-class_eval-and-instance_eval for more detailed explanation.

Clerihew answered 10/3, 2014 at 2:52 Comment(1)
Ah good point. I'm in the process of existing class_evaled classes.Johnsen
R
0

you cant alter the class without class_eval. just try to override one method, and all other methods are gone. with class_eval you avoid it. thats the ruby way.

Roughen answered 11/3, 2014 at 17:8 Comment(5)
@raj englighten me!Roughen
How does opening a class and over riding a method remove all other methods? Can you show an example?Sallyanne
maybe you're right. can't remember. might be rails specfic. in rails you need to use class_eval, otherwise the initial class evaportaes.Roughen
The initial class would never evaporate if you reopen a class in rails. Can you show me any example resource ? I couldnt find any.Sallyanne
i don't need any resource. that's just how rails is working. might has to do with its internal cache_classes ?Roughen
I
0

There is another way to solve this problem, which works quite well in the case of Spree. I thought I'd leave this answer for others working with Spree.

You can use prepend in order to 'schedule' the class reopening at whatever time that Spree is finally loaded.

module Spree
  # Decorates Spree::Order
  module OrderDecorator
    CANCELLATION_STATES = %w[canceled pre_canceled].freeze

    def self.prepended(base)
      base.belongs_to :delivery, class_name: 'Delivery', foreign_key: 'delivery_id', optional: true
      base.scope :deliverable, lambda { }
    end
  end
end

Spree::Order.prepend Spree::OrderDecorator

If your decorator modules gets too many methods, you can and should use multiple and control the prepend order.

Spree::Order.prepend Spree::OrderDecorator
Spree::Order.prepend Admin::SpreeOrderAdminable
Ina answered 31/12, 2023 at 5:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.