I'm having much trouble understanding the syntax of a Homebrew Formula.
Let's have a look at this example:
require "formula"
class Foo < Formula
url "http://example.com/foo-0.1.tar.gz"
homepage ""
sha1 "1234567890ABCDEF1234567890ABCDEF"
# depends_on "cmake" => :build
def install
system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking"
# system "cmake", ".", *std_cmake_args
system "make install"
end
end
What exactly does the following syntax means?
url "http://example.com/foo-0.1.tar.gz"
Is it some kind of a variable assignment? Construction of a url object?
I'm sorry but after passing over a whole Ruby tutorial, I still didn't understand it.
Also, please try to explain what this syntax is:
system "make install"
From what I have searched, Ruby doesn't have such method (or at least it doesn't call the system() method like this).
You'll find that these are calls to methods of the Formula class that Foo derives from (Foo < Formula). For example, the system method that's confusing you is just a method being called in Formula. Have a look in Formula.rb and you'll find most of your answers.
Homebrew is a complex program, with its functionality well-separated across different objects, as you'd expect. You may therefore need to trace some of the calls into other objects. For example, while Formula does have a url method, and that's what the url like you ask about is calling, you'll find that call is passed to a SoftwareSpec object, which then stores it in a Resource instance variable as well as adding it to the dependency collector.
Also, please try to explain what this syntax is:
system "make install"
From what I have searched, Ruby doesn't have such method (or at least
it doesn't call the system() method like this).
Ruby does in fact have a system() method, and it is called exactly like that, see here:
http://www.ruby-doc.org/core-2.1.2/Kernel.html
For instance, run this program:
system "ls *"
However, in ruby if a method does not have an explicit receiver, then ruby implicitly uses whatever object is self to call the method, i.e. self.system(...).
Inside a class, but outside any defs, self is the class:
class Dog
p self #=>Dog
end
And inside an instance method:
class Dog
def bark
p self
puts 'woof'
end
end
d = Dog.new
d.bark
--output:--
#<Dog:0x00000100a40280>
woof
self is the Dog instance that called the method, d in this case. Those hieroglyphics are what ruby uses to denote a instance of a class.
Whenever you see a method call without an explicit receiver, such as
system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking"
it's good practice to say to yourself, self.system(...) Which object is self? Your code boils down to this:
class Foo < Formula
def install
system(...)
end
end
self.system(..) Which object is self? self will be the instance of Foo that calls the install() method. I would immediately assume that the system() call finds ruby's system() method--and the only way that wouldn't happen is if the Formula class defines a method named system(), and as Matt Gibson astutely checked, Formula does define a system() method.
What exactly does the following syntax means?
url "http://example.com/foo-0.1.tar.gz"
Ruby translates that to:
self.url(""http://example.com/foo-0.1.tar.gz")
Related
Some context
I'm playing with Ruby to deepen my knowledge and have fun while at the same time improving my knowledge of Esperanto with a just starting toy project called Ĝue. Basically, the aim is to use Ruby facilities to implement a DSL that matches Esperanto traits that I think interesting in the context of a programming language.
The actual problem
So a first trait I would like to implement is inflection of verbs, using infinitive in method declaration (ending with -i), and jussive (ending with -u) for call to the method.
A first working basic implementation is like that:
module Ĝue
def method_missing(igo, *args, &block)
case igo
when /u$/
celo = igo.to_s.sub(/u$/, 'i').to_s
send(celo)
else
super
end
end
end
And it works. Now the next step is to make it more resilient, because there is no guaranty that celo will exists when the module try to call it. That is, the module should implement the respond_to? method. Thus the question, how do the module know if the context where module was required include the corresponding infinitive method? Even after adding extend self at the beginning of the module, inside of the module methods.include? :testi still return false when tested with the following code, although the testu call works perfectly:
#!/usr/bin/env ruby
require './teke/ĝue.rb'
include Ĝue
def testi; puts 'testo!' ;end
testu
Note that the test is run directly into the main scope. I don't know if this makes any difference with using a dedicated class scope, I would guess that no, as to the best of my knowledge everything is an object in Ruby.
Found a working solution through In Ruby, how do I check if method "foo=()" is defined?
So in this case, this would be checkable through
eval("defined? #{celo}") == 'method'
I am new to Ruby and I saw methods defined like:
def method_one
puts "method 1"
end
class MyClass
method_one
def method_two
puts "method 2"
end
end
The way method_one is used reminds me of Python decorators.The output of
c = MyClass.new
c.method_two
is
method 1
method 2
I have been trying to search for more information about this syntax/language feature in the Ruby documentation on the web but I don't know what keywords to search for.
What this is thing called?
TL;DR
This code doesn't do what you think it does. Don't do stuff like this.
Ruby's Top-Level Object
Ruby lets you define methods outside a class. These methods exist on a top-level object, which you can (generally) treat as a sort of catch-all namespace. You can see various posts like What is the Ruby Top-Level? for more details, but you shouldn't really need to care.
In your original post, method_one is just a method defined in the top-level. It is therefore available to classes and methods nested within the top-level, such as MyClass.
Methods in Classes
Despite what you think, the following doesn't actually declare a :method_one class or instance method on MyClass:
class MyClass
method_one
def method_two; end
end
Instead, Ruby calls the top-level ::method_one during the definition of the class, but it never becomes a class method (e.g. MyClass::method_one) or an instance method (e.g. MyClass.new.method_one). There might be a few use cases for doing this (e.g. printing debugging information, test injection, etc.) but it's confusing, error-prone, and generally to be avoided unless you have a really strong use case for it.
Better Options
In general, when you see something like this outside an academic lesson, the programmer probably meant to do one of the following:
Extend a class.
Add a singleton method to a class.
Include a module in a class.
Set up a closure during class definition.
The last gets into murky areas of metaprogramming, at which point you should probably be looking at updating your class initializer, or passing Proc or lambda objects around instead. Ruby lets you do all sorts of weird and wonderful things, but that doesn't mean you should.
I think you're a little mislead; the output of:
c = MyClass.new
c.method_two
is
#<MyClass:0x007feda41acf18>
"method 2"
You're not going to see method one until the class is loaded or if you're in IRB you enter the last end statement.
I would suggest looking into ruby's initialize method.
Is there a way to get the list of methods that implement a Ruby method when this method is invoked?
For example:
def foo
puts "foo"
end
def foo2
foo
end
I want to know that when calling "foo2" it calls 1st "foo" and 2nd "puts" and the corresponding files these methods are defined into. (If "puts" calls other methods, I would like to know them too)
Is that possible? and if 'yes' how? I could say that my question is about finding the method dependencies.
You can sort of get this using set_trace_func, but since Ruby is dynamic you would also need test code to call the methods so that the call order is printed.
set_trace_func proc { |event, filename, line, id, binding, klass| puts "#{klass}##{id}" }
In Ruby 2.0, TracePoint is a superior alternative.
Static code analysis, especially one you'd like to perform (listing all methods called within a method), is very hard in ruby (close to impossible) because the language is dynamic and allows for very strong metaprogramming techniques. Even the parser itself doesn't know the methods required until it tries to execute the code.
Example: calling eval with code read from a file.
Are only the core Ruby methods callable using object.functionName syntax? Is it possible to create methods on my own that are callable in the dot syntax fashion?
For this method:
def namechanger (name)
nametochange = name
puts "This is the name to change: #{nametochange}"
end
First one below works, the second does not.
namechanger("Steve")
"Steve".namechanger
I get an error on "Steve".namechanger
The error is:
rb:21:in `<main>': private method `namechanger' called for "Steve":String (NoMethodError)
Yes, you can add methods to the String class to achieve your desired effect; the variable "self" refers to the object which receives the method call.
class String
def namechanger
"This is the name to change: #{self}"
end
end
"Steve".namechanger # => This is the name to change: Steve
This practice is known as monkey patching and should be used carefully.
Instead of monkeypatching, you could alway subclass and thus:
Be precise about what you think the object really is.
Gain all the methods of String
For example:
class PersonName < String
def namechanger
puts "This is the name to change: #{self}"
end
end
s = PersonName.new( "Iain" )
s.namechanger
This is the name to change: Iain
=> nil
What you have here in the first form is a method which takes a parameter, which is very different than a method that doesn't take any parameters. Let me illustrate
ruby
namechanger("Steve")
Looks for a method named namechanger and passes a string argument to it. Straight forward. It looks up in some unknown context, probably the locals of another method which will look it up on the object that receives that method.
ruby
"Steve".namechanger
is a method that takes no arguments that exists on String. Typically these methods use the implicit self parameter to operate on some data.
If you want to be able to call "Steve".namechanger, you have to make namechanger a method of the String class like this:
class String
def namechanger
puts "This is the name to change: #{self}"
end
end
This is generally referred to as "monkey patching" and you might want to improve your general Ruby proficiency a bit before you get into the related considerations and discussions.
You could do
class String
def namechanger
puts "This is the name to change: #{self}"
end
end
The difference is that your first example is a method that's (basically) globally defined, which takes a string and operates on it. This code above however defines a method called "namechanger" which takes no parameters, and defines it directly on the String class. So any and all strings in your application will then have this method.
But as pst said, you should probably not dive into that style of programming until you get a little more familiar with Ruby, so that you can more easily see the upsides and downsides of doing monkeypatching like this. One of the considerations is that you probably have many strings that don't represent names, and it doesn't make a lot of sense for those strings to have a method called namechanger.
That said, if your goal is just to have a little fun with Ruby, to see what you can do, go for it, but remember to be more careful in projects that will have a longer lifespan.
In Ruby, super is a keyword rather than a method.
Why was it designed this way?
Ruby's design tends toward implementing as much as possible as methods; keywords are usually reserved for language features that have their own grammar rules. super, however, looks and acts like a method call.
(I know it would be cumbersome to implement super in pure Ruby, since it would have to parse the method name out of caller, or use a trace_func. This alone wouldn't prevent it from being a method, because plenty of Kernel's methods are not implemented in pure Ruby.)
It behaves a little differently, in that if you don't pass arguments, all of the current arguments (and block, if present) are passed along... I'm not sure how that would work as a method.
To give a rather contrived example:
class A
def example(a, b, c)
yield whatever(a, b) + c
end
end
class B < A
def example(a, b, c)
super * 2
end
end
I did not need to handle the yield, or pass the arguments to super. In the cases where you specifically want to pass different arguments, then it behaves more like a method call. If you want to pass no arguments at all, you must pass empty parentheses (super()).
It simply doesn't have quite the same behaviour as a method call.
super doesn't automatically call the parent class's method. If you imagine the inheritance hierarchy of a ruby class as a list, with the class at the bottom and Object at the top, when ruby sees the the super keyword, rather than just check the the parent class, it moves up the entire list until it finds the first item that has a method defined with that name.
I'm careful to say item because it could also be a module. When you include a module in to a class, it is wrapped in an anonymous superclass and put above your class in the list I talked about before, so that means if you had a method defined for your class that was also defined in the module, then calling super from the class's implementation would call the module's implementation, and not the parent class's:
class Foo
def f
puts "Foo"
end
end
module Bar
def f
puts "Bar"
super
end
end
class Foobar < Foo
include Bar
def f
puts "Foobar"
super
end
end
foobar = Foobar.new
foobar.f
# =>
# Foobar
# Bar
# Foo
And I don't believe that it is possible to access this 'inheritance list' from the ruby environment itself, which would mean this functionality would not be available (However useful it is; I'm not every sure if this was an intended feature.)
Hm, good qustion. I'm not sure how else (besides using super) you would you reference the super version of a given method.
You can't simply call the method by name, because the way that polymorphism works (how it figures out which version of that method to actually call, based on the object class) would cause your method to call itself, spinning into an infinite set of calls, and resulting in a stack overflow.