0

I wrote a small script which loops my current Jsonfile but it's not possible to append a key and value.

This is my file

[
  {
    "URL": "https://p59-caldav.icloud.com",
  }
]

I would like to append a key and value like this

[
  {
    "URL": "https://p59-caldav.icloud.com",
    "test": "test"
  }
]

My current script setup

#!/usr/bin/env ruby

require 'rubygems'
require 'json'
require 'domainatrix'

jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
array = JSON.parse(jsonHash)

File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|

  array.each do |child|
    url = Domainatrix.parse(child["URL"])
    json = {
      "url" => child["URL"],
      "provider" => url.domain,
      "service" => url.subdomain,
      "context" =>  url.path,
      "suffix" => url.public_suffix
    }

    f.write(JSON.pretty_generate(json))
  end
end

The script overwrite my whole jsonfile...this is not what I want :/

Gerry
  • 10,337
  • 3
  • 31
  • 40
BilalReffas
  • 8,132
  • 4
  • 50
  • 71
  • You really need to fix your indentation here because I think you're confused about what's inside the loop and what isn't. – tadman May 26 '17 at 19:45
  • You have to overwrite the original. You can't easily and safely append, insert, or modify a JSON (or a text file in general) that's on disk. – the Tin Man May 26 '17 at 20:38

2 Answers2

2

This is untested but looks about right:

ORIGINAL_JSON = 'sampleData.json'
NEW_JSON = ORIGINAL_JSON + '.new'
OLD_JSON = ORIGINAL_JSON + '.old'

json = JSON.parse(File.read(ORIGINAL_JSON))

ary = json.map do |child|
  url = Domainatrix.parse(child['URL'])
  {
    'url' => child['URL'],
    'provider' => url.domain,
    'service' => url.subdomain,
    'context' => url.path,
    'suffix' => url.public_suffix
  }
end

File.write(NEW_JSON, ary.to_json)

File.rename(ORIGINAL_JSON, OLD_JSON)
File.rename(NEW_JSON, ORIGINAL_JSON)
File.delete(OLD_JSON)

It's important to not overwrite the original file until all processing has occurred, hence writing to a new file, closing the new and old, then renaming the old one to something safe, renaming the new to the original name, and then being able to remove the original. If you don't follow a process like that you run a risk of corrupting or losing your original data if the code or machine crashes mid-stream.

See "How to search file text for a pattern and replace it with a given value" for more information.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
1

Probably the simplest way to use f.write would be to use it to replace the entire contents of the file. With that in mind, let's see if we can compose what we want the entire contents of the file to be, in memory, and then write it.

#!/usr/bin/env ruby

require 'rubygems'
require 'json'
require 'domainatrix'

write_array = []
jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
read_array = JSON.parse(jsonHash)
read_array.each do |child|
    url = Domainatrix.parse(child["URL"])
    write_array << {
        "url" => child["URL"],
        "provider" => url.domain,
        "service" => url.subdomain,
        "context" =>  url.path,
        "suffix" => url.public_suffix
    }
end

File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|
    f.write(JSON.pretty_generate(write_array))
end

Note some changes:

  1. Fixed indentation :)
  2. Removed some nesting
  3. Write once with the entire contents of the file. Unless you have a really big file or a really important need for pipelined I/O this is probably the simplest thing to do.
mattbornski
  • 11,895
  • 4
  • 31
  • 25
  • The last section can be more easily written as `File.write("/Users/BilalReffas/Desktop/sampleData.json", JSON.pretty_generate(write_array))`. – the Tin Man May 26 '17 at 20:40