DEV Community

Seiei Miyagi
Seiei Miyagi

Posted on

3 1

How to define the method for the DSL configuration file

You can define the method for the DSL configuration file1 by Refinements.

For example, the hi method in a following code can use only in this Rakefile, it shouldn't affect any code outside of the Rakefile.

# Rakefile
main = self

using Module.new {
  refine(main.singleton_class) do
    def hi
      puts :hi
    end
  end
}

desc 'hi'
task :hi do
  hi
end
Enter fullscreen mode Exit fullscreen mode
% rake hi
hi
Enter fullscreen mode Exit fullscreen mode

Common mistake 1

The following code defines the method at top level.

# Rakefile
def hi
  puts :hi
end

desc 'hi'
task :hi do
  hi
end
Enter fullscreen mode Exit fullscreen mode

Common mistake 2

The following code defines the method at top level.

# Rakefile
desc 'hi'
task :hi do
  def hi
    puts :hi
  end

  hi
end
Enter fullscreen mode Exit fullscreen mode

Common mistake 3

The following code defines the method at top level.


# Rakefile
m = Module.new do
  def hi
    puts :hi
  end
end

desc 'hi'
task :hi do
  include m
  hi
end
Enter fullscreen mode Exit fullscreen mode

Why should we avoid to define the method at top level?

It possibly breaks other libraries code.

For example:

# duck.rb
class Duck < Struct.new(:name)
  def sound
    puts 'quack'
  end
end

Enter fullscreen mode Exit fullscreen mode
# Rakefile
require_relative 'duck.rb'

def puts(*)
  print 'Hi! '
  super
end

desc 'hi'
task :hi do
  duck = Duck.new('Donald')
  puts duck.name
  duck.sound
end

Enter fullscreen mode Exit fullscreen mode
$ rake hi
Hi! Donald
Hi! quack
Enter fullscreen mode Exit fullscreen mode

The benefit of the Refinements

The ruby's Refinements are lexical in scope2.
Thus the top level method that defined by the Refinements couldn't breaks other libraries code, It's totally fine!

# Rakefile
require_relative 'duck.rb'

main = self

using Module.new {
  refine(main.singleton_class) do
    def puts(*)
      print 'Hi! '
      super
    end
  end
}

desc 'hi'
task :hi do
  duck = Duck.new('Donald')
  puts duck.name
  duck.sound
end

Enter fullscreen mode Exit fullscreen mode
$ rake hi
Hi! Donald
quack
Enter fullscreen mode Exit fullscreen mode

Other approach

Wrap the method and DSLs within a module.

# Rakefile
require_relative 'duck.rb'

Module.new {
  def puts(*)
    print 'Hi!, '
    super
  end
  extend(self)

  extend Rake::DSL

  desc 'hi'
  task :hi do
    duck = Duck.new('Donald')
    puts duck.name
    duck.sound
  end
}
Enter fullscreen mode Exit fullscreen mode
$ rake hi
Hi!, Donald
quack
Enter fullscreen mode Exit fullscreen mode

  1. e.g. Rakefile, config/routes.rb, unicorn.rb, etc... 

  2. https://docs.ruby-lang.org/en/trunk/syntax/refinements_rdoc.html#label-Scope 

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay