Lab42::OpenMap
OpenMap = OpenStruct with a rich Map API
N.B. All these code examples are verified with the speculate_about gem
Context Quick Starting Guide
Given an OpenMap
require "lab42/open_map/include" # aliases Lab42::OpenMap as OpenMap
let(:pet) { OpenMap.new }
Then we can see that it can be empty
expect( pet ).to be_empty
And that we can add fields like to a hash
pet[:name] = "Furfur"
expect( pet[:name] ).to eq("Furfur")
However we are not a hash.
Example: Only Symbol Keys please
expect{ pet["name"] = nil }.to raise_error(ArgumentError, %{"name" is not a symbol})
And that holds for construction too
expect{ OpenMap.new("verbose" => false) }
.to raise_error(ArgumentError, %{the following keys are not symbols: ["verbose"]})
But many Hash methods are applicable to OpenMap
Given that
let (:dog) {OpenMap.new(name: "Rantanplan", breed: "You are kidding?")}
Then we can access it like a hash
expect( dog.keys ).to eq(i[name breed])
expect( dog.values ).to eq(["Rantanplan", "You are kidding?"])
expect( dog.size ).to eq(2)
expect( dog.map.to_a ).to eq([[:name, "Rantanplan"], [:breed, "You are kidding?"]])
And we can use slice and get a nice counterpart without
expect( dog.slice(:name) ).to eq(name: "Rantanplan")
expect( dog.slice(:name, :breed) ).to eq(name: "Rantanplan", breed: "You are kidding?")
expect( dog.without(:breed) ).to eq(name: "Rantanplan")
expect( dog.without(:name, :breed) ).to eq({})
And last, but certainly not least: Named Access
expect(dog.name).to eq("Rantanplan")
dog.breed = "still unknown"
expect( dog.values ).to eq(["Rantanplan", "still unknown"])
Context All About Named Access
Given the same dog again
let (:dog) {OpenMap.new(name: "Rantanplan", breed: "You are kidding?")}
Then we cannot access a nonexistant field by name
expect{ dog.age }.to raise_error(NoMethodError, %r{\Aundefined method `age' for})
And we cannot create a new one either
expect{ dog.age = 10 }.to raise_error(NoMethodError, %r{\Aundefined method `age' for})
But we still can create new fields with []= or update
dog.update( age: 10 )
expect( dog.age ).to eq(10)
And of course the update method preserves our symbol keys only property
expect{ dog.update("verbose" => true) }
.to raise_error(ArgumentError, %{the following keys are not symbols: ["verbose"]})
Context Methods that create new OpenMap objects
Given a cat now, cannot risk losing half of the pet loving community ;)
let(:garfield) {OpenMap.new(name: "Garfield", yob: 1976, creator: "Jim Davis")} # Yes under a differnt name, but still
let!(:nermal) { garfield.merge(name: "Nermal", yob: 1979)}
Then exactly the following can be certified
expect( nermal ).to be_kind_of(OpenMap)
expect( garfield.values ).to eq(["Garfield", 1976, "Jim Davis"])
expect( nermal.values ).to eq(["Nermal", 1979, "Jim Davis"])
We also have a counterpart to without, called sans
And with sans we get this
partial_garfield = garfield.sans(:yob, :creator)
expect( partial_garfield.to_h ).to eq(name: "Garfield")
expect( garfield.values ).to eq(["Garfield", 1976, "Jim Davis"])
LICENSE
Copyright 2020 Robert Dober [email protected]
Apache-2.0 c.f LICENSE