Make module method available without scoping - ruby

I am trying to do something very similar to rspec's describe.
Say I have a module in my_mod.rb
module MyMod
def say_hello(name)
puts "hello #{name}"
end
end
And I use it in another file foo.rb
include MyMod # without the include it cannot find say_hello
say_hello "world"
My question is - how do I get this to work like rspec, i.e. require-ing the module should make the methods available, without having to do MyMod.say_hello.

Change your original foo.rb, replacing include with extend.
This way, you can use say_hello "world"
But, if you really want to use require, define the method without the module:
my_mod.rb:
def say_hello(name)
puts "hello #{name}"
end
then, in foo.rb:
require 'my_mod'
say_hello "world"

Related

How do I require a file without defining it's constants on Object in Ruby?

I would like to require a file in Ruby without defining that file's constants on Object. Instead I would like to include them only in a module in the requiring file. For instance if I have a file foo.rb that looks like this:
module Foo
def self.hello_world
puts 'Hello, World.'
end
end
A representation of the result I hope to achieve looks something like this:
module Bar
require_relative './foo.rb'
end
Foo.hello_world
# NameError: uninitialized constant Foo
Bar::Foo.hello_world
# Hello, World.
It seems like the way things are required in Ruby, anything defined at the top level of another file will be defined as a constant on Object and thus globally available. I'm having a problem because I need something from a file that conflicts with a constant in the global namespace.
I recognize that this problem may be fundamental to Ruby, but is it possible there's some metaprogramming technique to overcome this issue?
It looks like the following snippet works for what I'm trying to do:
module Bar
class_eval File.open('./foo.rb').read
end
It may be that I'm still missing something though.
If you don't need to access the ancestor, what you're looking for is extend
module Foo
def hello_world
puts 'Hello, World.'
end
end
module Bar
extend Foo
end
Bar.hello_world

Make Sinatra Helpers Available in Modules everywhere?

How can I make my Sinatra helpers available everywhere?
Sometimes I can't access them (e.g. from modules, see below). I'd like them to be tied to the 'global namespace' s.t. they can be invoked by their name, from anywhere.
Below is a working Sinatra app demonstrating the problem.
require 'sinatra'
helpers do
def bar
"bar"
end
end
get '/helper' do
bar #works
end
get '/module_and_helper' do
Foo.foo #crashes. How can I fix this?
end
module Foo
extend self
def foo
bar
end
end
Thanks!
Thanks to #engineersmnky. Instead of using 'helpers do' you can define a separate Module and include it in the app, apparently rendering it available everywhere.
require 'sinatra'
module Helpers
extend self
def barrio
"barrio"
end
end
include Helpers
get '/helper' do
barrio #works
end
get '/module_and_helper' do
Foo.foo #works!
end
module Foo
extend self
def foo
barrio
end
end

Using mixins during code parsing in Ruby

I want my Configurable module to include a config command to whatever app includes it.
edit: see the update on my reasoning a little further down
I get that error:
cli.rb:2:in '<module:Configurable>': undefined method 'desc' for Configurable:Module (NoMethodError)
I want to do the following in a commandline:
$ app something
> I did something!
$ app config
> You configured the app!
> I did something!
So here's the code:
# app.rb
require 'thor'
require_relative './cli'
class App < Thor
include Configurable
# def initialize ...
desc "something", "The Cli app does something"
def something
puts "I did something!"
end
end
# cli.rb
module Configurable
desc 'config', "You can configure the app"
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
end
As the above points out, when I comment out the desc 'config' .. line, it builds and runs, although Thor doesn't add the config command.
Thanks for your help!
UPDATE
I downloaded Thor's repo, and added traces when it encountered a desc command. So I tried calling Thor.desc instead, and I could see that it was loaded in Thor's system, but still didn't appear in commands list. So I played around and ended up with the following:
module Configurable
Thor.desc 'config', 'You can configure the app'
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
def self.included(klass)
puts "The module was included"
klass.desc "another", "another one"
end
def another
puts "Another!"
end
end
This way, I tested if calling desc before or after made a difference, but it didn't.
At this point, I would say it's Thor's limitations, and I can't achieve what I want with Thor and mixins.
desc is a method of Thor's singleton class, but Configurable isn't an instance of Thor's singleton class. (Obviously.) That's why you can't call desc without a receiver, you will have to call it explicitly:
(Note: I don't have Thor, therefore, I cannot test this. It may or may not work.)
module Configurable
Thor.desc 'config', 'You can configure the app'
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
end

In Ruby, is there a library to make command line scripts more user friendly, prompting me what to run?

So what I do now is my Ruby scripts have a bunch of methods, and I have to comment out which method calls I don't want to call, and un-comment the one I want to fire in my command line script.
Is there a Ruby library that makes it easy to prompt the user to which function to fire?
If you want code that will selectively execute a particular method in a source file, you'll need to write a dispatch table to take the input and call whichever routine is desired.
It's all pretty standard stuff for a programmer and easily done with OptionParser and some creative use of case/when statements.
You can use ARGV to iterate over your program's arguments. There is also Getopt::Declare, which is a library for dealing with command line arguments in a similar fashion to traditional Unix utilities.
If you need something that would really prompt user during the execution of the script, you can wrap the methods you need to prompt about:
module Confirmable
def confirm_first *methods
methods.each do |meth|
alias_method "orig_#{meth}", meth
define_method meth do |*args, &block|
print "Execute #{meth}?[Yn] "
s = gets.chomp
return if s.downcase == 'n'
send "orig_#{meth}", *args, &block
end
end
end
end
class MyClass
extend Confirmable
def foo arg
puts "starting foo"
puts arg
end
confirm_first :foo
end
c = MyClass.new
c.foo "bar"
This way, each method that you mark with confirm_first will first ask you for confirmation before actually executing.

Including the same module file within itself in Ruby?

I am learning ruby and about modules and mixins..
I tried the following code. The name of the ruby file test.rb.
module Mod1
def Mod1.sayHello()
puts "Hello Mod1"
end
end
module Mod2
def Mod2.sayHello()
puts "Hello Mod2"
end
end
class TestMod
require 'file'
Mod1.sayHello
end
t = TestMod.new
I am suprised to the output:
Hello Mod1
Hello Mod1 (twice)
I am don't have an explanation for this, can somebody help?
You did not define your initialize method for your class (the constructor). You are simply executing Mod1.sayHello inside the class definition (it is even executed before creating the instance). Try to comment out your t = TestMod.new statement. The output will still stay visible.
Since you include the exact same file, this ends up being executed twice (the file does not get included another time afterwards; ruby prevents this). The class should look like this:
class TestMod
def initialize
Mod1.sayHello
end
end
Why did you include the file anyway? This does not make sense to me.
EDIT: Removed a mistake.
I would recommend to replace the Mod1 and Mod2 inside your module definitions with self. This way you wont have to change the name everywhere if it changes some time.

Resources