Benjamin Tan Wei Hao
Benjamin Tan Wei Hao

Reputation: 9691

class_eval and open classes

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.

Upvotes: 13

Views: 1530

Answers (3)

New Alexandria
New Alexandria

Reputation: 7324

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

Upvotes: 0

Huiming Teo
Huiming Teo

Reputation: 393

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://stackoverflow.com/a/900508/474597 for more detailed explanation.

Upvotes: 6

Tim Kretschmer
Tim Kretschmer

Reputation: 2280

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.

Upvotes: -1

Related Questions