This, will be a very strange question. And I really doubt it is possible. Some will call this stupid, and I wouldn't agree more. But it is for mere curiosity!
class MyClass
def initialize
print "Ha"
end
end
Is there a way to print the class file? I mean, create a .txt file, containing exactly the code above?
Sure. You can use the magic constant __FILE__ which contains the path to the file that you use it in:
class MyClass
def initialize
puts File.read(__FILE__)
end
end
This will print the contents of the file containing the definition of MyClass every time you create a MyClass object.
Related
In the description on the left side panel, it says,
"The demo code we're about to show you includes a fancy trick: if you want to end a Ruby statement without going to a new line, you can just type a semicolon. This is a time saver when you're writing something very short, like an empty class or method definition."
Why would we wan to make an empty class? Why wouldn't we just leave it blank?
Thanks for any clarification.
You may want a custom error class that does nothing special except use its name to convey something:
class MySpecialError < Error; end
Or you may want to start by declaring a class and then tack on your functionality later (no problem with that because ruby classes are dynamic):
class Foo; end
def Foo.frobnicate; "something" ; end
Though in ruby, you could just as well do
Foo = Class.new
(The difference is that class Foo; end won't clear an already existing Foo class, whereas with Class.new you're starting from scratch).
I have classes like this:
require 'active_support/core_ext'
class Shelf
def initialize
#books = {}
end
def book(code: code)
#books[code] if #books.has_key?(code)
#books = Book.new(code: code)
end
end
class Shelf::Book
def initialize(code: code)
#code = code
end
end
It works fine, if I write it in a file.
I want to separate classes into two files shelf.rb and shelf/book.rb, but when I write require_relative 'shelf/book' in shelf.rb then it fails because class Shelf is not defined yet.
How should I organize files and directories?
Or am I using nested class in completely wrong way?
Read this for naming convention of an *.rb file. According to it if you have a class Shelf:
class Shelf
end
then your file name should be shelf.rb, and if you have a class named: Shelf::Book, then file name book.rb should be within shelf directory(of course this is not a constraint or mandatory to have it in shelf directory, but it's a good convention to follow since any other developer would be able to locate your file book.rb easily):
class Shelf::Book
end
But, your problem is that how you require Shelf::Book, in Shelf, for that you need to call require_relative 'shelf/book' inside Shelf class definition, since Ruby will not know about Shelf being a class prior to it. Like this:
class Shelf
require_relative 'shelf/book'
end
However, if you don't want Shelf class's definition to throw error irrespective of where you use line: require_relative 'shelf/book' then change you shelf/book.rb to something like this:
class Shelf
class Book
def initialize(code: code)
#code = code
end
end
end
Because here Ruby opens up/create a class Shelf and won't throw this error:
`': uninitialized constant Shelf (NameError)
You can write another file which does not contain class definitions but which will be used tu run your program/script.
At the top of this file
require_relative 'shelf'
require_relative 'shelf/book'
#more code instructions
You don't need to require 'shelf/book' in shelf.rb
I have a module with a class variable in it
module Abc
##variable = "huhu"
def self.get_variable
##variable
end
class Hello
def hola
puts Abc.get_variable
end
end
end
a = Abc::Hello.new
a.hola
Is it possible to get ##variable inside Hello without using get_variable method? I mean something like Abc.variable would be nice. Just curious.
You cannot access ##variable directly (i.e., Abc.variable) within the scope of the Hello class in the module Abc. Why? Because, when the Ruby interpreter sees something like Abc.variable, it would think variable as class/module method of Abc.
It is important to think the Ruby way when programming in Ruby.
try this
Abc.class_variable_get(:variable)
I have some rb files, all with the same structure:
class RandomName < FooBar
end
The randomname is a random class name which changes in each rb file but all inherits from Foobar.
how i can load all randomclass from there rb files?
I think there are 2 parts to the solution:
How to dynamically instantiate a class
a. Using String#constantize from ActiveSupport
klass = "SomeNamespace::SomeClassName".constantize
klass.new
b. Use Module#const_get (which doesn't handle namespaces)
klass = const_get(:SomeClassName)
klass.new
How to detect a class name
A convention followed widely in ruby is to name the file after the class that it contains, so random_name.rb would contain the RandomName class. If you follow this convention, then you could do something like:
Dir["/path/to/directory/*.rb"].each do |file|
require file
file_name = File.basename(file.path, '.rb')
# using ActiveSupport for camelcase and constantize
file_name.camelcase.constantize.new
end
I think you should explain what you are trying to accomplish. The approach you are taking seems unconventional and there may be a much more effective way of reaching your goal without doing all this loading of files and dynamic instantiation of classes with random names.
Remember, just because ruby lets you do something, it doesn't mean it's a good idea to actually do it!
you can define a method called inherited in the FooBar class. look here
class FooBar
def self.inherited(subclass)
puts "New subclass: #{subclass}"
end
end
Every time a subclass is created, you will get it in the callback. Then you can do whatever you want with all those subclasses.
I have a similar requirement, passing a class name in as a string. One trick with require is that it doesn't have to be at the start, so I prefer to only load the class I need.
I used eval because it doesn't have any Rails dependencies (I'm writing pure Ruby code here).
The following relies on convention (that the Class is in a file of the same name), but if you do know the class and file, this approach has the advantage of not requiring every file in a directory and only dynamically loading the one you need at the time you need it.
klass = "classname"
begin
# Load the file containing the class from same directory I'm executing in
require_relative klass # Or pass a local directory like "lib/#{klass}"
# Use eval to convert that string to a Constant (also capitalize it first)
k = eval(klass.capitalize).new
rescue
# Do something if the convention fails and class cannot be instantiated.
end
k.foo # Go ahead and start doing things with your new class.
I have a curiosity question. If I have a ruby class and then I dynamically add class methods, class variables, etc. to it during execution is there anyway for me to save the altered class definition so that next time I start my application I can use it again?
There is no built-in way to do this. Marshal can't save methods. If these methods and variables are generated in some systematic way, you could save the data necessary for the class to recreate them. For example, if you have a make_special_method(purpose, value) method that defines these methods, create an array of the arguments you need to pass to these methods and read it in when you want to reconstitute the state of the class.
Depending on what exactly you mean, there are a couple of ways to go about this.
The simplest case is the one where you've added variables or methods to an already-existing class, as in this example:
class String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
Here we've added the rot13 method to class String. As soon as this code is run, every String everywhere in your program will be able to #rot13. Thus, if you have some code that needs rot13-capable strings, you just ensure that the code above is run before the code in question, e.g. by putting the rot13 code in a file someplace and require()ing it. Very easy!
But maybe you've added a class variable to a class, and you want to preserve not just its existence but its value, as in:
class String
##number_of_tr_calls_made = 0
# Fix up #tr so that it increments ##number_of_tr_calls_made
end
Now if you want to save the value of ##number_of_tr_calls_made, you can do so in the same way you would with any other serializable Ruby value: via the Marshal library. Also easy!
But something in the way you phrased your question makes me suspect that you're doing something like this:
greeting = "Hello"
class <<greeting
def rot13
return self.tr('a-z', 'n-za-m')
end
end
encrypted_greeting = greeting.rot13
This is very different from what we did in the first example. That piece of code gave every String in your program the power to rot13 itself. This code grants that power to only the object referred to by the name 'greeting'. Internally, Ruby does this by creating an anonymous Singleton subclass of String, adding the rot13 method to it, and changing greeting's class to that anonymous subclass.
The problem here is that Singletons can't be Marshal'd (to see why, try to figure out how to maintain the Singleton invariant when any call to Marshal.load can generate copies of extant Singleton objects). Now greeting has a Singleton in its inheritance hierarchy, so if you want to save and load it you are hosed. Make a subclass instead:
class HighlySecurableString < String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
greeting = HighlySecurableString.new("hello")
Simply marshalling the object (as others have said) wont work. Lets look at an example. Consider this class:
class Extras
attr_accessor :contents
def test
puts "This instance of Extras is OK. Contents is: " + #contents.to_s
end
def add_method( name )
self.class.send :define_method, name.to_sym do
puts "Called " + name.to_s
end
end
end
Now lets write a program which creates an instance, adds a method to it and saves it to disk:
require 'extras'
fresh = Extras.new
fresh.contents = 314
fresh.test # outputs "This instance of Extras is OK. Contents is: 314"
fresh.add_method( :foo )
fresh.foo # outputs "Called foo"
serial = Marshal.dump( fresh )
file = File.new "dumpedExample", 'w'
file.write serial
So we can call the normal method 'test' and the dynamic method 'foo'. Lets look at what happens if we write a program which loads the instance of Example which was saved to disk:
require 'extras'
file = File.new 'dumpedExample', 'r'
serial = file.read
reheated = Marshal.load( serial )
reheated.test # outputs "This instance of Extras is OK. Contents is 314"
reheated.foo # throws a NoMethodError exception
So we can see that while the instance (including the values of member variables) was saved the dynamic method was not.
From a design point of view it's probably better to put all your added code into a module and load that into the class again when you next run the program. We'd need a good example of how you might want to use it though to really know this.
If you need extra information to recreate the methods then have the module save these as member variables. Implement included in the module and have it look for these member variables when it is included into the class.
http://ruby-doc.org/core/classes/Marshal.html
You're editing the class on the fly, and you want to save that? You could try using the Marshal module, it'll allow you to save objects to a file, and read them back in memory dynamically.