Removing Identical Objects in Ruby? - ruby

I am writing a Ruby app at the moment which is going to search twitter for various things. One of the problems I am going to face is shared results between searches in close proximity to each other time-wise. The results are returned in an array of objects each of which is a single tweet. I know of the Array.uniq method in ruby which returns an array with all the duplicates removed.
My question is this. Does the uniq method remove duplicates in so far as these objects point to the same space in memory or that they contain identical information?
If the former, whats the best way of removing duplicates from an array based on their content?

Does the uniq method remove duplicates
in so far as these objects point to
the same space in memory or that they
contain identical information?
The method relies on the eql? method so it removes all the elements where a.eql?(b) returns true.
The exact behavior depends on the specific object you are dealing with.
Strings, for example, are considered equal if they contain the same text regardless they share the same memory allocation.
a = b = "foo"
c = "foo"
[a, b, c].uniq
# => ["foo"]
This is true for the most part of core objects but not for ruby objects.
class Foo
end
a = Foo.new
b = Foo.new
a.eql? b
# => false
Ruby encourages you to redefine the == operator depending on your class context.
In your specific case I would suggest to create an object representing a twitter result and implement your comparison logic so that Array.uniq will behave as you expect.
class Result
attr_accessor :text, :notes
def initialize(text = nil, notes = nil)
self.text = text
self.notes = notes
end
def ==(other)
other.class == self.class &&
other.text == self.text
end
alias :eql? :==
end
a = Result.new("first")
b = Result.new("first")
c = Result.new("third")
[a, b, c].uniq
# => [a, c]

For anyone else stumbling upon this question, it looks like things have changed a bit since this question was first asked and in newer Ruby versions (1.9.3 at least), Array.uniq assumes that your object also has a meaningful implementation of the #hash method, in addition to .eql? or ==.

uniq uses eql?, as documented in this thread.
See the official ruby documentation for the distinction between ==, equal?, and eql?.

I believe that Array.uniq detects duplicates via the objects' eql? or == methods, which means its comparing based on content, not location in memory (assuming the objects provide a meaningful implementation of eql? based on content).

Related

Ruby: Why does `#hash` need to overridden whenever `#eql?` is overridden?

