Skip to content

Instantly share code, notes, and snippets.

@codekitchen
Created March 3, 2016 17:35
Show Gist options
  • Save codekitchen/071d57e418d8fb116fb5 to your computer and use it in GitHub Desktop.
Save codekitchen/071d57e418d8fb116fb5 to your computer and use it in GitHub Desktop.
require 'json'
module HashWithDupCheck
refine Hash do
def []=(k,v)
raise(ArgumentError, "key already exists: #{k.inspect}") if key?(k)
end
end
end
using HashWithDupCheck
puts JSON.parse(%[{"a": 5, "a": 6}])
@johana-star
Copy link

irb(main):001:0> module HashWithDupCheck
irb(main):002:1>   refine Hash do
irb(main):003:2*     def []=(k,v)
irb(main):004:3>       raise(ArgumentError, "key already exists: #{k.inspect}") if key?(k)
irb(main):005:3>     end
irb(main):006:2>   end
irb(main):007:1> end
=> #<refinement:Hash@HashWithDupCheck>
irb(main):008:0>
irb(main):009:0* using HashWithDupCheck
=> main
irb(main):010:0> hash = {}
=> {}
irb(main):011:0> hash[key] = "value"
NameError: undefined local variable or method `key' for main:Object
    from (irb):11
    from /Users/smccutchen/.rubies/ruby-2.2.2/bin/irb:11:in `<main>'
irb(main):012:0> hash["key"] = "value"
=> "value"
irb(main):013:0> hash["key"] = "new value"
=> "new value"

I expected an exception on the second key.

@johana-star
Copy link

require 'json'

module HashWithDupCheck
  refine Hash do
    def []=(k,v)
      raise(ArgumentError, "key already exists: #{k.inspect}") if self.key?(k)

      super
    end
  end
end

using HashWithDupCheck

hash_with_dups = %[{"a": 5, "a": 6}]

puts JSON.parse(hash_with_dups)

class HashWithDupCheck2 < Hash
  def []=(k,v)
    if self.key?(k)
      raise ArgumentError, "key already exists: #{k.inspect}"
    else
      super
    end
  end
end

puts JSON.parse(hash_with_dups, :object_class => HashWithDupCheck2)

returns

{"a"=>6}
../refined_hash.rb:22:in `[]=': key already exists: "a" (ArgumentError)
    from /Users/smccutchen/.gem/ruby/2.2.2/gems/json-1.8.2/lib/json/common.rb:155:in `parse'
    from /Users/smccutchen/.gem/ruby/2.2.2/gems/json-1.8.2/lib/json/common.rb:155:in `parse'
    from ../refined_hash.rb:29:in `<main>'

Should raise an error on the first parse invocation.

@johana-star
Copy link

I've written this behavior out as a spec…

require 'json'
require 'rspec'

module HashWithDupCheck2
  refine Hash do
    def []=(k,v)
      raise(ArgumentError, "key already exists: #{k.inspect}") if self.key?(k)

      super
    end
  end
end

using HashWithDupCheck2

class HashWithDupCheck < Hash
  def []=(k,v)
    if self.key?(k)
      raise ArgumentError, "key already exists: #{k.inspect}"
    else
      super
    end
  end
end

describe "duplicate checking" do
  let(:hash_with_dups) { %[{"a": 5, "a": 6}] }

  context "Hash" do
    it "raises an error parsing JSON with duplicates" do
      expect { JSON.parse(hash_with_dups) }.to raise_error
    end
  end

  context "HashWithDupCheck" do
    it "raises an error parsing JSON with duplicates" do
      expect {
        JSON.parse(hash_with_dups, :object_class => HashWithDupCheck)
      }.to raise_error
    end
  end
end

I'll figure out how to fix this behavior, and then add a spec to hold it in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment