Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Standalone PORO assertions and validations.
The primary goal of the gem is to make standalone assertions about objects and validate them.
No monkey patching, no dependency from ActiveSupport, no mutable instances of any class.
Define an assertion by inheriting it from the Assertion::Base
class with attributes to which it should be applied.
Then implement the method check
to describe if the assertion is truthy or falsey.
You can do it either in the classic style:
class IsAdult < Assertion::Base
attribute :age, :name
def check
age.to_i >= 18
end
end
or with more expressive builder:
IsAdult = Assertion.about :age, :name do
age.to_i >= 18
end
Define translations to describe both the truthy and falsey states of the assertion.
All the attributes are available in translations (that's why we declared the name
as an attribute):
# config/locales/en.yml
---
en:
assertion:
is_adult:
truthy: "%{name} is already an adult (age %{age})"
falsey: "%{name} is a child yet (age %{age})"
If you don't need to translate messages, define them for truthy
and falsey
states as methods:
class IsAdult < Assertion::Base
attribute :age, :name
def check
age.to_i >= 18
end
def truthy
"#{name} is already an adult (age #{age})"
end
def falsey
"#{name} is a child yet (age #{age})"
end
end
Check a state of an assertion for some argument(s), using class method []
:
john = { name: 'John', age: 10, gender: :male }
state = IsAdult[john]
# => #<Assertion::State @state=false, @messages=["John is a child yet (age 10)"]>
The state supports valid?
, invalid?
, messages
and validate!
methods:
state.valid? # => false
state.invalid? # => true
state.messages # => ["John is a child yet (age 10)"]
state.validate! # => #<Assertion::InvalidError @messages=["John is a child yet (age 10)"]>
Use the .not
class method to invert the assertion:
jack = { name: 'Jack', age: 21, gender: :male }
IsAdult.not[jack]
# => #<Assertion::State @state=false, @messages=["Jack is already an adult (age 21)"]>
You can also use !
alias to provide the inversion:
IsChild = !IsAdult
IsChild[jack]
# => #<Assertion::State @state=false, @messages=["Jack is already an adult (age 21)"]>
Notice that !IsAdult[jack]
wouldn't work. Use either IsAdult.not[jack]
, or (!IsAdult)[jack]
.
You can compose assertion states (results):
IsMale = Assertion.about :name, :gender do
gender == :male
end
# config/locales/en.yml
---
en:
assertion:
is_male:
truthy: "%{name} is a male"
falsey: "%{name} is a female"
Use method &
(or its alias +
) to compose assertion states:
jane = { name: 'Jane', age: 16, gender: :female }
state = IsAdult[jane] & IsMale[jane]
# => #<Assertion::State @state=false, @messages=["Jane is a child yet (age 16)", "Jane is a female"]>
The guard class is a lean wrapper around the state of its object.
It defines the #state
for the object and checks if the state is valid:
class VoterOnly < Assertion::Guard
alias_method :user, :object
def state
IsAdult[user.attributes] & IsCitizen[user.attributes]
end
end
Or using the builder Assertion.guards
:
VoterOnly = Assertion.guards :user do
IsAdult[user.attributes] & IsCitizen[user.attributes]
end
When the guard is called for some object, its calls #validate!
and then returns the source object. That simple.
jack = OpenStruct.new(name: "Jack", age: 15, citizen: true)
john = OpenStruct.new(name: "John", age: 34, citizen: true)
voter = VoterOnly[jack]
# => #<Assertion::InvalidError @messages=["Jack is a child yet (age 15)"]
voter = VoterOnly[john]
# => #<OpenStruct @name="John", @age=34>
This is not necessary, but for verbosity you could follow the rules:
Is
(Are
) for assertions (like IsAdult
, AreConsistent
etc.)Only
for guards (like AdultOnly
)You cannot define attributes with names already defined as istance methods,
or reserved by Base#check
and Guard#state
:
IsAdult = Assertion.about :check
# => #<Assertion::NameError @message="IsAdult#check is already defined">
AdultOnly = Assertion.guards :state
# => #<Assertion::NameError @message="AdultOnly#state is already defined">
The gem provides two sets of RSpec shared examples to specify assertions and guards in the expressive way.
To include them, require assertion/rspec
.
Use :validating_attributes
example:
require "spec_helper"
require "assertion/rspec"
describe IsAdult do # defines described_class
it_behaves_like :validating_attributes do
let(:attributes) { { name: "Joe", age: 10 } }
let(:locale) { :fr } # :en by default
subject(:valid) { false } # false by default
subject(:message) { "Joe est un enfant (10 ans)" } # can be skipped
end
end
If the spec description doesn't declare described_class
implicitly, you should define assertion
explicitly:
it_behaves_like :validating_attributes do
let(:assertion) { IsAdult }
# ...
end
Use :accepting_object
example:
require "spec_helper"
require "assertion/rspec"
describe IsAdult do # defines described_class
it_behaves_like :accepting_object do
let(:object) { { name: "Joe", age: 10 } }
let(:locale) { :fr } # :en by default
subject(:accepted) { false } # false by default
subject(:message) { "Joe est un enfant (10 ans)" } # can be skipped
end
end
If the spec description doesn't declare described_class
implicitly, you should define guard
explicitly:
it_behaves_like :accepting_object do
let(:guard) { AdultOnly }
# ...
end
Add this line to your application's Gemfile:
# Gemfile
gem "assertion"
Then execute:
bundle
Or add it manually:
gem install assertion
Tested under rubies compatible to MRI 1.9+.
Uses RSpec 3.0+ for testing and hexx-suit for dev/test tools collection.
git checkout -b my-new-feature
)git commit -am '[UPDATE] Add some feature'
)git push origin my-new-feature
)See the MIT LICENSE.
FAQs
Unknown package
We found that assertion demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.