Matcher
という物を作った。パブリックドメインとするので自由に使ってください。
ruby/matcher/matcher.rb at master from sorah/sandbox - GitHub
使い方
Matcher.new(obj, default = DEFAULT_KEY)
obj にハッシュを渡して、その後 Matcher#match?(*conds)
にマッチ条件を渡すと true
か false
が返ってくる。
また、Matcher#match(*conds)
でマッチした部分の配列等が返ってくる。
渡すハッシュでマッチ対象にできるのは {a: "b", b: "c"} といった1階層のHashだけで、複数の階層にわたるハッシュに対しては微妙。今回これを作った時にそれは想定してないのでどうでもいい。 誰かやってくれ。
引数 default
デフォルトだと Matcher::DEFAULT_KEY
.
default
は後述するマッチ条件でマッチ対象のキーが指定されてない時に参照するキーとなってる。
conds に使えるオブジェクト等
そもそも*conds
引数は可変数引数になっている。
まず複数の引数を渡すと、渡した条件のうちいずれか一つにマッチすればマッチした扱いになり、全部にマッチしなければマッチしない扱いになる。
条件には、Regexp
のオブジェクトを渡すとその正規表現にRegexp#match
でマッチするかどうかを確認、それ以外は==
メソッドで確認される。
m = Matcher.new({foo: "bar", bar: "foo"}, :foo)
p m.match?("bar") #=> true
p m.match?("foo", "bar") #=> true
p m.match?(/fo/) #=> true
p m.match?("bar") #=> false
p m.match?(/b/) #=> false
普通にArray
を渡すと、これも複数の引数を渡した時のように配列内のオブジェクトを条件とみなしどれかにマッチしたときにマッチした扱いにする。が、あまり意味はないよね。ここでは。
Hash
も渡す事ができる。Hash
を渡すと、:any
, :all
を除いたキー以外だと、デフォルトのキーではなくそのキーに対してマッチするかどうかになる。で、何も指定 (後述する:any
とか:all
とか) しない限りは、そのHash
のどれかのキー(もちろんany,all以外)がマッチすればマッチした事になる。
p m.match?(bar: "foo") #=> true
p m.match?(bar: /f/) #=> true
p m.match?(bar: /bar/, foo: "bar") #=> true
ただ :any
と :all
キーを除いては、そのキーにHash
を入れてさらに条件を指定しようとしても意味がない。そのHash
との比較になります。Array
は:all
とかを使っていない限りは「いずれかにマッチ」になる。
p m.match?(foo: ["foo", "bar"]) #=> true
そして :any
キー は、その名の通り :any
キーの値に入れた条件どれかにマッチすればマッチしたことになる。
:all
キーもその名前の通り :all
キーの値に入れた条件すべてにマッチすればマッチしたことになる
両方の値にはさっき書いた条件をそのまま評価するので何を入れても良い。ただ、その条件の「いずれかにマッチ」等が :all
だと「全てにマッチ」に変わるだけ。
:any
キーは :all
の中で一部を「このいずれか」にしたい時に便利。
普通の条件式等でいうと {all: {a: {any: [1,2,3]}, b: /c/}
は [1,2,3].include?(a) && /c/.match(b)
みたいな感じ。
p m.match?(all: {foo: "bar", bar: "foo"}) #=> true
p m.match?(all: {foo: "foo", bar: "foo"}) #=> false
p m.match?(all: {foo: [/^f/,/o$/], bar: "foo"}) #=> true
p m.match?(all: {foo: [/^o/,/o$/], bar: "foo"}) #=> false
:raw
キーのみを含んだハッシュをマッチ条件として渡したりすると、そのArrayと==
でtrue
になるか等になる。
要するに条件のカスタマイズではなくそれと比較させたいとかいう場合。
また match?
ではなく match
を使うと正規表現のMatchData等がとれ、条件にマッチしないときはfalse。
p m.match(foo: /b/, bar: /ba/) #=> [{:foo=>#<MatchData "b">}]
p m.match(foo: ["foo", /b/]) #=> [{:foo=>#<MatchData "b">}]
p m.match(/fo/, /ba/) #=> [#<MatchData "ba">]
p m.match(/fo/) #=> false
p m.match("foo", "bar") #=> ["bar"]
その他
その他使い方・返り値が帰ってくるのかは matcher_spec.rb を読んでください………
あとがき
しかし日本語でうまく書けないな。おれはもうだめだ。