-2

can you help me to solve this problem with this code?

total_user_input = []

while true
  print "Field Name: "
  user_input = gets.chomp
  break if user_input.empty?
  total_user_input << user_input
end


total_user_input.each do |input|
  aa = input.split(":").reduce {|first, second| "  \t'#{first}': '#{second}',\r\n".gsub("'",'"') }
  puts aa.chomp(',')
end

and the result I get

"name": "string",
"desc": "string",
"price": "integer",

but what I want is just remove the last comma only

"name": "string",
"desc": "string",
"price": "integer"

thank you for helping me

  • In your example what is `total_user_input`? Note that `each` (here [Array#each](https://ruby-doc.org/core-2.7.0/Array.html#method-i-each)) always returns its receiver. In your example that's `total_user_input`. – Cary Swoveland Oct 09 '21 at 07:33
  • Are you trying to generate JSON? – Stefan Oct 09 '21 at 07:36
  • yes am trying to generate json –  Oct 09 '21 at 07:37
  • 1
    Ruby comes with a JSON library. It takes care of all the formatting and escaping. See [Generating JSON](https://ruby-doc.org/stdlib/libdoc/json/rdoc/JSON.html#module-JSON-label-Generating+JSON) – Stefan Oct 09 '21 at 07:45
  • i know but i want to remove the last comma from my code only –  Oct 09 '21 at 07:58

2 Answers2

0

I don't know actualy what your scenario But I base on your expected and You can try it.

total_user_input = [
  "name:test",
  "age:30"
]

input_length = total_user_input.size
total_user_input.each_with_index do |input, index|
  aa = input.split(":").reduce {|first, second| "  \t'#{first}': '#{second}',\r\n".gsub("'",'"') }
  aa = aa.gsub(',', '') if index == input_length - 1 # or aa.slice(-1)
  puts aa
end

=> My result

"name": "test",
"age": "30"
Vo Quang
  • 16
  • 1
  • 3
0

TL;DR

I'm happy to answer the question you actually asked, but it needs to be pointed out that what you're doing is inherently an anti-pattern and not idiomatic Ruby.

I'll first show you a better way to do what you're doing, using stages of transformation rather than a single idiomatic method chain. Next I'll cover some alternatives that will help you with the String data you've already constructed.

At the end, I also provide a few caveats that you should generally be aware of, but aren't essential to answering your question. They're still useful, and will definitely help with addressing these sorts of problems when you're trying to debug something.

The Right Way

First of all, don't what you're doing if you can avoid it. Solving the problem in that way leads to very brittle solutions. Instead, just take your pairs of inputs and convert them to a Hash or JSON directly. For example:

require "json"

pp total_user_input
#=> ["name", "string", "desc", "string", "price", "integer"]

aa = total_user_input.each_slice(2).to_h
#=> {"name"=>"string", "desc"=>"string", "price"=>"integer"}

puts JSON.pretty_generate aa
{
  "name": "string",
  "desc": "string",
  "price": "integer"
}

This will transform your input in stages, and print a string to STDOUT suitable for writing to a file or otherwise pretty-printing as JSON.

Your Original Question Answered

If you insist on trying to modify the given String, we'll start by representing it as a here-document.

your_pseudo_json = <<~STRING
  "name": "string",
  "desc": "string",
  "price": "integer",
STRING

You have limited options with this given String. You're also complicating your life by using Windows-style newlines instead of Unix-style ones, but you can handle this one of two ways:

  1. Use the $/ record separator for your system, possibly defined by default, or set it yourself. Then you can just use String#chomp. For example:

     # If you have to set it explicitly, do so by assigning to $/
     # NB: You may not. I don't have a Windows system to check.
     $/ = "\r\n"
    
     your_pseudo_json.chomp!(",#{$/}")
    
  2. Use an anchored regular expression to remove just the items at the end. This will work regardless of your platform’s line endings. For example:

     your_pseudo_json.sub! /,(?:\r?\n)\z/, ""
    
  3. If you're running a newer Ruby that supports String#delete_suffix! then you can do this almost like #chomp, but with a simple String without interpolation. For example:

     # for Windows line endings
     your_pseudo_json.delete_suffix! ",\r\n"
    
     # for *nix-style line endings
     your_pseudo_json.delete_suffix! ",\n"
    

Caveats

Use Non-Bang Methods for Testing in Irb or Pry

As a testing note, use the non-bang methods of #chomp, #sub, and #delete_suffix in your REPL for testing, so that you don't have to keep recreating your string while you experiment. The bang methods will modify your string in-place, unless you're running with frozen strings enabled by default.

Frozen Strings

Also, note that if you're using the frozen strings pragma in your program, e.g.:

  • # frozen_string_literal: true at the top of your .rb file
  • RUBYOPT="--enable-frozen-string-literal" in your environment when calling your REPL

then use the non-bang methods and assign the results back to a different (or even the same) variable. Duplicating unfrozen copies of frozen strings is outside the scope of your current question, so I wouldn't even mention it at all except to prevent general bike-shedding by other readers on the subject. :)

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199