How to include/require/load a file in ruby with instance variables - ruby

I would like to put a large variable definition in a separate file for the sake of getting it out of the way. I must be doing something wrong though, because my puts call isn't putting anything out.
my_class.rb:
class foobar
def initialize
require 'datafile.rb'
puts #fat_data
end
end
datafile.rb:
#fat_data = [1,2,3,4,5,6,7,8,9,10]
Can you use require this way?

You can do something like this:
my_class.rb:
class Foobar
def initialize
init_fat_data
puts #fat_data
end
end
datafile.rb:
class Foobar
private
def init_fat_data
#fat_data = [1,2,3,4,5,6,7,8,9,10]
end
end
Or, perhaps, change class Foobar in datafile.rb to module MyData and then include the module to Foobar class in my_class.rb.

If you just want to get the data out of the class definition, you could also use __END__ and DATA:
Useless Ruby Tricks: DATA and __END__

Related

How to require file as part of a module in Ruby?

I have a file SomethingClass.rb which looks as follows:
class SomethingClass
def initialize
puts "Hello World"
end
end
I would like to require the file SomethingClass.rb, and make SomethingClass part of the module SomethingModule without changing the file.
Also, I would like to avoid making SomethingClass part of the namespace outside of that module at all. In other words, I want to require the file and the rest of my application should not change apart from the fact that SomethingModule will be defined.
This does not work (I assume because require is executed in Kernel scope):
module SomethingModule
require './SomethingClass.rb'
end
Is this possible in Ruby?
Without changing your class file, from what I've gathered, there are only kind of hacky ways to do this - see Load Ruby gem into a user-defined namespace and How to undefine class in Ruby?.
However I think if you allow yourself to modify the class file, it is a little easier. Probably the simplest thing to do would be to set the original class name to something that will surely have no name conflict, e.g.:
class PrivateSomethingClass
def initialize
puts "Hello World"
end
end
module SomethingModule
SomethingClass = PrivateSomethingClass
end
Now you have SomethingModule::SomethingClass defined but not SomethingClass on the global namespace.
Another way to do it would be to use a factory method and anonymous class:
class SomethingClassFactory
def self.build
Class.new do
def initialize
"hello world"
end
end
end
end
module SomethingModule
SomethingClass = SomethingClassFactory.build
end

Getting the name of the calling class in Ruby

I'm trying to figure out how to get the name of the class that called a module function in a plugin-based application of mine.
caller seems to give me a file/line number, which is workable, but seems a bit hacky and not idiomatic.
Example code:
module AwesomeModule
def self.get_caller
puts #some unknown code here
end
end
class AwesomeClass
def initialize
AwesomeModule::get_caller
end
end
a = AwesomeClass.new # ideal return => "AwesomeClass"
You typically use ruby modules by including them. Try this:
module AwesomeModule
def get_caller
self.class
end
end
class AwesomeClass
include AwesomeModule
def initialize
get_caller
end
end
a = AwesomeClass.new # "AwesomeClass"
Also, note that in your question get_caller is being called on the AwesomeModule module itself, further complicating the issue.

How to access class variables in included ruby modules?

