I am trying to write a script in ruby which involves converting a string to Class Names. Since I am using pure ruby I cannot use .constantize.
I have tried using Object.const_get('String') but not sure why it is throwing a uninitialized constant String (NameError)
I have require 'active_support' on the top of the file
The conventional way of assigning a name to an anonymous class is as follows.
bub = Class.new do
def b
'hi'
end
end
str = 'Bubba'
Object.const_set(str, bub)
Bubba.is_a?(Class)
#=> true
Bubba.new.b
#=> "hi"
Is that what you want to do? If so, as you see, you need to use Module#const_set.
Do you try to use const_get only for a class or it is under a namespace like ModuleA::ModuleB::ClassName?
Also converting a string to a class name makes a new class or assigns the value to it?
I am asking these questions because the answer will affect the method you have to use. Maybe const_set instead of const_get is the correct approach, I don't know.
From the comments you gave it looks like 'String' is just an example and not the value that you literally pass to const_get. The actual value apparently is 'Assignment', is this correct?
When you execute Object.const_get('Assignment') and you receive the uninitialized constant error it indicates that at this point the class Assignment has not been loaded yet.
When you are using Rails then a lot of autoloading takes place if the files are in the right folder and the classes follow the naming conventions. Since you are running a "standalone" ruby script, autoloading does not take place and you will need to load the file yourself.
Adding a line like
require_relative "somepath/assignment"
should work. somepath needs to be adapted to the directory/file layout you have. It will load the file and execute the ruby code in that file.
If assignment.rb defines something like
class Assignment
end
Then the const_get will work.
That being said: what is your exact use case for this? Why do you need to dynamically find classes? Also Note that this opens up your app to (an unlikely) potential security issues if you let user input define what classes are loaded.
Related
I have an object, and I want to dump all its information.
For debugging purpose, can I convert it to json or other suitable format?
I know using p object, sometimes can print out all its information; but not always. So I am asking is there other ways when p object becomes invalid
Try pry
It is excellent for exploring objects. Especially large objects because it has paging. The objects are also color coded to make it more readable.
Steps:
install pry
Add require 'pry' to the script file you want to debug
Add binding.pry below the object declaration of anywhere the object is in scope
Run your script
This will pop open the pry console with access to your object
Type in the object name
'ls object' will list all the instance variables of the object
There's couple ways you can go. Using json from the standard lib is one way to convert an object to json.
this converts an object in ruby to a json string:
require "json"
h = Hash.new(name: "example")
JSON.dump(h)
But you seem to be wanting to inspect an object in detail. The best solution is probably the "Pry" gem that others have suggested if you really need a lot of detail.
so after installing pry you can "cd" into objects and inspect instance variables public/private methods and the source code of methods/classes, etc. its really great stuff.
require "pry"
cd SomeObject
ls # this shows you everything defined in the object.
The problem with object.inspect that others have suggested is that it can be overriden, often is, and thus will oft not show you enough information. So it depends on what you want to find out.
puts o.instance_variables #=> shows all an objects instance variable names
puts o.instance_variable_get :#some_var #=> returns the value held by #some_var
puts o.methods - Object.methods #=> roughly speaking, shows you the methods defined on an object itself and not inheritted from parent objects
Unfortunately there's not a perfect answer here, but for debugging purposes I personally think nothing beats out pry especially with the pry debugger addon gem (forgot actual name) that allows you to step through the call stack.
You can use "inspect" : "Returns a string containing a human-readable representation of obj. By default, show the class name and the list of the instance variables and their values (by calling inspect on each of them). "
Example:
puts object.inspect
you can try puts my_object.as_json.to_json
If I load x.rb, then all the classes in that file are loaded. Is it possible to check and see what classes are being used and load those only?
Assuming x.rb contains both Hello and Goodbye classes, and my program only uses the Hello Class, is it possible to load only the Hello Class?
Happy with a script that checks the document, and outputs an .rb that has only the Hello Class and the code that uses it... Would be an interesting github project if doesn't exist, but I think it's out of my skillset atm.
When classes are defined in their own separate file, you could use the autoload¹² method:
autoload :Hello, 'x/hello'
autoload :Goodbye, 'x/goodbye'
When you write Hello, you are actually accessing the Hello constant. autoload uses const_missing to automatically require a file if the constant is not defined.
Note that we are still dealing with files here. The contents of x/hello.rb will simply be read and evaluated. That code can run any operation. It can require other files. It could define a million other classes.
That's because source code is really just text. This is especially true for interpreted languages. For example, in Java, you can usually only declare one public type per "compilation unit". In Ruby, there is no such thing.
¹ Matz strongly discourages the practice
² Ruby Inside article on autoload
NOTE: I misread part of the question and the other part somehow evaded me... I must have been multitasking big time. Anyway, this answer only answers half of the question, and incorrectly; just saying.
Okay, here's a possibly expensive way, but try something like this:
$ cat definer.rb
class Foo
def greet(person)
puts "Hello, #{person}!"
end
end
Bar = Class.new
$ cat finder.rb
$LOAD_PATH << File.dirname "."
before = Object.constants
require 'definer'
after = Object.constants
print (before - after).join(" ")
$ cat looker.rb
differences = `ruby finder.rb`.split(" ")
puts "The following constants will be defined when finder.rb is loaded: #{differences.join(", ")}"
Now for a cleaner and way, you could use sockets. I'll get an example of this up.
I am trying to write a small ruby script that will have two methods (TrySlot and LookAtCut). Each method needs to be able to call the other method. When ruby is parsing the first method, it fails because it doesn't understand the name of the second method, since I haven't defined it yet.
So, how do I tell ruby, there is a method called TrySlot that I will define later so I can call TrySlot in my definition for LookAtCut?
The reason you are getting problems is that Ruby usually assumes all names starting with an uppercase letter to be constants. However, it will also let you define methods with a name starting by an uppercase letter. What is happening is the following:
Ruby sees def LookAtCut and correctly defines a method named LookAtCut
Inside LookAtCut, Ruby sees TrySlot, assumes it is a constant, tries to find it and fails with an error, since it hasn't been defined.
The solution would be not to use method names starting with uppercase characters. Then, you can use a method that hasn't been defined yet inside another one:
def a
b
end
def b
puts "Hello!"
end
a #=> "Hello!"
I was trying to add a method to the String class. This method should mutate the current string (of course it would be possible to write a not mutating version but I'd prefer the mutating one). I had no idea how to do this and after some googling I found the method rb_str_modify which makes a given string mutable. That's exactly what I need but I couldn't find an equivalent in the Ruby language. Did I miss something or is there really no possibility in the language itself?
Reopening Classes
All classes in Ruby are open for extension so you can simply do this ...
Class String
def my_new_method(args)
# Some sort of modification to self
self.replace "SOME CALCULATED VALUE"
end
end
... somewhere in your code. I've modified string a few times in different applications - usually I just put the modifications into one particular module, making it easy to reuse them or remove them as required.
Modifying individual objects
Modifying a class in its entirety is dangerous as it's very difficult to identify all of the consequences - I once broke Merb by modifying a method in the String class. It's much safer to modify particular objects. This is easy in Ruby - you use the extend keyword. You define a module, add your function and then modify the target object. This example ...
module Humor
def tickle
"hee, hee!"
end
end
a = "Grouchy"
a.extend Humor
a.tickle » "hee, hee!"
is taken from the Pickaxe book
Chris
The method below exists in the Redcloth gem.
My question is: what does the construction "to(RedCloth::Formatters::HTML)" mean? "to" isn't a method in the class, nor in the superclass (which is String class).
def to_html( *rules )
apply_rules(rules)
to(RedCloth::Formatters::HTML)
end
When you search the entire RedCloth source for def to, besides finding a couple of methods that start with to, you'll also find the exact method to in ext/redcloth_scan/redcloth_scan.rb.rl.
There's two things that happen here. First, this file is preprocessed by Ragel. But for this question, you may safely ignore this fact and read past the weird syntax in that file. Focus on the Ruby bits.
Second, the class RedCloth::TextileDoc is reopend here. That means the class in this file and in lib/redcloth/textile_doc.rb are the same. So the to instance method will be available to the piece of code you quoted.
Yes, it's defined at in http://github.com/jgarber/redcloth/blob/master/ext/redcloth_scan/redcloth_scan.c.rl at line 200 and attached to the class at 221.
to(RedCloth::Formatters::HTML) is just calling the #to method and passing in the class of the formatter (the second argument in the redcloth_to C method; the first must always be self).
Could be it's defined on Object or in Kernel module.
EDIT: it's not. It's defined on line 220 of this file http://github.com/jgarber/redcloth/blob/master/ext/redcloth_scan/redcloth_scan.c.rl