What's the best practice for hiding variables in a Ruby file, like the equivalent of a (function() {})() closure in JavaScript?
So if I have a file:
foo = 5
bar = foo * foo
I only want to expose bar, not foo, when someone requires it.
If you have a file containing those two lines and someone requires that file, neither of the two variables will be exposed. Local variables are still local to the file even if they appear at the global scope.
If you want to expose bar, you'll need to turn it into a global variable $bar or, if you don't intend for the variable to change, into a constant Bar. By not doing the same thing to foo it will automatically not be exposed.
You might also consider wrapping the whole thing up in a module or class.
Ruby has scope as many other languages do. Variables are declared the first time they are used and will have scope based on where they are declared. If you use a local to a function:
def do_something
foo = 5
foo * foo
end
puts do_something
It will print 25, but foo will not be available outside of the do_something function.
Is this what you're looking for?
This post talks about Ruby's scoping in more depth Ruby Scoping Rules.
Related
I see in ruby classes some people using _ prefix to define instance variables like #_property while in normal condition attr_writer uses the normal name like #property to define instance variables.
What is the point of doing this and what is the difference?
The _ prefix isn't a language feature, it doesn't do anything special, it is just a convention.
In most cases, the developer wants to indicate that a variable is not in use, for example, a block variable that is not used in a block. Or they want to indicate that the variable is an internal variable of a module or gem and that others should not read or modify this variable directly.
There are 2 possible answers here depending on type of a variable.
Instance variable
When _ is used to prefix an instances variable (like in your question) it is usually just a convention to make it clear that that instance variable is private implementation detail and should not be used outside of the current scope. You might encounter it especially in modules which are to be included in some other classes - in which case the instance variable is defined and used by that module, but it belongs and is scoped to the object itself. I personally prefer object-scoped registries for this, but "private" instance variable is a quick, dirty and popular way to go. Alos, prefixing instance variable name with _ reduces chances of name conflict.
# Library code
module SomeExternalLibraryModule
def foo
#_something ||= SomeExternalLibraryModule::Something.new(self)
end
end
# Application code
class User
include SomeExternalLibraryModule
attr_reader :something # name conflict "avoided"! Phew!
def bar
#_something.do_sth
# "_" means - you'd better know what you're doing here!
# There is no guarantee that instance variable will be present in the future release
end
end
Local variable
When local variable is prefixed with _ this means that that variable is not being used in the code. It is especially useful when using iterators, or consuming other multi-element inputs of which you're interested in only one.
It is quite common to see just _ as a variable name. It has a bit of a special meaning for parser, which is you explicitly saying "I do not care what that is". As such, it is the only argument name that is allowed multiple time in a single definition:
def foo(_, _, a)
a
end
foo(1,2,3) #=> 3
def bar(a,a,b); end #=> SyntaxError
However, this is usually the best practice to use "I do not care" with a name, which will make your life easier in the future if you actually decide that you need to use other arguments:
def foo(_name, _html_options, options)
options.delete(:some_option)
super
end
The issue I am faced with is that I need to prevent a Ruby class from being manipulated after it is defined. I can freeze it, but that doesn't stop people from just overwriting it all together.
I realize that some will want to respond with some sort of "Ruby isn't meant to be used like this" mantra. I get it, but my case is very special. This is for codewars.com where user submitted solutions are combined with a custom test framework, so I need to stop the user-submitted code from tinkering with the Test class.
I had thought that it wasn't possible at all to make constants true constants, but I noticed that the $? global variable is like this. Its likely that its because its built-in to the language to be like this and not something that can be done with custom variables.
That's because it is built into the language.
In Ruby there is no way to truly define a constant. The closest you can come is writing custom getters/setters and throwing an error if a variable has already been set.
Throw exception when re-assigning a constant in Ruby?
This is defined as "The status of the last executed child process." so, if you assign something to that variable, it will be immediately overwritten by the language with the result of the last (your) assignation.
I would think about a custom implementation - perhaps extracted into some helper gem?
def foo
#foo
end
def foo=(foo)
if defined?(#foo)
warn "warning: already initialized foo"
else
#foo = foo
end
end
self.foo = :bar
puts foo # => bar
self.foo = :baz # => warning: already initialized foo
puts foo # => bar
More specifically:
When do you need to prefix the scope with :: (like ::Foo::Bar)
When is directly referring to a scoped const ok? (just Foo::Bar)
Is there a good reason why this behavior is so confusing?
EDIT: I am talking about stuff like this
module Foo
THING = 'thing'
module Bar
puts THING
end
end
#=> thing
module Foo::Bar
puts THING
end
#=> NameError: uninitialized constant Foo::Bar::THING
When do you need to prefix the scope
with :: (like ::Foo::Bar)
When there's another constant with the same name in the current namespace.
When is directly referring to a scoped
const ok? (just Foo::Bar)
When there isn't another constant with the same name in the current namespace. Ie. when that identifier is unambiguous. Similarly, you could just use Bar to aid readability if it was unambiguous.
Is there a good reason why this
behavior is so confusing?
It's balancing readability and ease of use against specificity. You don't always want to have to do ::Foo::Bar::Baz::Boo (the globally unique identifier) when you're deep down in your namespace.
In as far as I've understood/experienced it: when in a module/class Foo, then Bar refers to Foo::Bar unless it doesn't exist -- in which case it means ::Bar.)
Please take it with a grain of salt, though, because I'm new to ruby as well. :-P
In Ruby, you can easily access local variables programmatically by using local_variables and eval. I would really like to have meta-programming access to these variables using a single method call such as
# define a variable in this scope, such as
x = 5
Foo.explore_locals # inside the Foo#explore_locals method, access x
where Foo is some external module. The idea is to display and export local variables in a nice way.
What should be inside the explore_locals method? Is there any way to make this possible? If absolutely necessary, I guess it could be
Foo.explore_locals binding
but this is much less elegant for the application I have in mind.
It's a shame there isn't a built-in way to get the caller's binding. The block trick seems to be the usual answer to this question.
However there is another 'trick' which existed for older 1.8 Ruby versions called binding_of_caller. Looks like quix ported it to 1.9. You might want to check that out:
https://github.com/quix/binding_of_caller
Here is an example (but it requires extra braces {} which I would rather avoid if possible):
module Foo
def self.explore_locals &block
p block.binding.eval 'local_variables'
end
end
local_1 = 3
Foo.explore_locals{} # shows [:local_1, :_]
I often have functions which take a parameter, set an instance variable to that parameter, and then do other things, e.g.:
def updateFoo(self, foo):
self.foo = foo
fooProcessor1(foo)
fooProcessor2(self.foo)
Do you prefer to pass the parameter itself, as in fooProcessor1, or the newly-set instance variable, as in fooProcessor2? Why or why not?
A function named setFoo() really shouldn't do anything more than setting foo unless it is computing and caching a value derived from foo, in which case I would advise something along the lines of:
def setFoo(self, foo):
self.foo = foo
self.__fooUpdated()
def __fooUpdated(self):
# Recompute values derived from foo, dispatch signal to listeners, etc.
Of the options you suggested, I prefer fooProcessor1(foo). That said, it is mostly a matter of personal preference. As long as you are consistent, I don't think it matters all that much.
Coders should be lazy. self. is way too much to type at 1 am.