WithEase
Very basic but useful extensions to Ruby.
N.B.: still in alpha
Installation
gem install with_ease
With bundler
gem 'with_ease'
Usage
require 'with_ease'
For more sophisticated tools and imports into the current tools look at the speculations
In all the speculations we assume that require 'with_ease' has been used in the setup (spec_helper.rb or
speculations_helper.rb)
Synopsis
What can you do WithEase.
Have an OpenStruct with a complete Hash like API
- merge, update, slice
- pattern matching
Have a ClosedStruct with the same API but fixed keys
Have a lean wrapper Forward around Forwardable which is actually readable!
Have an Iterator class (and constructor function if you want).
Nothing you cannot do with Enumerator::Lazy but so much simpler again.
Extend the &:<method> cludge from symbols to arrays with Array#.to_proc
My philosophy on this, is either use both or hate both
Quick Start
All functionality is described in detail in the speculations (see links above for the specific speculations of a functionality).
But here is a quick overview (also tested with the speculate_about gem as all other speculations).
Context: OpenStruct
Given
require 'with_ease'
let(:subject) { OpenStruct.new(a: 1, b: 2) }
Then we can use it mostly like a Hash instance.
expect(subject.merge(a: 11, c: 31)).to eq(OpenStruct.new(a: 11, b: 2, c:31))
And we can pattern match
subject => {a:, b: 2}
expect(a).to eq(1)
Context: ClosedStruct
Given
require 'with_ease'
ClosedStruct = WithEase::ClosedStruct
let(:subject) { ClosedStruct.new(a: 1, b: 2) }
Then we can do pretty much the same as with OpenStruct
subject.update(a: 0)
expect(subject).to eq(ClosedStruct.new(a: 0, b: 2))
But you must not add a key
expect { subject.update(c: 3) }
.to raise_error(KeyError)
expect{ subject.merge(c: 3) }
.to raise_error(KeyError)
Context: Iterator
As mentioned above you can ~easily~ (it's not complicated but it is not easy!) create an iterator in Ruby, howver this one is so much simpler.
Given
require 'with_ease'
Iterator = WithEase::Iterator
let(:subject) { Iterator.new(0, &:succ) }
Then we can just advance it
expect(subject.value).to be_zero
expect(subject.advance.value).to eq(1)
It is an Enumerable of course and quite lazy, if you are intereted
here is more
Context: Forward
Given
require 'with_ease'
Forward = WithEase::Forward
N.B.: We could have used require 'with_ease/import_all' instead.
And
class Wrapper
extend Forward
forward :empty?, :size, to: :@array
def initialize(array) = @array = array.to_a
end
let(:subject) { Wrapper.new(0..9) }
Then we can see that
expect(subject).not_to be_empty
expect(subject.size).to eq(10)
But also
expect(Wrapper.new([])).to be_empty
Author
Copyright 2025 Robert Dober [email protected]
LICENSE
AGPL-3.0-or-later c.f LICENSE