In this presentation the speaker has created a value class.
In implementing it, he overrides #eql? and says that in Java development, the idiom is that whenever you override #eql? you must override #hash.
class Weight
# ...
def hash
pounds.hash
end
def eql?(other)
self.class == other.class &&
self.pounds == other.pounds
end
alias :== eql?
end
Firstly, what is the #hash method? I can see it returns an integer.
> 1.hash
=> -3708808305943022538
> 2.hash
=> 1196896681607723080
> 1.hash
=> -3708808305943022538
Using pry I can see that an integer responds to #hash but I cannot see where it inherits the method from. It's not defined on Numeric or Object. If I knew what this method did, I would probably understand why it needs to be overridden at the same time as #eql?.
So, why does #hash need to be overridden whenever eql? is overridden?
Firstly, what is the #hash method? I can see it returns an integer.
The #hash method is supposed to return a hash of the receiver. (The name of the method is a bit of a giveaway).
Using pry I can see that an integer responds to #hash but I cannot see where it inherits the method from.
There are dozens of questions of the type "Where does this method come from" on [so], and the answer is always the same: the best way to know where a method comes from, is to simply ask it:
hash_method = 1.method(:hash)
hash_method.owner #=> Kernel
So, #hash is inherited from Kernel. Note however, that there is a bit of a peculiar relationship between Object and Kernel, in that some methods that are implemented in Kernel are documented in Object or vice versa. This probably has historic reasons, and is now an unfortunate fact of life in the Ruby community.
Unfortunately, for reasons I don't understand, the documentation for Object#hash was deleted in 2017 in a commit ironically titled "Add documents". It is, however, still available in Ruby 2.4 (bold emphasis mine):
hash → integer
Generates an Integer hash value for this object. This function must have the property that a.eql?(b) implies a.hash == b.hash.
The hash value is used along with eql? by the Hash class to determine if two objects reference the same hash key. […]
So, as you can see, there is a deep and important relationship between #eql? and #hash, and in fact the correct behavior of methods that use #eql? and #hash depends on the fact that this relationship is maintained.
So, we know that the method is called #hash and thus likely computes a hash. We know it is used together with eql?, and we know that it is used in particular by the Hash class.
What does it do, exactly? Well, we all know what a hash function is: it is a function that maps a larger, potentially infinite, input space into a smaller, finite, output space. In particular, in this case, the input space is the space of all Ruby objects, and the output space is the "fast integers" (i.e. the ones that used to be called Fixnum).
And we know how a hash table works: values are placed in buckets based on the hash of their keys, if I want to find a value, then I only need to compute the hash of the key (which is fast) and know which bucket I find the value in (in constant time), as opposed to e.g. an array of key-value-pairs, where I need to compare the key against every key in the array (linear search) to find the value.
However, there is a problem: Since the output space of a hash is smaller than the input space, there are different objects which have the same hash value and thus end up in the same bucket. Thus, when two objects have different hash values, I know for a fact that they are different, but if they have the same hash value, then they could still be different, and I need to compare them for equality to be sure – and that's where the relationship between hash and equality comes from. Also note that when many keys and up in the same bucket, I will again have to compare the search key against every key in the bucket (linear search) to find the value.
From all this we can conclude the following properties of the #hash method:
It must return an Integer.
Not only that, it must return a "fast integer" (equivalent to the old Fixnums).
It must return the same integer for two objects that are considered equal.
It may return the same integer for two objects that are considered unequal.
However, it only should do so with low probability. (Otherwise, a Hash may degenerate into a linked list with highly degraded performance.)
It also should be hard to construct objects that are unequal but have the same hash value deliberately. (Otherwise, an attacker can force a Hash to degenerate into a linked list as a form of Degradation-of-Service attack.)
The #hash method returns a numeric hash value for the receiving object:
:symbol.hash # => 2507
Ruby Hashes are an implementation of the hash map data structure, and they use the value returned by #hash to determine if the same key is being referenced.
Hashes leverage the #eql? method in conjunction with #hash values to determine equality.
Given that these two methods work together to provide Hashes with information about equality, if you override #eql?, you need to also override #hash to keep your object's behavior consistent with other Ruby objects.
If you do NOT override it, this happens:
class Weight
attr_accessor :pounds
def eql?(other)
self.class == other.class && self.pounds == other.pounds
end
alias :== eql?
end
w1 = Weight.new
w2 = Weight.new
w1.pounds = 10
w2.pounds = 10
w1 == w2 # => true, these two objects should now be considered equal
weights_map = Hash.new
weights_map[w1] = '10 pounds'
weights_map[w2] = '10 pounds'
weights_map # => {#<Weight:0x007f942d0462f8 #pounds=10>=>"10 pounds", #<Weight:0x007f942d03c3c0 #pounds=10>=>"10 pounds"}
If w1 and w2 are considered equal, there should only be one key value pair in the hash. However, the Hash class is calling #hash which we did NOT override.
To fix this and truly make w1 and w2 equals, we override #hash to:
class Weight
def hash
pounds.hash
end
end
weights_map = Hash.new
weights_map[w1] = '10 pounds'
weights_map[w2] = '10 pounds'
weights_map # => {#<Weight:0x007f942d0462f8 #pounds=10>=>"10 pounds"}
Now hash knows these objects are equal and therefore stores only one key-value pair

Why is a string key for a hash frozen?

