Array of Types in Ruby - ruby

I am trying to create instances of objects of various types by iterating and checking for validity. I need an array of types so I can do something like this:
def tryClasses(in)
types = [Foo::A, Foo::B, Foo::C]
types.each do |type|
a = type.new(in)
return a != null
end
end
How do I create and array of class types?
Doing it this way I am getting a NoMethodError (undefined method 'A' for Foo)

Apart from the obvious syntactic errors (e.g. in is a reseved word, and null is spelled nil in Ruby), the code you showed should work just fine as it is, and indeed it does when I copy&paste it into my Ruby installation. This assumes, of course, that the classes Foo::A, Foo::B and Foo::C actually exist. If they don't, then the code obviously cannot possibly work.
It is, however, completely un-Rubyish and violates just about every coding convention in the book:
indentation is 2 spaces
method names are snake_case, not camelCase
explicitly checking for equality to nil is a no-no, simply calling #nil? is much preferred
try_classes isn't exactly an intention-revealing method name
and WTF does in mean?
Rubyists much prefer higher-order methods over explicit looping
Here's a more Rubyish version of the code you wrote:
def can_create_object?(*args)
[Foo::A, Foo::B, Foo::C].none? do |klass|
klass.new(*args).nil?
end
end
However, note that I am pretty convinced that the whole idea is fundamentally flawed.

Related

Why is there no `.split!` in Ruby?

