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
Development
Dependencies
Development
>= 0
Project Readme