According to the specification, strings that are used as a key to a hash are duplicated and frozen. Other mutable objects do not seem to have such special consideration. For example, with an array key, the following is possible.
a = [0]
h = {a => :a}
h.keys.first[0] = 1
h # => {[1] => :a}
h[[1]] # => nil
h.rehash
h[[1]] # => :a
On the other hand, a similar thing cannot be done with a string key.
s = "a"
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String
Why is string designed to be different from other mutable objects when it comes to a hash key? Is there any use case where this specification becomes useful? What other consequences does this specification have?
I actually have a use case where absence of such special specification about strings may be useful. That is, I read with the yaml gem a manually written YAML file that describes a hash. the keys may be strings, and I would like to allow case insensitivity in the original YAML file. When I read a file, I might get a hash like this:
h = {"foo" => :foo, "Bar" => :bar, "BAZ" => :baz}
And I want to normalize the keys to lower case to get this:
h = {"foo" => :foo, "bar" => :bar, "baz" => :baz}
by doing something like this:
h.keys.each(&:downcase!)
but that returns an error for the reason explained above.
In short it's just Ruby trying to be nice.
When a key is entered in a Hash, a special number is calculated, using the hash method of the key. The Hash object uses this number to retrieve the key. For instance, if you ask what the value of h['a'] is, the Hash calls the hash method of string 'a' and checks if it has a value stored for that number. The problem arises when someone (you) mutates the string object, so the string 'a' is now something else, let's say 'aa'. The Hash would not find a hash number for 'aa'.
The most common types of keys for hashes are strings, symbols and integers. Symbols and integers are immutable, but strings are not. Ruby tries to protect you from the confusing behaviour described above by dupping and freezing string keys. I guess it's not done for other types because there could be nasty performance side effects (think of large arrays).
Immutable keys make sense in general because their hash codes will be stable.
This is why strings are specially-converted, in this part of MRI code:
if (RHASH(hash)->ntbl->type == &identhash || rb_obj_class(key) != rb_cString) {
st_insert(RHASH(hash)->ntbl, key, val);
}
else {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
In a nutshell, in the string-key case, st_insert2 is passed a pointer to a function that will trigger the dup and freeze.
So if we theoretically wanted to support immutable lists and immutable hashes as hash keys, then we could modify that code to something like this:
VALUE key_klass;
key_klass = rb_obj_class(key);
if (key_klass == rb_cArray || key_klass == rb_cHash) {
st_insert2(RHASH(hash)->ntbl, key, val, freeze_obj);
}
else if (key_klass == rb_cString) {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
else {
st_insert(RHASH(hash)->ntbl, key, val);
}
Where freeze_obj would be defined as:
static st_data_t
freeze_obj(st_data_t obj)
{
return (st_data_t)rb_obj_freeze((VALUE) obj);
}
So that would solve the specific inconsistency that you observed, where the array-key was mutable. However to be really consistent, more types of objects would need to be made immutable as well.
Not all types, however. For example, there'd be no point to freezing immediate objects like Fixnum because there is effectively only one instance of Fixnum corresponding to each integer value. This is why only String needs to be special-cased this way, not Fixnum and Symbol.
Strings are a special exception simply as a matter of convenience for Ruby programmers, because strings are very often used as hash keys.
Conversely, the reason that other object types are not frozen like this, which admittedly leads to inconsistent behavior, is mostly a matter of convenience for Matz & Company to not support edge cases. In practice, comparatively few people will use a container object like an array or a hash as a hash key. So if you do so, it's up to you to freeze before insertion.
Note that this is not strictly about performance, because the act of freezing a non-immediate object simply involves flipping the FL_FREEZE bit on the basic.flags bitfield that's present on every object. That's of course a cheap operation.
Also speaking of performance, note that if you are going to use string keys, and you are in a performance-critical section of code, you might want to freeze your strings before doing the insertion. If you don't, then a dup is triggered, which is a more-expensive operation.
Update #sawa pointed out that leaving your array-key simply frozen means the original array might be unexpectedly immutable outside of the key-use context, which could also be an unpleasant surprise (although otoh it would serve you right for using an array as a hash-key, really). If you therefore surmise that dup + freeze is the way out of that, then you would in fact incur possible noticeable performance cost. On the third hand, leave it unfrozen altogether, and you get the OP's original weirdness. Weirdness all around. Another reason for Matz et al to defer these edge cases to the programmer.
See this thread on the ruby-core mailing list for an explanation (freakily, it happened to be the first mail I stumbled across when I opened up the mailing list in my mail app!).
I've no idea about the first part of your question, but hHere is a practical answer for the 2nd part:
new_hash = {}
h.each_pair do |k,v|
new_hash.merge!({k.downcase => v})
end
h.replace new_hash
There's lots of permutations of this kind of code,
Hash[ h.map{|k,v| [k.downcase, v] } ]
being another (and you're probably aware of these, but sometimes it's best to take the practical route:)
You are askin 2 different questions: theoretical and practical. Lain was the first to answer, but I would like to provide what I consider a proper, lazier solution to your practical question:
Hash.new { |hsh, key| # this block get's called only if a key is absent
downcased = key.to_s.downcase
unless downcased == key # if downcasing makes a difference
hsh[key] = hsh[downcased] if hsh.has_key? downcased # define a new hash pair
end # (otherways just return nil)
}
The block used with Hash.new constructor is only invoked for those missing keys, that are actually requested. The above solution also accepts symbols.
A very old question - but if anyone else is trying to answer the "how can I get around the hash keys are freezing strings" part of the question...
A simple trick you could do to solve the String special case is:
class MutableString < String
end
s = MutableString.new("a")
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String
puts h.inspect
Doesn't work unless you are creating the keys, and unless you are then careful that it doesn't cause any problems with anything that strictly requires that the class is exactly "String"

Delete Instance Variables from Objects in an Array

I'm new to Ruby and I'm just having a play around with ideas and what I would like to do is remove the #continent data from the country_array I have created. Done a good number of searches and can find quite a bit of info on removing elements in their entirety but can't find how to specifically remove #continent data. Please keep any answers fairly simple as I'm new, however any help much appreciated.
class World
include Enumerable
include Comparable
attr_accessor :continent
def <=> (sorted)
#length = other.continent
end
def initialize(country, continent)
#country = country
#continent = continent
end
end
a = World.new("Spain", "Europe")
b = World.new("India", "Asia")
c = World.new("Argentina", "South America")
d = World.new("Japan", "Asia")
country_array = [a, b, c, d]
puts country_array.inspect
[#<World:0x100169148 #continent="Europe", #country="Spain">,
#<World:0x1001690d0 #continent="Asia", #country="India">,
#<World:0x100169058 #continent="South America", #country="Argentina">,
#<World:0x100168fe0 #continent="Asia", #country="Japan">]
You can use remove_instance_variable. However, since it's a private method, you'll need to reopen your class and add a new method to do this:
class World
def remove_country
remove_instance_variable(:#country)
end
end
Then you can do this:
country_array.each { |item| item.remove_country }
# => [#<World:0x7f5e41e07d00 #country="Spain">,
#<World:0x7f5e41e01450 #country="India">,
#<World:0x7f5e41df5100 #country="Argentina">,
#<World:0x7f5e41dedd10 #country="Japan">]
The following example will set the #continent to nil for the first World object in your array:
country_array[0].continent = nil
irb(main):035:0> country_array[0]
=> #<World:0xb7dd5e84 #continent=nil, #country="Spain">
But it doesn't really remove the continent variable since it's part of your World object.
Have you worked much with object-oriented programming? Is your World example from a book or tutorial somewhere? I would suggest some changes to how your World is structured. A World could have an array of Continent's, and each Continent could have an array of Country's.
Names have meaning and variable names should reflect what they truly are. The country_array variable could be renamed to world_array since it is an array of World objects.
99% of the time I would recommend against removing an instance variable, because it's extra code for no extra benefit.
When you're writing code, generally you're trying to solve a real-world problem. With the instance variable, some questions to ask are:
What real world concept am I trying to model with the various states the variable can be in?
What am I going to do with the values stored in the variable?
If you're just trying to blank out the continent value stored in a World object, you can set #continent to nil as dustmachine says. This will work fine for the 99% of the cases. (Accessing a removed instance variable will just return nil anyway.)
The only possible case (I can think of) when removing the instance variable could be useful is when you're caching a value that may be nil. For example:
class Player
def score(force_reload = false)
if force_reload
# purge cached value
remove_instance_variable(:#score)
end
# Calling 'defined?' on an instance variable will return false if the variable
# has never been set, or has been removed via force_reload.
if not defined? #score
# Set cached value.
# Next time around, we'll just return the #score without recalculating.
#score = get_score_via_expensive_calculation()
end
return #score
end
private
def get_score_via_expensive_calculation
if play_count.zero?
return nil
else
# expensive calculation here
return result
end
end
end
Since nil is a meaningful value for #score, we can't use nil to indicate that the value hasn't been cached yet. So we use the undefined state to tell us whether we need to recalculate the cached value. So there are 3 states for #score:
nil (means user has not played any games)
number (means user played at least once but did not accrue any points)
undefined (means we haven't fetched the calculated score for the Player object yet).
Now it's true that you could use another value that's not a number instead of the undefined state (a symbol like :unset for example), but this is just a contrived example to demonstrate the idea. There are cases when your variable may hold an object of unknown type.

Is everything an object in ruby?

Is everything in ruby an object? Does this include Fixnums?
Depends on what you mean by "everything". Fixnums are, as the others have demonstrated. Classes also are, as instances of class Class. Methods, operators and blocks aren't, but can be wrapped by objects (Proc). Simple assignment is not, and can't. Statements like while also aren't and can't. Comments obviously also fall in the latter group.
Most things that actually matter, i.e. that you would wish to manipulate, are objects (or can be wrapped in objects).
Yes. Fixnum is a class, which inherits from Integer, which inherits from Numeric, which finally inherits from Object.
Or, why don't you just ask it? :)
1.is_a? Object # => true
1.class # => Fixnum
Fixnum.is_a? Object # => true
Reading the Ruby info and documentation on the website is a good idea too.
Practically everything in Ruby is an Object, with the exception of control structures. Whether or not under the covers a method, code block or operator is or isn't an Object, they are represented as Objects and can be thought of as such.
Take a code block for example:
def what_is(&block)
puts block.class
puts block.is_a? Object
end
> what_is {}
Proc
true
=> nil
Or for a Method:
class A
def i_am_method
"Call me sometime..."
end
end
> m = A.new.method(:i_am_method)
> m.class
Method
> m.is_a? Object
true
> m.call
"Call me sometime..."
And operators (like +, -, [], <<) are implemented as methods:
class String
def +
"I'm just a method!"
end
end
For people coming into programming for the first time, what this means in a practical sense is that all the rules that you can apply to one kind of Object can be extended to others. You can think of a String, Array, Class, File or any Class that you define as behaving in much the same way. This is one of the reasons why Ruby is easier to pick up and work with than some other languages.
Yes everything is an object in ruby, and that includes Fixnum
Ruby doen't have any primitives (like int, char etc in java), so every value (anything that can sit on the right of an assignment statement) is an object. However, control statements, methods, and other features of the language syntax aren't.
Yup.
> Fixnum.is_a?(Object) #=> true
To see the chain of inheritance:
> pp Fixnum.ancestors
[Fixnum,
Integer,
Precision,
Numeric,
Comparable,
Object,
...
Kernel]
=> nil

Access variables programmatically by name in Ruby

I'm not entirely sure if this is possible in Ruby, but hopefully there's an easy way to do this. I want to declare a variable and later find out the name of the variable. That is, for this simple snippet:
foo = ["goo", "baz"]
How can I get the name of the array (here, "foo") back? If it is indeed possible, does this work on any variable (e.g., scalars, hashes, etc.)?
Edit: Here's what I'm basically trying to do. I'm writing a SOAP server that wraps around a class with three important variables, and the validation code is essentially this:
[foo, goo, bar].each { |param|
if param.class != Array
puts "param_name wasn't an Array. It was a/an #{param.class}"
return "Error: param_name wasn't an Array"
end
}
My question is then: Can I replace the instances of 'param_name' with foo, goo, or bar? These objects are all Arrays, so the answers I've received so far don't seem to work (with the exception of re-engineering the whole thing ala dbr's answer)
What if you turn your problem around? Instead of trying to get names from variables, get the variables from the names:
["foo", "goo", "bar"].each { |param_name|
param = eval(param_name)
if param.class != Array
puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
return "Error: #{param_name} wasn't an Array"
end
}
If there were a chance of one the variables not being defined at all (as opposed to not being an array), you would want to add "rescue nil" to the end of the "param = ..." line to keep the eval from throwing an exception...
You need to re-architect your solution. Even if you could do it (you can't), the question simply doesn't have a reasonable answer.
Imagine a get_name method.
a = 1
get_name(a)
Everyone could probably agree this should return 'a'
b = a
get_name(b)
Should it return 'b', or 'a', or an array containing both?
[b,a].each do |arg|
get_name(arg)
end
Should it return 'arg', 'b', or 'a' ?
def do_stuff( arg )
get_name(arg)
do
do_stuff(b)
Should it return 'arg', 'b', or 'a', or maybe the array of all of them? Even if it did return an array, what would the order be and how would I know how to interpret the results?
The answer to all of the questions above is "It depends on the particular thing I want at the time." I'm not sure how you could solve that problem for Ruby.
It seems you are trying to solve a problem that has a far easier solution..
Why not just store the data in a hash? If you do..
data_container = {'foo' => ['goo', 'baz']}
..it is then utterly trivial to get the 'foo' name.
That said, you've not given any context to the problem, so there may be a reason you can't do this..
[edit] After clarification, I see the issue, but I don't think this is the problem.. With [foo, bar, bla], it's equivalent like saying ['content 1', 'content 2', 'etc']. The actual variables name is (or rather, should be) utterly irrelevant. If the name of the variable is important, that is exactly why hashes exist.
The problem isn't with iterating over [foo, bar] etc, it's the fundamental problem with how the SOAP server is returing the data, and/or how you're trying to use it.
The solution, I would say, is to either make the SOAP server return hashes, or, since you know there is always going to be three elements, can you not do something like..
{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param|
if param.class != Array
puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
puts "Error: #{param_name} wasn't an Array"
end
end
OK, it DOES work in instance methods, too, and, based on your specific requirement (the one you put in the comment), you could do this:
local_variables.each do |var|
puts var if (eval(var).class != Fixnum)
end
Just replace Fixnum with your specific type checking.
I do not know of any way to get a local variable name. But, you can use the instance_variables method, this will return an array of all the instance variable names in the object.
Simple call:
object.instance_variables
or
self.instance_variables
to get an array of all instance variable names.
Building on joshmsmoore, something like this would probably do it:
# Returns the first instance variable whose value == x
# Returns nil if no name maps to the given value
def instance_variable_name_for(x)
self.instance_variables.find do |var|
x == self.instance_variable_get(var)
end
end
There's Kernel::local_variables, but I'm not sure that this will work for a method's local vars, and I don't know that you can manipulate it in such a way as to do what you wish to acheive.
Great question. I fully understand your motivation. Let me start by noting, that there are certain kinds of special objects, that, under certain circumstances, have knowledge of the variable, to which they have been assigned. These special objects are eg. Module instances, Class instances and Struct instances:
Dog = Class.new
Dog.name # Dog
The catch is, that this works only when the variable, to which the assignment is performed, is a constant. (We all know that Ruby constants are nothing more than emotionally sensitive variables.) Thus:
x = Module.new # creating an anonymous module
x.name #=> nil # the module does not know that it has been assigned to x
Animal = x # but will notice once we assign it to a constant
x.name #=> "Animal"
This behavior of objects being aware to which variables they have been assigned, is commonly called constant magic (because it is limited to constants). But this highly desirable constant magic only works for certain objects:
Rover = Dog.new
Rover.name #=> raises NoMethodError
Fortunately, I have written a gem y_support/name_magic, that takes care of this for you:
# first, gem install y_support
require 'y_support/name_magic'
class Cat
include NameMagic
end
The fact, that this only works with constants (ie. variables starting with a capital letter) is not such a big limitation. In fact, it gives you freedom to name or not to name your objects at will:
tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie
Unfortunately, this will not work with array literals, because they are internally constructed without using #new method, on which NameMagic relies. Therefore, to achieve what you want to, you will have to subclass Array:
require 'y_support/name_magic'
class MyArr < Array
include NameMagic
end
foo = MyArr.new ["goo", "baz"] # not named yet
foo.name #=> nil
Foo = foo # but assignment to a constant is noticed
foo.name #=> :Foo
# You can even list the instances
MyArr.instances #=> [["goo", "baz"]]
MyArr.instance_names #=> [:Foo]
# Get an instance by name:
MyArr.instance "Foo" #=> ["goo", "baz"]
MyArr.instance :Foo #=> ["goo", "baz"]
# Rename it:
Foo.name = "Quux"
Foo.name #=> :Quux
# Or forget the name again:
MyArr.forget :Quux
Foo.name #=> nil
# In addition, you can name the object upon creation even without assignment
u = MyArr.new [1, 2], name: :Pair
u.name #=> :Pair
v = MyArr.new [1, 2, 3], ɴ: :Trinity
v.name #=> :Trinity
I achieved the constant magic-imitating behavior by searching all the constants in all the namespaces of the current Ruby object space. This wastes a fraction of second, but since the search is performed only once, there is no performance penalty once the object figures out its name. In the future, Ruby core team has promised const_assigned hook.
You can't, you need to go back to the drawing board and re-engineer your solution.
Foo is only a location to hold a pointer to the data. The data has no knowledge of what points at it. In Smalltalk systems you could ask the VM for all pointers to an object, but that would only get you the object that contained the foo variable, not foo itself. There is no real way to reference a vaiable in Ruby. As mentioned by one answer you can stil place a tag in the data that references where it came from or such, but generally that is not a good apporach to most problems. You can use a hash to receive the values in the first place, or use a hash to pass to your loop so you know the argument name for validation purposes as in DBR's answer.
The closest thing to a real answer to you question is to use the Enumerable method each_with_index instead of each, thusly:
my_array = [foo, baz, bar]
my_array.each_with_index do |item, index|
if item.class != Array
puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}"
end
end
I removed the return statement from the block you were passing to each/each_with_index because it didn't do/mean anything. Each and each_with_index both return the array on which they were operating.
There's also something about scope in blocks worth noting here: if you've defined a variable outside of the block, it will be available within it. In other words, you could refer to foo, bar, and baz directly inside the block. The converse is not true: variables that you create for the first time inside the block will not be available outside of it.
Finally, the do/end syntax is preferred for multi-line blocks, but that's simply a matter of style, though it is universal in ruby code of any recent vintage.

Resources