Ruby: Name a method for later definition? - ruby

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!"

Related

Convert Strings to Class Names in ruby

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.

Non-capitalized constant names in Ruby

So, there's a jokey repo called active_emoji, which basically adds a load of emoji aliases to Ruby methods.
It also includes this:
🔢 = Numeric
class 🔢
alias 🚶 step
end
However, when trying to write some specs for the repo, it fails with
active_emoji/lib/active_emoji/core_ext/numeric.rb:3: class/module name must be CONSTANT (SyntaxError)
Is there a way of forcing the emoji to be recognized as being a constant? I'm assuming this error is because Ruby sees that the 🚶 emoji symbol isn't capitalized...
The error is actually due to:
class 🔢
The first line, which assigns Numeric to a variable, works fine in IRB. So does aliasing the step method. But Ruby will only accept class [ConstantName] as valid -- you can't use a variable here.

When does Ruby know that a method exists?

One question that ran through my mind was how does the Ruby interpreter know that a method exists on a object if the definition is yet to be interpreted? Like, wouldn't it matter whether you define the method first than use it, rather than use it then define it?
It doesn't know, and it doesn't care - until execution. When a method call statement is executed, the interpreter looks to see if the class (object, not code!) has the named function. If it does not, it looks up the ancestor tree. If it does not find any, it calls the method_missing method. If that is not defined, you get your error.
If your function call does not get executed, you will not get any errors.
The interpreter doesn't know about undefined methods ahead of time, for example:
o = Object.new
o.foo # => Raises NoMethodError.
class Object
def foo
puts "Foo!"
end
end
o.foo # => prints "Foo!", since the method is defined.
However, Ruby has a neat feature called method_missing which let's the receiver of a method call take the method name and arguments as separate arguments and handle accordingly as long as no defined method already handles the call.
def o.method_missing(sym, *args)
puts "OK: #{sym}(#{args.inspect})"
# Do something depending on the value of 'sym' and args...
end
o.bar(1, 2, 3) #=> OK: bar(1, 2, 3)
"Method missing" is used by things like active record find methods and other places where it could make sense to have "dynamically defined" functions.
The problem is, the interpreter tried to find it when you use it, and since it won't be there, it may fail.
In ( some ) compiled languages, it doesn't matter, because while compiling, the compiler may say "I'll look for this on a second pass" but I don't think this is the case with Ruby.

Question about inheritance in Ruby

I've been attempting to teach myself Ruby over the past while and I've been trying to get something like the following to work but I'm getting the following error...
file.rb:44:infunc': undefined local variable or method number' #<classname:0xb75d7840 #array=[]> (NameError)
The code that's giving me this error is...
class A
def func
file = File.new("file", "r")
file.each_line {|line| #numbers << line.chomp.to_i}
#number = #array[0]
end
end
class B < A
def func
super number
puts number
end
end
Could someone please tell me what I'm doing wrong?
edit// Just a clarification that I want number in class B to inherit the value of #number in class A.
Just like it's telling you, you're calling super and puts with an the argument number — but this number (whatever it's supposed to be) hasn't been defined anywhere. Define number to be something meaningful and the code will almost work. Almost.
The other mistake, which you'll discover after you've fixed that one, is that you're calling super number, which calls A's func method with this mysterious number object as the argument — but A#func doesn't take any arguments.
You forgot the '#' symbol to reference the instance level variable.
It is a really bad design anyway. What if there are no lines in 'file'? #numbers is never initialized. You also wipe out #number completely on the next line with a variable (#array) that has never been defined. Stop trying to fit everything in as few lines as possible and properly initialize your variables.
EDIT: Also, as Chuck noticed, you are passing an argument to a method that takes no arguments.
Your problem is that while you use the instance variable #number, calling super number (which isn't what you want, as this calls the superclass version of whatever method you're in, passing number as an argument) and puts number look up the method number. If you really do want to just look up the instance variable, you just need #number; if you want to define such a method, put one of the following lines in your class:
class A
attr_accessor :number # Define reader (number) and writer (number=)
attr_reader :number # Define only a reader
attr_writer :number # Define only a writer; won't be useful here
# ...
end
And as Ed Swangren said, you ought to clean up A: initialize variables in initialize, make sure you define everything before using it, etc.
Edit 1: Corrected the description of the behavior of super.

What does this construction mean, in Ruby?

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

Resources