Must
====
add Object#must method to constrain its origin and conversions
# can write like this
num = params[:num].to_i.must.match(1..300) {10}
# rather than
num = params[:num].to_i
num = 10 unless (1..300) === num
and has duck-type features
1.must.duck?(:to_s) # => true
io.must.duck(:write) { io.extend Writable }
and has struct assetions
pages = [{:name=>"...", :url=>"...",} ...]
pages.must.struct([Hash])
You want Boolean class? try this!
flag = hash["flag"].must(true, false)
Asking Methods
==============
be : check whether object equals to the argument
kind_of : check whether object is a kind of the arguments
coerced : check whether object can be coerced to the argument
blank : check whether object is blank?
exist : check whether object is not nil (NOTE: false is ok)
Logical Methods
===============
not : logical NOT
Nop Methods
===========
a : return self
an : return self
These effect nothing but exist only for English grammar.
Duck Methods
============
duck("foo") : check whether object responds to "foo" method.
duck(:foo) : same above
duck(".foo") : same above
duck("#foo") : check whether object has "foo" instance method. (tested only in class/module)
duck?(...) : acts same as "duck", but this returns a just boolean
duck!("foo") : if foo exists, call it. otherwise raises Invalid
Struct Methods
============
struct(...) : check whether object has a same struct with ...
struct?(...) : acts same as "struct", but this returns a just boolean
Basic Examples
==============
# test its value exactly
1.must.be 1 # => 1
[1,2,3].must.be [1,2,3] # => [1,2,3]
# exceptions
1.must.be [] # Must::Invalid exception
1.must.be([]) {:ng} # => :ng
1.must.be(1) {:ng} # => 1
# as default value
name = params[:name].must.not.be.blank{ "No name" }
# existing test
1.must.exist # => 1
nil.must.exist # Must::Invalid exception
false.must.exist # => false
# test class : ensures that a class of the object is one of given arguments
1.must.be.kind_of(Integer) # => 1
1.must.be.kind_of(Integer, Array) # => 1
[].must.be.kind_of(Integer, Array) # => []
1.must.be.kind_of(String, Array) # Must::Invalid: expected String/Array but got Fixnum
# must(*args) is a syntax sugar for kind_of
1.must(Integer) # same as "1.must.be.kind_of(Integer)"
# coercing : looks like kind_of except converting its value if possible
1.must.be.coerced(Integer, String => proc{|val| val.to_i}) # => 1
"1".must.be.coerced(Integer, String => proc{|val| val.to_i}) # => 1
"1".must.be.coerced(Integer, String => :to_i) # => 1 (NOTE: inline Symbol means sending the method)
"1".must.be.coerced(Integer, Symbol, String => proc{:to_i}) # => :to_i (NOTE: use proc to return Symbol itself)
# struct assertions
uris = build_uris # ex) [{:host=>"...", :port=>"..."}, ...]
uris.must.struct([Hash])
Actual Examples
===============
1)
normal code:
def set_reader(reader)
if reader.is_a?(CSV::Reader)
@reader = reader
elsif file.is_a?(String)
@reader = CSV::Reader.create(i)
elsif file.is_a?(Pathname)
@reader = CSV::Reader.create(reader.read)
else
raise 'invalid reader'
end
end
refactor above code with must plugin
def set_reader(reader)
@reader = reader.must.be.coerced(CSV::Reader, Pathname=>:read, String=>{|i| CSV::Reader.create(i)}) {raise 'invalid reader'}
end
2)
class DateFolder
def initialize(date)
@date = date.must.be.coerced(Date, String=>proc{|i| Date.new(*i.scan(/\d+/).map{|i|i.to_i})})
end
end
# this can accept both formats
DateFolder.new Date.today
DateFolder.new "2008-12-9"
NOTE
====
"must(*args)" is a shortcut for not "be(*args)" but "kind_of(*args)" and "struct(*args)".
1.must(1) # => 1
1.must(Fixnum) # => 1
1.must(2) # => 1 # NOTE
1.must.be(2) # Invalid
Fixnum.must(1) # => Fixnum
Bundled Class
=============
struct = Must::StructInfo.new({"1.1" => {"jp"=>[{:a=>0},{:b=>2}]}})
struct.types # => [Hash, String, Array, Symbol, Fixnum]
struct.compact # => {String=>{String=>[{Symbol=>Fixnum}]}}
struct.inspect # => "{String=>{String=>[{Symbol=>Fixnum}]}}"
TODO
====
* add proper error messages
Install
=======
gem install must
% irb -r rubygems -r must
irb(main):001:0> 1.must.be 1
=> 1
Github
======
http://github.com/maiha/must
Author
======
maiha@wota.jp
Project
must
add Object#must method to constrain its origin and conversions
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
Development
Dependencies
Development
>= 0
Project Readme