Issue #14344 has been updated by kddeisz (Kevin Deisz).


Just to take a real example from my current application, here's a job (from Rails ActiveJob) that I want to refine by moving the logic into the class in which it belongs. It currently looks like this:

~~~ruby
class EventEndActionsJob < ApplicationJob
  queue_as :default

  def perform(event)
    return if event.end_actions_completed?
    event.update!(end_actions_completed: true)
    activate_survey_for(event) if event.survey
  end

  private

  def activate_survey_for(event)
    event.survey.update!(active: true)

    event.rsvps.not_declined.each do |rsvp|
      EmailJob.perform_later('PostEventSurvey', rsvp)
    end
  end
end
~~~

but I want it to look like this:

~~~ ruby
class EventEndActionsJob < ApplicationJob
  refine Event do
    def perform_end_actions
      return if end_actions_completed?

      update!(end_actions_completed: true)
      activate_survey if survey
    end

    private

    def activate_survey
      survey.update!(active: true)

      rsvps.not_declined.each do |rsvp|
        EmailJob.perform_later('PostEventSurvey', rsvp)
      end
    end
  end

  queue_as :default

  def perform(event)
    event.perform_end_actions
  end
end
~~~

now all of the logic is in the right place (in the Event model) but I don't have to clutter up the class definition with a method that will only be used in this one place. I don't need to refine multiple classes, so I don't want to build a whole module, but instead right now I have to:

~~~ruby
class EventEndActionsJob < ApplicationJob
  using(
    Module.new do
      refine Event do
        def perform_end_actions
          return if end_actions_completed?

          update!(end_actions_completed: true)
          activate_survey if survey
        end

        private

        def activate_survey
          survey.update!(active: true)

          rsvps.not_declined.each do |rsvp|
            EmailJob.perform_later('PostEventSurvey', rsvp)
          end
        end
      end
    end
  )

  queue_as :default

  def perform(event)
    event.perform_end_actions
  end
end
~~~

----------------------------------------
Feature #14344: refine at class level
https://bugs.ruby-lang.org/issues/14344#change-69528

* Author: kddeisz (Kevin Deisz)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I rely on refinements a lot, but don't want to keep writing `Module.new` in code. I'm proposing `Object::refine`, which would create an anonymous module behind the scenes with equivalent functionality. So:

~~~ ruby
class Test
  using Module.new {
    refine String do
      def refined?
        true
      end
    end
  }
end
~~~

would become

~~~ ruby
class Test
  refine String do
    def refined?
      true
    end
  end
end
~~~

It's a small change, but reads a lot more clearly. Thoughts?



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>