Lucas Steffen
Lucas Steffen

Reputation: 1364

Access `self` of an object through the parameters

Let's say I want to access an element of an array at a random index this way:

[1, 2, 3, 4].at(rand(4))

Is there a way to pass the size of the array like the following?

[1, 2, 3, 4].at(rand(le_object.self.size))

Why would I do that?--A great man once said: Science isn't about why, it is about why not.

Upvotes: 4

Views: 230

Answers (4)

Stefan
Stefan

Reputation: 114138

Not recommended, but instance_eval would somehow work:

[1, 2, 3, 4].instance_eval { at(rand(size)) }

And you can also break out of tap:

[1, 2, 3, 4].tap { |a| break a.at(rand(a.size)) }

There's an open feature request to add a method that yields self and returns the block's result. If that makes it into Ruby, you could write:

[1, 2, 3, 4].insert_method_name_here { |a| a.at(rand(a.size)) }

Upvotes: 4

Wand Maker
Wand Maker

Reputation: 18762

You can use instance_eval to execute ruby code with the binding of the array variable

[1, 2, 3, 4].instance_eval { at(rand(size)) }

Assuming you are interested in a random element as Array#at returns an element at given index, you can use Array#sample to pick a random element from an array.

[1,2,3,4].sample
#=> 3

If you do not want to use instance_eval (or any form of eval), then, you can add a method to Array class by monkey patching - generally speaking, I am not sure whether it's a wise idea to monkey patch though

class Array
  def random_index
    rand(size)
  end
end

["a","b","c","d"].random_index
#=> 2

Upvotes: 2

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230286

No, you can't do that. Receiver of a method (that array) is not accessible by some special name at the call site. Your best bet is assigning a name to that object.

ary = [1, 2, 3, 4]
ary.at(rand(ary.size))

Of course, if all you need is a random element, then .sample should be used. Which does not require evaluation of any arguments at the call site and its self is the array.

Upvotes: 4

Leo Brito
Leo Brito

Reputation: 2051

You could do something similar with lambda:

getrand = ->(x) { x[rand(x.count)] }
getrand.call [1,2,3]
# => 2 

Upvotes: 1

Related Questions