I've just started programming in Ruby and i'm trying to work on a little debug switch that works similar as to below, similar to a C extern variable. My problem is, Im not sure how to have a variable in one file in module X of one file, and access it in the same module of another file.
I'd prefer to not use global variables as they are not limited by scope - is there a scope wide variable I can do this with?
(note, this is std ruby 2.0.0 - NOT rails!)
Cheers,
Chris
#file A.rb
module foo
##myVariable = 'ruby'
##do something
end #end foo
#file B.rb
module foo
module self.bar(x)
if(##myVariable == 'ruby')
puts 'do a barrel roll'
end
end #end bar
##do something
end #end foo
undefined variable ##myVariable
In order for file A to affect the code in file B, B needs to require A.
A.rb
module Foo
##x = 1
end
B.rb
require './A'
module Foo
def self.bar
##x
end
end
p Foo.bar
# 1
Try this:
# file_a.rb
module Foo
BARREL_ROLL = true
end
# file_b.rb
require_relative 'file_a'
module Bar
if Foo::BARREL_ROLL == true
puts 'do a barrel roll'
end
end
Notes:
##myVariable is a class variable and typically not recommended to use, try to refrain from using it.
I understand you are just starting out Ruby, perhaps checking out the style guide may help you improve to a more Rubyesque way of doing things; your code seems to be influenced by your previous language's style. Following the guide will make your code more readable for most in the community and soon for yourself.
Related
Consider the following code in two files:
create_object.rb
def create_object
method = 'new'
Object.send(method)
end
debug.rb
require_relative './create_object'
def foo
object = create_object
bar(object)
end
def bar(object)
# history_of_life - some method that returns object info
puts object.history_of_life
end
foo
Run ruby debug.rb. I expect history_of_life method returns something like this:
<Object:0x007f874b083430> initialized in create_object.rb:3
Are there tools like pry-stacktrace to determine the place in the code where the Object was initialized?
It’s obviously off by default due to enormous footprint, but one might achieve more-or-less desired behaviour with ObjectSpace#allocation_class_path.
In general, ObjectSpace tweaks are your friends in tasks like this one on the top (ruby) abstraction level.
ObjectSpace.allocation_sourcefile returns the source file origin from the given object. Thanks for Aleksei Matiushkin advice.
debug.rb
require 'objspace'
require_relative './create_object'
def foo
object = create_object
bar(object)
end
def bar(object)
puts ObjectSpace.allocation_sourcefile(object)
end
ObjectSpace.trace_object_allocations do
foo
end
output
/home/user/pro/test/create_object.rb
I have a file foo.rb that has the following:
class Foo
def do_stuff
puts "Doing stuff"
end
def do_other_stuff
puts "Doing other stuff"
end
end
f = Foo.new
f.do_stuff
I want require this file in another file bar.rb and access to the methods in the Foo class without executing the instructions in foo.rb.
Expecting to output just:
Doing other stuff
I tried the following in bar.rb:
require 'foo'
f = Foo.new
f.do_other_stuff
However, requiring the file executes the code of foo.rb, and my output is this:
Doing stuff
Doing other stuff
Is there a good way to get around this execution?
requiring a file will execute the code. I think its a bad design, what you are trying to achieve. However you can still circumvent it by putting the code in if __FILE__ == $0 block:
if __FILE__ == $0
f = Foo.new
f.do_stuff
end
if __FILE__ == $0 will make sure the code inside the block is executed only when run directly and not when required, as in your example.
If you just want to block the outputs, do something like this:
stdout_old = $stdout.dup
stderr_old = $stderr.dup
$stderr.reopen(IO::NULL)
$stdout.reopen(IO::NULL)
require "foo"
$stdout.flush
$stderr.flush
$stdout.reopen(stdout_old)
$stderr.reopen(stderr_old)
I want require this file in another file bar.rb and access to the methods in the Foo class without executing the instructions in foo.rb.
Since the methods in the Foo class are defined by executing the instructions in foo.rb, this is obviously non-sensical and impossible: either you want Foo, then you have to execute the instructions, or you don't execute the instructions, but then you don't get Foo.
I have a hierarchy like
ABC(Folder) ----> abc.rb, def.rb
DEF(Folder) ----> a1.rb, b1.rb
GHI(Folder) ----> x1.rb, y1.rb
I want to inherit/include def.rb, which is a module into abc.rb and then a1 should inherit abc.rb and should be able to access all methods defined in def.rb.
Right now, I am including def.rb in every script file, but I don't want to do this. I just want to inherit vertically.
It's hard to deal with ABC-like naming system )
If you want to include 10 modules in each of your classes, you can do it this way. Let's imagine you have modules ModuleTest::Files and ModuleTest::Network:
in module_test/network.rb
module ModuleTest
module Network
def network
puts 'hello from ModuleTest::Network#network'
end
end
end
in module_test/files.rb
module ModuleTest
module Files
def files
puts 'hello from ModuleTest::Files#files'
end
end
end
You can make some ModuleTest::Base class like this:
require 'module_test/files'
require 'module_test/network'
module ModuleTest
class Base
include Files
include Network
end
end
This class includes all the functionality you have, so inherit your classes from it:
require 'module_test/base'
class Foo < ModuleTest::Base
end
foo = Foo.new
foo.network
foo.files
Output:
>ruby -I. foo.rb
hello from ModuleTest::Network#network
hello from ModuleTest::Files#files
Let my first point out that I suspect that I'm misinterpreting your question, because I can't see why you'd want to do this. So if that's the case, please point it out and I'll delete this.
The process you describe works (at least for me in Ruby 1.9.3).
module Def
def method_from_def
puts "Method from Def"
end
end
class Abc
include Abc
end
class X < Abc
end
X.new.method_from_def #=> "Method from Def"
You might need to be a little specific in your require statements, but if you're already able to 'include' the script you've already got that down. (Unless by 'include' you mean copy and paste it into the source file.)
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
I'm doing some metaprogramming in Ruby, and I need to dynamically generate a sibling class inside of a module. In doing so, I want to call const_set on the module, but I don't know which Module constant to call that on until runtime. An example:
Given classes
Foo::Bar::Baz
Foo::Quox::Quack
I want to be able to call a function like this (oversimplified here):
def generate_from klass
mod = klass.enclosing_module # <- THIS LINE is the one I need to figure out
mod.const_set("GeneratedClassName", Class.new)
end
and what I want to end up with, when calling with Baz, is a new class defined as
Foo::Bar::GeneratedClassName
and with a Quack, I want
Foo::Quox::GeneratedClassName
The only way I know of is to split up klass.name, then repeatedly call const_get on those strings, constantized. Does anyone know of a more elegant way?
This should get you on track:
module Foo
module Bar
class Baz
def initialize
#nesting = Module.nesting
end
def enclosing_module
#nesting.last
end
end
end
end
puts Foo::Bar::Baz.new.enclosing_module #=> Foo
Relevant documentation:
http://ruby-doc.org/core/classes/Module.html#M000441
Got it.
ActiveSupport has this Ruby extension, Module#parent. It's good enough for my use.
In Rails you can use a combination of deconstantize and constantize.
'Foo::Bar::Baz'.deconstantize.constantize # => Foo::Bar
so in a method of the class it can be used like this:
self.class.name.deconstantize.constantize
In case anyone is looking for a pure ruby version:
def get_parent_type
#Note: This will break for base types (lacking '::' in the name)
parent_type=self.class.name.split('::')[0...-1]
begin
Object.const_get(parent_type.join('::'))
rescue NameError => e
nil
end
end