must 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|