Non-capitalized constant names in Ruby - 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.

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.

Ruby: Name a method for later definition?

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

how do you assert an exception from another ruby module is thrown? (using assert_throws)

I'm trying to write code like this:
assert_throws(:ExtractionFailed) { unit.extract_from('5 x 2005')}
ExtractionFailed is a trivial subclass of Exception, and under test/unit, I'm trying to assert that it is thrown when I call unit.extract_from(... bad data...)
I've moved ExtractionFailed into the SemanticText module, so now test/unit says:
<:ExtractionFailed> expected to be thrown but
<:"SemanticText::ExtractionFailed"> was thrown.
I tried writing assert_throws(:SemanticText::ExtractionFailed) {...} but I got the rather confusing message: TypeError: SemanticText is not a class/module
I can make it work by doing the following (although it seems like a hack):
assert_throws(SemanticText::ExtractionFailed.to_s.to_sym) { unit.extract_from('5 x 2005')}
So what's the right way to say this assertion in ruby?
Put quotes around the symbol name after the colon e.g.
assert_throws(:"SemanticText::ExtractionFailed") { unit.extract_from('5 x 2005')}
The quotes are necessary for a symbol that contains colons or other special characters.
If you try :"SemanticText::ExtractionFailed".class in irb you will see that it is a Symbol, removing the need to use to_s and/or to_sym.

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

What is the real reason for Ruby class names being capitalised?

Ok, so everyone knows that capitalised identifiers are seen to be ‘constant’ in Ruby.
However, it is possible to assign a new value to constants, so the following works
class A
def self.hi; "hi"; end
end
class B
def self.hi; "ho"; end
end
A.hi # => "hi"
B.hi # => "ho"
A = B
# warning: already initialized constant A
# => B
A.hi # => "ho"
and also does assigning to a lowercase identifier work:
a = B
a.hi # => "ho"
However, the internal name is set to ‘B’ in all cases and the new identifier names are also only referencing ‘B’.
But if it’s technically okay for the identifier to have a lowercase name, why is this restriction on the internal name for the class? It can’t be that it needs to be constant, because it isn’t constant; so the other reason could be that lowercase identifiers have a different scope. But then: why not having a class with lowercase scope?
I’m wondering because the parser even allows for method names in unicode and such, so it seems strange that for classes it’s so much more restricted.
As you said, the name of a class is that of the first constant it has been assigned to. You can only use constants with the class keyword because it has been decided that the class keyword should only be used to create named classes.
The rationale probably being that allowing local variables would confuse uses, who would use class lowercase_class_name, not knowing the difference between lower case and upper case identifiers and then wonder why the classname was not visible everywhere (i.e. why def foo() lowercase_class_name.new end did not work).
By making the default way to create classes specific to constants, classes defined this way will be visible everywhere and there is at least a suggestion that the value associated with that name should not change (i.e. you get a warning otherwise).
People who know what they're doing can still do local_variable = Class.new { ... } if they need to.
The interpreter needs one way to find out if it is a Class name or a member variable of the current class/module.
The interpreter has to lookup class names in a global hash table while the member variables are in the class hash table. Local variables are different as they can be resolved by the interpreter without looking up hash tables at all (they have precedence over member variables).
And the only thing the interpreter knows about an identifier are the characters. Therefore there is the notational difference. Thats also the reason why global variables have a preceding $ and class variables an # character. For this the interpreter has other hash tables it has to search.
Other script languages have similar restrictions, for example PHP needs a dollar in front of each variable.

Resources