must 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +14 -0
- data/lib/must/rule.rb +5 -4
- data/lib/must/struct_info.rb +101 -0
- data/lib/must/version.rb +1 -1
- data/lib/must.rb +2 -2
- data/test/must_test.rb +24 -0
- data/test/struct_info_test.rb +53 -0
- data/test/struct_test.rb +32 -25
- metadata +6 -5
- data/lib/must/same_struct.rb +0 -47
data/README
CHANGED
@@ -148,6 +148,20 @@ NOTE
|
|
148
148
|
Fixnum.must(1) # => Fixnum
|
149
149
|
|
150
150
|
|
151
|
+
Bundled Class
|
152
|
+
=============
|
153
|
+
|
154
|
+
struct = Must::StructInfo.new({"1.1" => {"jp"=>[{:a=>0},{:b=>2}]}})
|
155
|
+
struct.types # => [Hash, String, Array, Symbol, Fixnum]
|
156
|
+
struct.compact # => {String=>{String=>[{Symbol=>Fixnum}]}}
|
157
|
+
struct.inspect # => "{String=>{String=>[{Symbol=>Fixnum}]}}"
|
158
|
+
|
159
|
+
|
160
|
+
TODO
|
161
|
+
====
|
162
|
+
* add proper error messages
|
163
|
+
|
164
|
+
|
151
165
|
Install
|
152
166
|
=======
|
153
167
|
gem install must
|
data/lib/must/rule.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'set'
|
2
|
-
require "must/
|
2
|
+
require "must/struct_info"
|
3
3
|
|
4
4
|
module Must
|
5
5
|
class Rule
|
@@ -39,12 +39,13 @@ module Must
|
|
39
39
|
be(nil, &block)
|
40
40
|
end
|
41
41
|
|
42
|
-
def kind_of(*targets)
|
42
|
+
def kind_of(*targets, &block)
|
43
43
|
bool = targets.any?{|klass| is_a?(klass)}
|
44
|
-
|
44
|
+
block ||= proc {
|
45
45
|
target = targets.map{|i| instance?(i) ? i.class.name : i.name}.join('/')
|
46
46
|
raise Invalid, "expected #{target} but got #{object.class}"
|
47
47
|
}
|
48
|
+
valid?(bool, &block)
|
48
49
|
end
|
49
50
|
|
50
51
|
def one_of(target, &block)
|
@@ -89,7 +90,7 @@ module Must
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def struct?(target)
|
92
|
-
Must::
|
93
|
+
Must::StructInfo.new(@object).same?(target)
|
93
94
|
end
|
94
95
|
|
95
96
|
def struct(target, &block)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Must
|
2
|
+
class StructInfo
|
3
|
+
|
4
|
+
module Classify
|
5
|
+
def classify(obj)
|
6
|
+
class?(obj) ? obj : obj.class
|
7
|
+
end
|
8
|
+
|
9
|
+
def class?(obj)
|
10
|
+
obj.class.to_s =~ /\A(Class|Module)\Z/o
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Browser
|
15
|
+
include Classify
|
16
|
+
|
17
|
+
def compact(obj)
|
18
|
+
case obj
|
19
|
+
when Hash
|
20
|
+
Hash[*(obj.first || []).map{|i| compact(i)}]
|
21
|
+
when Array
|
22
|
+
obj.empty? ? [] : [compact(obj.first)]
|
23
|
+
else
|
24
|
+
classify(obj)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def types(obj)
|
29
|
+
case obj
|
30
|
+
when Hash
|
31
|
+
([Hash] + (obj.first || []).map{|i| types(i)}.flatten).uniq
|
32
|
+
when Array
|
33
|
+
([Array] + obj.map{|i| types(i)}.flatten).uniq
|
34
|
+
else
|
35
|
+
[classify(obj)]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def same?(src, dst)
|
40
|
+
case src
|
41
|
+
when Hash
|
42
|
+
return true if dst == Hash
|
43
|
+
dst.must(Hash)
|
44
|
+
return true if src.empty?
|
45
|
+
return true if dst.empty?
|
46
|
+
key1, val1 = src.first
|
47
|
+
key2, val2 = dst.first
|
48
|
+
key1.must(key2)
|
49
|
+
val1.must(val2)
|
50
|
+
|
51
|
+
when Array
|
52
|
+
return true if dst == Array
|
53
|
+
dst.must(Array)
|
54
|
+
return true if src.empty?
|
55
|
+
return true if dst.empty?
|
56
|
+
src.first.must(dst.first)
|
57
|
+
|
58
|
+
else
|
59
|
+
# 1.must.struct(2)
|
60
|
+
# 1.must.struct(Integer)
|
61
|
+
dst_class = classify(dst)
|
62
|
+
return true if classify(src).ancestors.include?(dst_class)
|
63
|
+
|
64
|
+
# Fixnum.must.struct(2)
|
65
|
+
return true if class?(src) and src.ancestors.include?(dst_class)
|
66
|
+
|
67
|
+
return false
|
68
|
+
end
|
69
|
+
return true
|
70
|
+
|
71
|
+
rescue Must::Invalid
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
|
75
|
+
extend self
|
76
|
+
end
|
77
|
+
|
78
|
+
######################################################################
|
79
|
+
### StructInfo
|
80
|
+
|
81
|
+
def initialize(obj)
|
82
|
+
@obj = obj
|
83
|
+
end
|
84
|
+
|
85
|
+
def types
|
86
|
+
Browser.types(@obj)
|
87
|
+
end
|
88
|
+
|
89
|
+
def compact
|
90
|
+
Browser.compact(@obj)
|
91
|
+
end
|
92
|
+
|
93
|
+
def same?(dst)
|
94
|
+
Browser.same?(@obj, dst)
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspect
|
98
|
+
compact.inspect
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/must/version.rb
CHANGED
data/lib/must.rb
CHANGED
@@ -5,9 +5,9 @@ module Must
|
|
5
5
|
class Invalid < StandardError; end
|
6
6
|
class ShouldNotEmpty < Invalid; end
|
7
7
|
|
8
|
-
def must(*args)
|
8
|
+
def must(*args, &block)
|
9
9
|
if args.size > 0
|
10
|
-
Rule.new(self).be.kind_of(*args)
|
10
|
+
Rule.new(self).be.kind_of(*args, &block)
|
11
11
|
else
|
12
12
|
Rule.new(self)
|
13
13
|
end
|
data/test/must_test.rb
CHANGED
@@ -4,6 +4,9 @@ require File.join(File.dirname(__FILE__), '../init')
|
|
4
4
|
|
5
5
|
class MustTest < Test::Unit::TestCase
|
6
6
|
|
7
|
+
######################################################################
|
8
|
+
### must be
|
9
|
+
|
7
10
|
def test_must_be
|
8
11
|
assert_nothing_raised {1.must.be 1}
|
9
12
|
assert_nothing_raised {[1,2,3].must.be [1,2,3]}
|
@@ -28,6 +31,9 @@ class MustTest < Test::Unit::TestCase
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
34
|
+
######################################################################
|
35
|
+
### must(xxx)
|
36
|
+
|
31
37
|
def test_must_accepts_args_as_kind_of
|
32
38
|
assert_equal "ok", "ok".must(String)
|
33
39
|
assert_raises(Invalid) {"ok".must(Integer)}
|
@@ -36,5 +42,23 @@ class MustTest < Test::Unit::TestCase
|
|
36
42
|
# NOTE: this passes because 1(integer) is a kind of 2(integer)
|
37
43
|
assert_equal 1, 1.must(2)
|
38
44
|
end
|
45
|
+
|
46
|
+
def test_must_with_block
|
47
|
+
assert_equal :error, "ok".must(Integer) {:error}
|
48
|
+
end
|
49
|
+
|
50
|
+
######################################################################
|
51
|
+
### kind_of
|
52
|
+
|
53
|
+
def test_kind_of
|
54
|
+
assert_equal "ok", "ok".must.be.kind_of(String)
|
55
|
+
assert_raises(Invalid) {"ok".must.be.kind_of(Integer)}
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_kind_of_several_args
|
59
|
+
assert_equal "ok", "ok".must.be.kind_of(Integer,String)
|
60
|
+
assert_equal "ok", "ok".must.be.kind_of(String,Integer)
|
61
|
+
assert_raises(Invalid) {"ok".must.be.kind_of(Integer, Array)}
|
62
|
+
end
|
39
63
|
end
|
40
64
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require File.join(File.dirname(__FILE__), '../init')
|
4
|
+
|
5
|
+
class StructInfoTest < Test::Unit::TestCase
|
6
|
+
######################################################################
|
7
|
+
### same?
|
8
|
+
|
9
|
+
def test_same_p
|
10
|
+
assert Must::StructInfo.new(1).same?(Integer)
|
11
|
+
assert Must::StructInfo.new(1).same?(Numeric)
|
12
|
+
assert ! Must::StructInfo.new(1).same?(String)
|
13
|
+
|
14
|
+
assert Must::StructInfo.new(Integer).same?(Integer)
|
15
|
+
assert Must::StructInfo.new(Integer).same?(Numeric)
|
16
|
+
assert Must::StructInfo.new(Fixnum).same?(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
######################################################################
|
20
|
+
### types
|
21
|
+
|
22
|
+
def test_types
|
23
|
+
assert_equal [Fixnum], Must::StructInfo.new(1).types
|
24
|
+
assert_equal [Hash, Symbol, String, Float], Must::StructInfo.new({:a=>{"1"=>0.25}}).types
|
25
|
+
end
|
26
|
+
|
27
|
+
######################################################################
|
28
|
+
### struct
|
29
|
+
|
30
|
+
def test_compact
|
31
|
+
assert_equal(Fixnum, Must::StructInfo.new(1).compact)
|
32
|
+
assert_equal({}, Must::StructInfo.new({}).compact)
|
33
|
+
assert_equal({String=>Fixnum}, Must::StructInfo.new({"a"=>1}).compact)
|
34
|
+
assert_equal([{String=>Float}], Must::StructInfo.new([{"1"=>0.25}]).compact)
|
35
|
+
assert_equal({String=>{String=>[{Symbol=>Fixnum}]}}, Must::StructInfo.new({"1.1" => {"jp"=>[{:a=>0},{:b=>2}]}}).compact)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_compact_array_into_first_element
|
39
|
+
assert_equal [Fixnum], Must::StructInfo.new([1, "a"]).compact
|
40
|
+
assert_equal [String], Must::StructInfo.new(["a", 1]).compact
|
41
|
+
end
|
42
|
+
|
43
|
+
######################################################################
|
44
|
+
### pp
|
45
|
+
|
46
|
+
def test_inspect
|
47
|
+
assert_equal "Fixnum", Must::StructInfo.new(1).inspect
|
48
|
+
assert_equal "{}", Must::StructInfo.new({}).inspect
|
49
|
+
assert_equal "{String=>Fixnum}", Must::StructInfo.new({"a"=>1}).inspect
|
50
|
+
assert_equal "[{String=>Float}]", Must::StructInfo.new([{"1"=>0.25}]).inspect
|
51
|
+
assert_equal "{String=>{String=>[{Symbol=>Fixnum}]}}", Must::StructInfo.new({"1.1" => {"jp"=>[{:a=>0},{:b=>2}]}}).inspect
|
52
|
+
end
|
53
|
+
end
|
data/test/struct_test.rb
CHANGED
@@ -3,39 +3,46 @@ require 'rubygems'
|
|
3
3
|
require File.join(File.dirname(__FILE__), '../init')
|
4
4
|
|
5
5
|
class StructTest < Test::Unit::TestCase
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
assert_equal true, 1.must.struct?(Fixnum)
|
10
|
-
assert_equal true, 1.must.struct?(2)
|
11
|
-
assert_equal true, Fixnum.must.struct?(Fixnum)
|
12
|
-
assert_equal true, Fixnum.must.struct?(2)
|
6
|
+
def test_struct_basic_object
|
7
|
+
assert [].must.struct?([])
|
8
|
+
assert ! [].must.struct?({})
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
assert 1.must.struct?(Integer)
|
11
|
+
assert 1.must.struct?(Fixnum)
|
12
|
+
assert 1.must.struct?(2)
|
13
|
+
assert ! 1.must.struct?(String)
|
14
|
+
assert Fixnum.must.struct?(Fixnum)
|
15
|
+
assert Fixnum.must.struct?(2)
|
16
|
+
assert ! Integer.must.struct?(Fixnum)
|
21
17
|
end
|
22
18
|
|
23
|
-
def
|
24
|
-
assert_equal false, [].must.struct?({})
|
25
|
-
assert_equal false, Integer.must.struct?(Fixnum)
|
26
|
-
|
19
|
+
def test_struct_composite_objects
|
27
20
|
obj = {"foo" => 1}
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
assert obj.must.struct?({String => Integer})
|
22
|
+
assert ! obj.must.struct?(String)
|
23
|
+
assert ! obj.must.struct?(Array)
|
24
|
+
assert ! obj.must.struct?([String])
|
25
|
+
assert ! obj.must.struct?({String => String})
|
32
26
|
|
33
27
|
obj = [{:a=>1}, {:a=>3}]
|
34
|
-
|
28
|
+
assert obj.must.struct?([Hash])
|
29
|
+
assert ! obj.must.struct?([Array])
|
30
|
+
|
31
|
+
obj = {"foo" => [{:a=>1}, {:a=>3}]}
|
32
|
+
assert obj.must.struct?(Hash)
|
33
|
+
assert ! obj.must.struct?(Array)
|
34
|
+
assert obj.must.struct?({String => Array})
|
35
|
+
assert ! obj.must.struct?({Array => Array})
|
36
|
+
assert obj.must.struct?({String => [Hash]})
|
35
37
|
|
36
38
|
obj = {"foo" => [{:a=>1}, {:a=>3}]}
|
37
|
-
|
38
|
-
|
39
|
+
assert obj.must.struct?({String => []})
|
40
|
+
assert obj.must.struct?({String => Array})
|
41
|
+
assert ! obj.must.struct?({String => Hash})
|
42
|
+
assert obj.must.struct?({String => [Hash]})
|
43
|
+
assert obj.must.struct?({String => Array(Hash)})
|
44
|
+
assert ! obj.must.struct?({String => [Array]})
|
45
|
+
assert ! obj.must.struct?({String => Array(String)})
|
39
46
|
end
|
40
47
|
|
41
48
|
def test_struct_complicated
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: must
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 5
|
10
|
+
version: 0.2.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- maiha
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-02-09 00:00:00 +09:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -35,13 +35,14 @@ files:
|
|
35
35
|
- install.rb
|
36
36
|
- lib/must.rb
|
37
37
|
- lib/must/rule.rb
|
38
|
-
- lib/must/
|
38
|
+
- lib/must/struct_info.rb
|
39
39
|
- lib/must/version.rb
|
40
40
|
- must.gemspec
|
41
41
|
- test/coerced_test.rb
|
42
42
|
- test/duck_test.rb
|
43
43
|
- test/match_test.rb
|
44
44
|
- test/must_test.rb
|
45
|
+
- test/struct_info_test.rb
|
45
46
|
- test/struct_test.rb
|
46
47
|
has_rdoc: true
|
47
48
|
homepage: http://github.com/maiha/must
|
data/lib/must/same_struct.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module Must
|
2
|
-
module SameStruct
|
3
|
-
def self.check(src, dst)
|
4
|
-
case src
|
5
|
-
when Hash
|
6
|
-
return true if dst == Hash
|
7
|
-
dst.must(Hash)
|
8
|
-
return true if src.empty?
|
9
|
-
return true if dst.empty?
|
10
|
-
key1, val1 = src.first
|
11
|
-
key2, val2 = dst.first
|
12
|
-
key1.must(key2)
|
13
|
-
val1.must(val2)
|
14
|
-
|
15
|
-
when Array
|
16
|
-
return true if dst == Array
|
17
|
-
dst.must(Array)
|
18
|
-
return true if src.empty?
|
19
|
-
return true if dst.empty?
|
20
|
-
src.first.must(dst.first)
|
21
|
-
|
22
|
-
else
|
23
|
-
# 1.must.struct(2)
|
24
|
-
# 1.must.struct(Integer)
|
25
|
-
dst_class = classify(dst)
|
26
|
-
return true if classify(src).ancestors.include?(dst_class)
|
27
|
-
|
28
|
-
# Fixnum.must.struct(2)
|
29
|
-
return true if class?(src) and src.ancestors.include?(dst_class)
|
30
|
-
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
return true
|
34
|
-
|
35
|
-
rescue Must::Invalid
|
36
|
-
return false
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.classify(obj)
|
40
|
-
class?(obj) ? obj : obj.class
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.class?(obj)
|
44
|
-
obj.class.to_s =~ /\A(Class|Module)\Z/o
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|