简体   繁体   中英

Ruby Last Iteration of Each Loop

I am attempting to insert a comma at the end of each line in an each loop in ruby. I don't want the comma on the last line. I know about the array.join(',') feature but I am a little confused in this circumstance.

How can I refactor my first attempt to do what I require?

Important Lines

@headers.each do |header|
          file.puts "`#{table[:source_database]}`.`#{table[:current_name]}`.`#{header[:current_name]}` AS `#{header[:magi_name]}`#{("," unless @headers.last == header)}" if header[:table_id] == table[:id]
        end

Full Class

class Table < ActiveRecord::Base        
  has_many :headers

  #--------------------------------------------------------------------------------------------------#

  def self.generate
    @tables = Table.select([:id, :source_database, :current_name, :magi_name])
    @headers = Header.select([:id, :table_id, :current_name, :magi_name])

    File.new("magi_generation.sql", "w")
    @tables.each do |table|
      File.open("magi_generation.sql", "a+") do |file|
        file.puts "#Drops current view #{table[:magi_name]} and then recreates it using updated columns"
        file.puts "DROP VIEW IF EXISTS `#{table[:magi_name]}`;"
        file.puts "CREATE ALGORITHM=UNDEFINED DEFINER=`user`@`127.0.0.1` SQL SECURITY DEFINER VIEW `#{table[:magi_name]}`"
        file.puts "AS select"
        @headers.each do |header|
          file.puts "`#{table[:source_database]}`.`#{table[:current_name]}`.`#{header[:current_name]}` AS `#{header[:magi_name]}`#{("," unless @headers.last == header)}" if header[:table_id] == table[:id]
        end
        file.puts "FROM `#{table[:source_database]}`.`#{table[:current_name]}`;"
        file.puts ""
      end
    end

  end

end

You can use each_with_index that gives you the current element and the index. In this way, you can compare the size of the array with the current element.

However, I don't like this approach. In your case that's not clean because you are filtering records inside the loop. I would rather filter the records, then only loop valid records.

file.puts @headers.
    # keep only elements where the condition matches
    select { |header| header[:table_id] == table[:id] }.
    # convert each element into a line
    map { |header| "`#{table[:source_database]}`.`#{table[:current_name]}`.`#{header[:current_name]}` AS `#{header[:magi_name]}`" }.
    # merge everything into a single string
    join(", ")

Process everything like you want, putting a comma and newline at the end and throw it into a String variable. After you are done, chop off the last two characters of the string and then write it to the file.

for_file = ""
@header.each do |header|
   for_file << header + ",\n"
end
for_file.chop.chop # Gets rid of last newline and comma
file.puts for_file

I realize my example loop doesn't encompass the extent of what you are doing in your loop but the important thing it putting it in a string and then .chop.chop .

Also, instead of having file.puts ... for every new line, consider a heredoc.

file.puts <<EOF
SELECT 'nothing'
FROM dual
UNION
SELECT 'something'
FROM dual;
EOF

It might make your SQL a little more readable and you can still use string interpolation.

This is how I generate SQL code with string interpolation in my own scripts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM