>>=20
>=20
> Minor nit: by convention, Ruby people tend to use CamelCase for =
constants=20
> only, and underscores for variables. Call it array_collection.

When I keep to that convention, I find my code's more readable. I can =
tell what something is by looking at it. Thanks for the reminder :)


>=20
> Anyway, seems like one obvious way would be recursion:
>=20
> def each_join array, context=3D[], &block
>  if array.length =3D=3D 0
>    yield context
>  else
>    first =3D array.first
>    rest =3D array[1...array.length]
>    first.each do |elem|
>      each_join rest, context+[elem], &block
>    end
>  end
> end
>=20
> Not pretty, and I'm sure someone could improve it, but it works.

That it does, that it does. Unfortunately, I don't understand it. If =
you've got a minute, would you give a hand?

It looks to me like:

each_join takes three arguments. The first is an array, the second is =
predefined to be an empty array, the third is a reference to a block.=20

First, I don't understand why you need to pass in a reference to a =
block, or why one would want to do that in general. Programming Ruby =
covers it by saying that this allows a block to be treated as a Proc =
object. I guess my misunderstanding, then, is what the hell a Proc =
object is really used for. I've been putting this off, and it meant that =
a simple solution escaped me, apparently. Onwards with understanding, =
then!

A Proc object lets you assign a block to a variable. My naive reading of =
http://ruby-doc.org/core/classes/Proc.html leads me to imagine that the =
first benefit of this is that you can assign what's essentially a method =
call to a variable, almost like you're making a new object out of the =
variable. What does the object do? Take some number of arguments to its =
call method, and do something with those arguments.

Why would you want to use this? I don't know. But it looks like that's =
all it does.

And what does this have to do with each_join?

Okay. The second argument, context. I'm not sure what it's doing. It's =
an empty array which is handed back to the block when the length of the =
original argument array is zero. I don't see how the argument array ever =
gets set to zero, though.

Okay, here goes my explanation:

Why is &block passed in? So that on successive calls to each_join, the =
block is correctly associated with the method.

At the if statement, array.length is non-zero. As such, we go to the =
else clause.
The first sub-array is assigned to the variable "first". The other =
subarrays are assigned to the variable "rest".
So in the case of an array of arrays:
[["bacon", "time", "ostrich"], ["jam", "bees", "please"], ["1", "2", =
"3"]]

After the first pass:

first =3D ["bacon", "time", "ostrich"]
rest =3D [["jam", "bees", "please"], ["1", "2", "3"]]

And then you start iterating over first.

first.each do |elem| #first time around, elem =3D=3D "bacon"
each_join rest, context+[elem], &block

So what happens now?

first =3D ["jam", "bees", "please"]
rest =3D ["1", "2", "3"]

elem is set to "jam" on the iteration over first, context becomes =
["bacon", "jam"] and we enter the whole thing again.


Okay, the above is a nice start for any other new folks looking to trace =
this, but I just finished up and my mind =3D=3D blown. It took me a =
while to realise that the control structure here is actually:

first.each do |elem|

and that's what's driving everything. For anyone else wanting to follow =
along, try this out:

arrayCollection =3D [["bacon", "1", "2", "4"], ["jam", "bees", =
"please"], ["6", "7", "8"]]

def each_join array, context=3D[], &block
 if array.length =3D=3D 0
   puts "now context is #{context}"
   yield context
 else
   first =3D array.first
   puts "context is #{context}"
   puts "first is #{first}"
   rest =3D array[1...array.length]
   puts "rest is #{rest}"
   first.each do |elem|
     puts "elem is #{elem}"
     puts ""
     each_join rest, context+[elem], &block=20
   end
 end
end


each_join(arrayCollection) do |b|
  puts "-------"
  puts "#{b}"
  puts "-------"
 =20
end







>=20
> It does seem pretty weird, though. Out of curiosity, what do you need =
this=20
> for?
>=20



Okay, you gave me quite an education today, so turn about is fair play.

I have a program which accepts input and outputs output.
It has both a gui and a scripting environment.

For the scripting environment, I documented every option that you can =
pass in. The options look like:

foo=3Dbar

or
foo=3D1

and several can be handed in at a time.

foo=3Dbar;jet=3Dbam;

and so on. Each option can only be specified once, but each option can =
have multiple valid values. In order to verify that every option that =
can be handed in actually works as expected, I want to generate a set of =
scripts from the documentation I wrote. The parser I have for the =
documentation finds a series of lines of type:

foo=3Dbar -- does something fooish
foo=3Dbam -- does something else fooish

jet=3Dbar -- does something jetish
jet=3Dbam -- does something else jetish

and so on. I'm popping each option string into an array:

[[foo=3Dbar, foo=3Dbam], [jet=3Dbar, jet=3Dbam]]

And from there, generate every possible combination of all options. I'd =
done everything else, but that last item on the list was killin' me.