Project

l42_map

0.0
No release in over a year
Immutable OpenStruct On Steroids, it combines Hash's and OpenStruct's semantics
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

 Project Readme

Issue Count CI Coverage Status Gem Version Gem Downloads

l42_map

Immutable OpenStruct On Steroids, combining Hash and OpenStruct semantics

How does it work?

Let us speculate about that:

Context Polluting the global namespace, or not?

Given that we included l42/map

    require 'l42/map'

Then the global namespace is not polluted

  expect {
    Map
  }.to raise_error(NameError, "uninitialized constant Map")

But we can access it inside the namespace

  expect {
    L42::Map
  }.not_to raise_error

In order to access Map inside the global namespace one needs to do

    require 'l42/map/global'

Context Setup

Given instance of L42::Map

  let(:empty) { L42::Map.new }
  let(:single) { L42::Map.new(a: 1) }
  let(:map) { L42::Map.new(a: 10, b: 20, c: 30) }

Context The OpenStruct API

Then they can be accessed by name

  expect(single.a).to eq(1)
  expect(map.a).to eq(10)
  expect(map.c).to eq(30)

And we can use the [] syntax

  expect(empty[:a]).to be_nil
  expect(single[:a]).to eq(1)
  expect(map[:b]).to eq(20)

Context Extensions to the OpenStruct API

And we can use fetch

  expect {
    empty.fetch(:a)
  }.to raise_error(KeyError)

  expect(empty.fetch(:a, 42)).to eq(42)
  expect(empty.fetch(:a) { 43 }).to eq(43)

  expect(single.fetch(:a)).to eq(1)

And we can merge into new instances

  clone = empty.merge(x: "x")
  expect(clone.x).to eq("x")
  expect(empty).to be_empty

Context with_default

Given a Map instance with with_default

  let(:wd) { L42::Map.new.with_default(42) }

Then any access will yield 42

    expect(wd.some_value).to eq(42)

And the default value is passed on to clones

    also_wd = wd.merge(a: 43)
    expect(wd.a).to eq(42)
    expect(also_wd.a).to eq(43)
    expect(also_wd.b).to eq(42)

Context Hash methods

And our instance behaves much like a Hash

    expect(map.slice(:a, :c)).to eq(L42::Map.new(a: 10, c: 30))

Additional methods

And we can remove keys

    expect(map.without(:a, :b)).to eq(L42::Map.new(c: 30))

Context Enumerable

And we can iterate

    result = map.inject(0) { |s, (_k, v)| s + v }
    expect(result).to eq(60)

Context Pattern Matching

And of course it behaves like a Hash in pattern matching

    map => c:
    expect(c).to eq(30)
    expect {
      map => a:, b:, **nil
    }.to raise_error(NoMatchingPatternError) # sic, it is indeed a PatternMatchingError

LICENSE

Copyright 2022] Robert Dober robert.dober@gmail.com,

Apache-2.0 c.f LICENSE