I need to know if it is possible for included ruby modules to have access to class variables. Lets say:
require 'bar'
class Foo
#i_am_important
Bar.do_stuff
end
Module Bar
def Bar.do_stuff
#i_am_important.stuff...
end
end
Is there a way to make the above working?
edit: improved example,
edit2: solved problem
I just changed my approach: Bar became a class of its own and gets "i_am_important" passed when initialized. Might not be the best solution, but works at last. Thanks for you help.
You can include module inside the class to get access like
module MyModule
##my_val = 4
end
class MyClass
include MyModule
value = ##my_val
end
Why you want to use variable across the gates of classes and module? I think there is such way:
module Bar
def do_stuff
puts im_am_important
end
end
class Foo
include Bar
def im_am_important
100
end
end
Foo.new.do_stuff # => 100
How about:
#foo.rb
#var
module My_foo
var = #var
def My_foo.my_method(var)
puts(var)
end
end
#bar.rb
require 'foo'
class Bar
extend My_foo
#important_var = "bla"
My_foo.my_method(#important_var)
end
ruby bar.rb => bla

Get a reference to the enclosing module in ruby

How do you get a reference to the enclosing module in ruby?
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{Foo.variable}" #<--this won't run, resolving Foo
# as the class instead of the module
end
end
class Foo
... # doesn't matter what's here
end
end
I ran into this question caused by naming confusion. While the names are easy enough to fix, I"m wondering what the "correct" way is to do this in ruby. If I try to run this it seems like ruby is trying to resolve Foo.variable as Foo::Foo.variable which of course fails. It seems like there should be a simple way in the language to refer to the outer module method.
You can get the outer module reference by adding the :: prefix to Foo:
::Foo.variable
In your example code:
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{::Foo.variable}"
end
end
class Foo
... # doesn't matter what's here
end
end

Add existing classes into a module

I have some existing ruby classes in a app/classes folder:
class A
...
end
class B
...
end
I'd like to group those classes in a module MyModule
I know I could do like:
module MyModule
class A
...
end
class B
...
end
end
but is there a meta programming shortcut that could do the same so I could "import" all the existing classes ?
Thanks,
Luc
module Foo
A = ::A
B = ::B
end
Foo::A.new.bar
Note that the :: prefix on a constant starts searchign the global namespace first. Like a leading / on a pathname. This allows you differentiate the global class A from the modularized constant Foo::A.
Use the const_missing hook. If the constant can't be found in the current module, try to resolve in the global namespace:
class A; end
class B; end
module M
def self.const_missing(c)
Object.const_get(c)
end
end
M::A.new
M::B.new
#Squeegy's answer already tells you what to do, but I think it is equally important to understand why that works. And it's actually pretty simple: classes in Ruby are nothing special. They are just objects like any other object that get assigned to variables just like any other variable. More precisely: they are instances of the Class class and they usually get assigned to constants (i.e. variables whose name starts with an uppercase letter).
So, just like you can alias any other object to multiple variables:
a = ''
b = a
a << 'Hello'
c = b
b << ', World!'
puts c # => Hello, World!
You can also alias classes to multiple variables:
class Foo; end
bar = Foo
p bar.new # => #<Foo:0x1d9f220>
If you want to move the classes into the namespace instead of just aliasing them, you also need to set the original variables to some other object like nil, in addition to #Squeegy's answer:
::A = nil
::B = nil
If you do want to put them in a module I don't see the point of first including them in the global namespace and then aliasing them inside the module.
I think what you want to do (although I doubt it is a good thing to do) is something like this:
file classes/g1.rb
class A1
def self.a
"a1"
end
end
class B1
def self.b
"b1"
end
end
file classes/g2.rb
class A2
def self.a
"a2"
end
end
class B2
def self.b
"b2"
end
end
file imp.rb
module MyModule
["g1.rb", "g2.rb"].each do |file|
self.class_eval open("classes/#{file}"){ |f| f.read }
end
end
puts defined? MyModule
puts defined? A1
puts defined? MyModule::A1
puts MyModule::A1.a
puts MyModule::B2.b
outputs
constant
nil
constant
a1
b2
I can think of a few disadvantages of this approach (harder to debug for one thing, and probably a bit slower to load although I am only guessing).
Why don't you just do something like this:
Dir["classes/*.rb"].each do |file|
contents = open(file) { |f| f.read }
open(file, "w") do |f|
f.puts "module MyModule\n"
contents.each { |line| f.write " #{line}" }
f.puts "\nend"
end
end
That'll fix your classes to be in your module since in ruby you can reopen a module at any time. Then just include them like you do normally.
Yes, in your module create the class and have it inherit from your outside classes.
For example,
class A
...
end
module MyModule
class NewA < A
end
end
The class MyModule::NewA will have all the attributes and methods of class A.
Then again, modules in ruby are never locked, so there is nothing stopping you just writing the class definition straight into the module.

Resources