Is this pattern considered idiomatic for declaring class options? - ruby

Is this pattern OK for declaring class level options? What is Options considered here? A class (class names start with a capital letter)? A constant? A normal variable inside the class?
class Markdown
Options = {
no_intra_emphasis: true,
fenced_code_blocks: true,
strikethrough: true
}
def initialize(text, options = {})
#text = text
#options = options.reverse_merge!(Options)
end
end

Whether it is usual or unusual does not matter. It is valid, and can be useful. It is a constant referring to a hash, not a class, nor a variable.
It is not that particularly a class name starts with a capital letter. A constant starts with a capital letter, of which a class name is a special case. But a capital does not necessarily mean a constant. Method names may or may not start with a capital.

As Options is a constant, I would rather use a name like OPTIONS, which is closer to Ruby convention (you can see that id uses names like File::Constants::APPEND, in http://www.ruby-doc.org/core-2.1.0/File/Constants.html). The way it is written now, it makes me think of a class rather than a constant.

Can you tell what it's doing and why within a few seconds of looking at it? If so, it communicates its point effectively, even if it is somewhat non-idiomatic. In this case, it looks like it defines some default values for #options, so it looks good to me - unless it does something else in the context of your overall program, in which case it's confusing because it does something besides what it looks like it's doing.
Also, Options is capitalized to indicate that should be treated as a constant and ideally shouldn't be changed at runtime. That's also why class names are usually capitalized: they are usually constants. (Ruby doesn't actually enforce this. It's a convention used to make it easier to tell what values shouldn't be changed without deliberately using metaprogramming techniques.)

The CSV library does this too; the constant is called DEFAULT_OPTIONS there.

Related

Provide alias for Ruby's built-in keyword

For example, I want to make Object#rescue another name so I can use in my code like:
def dangerous
something_dangerous!
dont_worry # instead of rescue here
false
end
I tried
class ::Object
alias :dont_worry :rescue
end
But cannot find the rescue method on Object:
`<class:Object>': undefined method `rescue' for class `Object' (NameError)
Another example is I would like to have when in the language to replace:
if cond
# eval when cond is truthy
end
to
when cond
# eval when cond is truthy
end
Is it possible to give a Ruby keyword alias done in Ruby?
Or I need to hack on Ruby C source code?
Thanks!
This is not possible without some deep changes to the Ruby language itself. The things you describe are not methods but keywords of the language, i.e. the actual core of what is Ruby. As such, these things are not user-changeable at all.
If you still want to change the names of the keywords, you would at least have to adapt the language parser. If you don't change semantics at all, this might do it as is. But if you want to change what these keywords represent, things get messy really quick.
Also note that Ruby in itself is sometimes quite ambiguous (e.g. with regards to parenthesis, dots, spacing) and goes to great length to resolve this in a mostly consistent way. If you change keywords, you would have to ensure that things won't get any more ambiguous. This could e.g. happen with your change of if to when. when is used as a keywords is case statements already and would thus could be a source of ambiguity when used as an if.

Is it good practice having local variables starting with underscore?

I'm just getting into Ruby and come from the Java and C/C++ environment.
While coding a first little project in Ruby, I somehow got used to let all local variables start with an underscore. I guess my main motivation for this was a better readability and distinction from method calls.
As in principle there are only three types of variables ($global, #instance and local), the vast majority of variables start with an underscore. I'm not really sure, whether this is good or bad. Besides, in a lot other languages, the underscore would be substituted to some other character.
Is there somehow a best practice concerning variable naming beside the usual CamelCase and/or underscore separated? What are the habits of the professional "rubyists"? Have I overlooked some general Ruby conventions, when I chose the leading underscore?
edit
Thanks to all answers and suggestions. It helped me a lot.
Short Summary of Answers and Comments below
(for the short-on-time visitor)
Leading underscores go with:
method arguments: def my_method(_my_arg)
block arguments: e.g. my_array.each { |_x| puts _x}
All other local variables without leading underscores, as programmers coming from e.g. JavaScript might get confused about intended behaviour of the variables.
For visual separation between variable names and method calls, forcing oneself to use "(" brackets ")" with all method calls might increase readability significantly.
Existing answers to this question are now a few years old, and conventions have changed. You should only ever use a leading underscore (_some_param), or a standalone underscore (_), to indicate that you don't care about the value. The rubocop style linting tool will carp about a "useless assignment" if you assign a variable but don't use it, but it will ignore variables with a leading underscore. This allows you to expressly indicate that you don't care about the value and don't intend to use it.
Here's a somewhat-contrived example use-case in an RSpec context:
describe 'login' do
let(:user) { FactoryGirl.create(:user, login: 'bob') }
it 'must be unique' do
_user1 = user
user2 = User.new login: 'bob'
expect(user2.valid?).to be_false
end
end
Here we're indicating that our user helper has a side-effect and returns something, but we don't care about it. You could also just skip the assignment entirely, but seeing a bare user on a line by itself looks odd and doesn't reveal the intention as clearly:
describe 'login' do
let(:user) { FactoryGirl.create(:user, login: 'bob') }
it 'must be unique' do
user
user2 = User.new login: 'bob'
expect(user2.valid?).to be_false
end
end
Other scenarios include ignoring values in iterators, or overriding a method where you want to keep the original method signature but don't care about some of the values:
def greet(name, _title)
puts "Hi, #{name}!"
end
In my experience, underscore-prefixed variables in Ruby are much like underscore-prefixed variables in JavaScript: a "don't touch" flag. More specifically, they are used when the implementer is doing something that really is not supposed to be understood as a part of the object, or shouldn't be thought of as the conceptual interface of the object.
This is more clear in the JavaScript world, where somebody is emulating "private" by prefixing a variable with an underscore. They are encoding that there's part of the object that's under the hood and can be ignored when looking at the object from the outside.
In Ruby, I've only really seen this with things like a cache or a singleton instance - the kind of thing that should be invisible to consumers of your object. Non-underscored variables are things that people using your object might be interested to know are there.
In any case, they seem fairly rare, and I would avoid them unless you want to send a signal to the next guy that's coming along that there's some extra magic or voodoo happening.
As far as making a distinction for method calls, if you're worried that there can be confusion between a method and a local variable, I would call the method on self to clarify. For instance:
def foo
...
end
def some_method
foo # method
bar # variable
end
If this seems unclear for whatever reason, you can clarify with
def some_method
self.foo
bar
end
Nothing wrong with your idea. But if I was having trouble distinguishing local vars from method calls, I would probably just force myself to always use ()'s on methods. (My team at work has discussed making this part of our coding standards).
a = thing # var
b = thing() # method
The possible advantage to this is readability to others. Someone may wonder at your leading _'s, but using ()'s on all method calls should be clear to everyone.
Seeing as how instance variables have the # sign in front of them, and global variables have the $ sign in front of them already in ruby, it is probably unnecessary to put an underscore character in front of the variable names. That being said, I don't think it is a bad practice necessarily. If it helps you to read or write your code in Ruby, then you should use it.
I have sometimes seen Ruby code where an argument for an instance method on a class has an underscore in front of it. Such as:
def my_method(_argument1)
# do something
end
And I think that when you are dealing with a class that may have it's own attributes, like a model file in rails, for instance, this can be helpful so that you know you are dealing with a variable that has been passed into the method as opposed to one of the attributes that belongs to the class/model.

Built-in way to determine whether a string is a Ruby reserved word?

Is there something built-in with Ruby to determine if a string is a reserved word? Something like "next".is_keyword??
The only way I can think of is loading an array with all the keywords you know about.
class String
def is_keyword?
%w{__FILE__ __LINE__ alias and begin BEGIN break case class def defined? do else elsif end END ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield}.include? self
end
end
"foobar".is_keyword? # => false
"for".is_keyword? # => true
For reference:
I know this isn't a built-in way, it's just the only way I could think of. Don't downvote me for it.
The list I included is that of true keywords. public, protected and friends aren't really keywords, just the names of important methods which are called during the creation of modules or classes. You can think of it as elements of the Ruby DSL.
As far as I know, protected isn't really a reserved word. It's just the name of an important method.
http://wiki.rubyonrails.org/rails/pages/reservedwords lists reserved words you can't use (some of them only apply if you're using Rails or its dependencies), and method names that can cause problems.
If this doesn't fully answer your question, can you define more fully whether you're interested in method names or variable names, and whether you're worried about words that can't be used at all, or words that may cause other things to go wrong?
Use Ruby gem rubykeyword. It does more than identifying the keyword. string.keyword? tells you if its keyword or not. string.define gives a definition of the keyword. There is string.example too.
If you have a class where you want to implement a method called "protected", then before you define that method make an instance of that class and call
instance.methods
This will show you all the methods inherited for the class, and if "protected" is there then it is reserved by ruby.

How do I define a setter for a property whose name ends with a question mark?

I'm trying to add a property called "enabled?" to a model with both a getter and a setter. However, when I do the following:
def enabled?= value
# .. logic goes here ..
end
I get syntax error, unexpected '?', expecting '\n' or ';'
What should I be doing instead?
Yes, ruby syntax only allows ? in method names if it's the last character, so foo?= is not valid. One thing you could do, that would be pretty idiomatic, is to define enabled?, enable and disable (or enable! and disable! if you want to emphasize that they're mutating methods).
If that doesn't fit your needs, you can just name the methods enabled? and enabled= and just live with the slight incosistency between the names.
A method name in ruby starts with a lower case letter or underscore optionally followed by upper and lower case letters underscores and digts. A method name may optionally end with a question mark, exclamation mark or equals sign.
So you can't!
You could follow the usual ruby idiom of defining enabled as follow :-
def enabled?
#enabled
end
def enabled=(value)
#enabled = value
end
To summarise. If you want to expose properties to the outside world then ensure your variable name will allow that within the confines of the rules for method names.
One small variation would be to alias the getter method, allowing both enabled and enabled?:
def enabled
#enabled
end
def enabled=(value)
#enabled = value
end
alias_method :enabled?, :enabled
Name your property just enabled
The query methods are just syntactic sugar, they are not mean to be used as properties or instance variables. You can add the method enabled? for syntactic sugar if you wish too.
I always name my boolean variables to start with 'is', as in 'isEnabled'. Then it has the same meaning as having the question mark w/o the need for complexity.

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