It just seems pretty logical to have it when there's even a downcase!. Has anyone else run into this use case in Ruby?
For the curious, I'm trying to do this:
def some_method(foo)
foo.downcase!.split!(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Instead of this:
def some_method(foo)
foo = foo.downcase.split(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Which isn't a really big deal...but ! just seems cooler.
Why is there no .split! in Ruby?
It just seems pretty logical to have it when there's even a downcase!.
It may be logical, but it is impossible: objects cannot change their class or their identity in Ruby. You may be thinking of Smalltalk's become: which doesn't and cannot exist in Ruby. become: changes the identity of an object and thus can also change its class.
I don't see this "use case" as very important.
The only thing a "bang method" is doing is saving you the trouble of assigning a variable.
The reason "bang methods" are the exception instead of the rule is they can produce confusing results if you don't understand them.
i.e. if you write
a = "string"
def my_upcase(string)
string.upcase!
end
b = my_upcase(a)
then both a and b will have transformed value even if you didn't intend to change a. Removing the exclamation point fixes this example, but if you're using mutable objects such as hashes and arrays you'll have to look out for this in other situations as well.
a = [1,2,3]
def get_last_element(array)
array.pop
end
b = get_last_element(a)
Since Array#pop has side effects, a is now 1,2. It has the last element removed, which might not have been what you intended. You could replace .pop here with [-1] or .last to get rid of the side effect
The exclamation point in a method name is essentially warning you that there are side effects. This is important in the concept of functional programming, which prescribes side effect free code. Ruby is very much a functional programming language by design (although it's very object oriented as well).
If your "use case" boils down to avoiding assigning a variable, that seems like a really minor discomfort.
For a more technical reason, though, see Jorg Mittag's answer. It's impossible to write a method which changes the class of self
this
def some_method(foo)
foo = foo.downcase.split(" ")
end
some_method("A String like any other")
is the same as this
def some_method(foo)
foo.downcase.split
end
some_method("A String like any other")
Actually, both of your methods return the same result. We can look at a few examples of methods that modify the caller.
array.map! return a modified original array
string.upcase! return a modified original string
However,
split modifies the class of the caller, changing a string to an array.
Notice how the above examples only modify the content of the object, instead of changing its class.
This is most likely why there isn't a split! method, although it's pretty easy to define one yourself.
#split creates an array out of a string, you can't permanently mutate(!) the string into being an array. Because the method is creating a new form from the source information(string), the only thing you need to do to make it permanent, is to bind it to a variable.

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.

Make a NullObject evaluate to falsy in Ruby

After implementing Null Object Pattern in a Rails application (also described in RubyTapas episode 112) I refactored out some code, but there's a syntax construct that seems to not work anymore.
I used to write statements like current_user || redirect_out, where, if current_user was set it would return it, and if it was nil it redirects out, but now current_user may be an instance of Null::User and thus "truthy", and that snippet would never redirect out.
I tried defining the || operator, but didn't work. Is there any way this syntax can still be used with null (but "truthy") objects?
I think you have only halfway adopted that pattern, and have not correctly adopted its spirit. My understanding is that the very purpose of the pattern is to avoid ||.
You should have some purpose for calling current_user || redirect_out, and that could be doing something with it, or getting some attribute of it. For example, suppose your code has:
(current_user || redirect_out).foo
When current_user is not an instance of Null::User, you wanted to call foo on it. In that case, what you should do is define Null::User#foo to be redirect_out (possibly followed by some more operations like foo on other classes).
class Null::User
def foo; redirect_out ... end
end
and in place of (current_user || redirect_out).foo, you should just do
current_user.foo
When current_user is not a Null::User instance, it will call foo. When it is such instance, then the redirect_out ... routine will be called on it.
I once wrote an article about how it's not possible to define "falsy" objects in Ruby, and why attempts to make a Null Object falsy are generally misguided.
Basically, the best you can do is come up with a confusingly inconsistent object using #!, nil?, etc.
As others have noted, usually when you want to make a Null Object "falsy" it's because you're not full leveraging polymorphism. The whole point of a Null Object is to avoid type checks, and checking for NilClass in the form of an if statement is just as much a type check as any other.
That said, sometimes it's unavoidable. That's why in my Naught library I generate a helper conversion function called Actual() (among several other conversions). Actual() converts Null Objects back to nil values, but leaves all other objects alone. So for the cases where you need to switch on an object's truthiness, you can do it like this:
if Actual(obj_that_might_be_null)
# ...do stuff...
end
There are exactly two objects which are falsy in Ruby: nil and false. Period.
Unfortunately, it is not possible to define your own falsy objects, nor is it possible to override the Boolean operators (except for not/!). This is a shame, really: it is one of the basic pillars of OO that an object can simulate another object, but in Ruby it is not possible to simulate false or nil, therefore breaking one of the fundamental properties of OO in a language with an otherwise pretty good OO 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.

Why is NilClass#to_hash lacking?

Various methods defined on NilClass are handy to avoid Method undefined on NilClass errors, and frees you from using try, oror, andand, ||, && in various occasions:
to_a for multiple dimensioned array when there might not be some values for some indices:
array[i].to_a[j].to_a[k]
to_s pattern match that might fail:
string[regex].to_s*2
to_i, to_f, to_c for index search that might fail, etc:
array.index(element).to_i*3
But there is no NilClass#to_hash although there is Hash#to_hash.
If such method existed (class NilClass; def to_hash; {} end end), then we would be able to do:
to_hash for multiple embedded hash when there might not be some values for some keys:
hash[:a].to_hash[:b].to_hash[:c]
The best alternative I can think of is:
hash.fetch(:a, {}).fetch(:b, {})[:c]
but it would be nice if we had NilClass#to_hash. Why is it missing?
It's a good point, and in Ruby, you can always monkeypatch such a method into nil, and the libraries in Rails do quite a bit of that kind of monkeypatching. Personally, I try to avoid doing much of that, because altering the behavior of a widely-used class can have unforeseen side effects in other libraries. If the patch is being performed by a popular framework, that's fine, because other libraries should have been tested with that, but doing it willy nilly is something else, altogether.
I'm thinking a NilClass#to_hash would exist by now, if that would address a pain point that a lot of folks were feeling. The try syntax is not any longer, and not too horribly ugly.
hash.try(:[],a).try(:[],b).try(:[],c)
Edited
I sent a request about NilClass#to_hash to ruby development. Matz rejected it shortly. Andrew notified me in the comment below that Matz gave a comment to it. Answer to the question is thus given my Matz, and you can see that by following Andrew's link below.
I would also be interested in a NilClass#to_hash method.
Here is the answer by Matz:
to_a, etc. are explicit conversion methods, whereas to_int, to_hash,
etc. are implicit conversion methods. I don't see any good reason to
add implicit conversion methods to nil.
Here is the question by Tsuyoshi Sawada:
Various methods defined on NilClass are handy to avoid Method
undefined on NilClass errors. For example,
to_a for multiple dimensioned array when there might not be some values for some indices:
array[i].to_a[j].to_a[k]
to_s for pattern match that might fail:
string[regex].to_s*2
to_i, to_f, to_c for index search that might fail, etc:
array.index(element).to_i*3
But there is no NilClass#to_hash even though there is
Hash#to_hash. If such method existed (equivalent to class
NilClass; def to_hash; {} end end), then we would be able to do:
to_hash for multiple embedded hash when there might not be some values for some keys:
hash[:a].to_hash[:b].to_hash[:c]
Is there any reason why to_a, to_s, to_i, to_f, to_c are all
defined on NilClass but not for to_hash? If there is not, I would
like to request this feature.
Source

Resources