1

I have a loop which should assign different variable names depending on filesname which are contained in an array.

Each variable is set as an empty array.

filenames = ['file1', 'file2']

filenames.each do |filename|
  "@data_" + "#{filename}" = []        # used @ as I need these variables externaly from the loop
end

This gives me the following error

syntax error, unexpected '=', expecting keyword_end

What I don't understand is if I use

filenames.each do |filename|
  p "@data_" + "#{filename}"
end

it renders correctly

@data_file1
@data_file2

And if I set an empty array through the loop

filenames.each do |filename|
  @data = []
end
p @data
#=> []

it works too...

Thanks for your help!

1
  • +1 for trying to work it out yourself. Commented Aug 15, 2011 at 22:16

4 Answers 4

4

I would recommend using a data structure rather than synthesizing instance variables1 with meta-programming.

Why not just:

@data = filenames.inject({}) { |h, v| h[v] = []; h }
# => { "file1" => [], "file2" => [] }

Now you can just reference @data['file1'] where you want the 'file1' Array object.


1. But for the record, here is one way:

class A
  def f x, y
    self.class.send :attr_accessor, x
    send "#{x}=", y
  end
end

a = A.new
a.f 'new_instance_variable', 12345
p a.new_instance_variable

Sign up to request clarification or add additional context in comments.

2 Comments

Hash[pairs] is perhaps a somewhat cleaner way of creating a hash. Let's hope Ruby gets Enumerable#mash some day and we all agree how to create a hash from an enumerable.
each_with_object is simpler than inject in this case.
2

Simplest solution, if you're sure about the sanitsed-ness of your filenames array, would be:

filenames = ['file1', 'file2']

filenames.each do |filename|
  eval "@data_#{filename} = []"
end

1 Comment

You should probably add that this will not work anymore in Ruby 1.9.
2

What you're doing in "@data_" + "#{filename}" = [] is assigning empty Array instance ([]) to a String instance ("@data_file1"), hence syntax error, unexpected '=', expecting keyword_end

You should want to do is to assign [] to instance variable: @data_file, not string: "@data_file".

You can achieve that with instance_variable_set method of class Object:

filenames = ['file1', 'file2']

filenames.each do |filename|
    instance_variable_set("@data_#{filename}".to_sym, [])
end

Comments

1

Why are you using string concatenation and interpolation in the same string...

something like

p "@data_#{filename}"

is the same as your

p "@data_" + "#{filename}"

Now this won't work because you are trying to say string = something else you need to evaluate the string

eval("@data_#{filename} = []")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.