Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting an Error - "cannot be used in conjunction (ArgumentError)" Ruby

Tags:

ruby

I am working on a Ruby course and I came across an error when running one of the examples. Here is my Ruby class:

require 'json'

class User

  attr_accessor :email, :name, :permissions

  def initialize(*args)
    @email = args[0]
    @name = args[1]
    @permissions = User.permisisons_from_template
  end

  def self.permisisons_from_template
    file = File.read 'user_permissions_template.json'
    JSON.load(file, nil, symbolize_names: true)
  end

  def save
    self_json = {email: @email, name: @name, permissions: @permissions}.to_json
    open('users.json', 'a') do |file|
      file.puts self_json
    end
  end

end

My runner file code looks like this:

require 'pp'
require_relative 'user'

user = User.new '[email protected]', 'John Doe'

pp user

user.save

I get this error when I run this command "ruby runner.rb":

/usr/local/rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/json/common.rb:156:in `initialize': options :symbolize_names and :create_additions cannot be  used in conjunction (ArgumentError)
        from /usr/local/rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/json/common.rb:156:in `new'
        from /usr/local/rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/json/common.rb:156:in `parse'
        from /usr/local/rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/json/common.rb:335:in `load'
        from /home/ec2-user/environment/section2_project/user.rb:15:in `permisisons_from_template'
        from /home/ec2-user/environment/section2_project/user.rb:10:in `initialize'
        from runner.rb:4:in `new'
        from runner.rb:4:in `<main>'

I looked for help on the site and the suggested fix was to remove the nil parameter. Now, I am from a .Net background and I surmised that I could use proc: nil and that would work as well, which it did. My assumption is that it didn't like the mixing of named parameters and positional parameters, but this isn't .Net, so I may just have gotten lucky with my guess. The moderator for the site wasn't sure why the code failed and why removing nil fixed the issue. So, my question is:

Why did the line JSON.load(file, nil, symbolize_names: true) fail, but JSON.load(file, proc: nil, symbolize_names: true) work? Thanks.

Wade

like image 765
Wade73 Avatar asked Dec 17 '22 23:12

Wade73


1 Answers

What's happening here is that the arguments aren't being parsed in the way you're expecting. There's a feature in Ruby where any key: value at the end of the argument list are made into a Hash without the need to put the {} around them.

For example if you write a method:

def load(source, options = {})
end

This can be called as load(source) in which case options will be {}, or as something like load(source, foo: 5, bar: true) in which case options will be {foo: 5, bar: true}

The other detail is that optional parameters with default values are filled left to right.

Why is this relevant?

Well, in the case of JSON.load(file, proc: nil, symbolize_names: true) the proc: nil, symbolize_names: true becomes the Hash {proc: nil, symbolize_names: true} and this then fills the proc position in the argument list, leaving the options parameter with its default value. i.e. you aren't actually setting symbolize_names: true when you thought you were.

In the case of JSON.load(file, nil, symbolize_names: true), the nil fills the value of the proc parameter, and symbolize_names: true becomes options. This gets combined with the default options in the JSON library to give the full set of options, {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true, :symbolize_names=>true} which then contains the conflict that the error message is referencing.

like image 199
mikej Avatar answered May 22 '23 15:05

mikej