Help please

Recently I asked here about where “end” goes, in relation to code
blocks. I was given some good answers which helped but now either I’m
having a same / similar problem or this is perhaps something
completely different.

What I’m attempting to do in the code below is
1-Search a directory for files
2-Check if the files exist
3-Ask user to confirm if they want file to be moved
4-If user answers no , then file is removed from array.
5-After user has gone through the entire list one by one, then the
updated array should list out the files (minus the ones that said no
to move on.

Right now, the problem is step five (listing the updated array) is
happening with each question. Plus it looks like the elements are not
being removed where appropriate. Please let me know if I ask too many
questions here :).

Dir.chdir ‘C:/PicturesMoved’

First we find all of the pictures to be moved.

pic_names = Dir[‘C:/PicturesMoved/*.{BMP,bmp}’]

pic_names.each do |name|
fcheck = FileTest.exist?(name)
if fcheck == true
puts 'Do you wish to move ’ + name + ‘file?’
puts 'Please answer “yes” or “no” ’
else puts ‘file does not exist’

   end
 end



   response = true
    while (response)
      decision = gets.chomp.downcase
      if decision == 'yes'
        response = false
        else
          puts 'File will not be moved'
          pic_names.delete(name)
        end
      end


      puts 'these files will be moved'
      pic_names.each do |name|
        puts name

      end

p.s. The code is indented in my email here , hopefully it remains
formatted as such when it hits the list.

On Jul 1, 2006, at 13:24, Dark A. wrote:

Recently I asked here about where “end” goes, in relation to code
blocks. I was given some good answers which helped but now either I’m
having a same / similar problem or this is perhaps something
completely different.

pic_names.each do |name|
fcheck = FileTest.exist?(name)
if fcheck == true
puts 'Do you wish to move ’ + name + ‘file?’
puts 'Please answer “yes” or “no” ’
else puts ‘file does not exist’

  end
end

It looks a bit to me like the formatting didn’t come through entirely
intact, but this bit still gives me a hunch at where you’re going
wrong, and it’s still a question of where the ‘end’ goes for a
statement.

‘if’ statements behave a little differently than loops: the ‘else’
and ‘elsif’ (if they’re used) don’t require their own 'end’s, they’re
considered part of the if statement, and are generally indented to
the same level as the initial ‘if’. In other words: the ‘if’ is the
beginning of the statement, so that’s what matches the ‘end’. Here’s
the usual formatting for the ‘if’ statement:

if

elsif

else

end

You can have as many elsif statements as you like (including zero),
and zero or one else statements, and the whole construct is finished
off with an ‘end’

If we reformat the snippet of code above, matching the 'end’s with
what they actually match, it ends up looking like this:

pic_names.each do |name|
fcheck = FileTest.exist?(name)
if fcheck == true
puts 'Do you wish to move ’ + name + ‘file?’
puts 'Please answer “yes” or “no” ’
else
puts ‘file does not exist’
end
end

From that I think you can see what part of the problem is. You’ve
got what looks like a similar construction in the while loop as
well. I’m not sure that’s the only problem in the code, but fixing
up your 'end’s will certainly get you on your way.

matthew smillie.

PS: Is your editor using tabs or spaces for indentation? I tried to
send myself code over gmail and it came through just fine unless I
had a mix of spaces and tabs as indentation, which turned it into
muck. If this is the case, there may be an option to indent using
spaces. Otherwise, you could probably enter the code manually using
spaces to preserve indentation.

After I sent this I regretted it. I should try to work this out on my
own.

Stuart

On 7/1/06, Matthew S. [email protected] wrote:

On Jul 1, 2006, at 13:24, Dark A. wrote:

if

elsif

else

end

You can have as many elsif statements as you like (including zero),
and zero or one else statements, and the whole construct is finished
off with an ‘end’

So, all if / else must have a following end ? I realize it must be
somewhere, but do they always necessarily follow the if / else or
perhaps could they be further down depending on the code logic ?

PS: Is your editor using tabs or spaces for indentation? I tried to
send myself code over gmail and it came through just fine unless I
had a mix of spaces and tabs as indentation, which turned it into
muck. If this is the case, there may be an option to indent using
spaces. Otherwise, you could probably enter the code manually using
spaces to preserve indentation.

I think guilty as charged. Using a combo of tabs and spaces in Scite.
Here (and I dont’ want to keep posting new designs) but here is
something that looks logical to me: What is happening with this code
is it keeps asking about the same file. I thought the ‘each do’ would
continue to loop through. Doesn’t seem to be the case. I tried
adding something to the while like ‘until pic_names.length’ , didn’t
go over well. :slight_smile:
btw , i removed tabs and spaces from paste, and then spaced in Gmail.

pic_names = Dir[‘C:/PicturesMoved/*.{BMP,bmp}’]

  pic_names.each do |name| #start of array loop
  continue = true # setting up the conditon to end the while loop
             while (continue)
             fcheck = FileTest.exist?(name) #should be confirming

files exist in directory

#probably this is out of context though I don’t

#believe it’s doing any damage
if fcheck == false
puts ‘file does not exist’

                   else
                    puts 'Do you wish to move ' + name +

‘file?,“yes” or “no” ?’
decision = gets.chomp.downcase

                   end # for 1st if block perhaps wrong ?

                   if decision == 'no'
                      puts 'file will not be moved'
                      pic_names.delete(name)

                      end # for 2nd if block
                  end # for array loop
              end # for while loop

Dark A. wrote:

Please let me know if I ask too many
questions here :).

You can never ask too many questions here.

There’s the chance, of course, that they may not always be answered, or
answered in a timely manner, but so long as you show good faith in
trying to work things out on your own, and first check the available
resources (Google, RubyGarden wiki, ruby-doc.org, ri, ruby-talk list
archives, and so on) you should be fine.


James B.

http://www.ruby-doc.org - Ruby Help & Documentation
Ruby Code & Style - The Journal By & For Rubyists
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://yourelevatorpitch.com - Finding Business Focus

On Sun, 2 Jul 2006, James B. wrote:

Dark A. wrote:

Please let me know if I ask too many
questions here :).

You can never ask too many questions here.

i thought the limit was 8?

:wink:

-a

On Jul 1, 2006, at 15:39, Dark A. wrote:

So, all if / else must have a following end ? I realize it must be
somewhere, but do they always necessarily follow the if / else or
perhaps could they be further down depending on the code logic ?

I’m not 100% sure exactly what you mean here. You can have as much
code as you like between the ‘if’ or ‘else’ and the corresponding
‘end’. What you can’t do is overlap the start of one statement with
the end of another, which seems to be what you’re saying here:

pic_names.each do |name| #start of array loop
while (continue)
[…]
end # for array loop
end # for while loop

Judging from your code, you’re still mixed up about which ‘end’
matches which statement - you’ve labelled the end of the while loop
and the end of the array loop backwards from what they actually are.

You need to remember that the statements are nested one inside the
other. Suppose you have something like the following:

a.each do |x| # a <--------
# |
b.each do |y| # b <----- |
# | |
c.each do |z| # c <-- | |
[…] # | | |
end # c — | |
# | |
end # b ------ |
# |
end # a ---------

Three starts to the statements, and three ends. The indentation
gives you a clue as to which ‘end’ belongs to which loop. In other
words, if you start a set of statements a, b, c, then you have to
finish them in reverse order: c, b, a.

if/elsif/else is only very slightly different. The ‘elsif’ and/or
‘else’ aren’t separate statements, they’re part of the main ‘if’
statement. For example, you can’t have ‘elsif foo’ in your code
outside of an ‘if’ statement. So all together, they only need one
‘end’. Modifying the above diagram:

a.each do |x| # a <--------
# |
b.each do |y| # b <----- |
# | |
if c # c <-- | |
[1] # | | |
else # | | |
[2] # | | |
end # c — | |
# | |
end # b ------ |
# |
end # a ---------

The code in [1] gets execute when something == true, otherwise the
code in [2] gets executed. You can think of the ‘else’ as implicitly
ending the ‘if’, I suppose, but you still only need one ‘end’. [1]
or [2] could contain other if statements, and they’d nest just like
anything else would:

if a # ------
if b # ---- |
[a true, b true] # | |
else # | |
[a true, b false] # | |
end # ---- |
else # |
if b # ---- |
[a false, b true] # | |
else # | |
[a false, b false] # | |
end # ---- |
end # ------

So, if you look at your code, you’ll see a few things:
1.a) ‘continue’ is never set to false, so the while-loop never ends,
which implies:

1.b) the end of the each-loop is never reached, and so ‘name’ is
never set to the next element of the array.

  1. the ‘end’ of the first if block does ‘end’ the first if block,
    certainly, but I don’t think that’s where you want it to be. Think
    about what would happen if the file didn’t exist - decision wouldn’t
    have a correct value, and the second if statement would do something
    unpredictable (probably raise an exception in this specific case).

matthew smillie.

2 of the 8 must be YAML related. Credits are needed for collections
or non standard libraries.

Stuart

[email protected] wrote:

i thought the limit was 8?

That’s one; only seven more, Ara.

:slight_smile:

On Jul 1, 2006, at 23:36, Dark A. wrote:

| |
[a false, b true] # |

Did I make the right connections ? If I did it’s still confusing
(sure I’ll get used to it) to have the else right after the end.

From what I can see, no. The first statement started is the last
one ended, not the first one.

if a # start of 1
if b # start of 2

else # else clause of 2

end # end of 2
else # else clause of 1
if c # start of 3

else # else clause of 3

end # end of 3
end # end of 1

Just out of curiosity, what did you think the connections I drew were
meant to represent?

matthew smillie.

On 7/1/06, Matthew S. [email protected] wrote:

 if b                 # ---- | <--------------------------------------|----------
   [a false, b true]  #    | |                                     |         |
 else                 #    | |                                        |         |
   [a false, b false] #    | |                                     |        |
 end                  # ---- | <------------------------------------         |                                    |

end # ------ This ends first ‘if b’ above <--------

Did I make the right connections ? If I did it’s still confusing
(sure I’ll get used to it) to have the else right after the end.

matthew smillie.

Stuart

I’m responding on my post above (re: why pic_names.delete(name), jumps
an element in the loop.
There must be a reason for this and still would like to some
elucidation on the matter.

However I found by creating a new array pix2bmoved =[]
and doing a pix2bmoved.push[name], things seem to work right.

Stuart

On Jul 2, 2006, at 17:07, Dark A. wrote:

I’m responding on my post above (re: why pic_names.delete(name), jumps
an element in the loop.
There must be a reason for this and still would like to some
elucidation on the matter.

However I found by creating a new array pix2bmoved =[]
and doing a pix2bmoved.push[name], things seem to work right.

You’re one step away from answering your own question: you’re
modifying the same array that you’re iterating over, which can make
things go slightly crazy. Try this example, for instance:

a = (1…10).to_a
a.each { |x|
puts x
a.delete(x)
}

This only prints 1, 3, 5, 7, 9. The technical reason for this is
that (if I recall correctly) Ruby is using an internal array index to
keep track of which element of a it’s on. When you delete a[0]
(which is 1), everything shifts down in the array. The correct thing
to do would be to use a[0] again (which is now 2), but Ruby instead
uses a[1] (which is now 3). Then a[1] (3) gets deleted, something
new moves to a[1] (4), and Ruby skips that to do a[2] (5), and so on.

The general explanation is that modifying the array (or hash, or
whatever) that you’re enumerating over can cause unpredictable
behaviour. This is true in many languages, not just Ruby, because
detecting and correcting for modifications during such an iteration
is a difficult problem in general. The safest thing to do (as you’ve
discovered) is to make modifications to a separate array.

matthew smillie.

Just out of curiosity, what did you think the connections I drew were
meant to represent?

I blanked on the | and ||.

On 7/1/06, Matthew S. [email protected] wrote:

From what I can see, no. The first statement started is the last
one ended, not the first one.
else # else clause of 3

end # end of 3
end # end of 1

It makes sense to me, I see it, I’m filing this email as a keeper
because I know I’ll need to go back and refer to it. At this point the
best way to proceed for me is to worry less about all the code that
needs to be inside a block and create the scaffolds for the blocks
first with some puts statements just to makes sure things are
branching correctly. I started with the original code I posted in
this thread. I dropped the ‘while’ loop completely thinking it didn’t
make sense considering the array loop was already in place performing
the same behaviour.

Dir.chdir ‘C:/PicturesMoved’
pic_names = Dir[‘C:/PicturesMoved/*.{BMP,bmp}’]

 pic_names.each do |name| # (1) array loop
      puts 'Do you wish to move ' + name + 'file?,"yes" or "no" ?'
      decision = gets.chomp.downcase

           if decision == 'no' # 1st if statement
               puts 'This file will not be moved'
           else
               puts 'This file will be moved'

           end # end for 1st if statement
 end # end of array loop

This seems to work fine, however if I add this to the ‘if statement’
if decision == ‘no’
pic_names.delete(name)
puts 'This file will not…
else …
end…

Then the next file in the array is skipped. As an example, if it’s
‘pic1’ and I say ‘no’, then the next name to come up for the gets
statement is ‘pic 3’. I never get to decide on ‘pic 2’ (saying yes to
moving ‘pic 1’ moves the next gets to ‘pic 2’)

So I decided to see what elements is assigned to
'pic_names.delete(name). It’s correct (i.e. no to pic 1, puts ‘This’

  • name + ’ will not be moved’ , returns
    This C:/PicturesMoved/copypics01 .bmp will not be moved. Yet right
    after that prints out I get:
    Do you wish to move C:/PicturesMoved/copypics03 .bmpfile?,“yes” or “no”
    ?
    Not sure what happened to pic2 ?

I sense that I may still (as simple as this looks) some errors
somewhere in if / else.

Stuart