What does this construction mean, in Ruby? - 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

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.

what is a variable/object/thing starting with a # in ruby

I am new to Ruby, so go easy :).
Anyway, I am trying to work out some stuff in the chef-provisioning-aws gem. One thing in particular is that there is an object called:
new_resource.driver.ec2_client
When I do an inspect on that object it returns exactly this:
#<Aws::EC2::Client>
So, my question is: what is this? What sort of "thing" in Ruby starts with a pound sign (hash) and has <...> in it?
Much appreciated.
The output of Ruby's inspect method is roughly like this unless you override it:
"#<#{self.class}:0x#{self.object_id.to_s(16)}"
So in other words: "#<ClassName:0xobject_id in hex>".
class Foo ; end
Foo.new.inspect
#=> "#<Foo:0x007ffe0eeea520>"
It seems that for Aws::EC2::Client it was overriden and does not include the object id.
It's the default implementation of the inspect method (although then the object ID should be included). It may be useful in some situations to implement your own method, so you can get an instant overview of what you want to know about this object. The # is just a random character and has no further meaning here.

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

What's the rationale/history for the # convention of identifying methods in Ruby?

For example, I've always seen methods referred to as String#split, but never String.split, which seems slightly more logical. Or maybe even String::split, because you could consider #split to be in the namespace of String. I've even seen the method alone, when the class is assumed/implied (#split).
I understand that this is the way methods are identified in ri. Which came first?
Is this to differentiate, for example, methods from fields?
I've also heard that this helps differentiates instance methods from class methods. But where did this start?
The difference indicates how you access the methods.
Class methods use the :: separator to indicate that message can be sent to the class/module object, while instance methods use the # separator to indicate that the message can be sent to an instance object.
I'm going to pick the Complex class (in Ruby 1.9) to demonstrate the difference. You have both Complex::rect and Complex#rect. These methods have different arity and they serve entirely different purposes. Complex::rect takes a real and an imaginary argument, returning a new instance of Complex, while Complex#rect returns an array of the real and imaginary components of the instance.
ruby-1.9.1-p378 > x = Complex.rect(1,5)
=> (1+5i)
ruby-1.9.1-p378 > x.rect
=> [1, 5]
ruby-1.9.1-p378 > x.rect(2, 4) # what would this even do?
ArgumentError: wrong number of arguments(2 for 0)
from (irb):4:in `rect'
from (irb):4
from /Users/mr/.rvm/rubies/ruby-1.9.1-p378/bin/irb:17:in `<main>'
I think the reason that they don't use . as the separator for everything is that it would be ambiguous whether the method belongs to a class or an instance. Now that I'm used to Ruby doing this, I actually see it as a drawback to other languages' conventions, to be honest.
Also, this is somewhat of a completely unrelated topic from fields because all messages you can send are messages, properly speaking, even if it looks like a publicly accessible field. The closest thing you have to fields are attributes or instance variables, of course, which are always prefixed with # and are not directly accessible from outside the instance unless you are using inheritance or Object#instance_variable_get/_set.
As to specifically why they chose :: and #? :: makes sense to me because it conventionally separated namespaces, but # was probably just a symbol that wasn't used in other nomenclature and could unambiguously be recognized as an instance-method separator.
I understand that this is the way methods are identified in ri. Which came first?
Yes, this is where it came from. When you use #, it automatically hyperlinks your methods, so references to other methods in documentation began being prefixed by the # sign. See here:
Names of classes, source files, and any method names containing an underscore or preceded by a hash character are automatically hyperlinked from comment text to their description.
You can't actually invoke a method this way, however. But that shouldn't be surprising; after all, <cref ...> is an invalid statement in C# despite being a valid documentation tag.

rb_str_modify() equivalent in the Ruby language

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

Resources