Ruby method that returns itself - ruby-on-rails

I am doing some reflection, and ran into an unexpected road block.
Is there an object method in ruby (or rails) that returns itself
ruby-1.9.2> o = Object.new
=> #<Object:0x00000104750710>
ruby-1.9.2> o.class
=> Object
ruby-1.9.2> o.send :self
NoMethodError: undefined method `self' for #<Object:0x00000104750710>
What I want
ruby-1.9.2> o.send :self
=> #<Object:0x00000104750710>
Is this built in? Or do I need to extend Object (It always gets me nervous opening up Object):
class Object
def itself
self
end
end
And then so:
ruby-1.9.2> o.send :itself
=> #<Object:0x00000104750710>
Ok, some background on what I am trying to achieve. I have a generic table helper in my rails app, and you call if like so:
render_list #person, [{field: :name, link_to: :itself},
{field: {address: :name}, link_to: :address}]
I was struggling on the right way to call :itself -- but i'm thinking that my patch is the way to go.

Yes! If you have Ruby 2.2.0 or later, you can use the Kernel#itself method.
You can see the extensive discussion of this feature here: https://bugs.ruby-lang.org/issues/6373. The patch was submitted by Rafael França in message #53.
You can see it in the official Ruby source by looking in object.c.

There is a discussion about adding such method: http://bugs.ruby-lang.org/issues/6373

If you are using Ruby version >= 1.9 you can use tap method with empty block:
Object.tap{} => Object
Object.new.tap{} => #<Object:0x5f41334>

self is the object itself, no need to extra fetch it. After your patch, try the following:
>> a=[2,3,4] #=> [2, 3, 4]
>> a == a.itself #=> true
>> a.object_id #=> 71056290
>> a.itself.object_id #=> 71056290
...it is exactly the same

self is a keyword referring to the default receiver. It is not a method. See this page for an example.
Your itself method works fine. You can also say:
o.instance_eval('self')
For a class, use class_eval instead:
Object.class_eval('self')

There is a #yourself method in Smalltalk. It has sense because of the syntax of the language where you can send several messages to the same object and want to get the object itself at the end of the phrase.
aList add: (anObjet doThis; andThat; yourself).
Also in Smalltalk the default return value for a method is self, but in Ruby it's the last instruction's return value (or nil if there is nothing in the method).
Anyway maybe we should all start using explicit returns :)
If for some weird logic reason you have to call a method on some object but what you want is really the object itself, then I don't see why you couldn't extend the Object class to do just that.
There's really no reason why it would break your program unless the method exists somewhere else (did or will exist) and did (or will) do something else. Maybe a slight loss in performance?

Try .presence
>> a=[2,3,4]
=> [2, 3, 4]
>> a == a.presence
=> true

Related

trying to understand specific bit of ruby syntax

I'm new to both Ruby and Rails, and as I go over various tutorials, I occasionally hit on a bit of Ruby syntax that I just can't grok.
For instance, what does this actually do?
root to: "welcome#index"
I can gather that this is probably a method named "root", but I'm lost after that. "To" isn't a symbol, is it? The colon would be before, as in ":to" if it were. Is this some form of keyword argument utilizing hashes? I can't make this syntax work when trying it in irb with ruby1.9.3.
I know this might be a RTFM question, but I can't even think of what to google for this.
Thanks!
I'm still playing around with this syntax,
def func(h)
puts h[:to]
end
x = { :to => "welcome#index" }
y = :to => "welcome#index"
z = to: "welcome#index"
func to: "welcome#index"
I see that this example only works with the lines defining "y" and "z" commented out. So the braceless and the "colon-after" syntax are only valid in the context of calling a method?
First, that's right - root is a method call.
Now
to: 'welcome#index'
is equivalent to
:to => 'welcome#index'
and it's a Hash where the key is :to symbol and value is 'welcome#index' string. You can use this syntax in defining hashes since Ruby 1.9.
It's equivalent to
root(:to => "welcome#index")
I'm having trouble finding the official documentation on the new hash syntax, but when you see foo: bar, it means that foo is a symbol used as a key in the hash and has a value bar.
Here is an example of defining a function foo which takes a hash, and prints to screen.
def foo(hash)
puts hash.inspect
puts hash[:to]
end
foo to: "wecome#index" #method call without paratheses
Output of method call above:
{:to=>"welcome#index"}
welcome#index
Equivalent declarations:
h = {:to => "welcome#index"}
h = {to: "wecolme#index"}
Also, you can use Ripper (part of Ruby standard library) to understand how Ruby parses code. In the example below, I have already defined foo as above. Now, I call foo without using Ripper. Then I use Ripper to see how Ruby parses the method call.
[2] pry(main)> foo to: "welcome#index"
{:to=>"welcome#index"}
welcome#index
=> nil
[3] pry(main)> require 'ripper'
=> true
[4] pry(main)> Ripper.sexp 'foo to: "welcome#index"'
=> [:program,
[[:command,
[:#ident, "foo", [1, 0]],
[:args_add_block,
[[:bare_assoc_hash,
[[:assoc_new,
[:#label, "to:", [1, 4]],
[:string_literal,
[:string_content, [:#tstring_content, "welcome#index", [1, 9]]]]]]]],
false]]]]
In ruby braces in method calls are optional, so it can be rewritten as:
root(to: "welcome#index")
and it can be rewritten again as
root(:to => "welcome#index")
Hashes as keyword arguments(ruby 1.9) explained here as well: hash-constructor-parameter-in-1-9
P.S. and by the way general rule of the thumb for the rails-newcomers is "learn ruby first, then learn rails" ;)
As you correctly gathered, root is a method call. Or rather, it's a message send. Ruby, like Smalltalk, builds upon a messaging metaphor, where objects send messages to other objects, and those objects (called the receiver) respond to those messages.
In this case, you pass an argument to root, that's how you know it's a message send. Message sends are the only thing that can take arguments, if you see an argument, then it must be a message send. There are no functions, no static methods, no constructors, no procedures, only methods and message sends.
So, what is the argument? Well, in Ruby, a lot of things that are syntactically required in other languages are optional. For example, parenthesis around the argument list:
foo.bar(baz)
# can also be written as
foo.bar baz
If the very last argument to the message send is a Hash literal, you can leave off the curly braces:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar(:baz => 23, :quux => 42)
Put the two together, and you get:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar :baz => 23, :quux => 42
In Ruby 1.9, a new alternative Hash literal syntax was introduced. This literal syntax is very limited compared to the original one, because it can only express Hashes whose keys are Symbols which are also valid Ruby identifiers, whereas with the original syntax, you can write down a Hash with any arbitrary object as key. But, for that limited use case, it is very readable:
{ :baz => 23, :quux => 42 }
# can also be written as
{ baz: 23, quux: 42 }
If we put that feature together with the other two, we get the message send syntax you are asking about:
foo.bar baz: 23, quux: 42
If we have method declared with a single argument like this:
def foo.bar(opts) p opts end
opts will be bound to a single Hash with two key-value pairs.
These features were often used to emulate keyword arguments as found in other languages. And it has long been a desire of the Ruby community to get support for real keyword arguments. This support was implemented in two steps: first, the new Hash literal syntax was introduced in Ruby 1.9, which allows you to make message sends which look like they are using keyword arguments, even though they are really just a Hash. And then in a second step, in Ruby 2.0 real keyword arguments were introduced. The modified method signature would look like this:
def foo.bar(baz: nil, quux: nil) p baz, quux end
Note that at the moment, it is not possible to have required keyword arguments, they always need to have a default value and are thus always optional. You can, however, use the fact that default values can be arbitrary expressions and do something like this:
def foo.bar(baz: raise ArgumentError '`baz` must be supplied!',
quux: raise ArgumentError '`quux` must be supplied!') p baz, quux end
In a future version of Ruby (it was actually already implemented in February and will likely be in 2.1), required keyword arguments can be specified by omitting the default value:
def foo.bar(baz:, quux:) p baz, quux end
Note that there is a syntactic ambiguity now:
foo.bar baz: 23, quux: 42
# is this sending the message `bar` to `foo` with *one* `Hash` or *two* keywords?
This ambiguity is actually intentional, because it allows old client code written against APIs which use a Hash argument to work unchanged with new APIs that use keyword arguments. There are some semi-complex rules which determine whether that syntax will be interpreted as a Hash or as keywords, but mostly those rules work out the way you would expect them to.

Ruby 1.9.2 non-existent hash element

I'm on Rails 3.0.x, Ruby 1.9.2 and needs a way to test for params that may or may not exists, e.g.,
params[:user] #exists
params[:user][:login] #may not exist
What's the proper Ruby syntax for the 2nd check so it doesn't barf?
Try following:
params.has_key? :user #=> true because exists
params[:user].has_key? :login #=> true if exist otherwise false
#WarHog has it right, pretty much. It's very unusual for an item in params to sometimes return a string but other times return a Hash, but regardless you can handle that easily enough:
if params.has_key?(:user) && params[:user].respond_to?(:has_key?)
do_something_with params[:user][:login]
end
Instead of respond_to? :has_key? you could also do respond_to? :[] or just is_a? Hash. Mostly a matter of preference.
You would just get nil in the second case.. that shouldn't be a problem, no?
e.g. params[:user][:login] just returns nil, which evaluates to false if the :user entry exists in the first Hash.
However if the nesting would be one or more levels deeper, and the missing hash entry was somewhere in the middle, you would have problems. e.g.:
params[:user][:missing_key][:something]
in that case Ruby would try to evaluate nil[:something] and raise an exception
you could do something like this:
begin
x = params[:user][:missing_key][:something]
rescue
x = nil
end
... which you could further abstract...

Memcache basic use in rails 3

So I'm trying to learn how to use memcache. I installed it in my system. I'm running it. I installed the dalli gem.
All that seems to be just fine.
Lets say I'd like to cache my users table.
I put this in my User.rb file:
def self.all_cached
Rails.cache.fetch('User.all') { all }
end
Then in my controller file, I used to have:
#users = User.where(:group_id => current_user.group_id)
So now I'd like to have something like:
#users = User.all_cached.where(:group_id => current_user.group_id)
I'm getting a no method error for where... Any ideas for how I should accomplish this?
Based on your comment there, I take it you are getting an error like:
undefined method `where' for #<Array:0x00000004d92520>
That's because where works on a model, but when you do User.all, it returns basically an array, and there is no where method defined for an array.
You may want to use the find_all method for enumerables (and arrays) instead (as seen here: http://www.ruby-doc.org/core/classes/Enumerable.html#M001484), or even try a different approach all together. That's your choice.
Here is the example they give to give you an idea off the bat of how it would work:
(1..10).find_all {|i| i % 3 == 0 } #=> [3, 6, 9]

Ruby === not acting as it when left-hand argument is a class

I'm using Ruby 1.8.7 with Rails 3.0.1 and am having a problem whose root cause appears to be the "Array === object" operation. I saw the same behavior before in a class of my own creation, and programmed around it by not using the "===" operator (I assumed that there was some flaw in my knowledge of Ruby, which is still rather limited). But now that it is happening inside ActionPack, I need to do something about it.
This surfaced when the FormHelper "fields_for" was not acting the way it should. The following view code snippet ("<% %>" removed to improve readability):
form_for #coupon do |f|
...
f.fields_for #coupon.participants do |cp|
...
end
end
gave the error "ActionView::Template::Error (undefined method `model_name' for Array:Class):"
inside the form_for helper method. I determined that it was executing the wrong branch of a "case" command, set a breakpoint and started testing. Here are the results:
/Library/Ruby/Gems/1.8/gems/actionpack-3.0.1/lib/action_view/helpers/form_helper.rb:1152
case record_or_name_or_array
(rdb:1) pp record_or_name_or_array.instance_of? Array
true
(rdb:1) pp Array === record_or_name_or_array
false
(rdb:1) pp Array.object_id
2148267660
(rdb:1) pp record_or_name_or_array.class.object_id
2148267660
This shows pretty definitively that, while "record_or_name_or_array" is definitely an array, "Array === record_or_name_or_array" is returning false.
BTW, in case you're suspecting that "#f.fields_for" is the wrong syntax, I tried it both with and without the "#f." and got the same result. I have also restarted RoR and my machine and the results remain unchanged.
Try this:
#coupon = Coupon.last
Array === #coupon.participants #=> false
Array === #coupon.participants.find(:all) #=> true
Association #coupon.participants is not an array, it is a proxy. The reason why #coupon.participants.class == Array is true is described in activerecord-3.0.9/lib/active_record/associations/association_proxy.rb:25
Added: Another interesting experiment would be #coupon.participants.superclass.
From the console (rails c) try running:
#coupon = Coupon.last
Array == #coupon.participants
If that call returns false, it is most likely that your associations are incorrectly setup (i.e. has_many :participants and belongs_to :coupon).
#coupon.is_a? Array should return true, #coupon === Array would mean #coupon was equal to the singleton instance of Array

Equivalent of .try() for a hash to avoid "undefined method" errors on nil? [duplicate]

This question already has answers here:
How to avoid NoMethodError for nil elements when accessing nested hashes? [duplicate]
(4 answers)
Closed 7 years ago.
In Rails we can do the following in case a value doesn't exist to avoid an error:
#myvar = #comment.try(:body)
What is the equivalent when I'm digging deep into a hash and don't want to get an error?
#myvar = session[:comments][#comment.id]["temp_value"]
# [:comments] may or may not exist here
In the above case, session[:comments]try[#comment.id] doesn't work. What would?
You forgot to put a . before the try:
#myvar = session[:comments].try(:[], #comment.id)
since [] is the name of the method when you do [#comment.id].
The announcement of Ruby 2.3.0-preview1 includes an introduction of Safe navigation operator.
A safe navigation operator, which already exists in C#, Groovy, and
Swift, is introduced to ease nil handling as obj&.foo. Array#dig and
Hash#dig are also added.
This means as of 2.3 below code
account.try(:owner).try(:address)
can be rewritten to
account&.owner&.address
However, one should be careful that & is not a drop in replacement of #try. Take a look at this example:
> params = nil
nil
> params&.country
nil
> params = OpenStruct.new(country: "Australia")
#<OpenStruct country="Australia">
> params&.country
"Australia"
> params&.country&.name
NoMethodError: undefined method `name' for "Australia":String
from (pry):38:in `<main>'
> params.try(:country).try(:name)
nil
It is also including a similar sort of way: Array#dig and Hash#dig. So now this
city = params.fetch(:[], :country).try(:[], :state).try(:[], :city)
can be rewritten to
city = params.dig(:country, :state, :city)
Again, #dig is not replicating #try's behaviour. So be careful with returning values. If params[:country] returns, for example, an Integer, TypeError: Integer does not have #dig method will be raised.
The most beautiful solution is an old answer by Mladen Jablanović, as it lets you to dig in the hash deeper than you could with using direct .try() calls, if you want the code still look nice:
class Hash
def get_deep(*fields)
fields.inject(self) {|acc,e| acc[e] if acc}
end
end
You should be careful with various objects (especially params), because Strings and Arrays also respond to :[], but the returned value may not be what you want, and Array raises exception for Strings or Symbols used as indexes.
That is the reason why in the suggested form of this method (below) the (usually ugly) test for .is_a?(Hash) is used instead of (usually better) .respond_to?(:[]):
class Hash
def get_deep(*fields)
fields.inject(self) {|acc,e| acc[e] if acc.is_a?(Hash)}
end
end
a_hash = {:one => {:two => {:three => "asd"}, :arr => [1,2,3]}}
puts a_hash.get_deep(:one, :two ).inspect # => {:three=>"asd"}
puts a_hash.get_deep(:one, :two, :three ).inspect # => "asd"
puts a_hash.get_deep(:one, :two, :three, :four).inspect # => nil
puts a_hash.get_deep(:one, :arr ).inspect # => [1,2,3]
puts a_hash.get_deep(:one, :arr, :too_deep ).inspect # => nil
The last example would raise an exception: "Symbol as array index (TypeError)" if it was not guarded by this ugly "is_a?(Hash)".
The proper use of try with a hash is #sesion.try(:[], :comments).
#session.try(:[], :comments).try(:[], commend.id).try(:[], 'temp_value')
Update: As of Ruby 2.3 use #dig
Most objects that respond to [] expect an Integer argument, with Hash being an exception that will accept any object (such as strings or symbols).
The following is a slightly more robust version of Arsen7's answer that supports nested Array, Hash, as well as any other objects that expect an Integer passed to [].
It's not fool proof, as someone may have created an object that implements [] and does not accept an Integer argument. However, this solution works great in the common case e.g. pulling nested values from JSON (which has both Hash and Array):
class Hash
def get_deep(*fields)
fields.inject(self) { |acc, e| acc[e] if acc.is_a?(Hash) || (e.is_a?(Integer) && acc.respond_to?(:[])) }
end
end
It can be used the same as Arsen7's solution but also supports arrays e.g.
json = { 'users' => [ { 'name' => { 'first_name' => 'Frank'} }, { 'name' => { 'first_name' => 'Bob' } } ] }
json.get_deep 'users', 1, 'name', 'first_name' # Pulls out 'Bob'
say you want to find params[:user][:email] but it's not sure whether user is there in params or not. Then-
you can try:
params[:user].try(:[], :email)
It will return either nil(if user is not there or email is not there in user) or otherwise the value of email in user.
As of Ruby 2.3 this gets a little easier. Instead of having to nest try statements or define your own method you can now use Hash#dig (documentation).
h = { foo: {bar: {baz: 1}}}
h.dig(:foo, :bar, :baz) #=> 1
h.dig(:foo, :zot) #=> nil
Or in the example above:
session.dig(:comments, #comment.id, "temp_value")
This has the added benefit of being more like try than some of the examples above. If any of the arguments lead to the hash returning nil then it will respond nil.
#myvar = session.fetch(:comments, {}).fetch(#comment.id, {})["temp_value"]
From Ruby 2.0, you can do:
#myvar = session[:comments].to_h[#comment.id].to_h["temp_value"]
From Ruby 2.3, you can do:
#myvar = session.dig(:comments, #comment.id, "temp_value")
Another approach:
#myvar = session[:comments][#comment.id]["temp_value"] rescue nil
This might also be consider a bit dangerous because it can hide too much, personally I like it.
If you want more control, you may consider something like:
def handle # just an example name, use what speaks to you
raise $! unless $!.kind_of? NoMethodError # Do whatever checks or
# reporting you want
end
# then you may use
#myvar = session[:comments][#comment.id]["temp_value"] rescue handle
When you do this:
myhash[:one][:two][:three]
You're just chaining a bunch of calls to a "[]" method, an the error occurs if myhash[:one] returns nil, because nil doesn't have a [] method. So, one simple and rather hacky way is to add a [] method to Niclass, which returns nil: i would set this up in a rails app as follows:
Add the method:
#in lib/ruby_extensions.rb
class NilClass
def [](*args)
nil
end
end
Require the file:
#in config/initializers/app_environment.rb
require 'ruby_extensions'
Now you can call nested hashes without fear: i'm demonstrating in the console here:
>> hash = {:foo => "bar"}
=> {:foo=>"bar"}
>> hash[:foo]
=> "bar"
>> hash[:doo]
=> nil
>> hash[:doo][:too]
=> nil
Andrew's answer didn't work for me when I tried this again recently. Maybe something has changed?
#myvar = session[:comments].try('[]', #comment.id)
The '[]' is in quotes instead of a symbol :[]
Try to use
#myvar = session[:comments][#comment.id]["temp_value"] if session[:comments]

Resources