For some reason I store methods in a Proc and I want to check if they are defined.
If I do : defined? 1.+ I get method in return so I know the + method is defined.
Now if I store the methods in a Proc : p = Proc.new { 1.+ },
I want to know how i can check if the method stored in p is defined
I have tested defined? p or defined? p.call but it's not the attended results ...
Thanks for your help !
defined? is used to test if variables are defined or constants exist, not methods per-se.
For that you should use:
1.method(:+)
Where if that method doesn't exist you get a NameError exception. That's not the best way to test, though, instead there's a much simpler method for it:
1.respond_to?(:+)
Where if that method "responds to" that method call it will (usually) return true. Since Ruby is a highly dynamic programming language and methods can be made-up on the spot through method_missing and other tricks, this might not be 100% accurate, but it is for pre-defined methods.
Unfortunately once you've wrapped some valid Ruby code inside a Proc it's not possible to test any more if it will or won't work without executing it. This means if you have a Proc, it's basically a black box, short of delving in through tricks in the VM, but that's Ruby implementation specific.
Related
Rubocop dislikes the following; it issues Pass a binding, __FILE__ and __LINE__ to eval.:
sort_lambda = eval "->(a) { a.date }"
Yes, I know that eval is a security problem. The issue of security is out of scope for this question.
The Ruby documentation on binding says:
Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use. The variables, methods, value of self, and possibly an iterator block that can be accessed in this context are all retained. Binding objects can be created using Kernel#binding, and are made available to the callback of Kernel#set_trace_func and instances of TracePoint.
These binding objects can be passed as the second argument of the Kernel#eval method, establishing an environment for the evaluation.
The lambda being created does not need to access any variables in any scopes.
A quick and dirty binding to the scope where the eval is invoked from would look like this:
sort_lambda = eval "->(a) { a.date }", self.binding, __FILE__, __LINE__
Ideally, a null binding (a binding without anything defined in it, nothing from self, etc.) should be passed to this eval instead.
How could this be done?
Not exactly, but you can approximate it.
Before I go further, I know you've already said this, but I want to emphasize it for future readers of this question as well. What I'm describing below is NOT a sandbox. This will NOT protect you from malicious users. If you pass user input to eval, it can still do a lot of damage with the binding I show you below. Consult a cybersecurity expert before trying this in production.
Great, with that out of the way, let's move on. You can't really have an empty binding in Ruby. The Binding class is sort of compile-time magic. Although the class proper only exposes a way to get local variables, it also captures any constant names (including class names) that are in scope at the time, as well as the current receiver object self and all methods on self that can be invoked from the point of execution. The problem with an empty binding is that Ruby is a lot like Smalltalk sometimes. Everything exists in one big world of Platonic ideals called "objects", and no Ruby code can truly run in isolation.
In fact, trying to do so is really just putting up obstacles and awkward goalposts. Think you can block me from accessing BasicObject? If I have literally any object a in Ruby, then a.class.ancestors.last is BasicObject. Using this technique, we can get any global class by simply having an instance of that class or a subclass. Once we have classes, we have modules, and once we have modules we have Kernel, and at that point we have most of the Ruby built-in functionality.
Likewise, self always exists. You can't get rid of it. It's a fundamental part of the Ruby object system, and it exists even in situations where you don't think it does (see this question of mine from awhile back, for instance). Every method or block of code in Ruby has a receiver, so the most you can do is try to limit the receiver to be as small an object as possible. One might think you want self to be BasicObject, but amusingly there's not really a way to do that either, since you can only get a binding if Kernel is in scope, and BasicObject doesn't include Kernel. So at minimum, you're getting all of Kernel. You might be able to skimp by somehow and use some subclass of BasicObject that includes Kernel, thereby avoiding other Object methods, but that's likely to cause confusion down the road too.
All of this is to emphasize that a hypothetical null binding would really only make it slightly more complicated to get all of the global names, not impossible. And that's why it doesn't exist.
That being said, if your goal is to eliminate local variables and to try, you can get that easily by creating a binding inside of a module.
module F
module_function def get_binding
binding
end
end
sort_lambda = eval "->(a) { a.date }", F.get_binding
This binding will never have local variables, and the methods and constants it has access to are limited to those available in Kernel or at the global scope. That's about as close to "null" as you're going to get in the complex nexus of interconnected types and names we call Ruby.
While I originally left this as a comment on #Silvio Mayolo's answer, which is very well written, it seems germane to post it as an answer instead.
While most of what is contained within that answer is correct we can get slightly closer to a "Null Binding" through BasicObject inheritance:
class NullBinding < BasicObject
def get_binding
::Kernel
.instance_method(:binding)
.bind(self)
.call
end
end
This binding context has as limited a context as possible in ruby.
Using this context you will be unable to reference constants solely by name:
eval 'Class', NullBinding.new.get_binding
#=> NameError
That being said you can still reference the TOP_LEVEL scope so
eval '::Class', NullBinding.new.get_binding
#=> Class
The methods directly available in this binding context are limited only to the instance methods available to BasicObject. By way of Example:
eval "puts 'name'", NullBinding.new.get_binding
#=> NoMethodError
Again with the caveat that you can access TOP_LEVEL scope so:
eval "::Kernel.puts 'name'", NullBinding.new.get_binding
# name
#=> nil
Most of the Factorybot factories are like:
FactoryBot.define do
factory :product do
association :shop
title { 'Green t-shirt' }
price { 10.10 }
end
end
It seems that inside the ":product" block we are building a data structure, but it's not the typical hashmap, the "keys" are not declared through symbols and commas aren't used.
So my question is: what kind of data structure is this? and how it works?
How declaring "association" inside the block doesn't trigger a:
NameError: undefined local variable or method `association'
when this would happen on many other situations. Is there a subject in compsci related to this?
The block is not a data structure, it's code. association and friends are all method calls, probably being intercepted by method_missing. Here's an example using that same technique to build a regular hash:
class BlockHash < Hash
def method_missing(key, value=nil)
if value.nil?
return self[key]
else
self[key] = value
end
end
def initialize(&block)
self.instance_eval(&block)
end
end
With which you can do this:
h = BlockHash.new do
foo 'bar'
baz :zoo
end
h
#=> {:foo=>"bar", :baz=>:zoo}
h.foo
#=> "bar"
h.baz
#=> :zoo
I have not worked with FactoryBot so I'm going to make some assumptions based on other libraries I've worked with. Milage may vary.
The basics:
FactoryBot is a class (Obviously)
define is a static method in FactoryBot (I'm going to assume I still haven't lost you ;) ).
Define takes a block which is pretty standard stuff in ruby.
But here's where things get interesting.
Typically when a block is executed it has a closure relative to where it was declared. This can be changed in most languages but ruby makes it super easy. instance_eval(block) will do the trick. That means you can have access to methods in the block that weren't available outside the block.
factory on line 2 is just such a method. You didn't declare it, but the block it's running in isn't being executed with a standard scope. Instead your block is being immediately passed to FactoryBot which passes it to a inner class named DSL which instance_evals the block so its own factory method will be run.
line 3-5 don't work that way since you can have an arbitrary name there.
ruby has several ways to handle missing methods but the most straightforward is method_missing. method_missing is an overridable hook that any class can define that tells ruby what to do when somebody calls a method that doesn't exist.
Here it's checking to see if it can parse the name as an attribute name and use the parameters or block to define an attribute or declare an association. It sounds more complicated than it is. Typically in this situation I would use define_method, define_singleton_method, instance_variable_set etc... to dynamically create and control the underlying classes.
I hope that helps. You don't need to know this to use the library the developers made a domain specific language so people wouldn't have to think about this stuff, but stay curious and keep growing.
Working on some functionality where I need to be able to define methods and local vars from strings via a binding
I think the code speaks best for itself, so here is what I'm trying to accomplish:
mybind = binding
mybind.eval("a = 5")
mybind.eval("a") #=> 5
a #=> NameError: undefined local variable or method `a'...
# Calling it in global/main scope doesn't find anything, but it's found in the `mybind` scope
mybind.eval("def thing; 3; end")
mybind.eval("thing") #=> 3
thing #=> NameError: undefined local variable or method `thing'...
# Calling it in global/main scope doesn't find anything, but it's found in the `mybind` scope
Essentially, I don't want any methods/vars defined to go to the global scope, but I want them to be callable within a second call to the same binding/eval. These will come through as strings, so callable blocks is out of the question as well.
I've tried instance_eval, class_eval, eval, and instance_exec
instance_eval is ALMOST perfect, except for some reason any local vars defined cannot be accessed within the next instance_eval called.
I'm a bit new to using binding, so if there is something obvious I'm missing, please let me know. Otherwise if there is anybody that has any idea on how to accomplish this, even with a different flow I would really appreciate any help.
Thanks!
I'm on Ruby 2.7.2, but can upgrade if that will provide a solution.
binding, by its design, gets the current binding whenever it's called. If you call it in the global scope, you'll get the global binding. What it sounds like you want is a binding that's not accessible to the user. We can create one of those easily, simply by calling binding inside of an otherwise empty function.
def new_binding
binding
end
Now, every time I call new_binding, I get a fresh scope that inherits lexically from Ruby's standard global scope but that nobody else can access without that object.
irb(main):012:0> new_binding == new_binding
=> false
irb(main):013:0> my_binding = new_binding
=> #<Binding:0x00005562fd103a00>
irb(main):014:0> my_binding.eval("a = 1")
=> 1
irb(main):015:0> my_binding.eval("a")
=> 1
--
Edit after your comment
We can get a little closer to what you're looking for by wrapping new_binding in a trivial eigenclass.
def new_binding
class <<Object.new
return binding
end
end
Now you can define methods, but you have to do so with an explicit self.
new_binding.eval("def self.thing; 3; end")
new_binding.eval("thing")
It's very possible there's some trickery that can be done with method_added to get around the explicit receiver, but for whatever reason it seems like method_added doesn't want to work on eigenclasses. I might end up opening a new SO question about that myself to be honest, as the behavior is quite odd.
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.
Today I came across the strange ruby syntax in the Rational class:
Rational(a,b)
(Notice the absence of the .new()portion compared to the normal Ruby syntax). What does this mean, precisely, compared to the normal new syntax? More importantly, how do I implement something like this in my own code, and why would I implement something like this? Specifically for the Rational class, why is this syntax used instead of the normal instantiation? And why is the new method private in the rational class? (And how/why would I do this in my own ruby code?)
Thanks in advance for your answers, especially since I've asked so many questions.
All you have to do is declare a global function with the same name as your class. And that is what rational.rb does:
def Rational(a, b = 1)
if a.kind_of?(Rational) && b == 1
a
else
Rational.reduce(a, b)
end
end
to make the constructor private:
private :initialize
and similarly for the new method:
private_class_method :new
I suppose Rational.new could be kept public and made to do what Rational() does, but having a method that turns its arguments into instances is consistent with Array(), String(), etc. It's a familiar pattern that's easy to implement and understand.
The method Rational() is actually an instance method defined outside of the class Rational. It therefore becomes an instance method of whatever object loads the library 'rational' (normally main:Object) in the same way that 'puts' does, for example.
By convention this method is normally a constructor for the class of the same name.