typed 0.1.1 → 0.1.2

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/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem 'activesupport'
4
- gem 'must', '>= 0.2.5'
4
+ gem 'must', '>= 0.2.6'
data/lib/typed.rb CHANGED
@@ -5,7 +5,6 @@ require "typed/hash"
5
5
 
6
6
  module Typed
7
7
  NotDefined = Class.new(RuntimeError)
8
- LazyValue = Struct.new(:block)
9
8
 
10
9
  autoload :Default, "typed/default"
11
10
  autoload :Schema , "typed/schema"
data/lib/typed/default.rb CHANGED
@@ -12,7 +12,7 @@ module Typed
12
12
  def regsiter_lazy(key, block)
13
13
  return if @kvs.exist?(key)
14
14
  raise ArgumentError, "Lazy default value needs block: #{key}" unless block
15
- @kvs[key] = LazyValue.new(block)
15
+ @kvs[key] = Schema::LazyValue.new(block)
16
16
  end
17
17
  end
18
18
  end
data/lib/typed/hash.rb CHANGED
@@ -11,7 +11,7 @@ module Typed
11
11
  def initialize(options = {})
12
12
  @hash = {}
13
13
  @options = DEFAULT_OPTIONS.merge(options.must(::Hash))
14
- @schema = Schema.new(self)
14
+ @schema = Schema.new
15
15
  @default = Default.new(self)
16
16
  end
17
17
 
@@ -54,38 +54,25 @@ module Typed
54
54
  end
55
55
 
56
56
  def []=(key, val)
57
- if check_schema?(key)
58
- if @schema.exist?(key)
59
- case val
60
- when LazyValue
61
- # not schema
62
- when [], {}
63
- # not schema cause already declared
64
- else
65
- struct = Must::StructInfo.new(val).compact
66
- # when schema format, try update schema
67
- @schema[key] = val if struct == val
68
- end
69
- @schema.check!(key, val)
70
-
71
- else
72
- case val
73
- when LazyValue
74
- # not schema
75
- when [], {}
76
- # ambiguous
77
- @schema[key] = val
78
- when nil, true, false
79
- # no information
80
- else
81
- struct = Must::StructInfo.new(val).compact
82
- @schema[key] = struct
83
- # when schema format, just declare schema and return
84
- return if struct == val
85
- end
86
- end
57
+ declare = @schema.declare_method(val)
58
+ case declare
59
+ when Schema::LazyValue
60
+ # not schema
61
+ update(key, val)
62
+ when Schema::Ambiguous
63
+ # TODO: How to treat these classes
64
+ update(key, val)
65
+ check(key)
66
+ when Schema::Explicit
67
+ @schema.declare!(key, declare)
68
+ check(key) if exist?(key)
69
+ when Schema::Implicit
70
+ @schema.declare!(key, declare)
71
+ update(key, val)
72
+ check(key)
73
+ else
74
+ raise NotImplementedError, "[BUG] no assignment logic for: #{declare.class}"
87
75
  end
88
- update(key, val)
89
76
  end
90
77
 
91
78
  ######################################################################
@@ -100,13 +87,8 @@ module Typed
100
87
  end
101
88
 
102
89
  def check(key, type = nil)
103
- return @schema.check!(key, self[key]) unless type
104
-
105
- self[key].must.struct(type) {
106
- got = Must::StructInfo.new(self[key]).compact.inspect
107
- value = self[key].inspect.truncate(200)
108
- raise TypeError, "%s(%s) got %s: %s" % [key, type.inspect, got, value]
109
- }
90
+ type ||= @schema[key]
91
+ @schema.validate!(key, self[key], type)
110
92
  end
111
93
 
112
94
  ######################################################################
@@ -133,12 +115,11 @@ module Typed
133
115
 
134
116
  private
135
117
  def load(key)
136
- # LazyValue should be evaluated at runtime
137
118
  value = @hash[key]
138
- if value.is_a?(LazyValue)
139
- value = value.block.call
140
- self[key] = value
141
- end
119
+
120
+ # LazyValue should be evaluated at runtime
121
+ return (self[key] = value.value.call) if value.is_a?(Schema::LazyValue)
122
+
142
123
  return value
143
124
  end
144
125
 
data/lib/typed/schema.rb CHANGED
@@ -1,41 +1,102 @@
1
1
  module Typed
2
2
  class Schema
3
3
  NotFound = Class.new(RuntimeError)
4
+ Declared = Struct.new(:value)
5
+ class Ambiguous < Declared; end
6
+ class Implicit < Declared; end
7
+ class Explicit < Declared; end
8
+ class Nothing < Declared; end
9
+ class LazyValue < Declared; end
4
10
 
5
- def initialize(kvs)
6
- @kvs = kvs
7
- @types = {}
11
+ def self.schema?(obj)
12
+ return true if obj.is_a?(Class) or obj.is_a?(Module)
13
+ return false if obj == [] or obj == {}
14
+ return schema?(obj.first) if obj.is_a?(Array)
15
+ return obj.first.any?{|i| schema?(i)} if obj.is_a?(::Hash)
16
+ return false
8
17
  end
9
18
 
10
- def exist?(key)
11
- @types.has_key?(key)
19
+ def self.struct(obj)
20
+ struct = Must::StructInfo.new(obj).compact
21
+ struct = Array if struct == []
22
+ struct = ::Hash if struct == {}
23
+ return struct
12
24
  end
13
25
 
14
- def [](key)
26
+ def self.declare_method(val)
27
+ case val
28
+ when LazyValue; val
29
+ when true,false,nil; Ambiguous.new(val)
30
+ else; schema?(val) ? Explicit.new(val) : Implicit.new(val)
31
+ end
32
+ end
33
+
34
+ delegate :schema?, :declare_method, :to => "self.class"
35
+
36
+ def initialize
37
+ @types = ::Hash.new{ Nothing.new }
38
+ end
39
+
40
+ def definition(key)
15
41
  @types[key]
16
42
  end
17
43
 
18
- def []=(key, val)
19
- # update schema if sub-class, otherwise raises
20
- val.must.struct(@types[key]) {
21
- raise TypeError, "%s is already typed as `%s'" % [key, @types[key].inspect]
22
- } if exist?(key)
44
+ def [](key)
45
+ @types[key].value
46
+ end
47
+
48
+ def declare!(key, declare)
49
+ case declare.must.be.kind_of(Explicit, Implicit)
50
+ when Explicit
51
+ case @types[key]
52
+ when Explicit
53
+ raise TypeError, "%s has already been declared as `%s'" % [key, @types[key].value.inspect]
54
+ when Implicit
55
+ # update schema if sub-class, otherwise raises
56
+ declare.value.must.struct?(@types[key].value) or
57
+ raise TypeError, "%s has already been typed as `%s'" % [key, @types[key].value.inspect]
58
+ end
59
+ explicit(key, declare)
23
60
 
24
- @types[key] = val
61
+ when Implicit
62
+ case @types[key]
63
+ when Explicit
64
+ # nop
65
+ when Implicit
66
+ # update schema if sub-struct
67
+ struct = self.class.struct(declare.value)
68
+ if struct.must.struct?(@types[key].value)
69
+ implicit(key, struct)
70
+ end
71
+ else
72
+ implicit(key, self.class.struct(declare.value))
73
+ end
74
+ end
25
75
  end
26
76
 
27
- def check!(key, val)
28
- struct = @types[key] or
29
- raise Schema::NotFound, key.to_s
77
+ def validate!(key, val, klass)
78
+ return true unless klass
79
+ # raise Schema::NotFound, key.to_s unless klass
30
80
 
31
- if val.must.struct?(struct)
81
+ if val.must.struct?(klass)
32
82
  return true
33
83
  else
34
- expected = @types[key].inspect
84
+ expected = klass.inspect
35
85
  got = Must::StructInfo.new(val).compact.inspect
36
86
  value = val.inspect.truncate(200)
37
87
  raise TypeError, "%s(%s) got %s: %s" % [key, expected, got, value]
38
88
  end
39
89
  end
90
+
91
+ private
92
+ def implicit(key, val)
93
+ val = Implicit.new(val) unless val.is_a?(Implicit)
94
+ @types[key] = val
95
+ end
96
+
97
+ def explicit(key, val)
98
+ val = Explicit.new(val) unless val.is_a?(Explicit)
99
+ @types[key] = val
100
+ end
40
101
  end
41
102
  end
data/lib/typed/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Typed
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/spec/hash_spec.rb CHANGED
@@ -36,9 +36,12 @@ describe Typed::Hash do
36
36
  end
37
37
 
38
38
  describe "#[]=" do
39
- it "should set not data but schema when schema given" do
39
+ it "should accept as schema when class is given" do
40
40
  data[:foo] = String
41
41
  data.exist?(:foo).should == false
42
+
43
+ data[:bar] = Hash
44
+ data.exist?(:bar).should == false
42
45
  end
43
46
 
44
47
  it "should check schema if exists" do
@@ -49,11 +52,29 @@ describe Typed::Hash do
49
52
  }.should raise_error(TypeError)
50
53
  end
51
54
 
52
- it "should guess and check schema if not exists" do
55
+ it "should implicitly declare schema when assigned" do
53
56
  data[:foo] = 1
54
- lambda {
55
- data[:foo] = "test"
56
- }.should raise_error(TypeError)
57
+ data.schema(:foo).should == Fixnum
58
+
59
+ data[:bar] = {:a => 1}
60
+ data.schema(:bar).should == {Symbol => Fixnum}
61
+ end
62
+
63
+ it "should implicitly declare schema if not exists" do
64
+ data[:foo] = 1
65
+ data.schema(:foo).should == Fixnum
66
+ end
67
+
68
+ # TODO: How can we declare Boolean? How to treat nil?
69
+ it "should not implicitly declare schema when nil,true,false" do
70
+ data[:foo] = nil
71
+ data.schema(:foo).should == nil
72
+
73
+ data[:bar] = true
74
+ data.schema(:bar).should == nil
75
+
76
+ data[:baz] = false
77
+ data.schema(:baz).should == nil
57
78
  end
58
79
 
59
80
  it "can override existing value if same type" do
@@ -76,21 +97,67 @@ describe Typed::Hash do
76
97
  data[:foo].should == 0.5
77
98
  end
78
99
 
79
- it "should raise TypeError when schema given twice" do
80
- data[:foo] = String
100
+ it "should create new objects for Array,Hash is given for schema" do
101
+ data[:a] = []
102
+ data[:a][0] = 1
103
+ data.schema(:a).should == Array
104
+
105
+ data[:h] = {}
106
+ data[:h]["x"] = 1
107
+ data.schema(:h).should == Hash
108
+ end
109
+
110
+ it "should check existing value when explicit declarement is given" do
111
+ data[:foo] = {}
112
+ data[:foo][:a] = 1
81
113
  lambda {
82
- data[:foo] = Integer
114
+ data[:foo] = {String => Integer}
83
115
  }.should raise_error(TypeError)
84
116
  end
85
117
 
86
- it "can ovreride schema when given schema is sub-class of existing one" do
118
+ it "cannot ovreride explicit declarement" do
87
119
  data[:num] = Numeric
88
- data[:num] = 10
89
- data.schema(:num).should == Numeric
90
- data[:num] = Fixnum
91
- data.schema(:num).should == Fixnum
92
- data[:num] = 20
93
- data.schema(:num).should == Fixnum
120
+ lambda {
121
+ data[:num] = Fixnum
122
+ }.should raise_error(TypeError)
123
+ end
124
+
125
+ it "can override implicitly declared schema by sub-struct schema" do
126
+ data[:foo] = {}
127
+ data[:foo].should == {}
128
+ data.schema(:foo).should == Hash
129
+
130
+ data[:foo] = {String => Integer}
131
+ data[:foo].should == {}
132
+ data.schema(:foo).should == {String => Integer}
133
+ end
134
+
135
+ it "should implicitly override schema when given schema is sub-struct of existing one" do
136
+ data[:foo] = {}
137
+ data[:foo].should == {}
138
+ data.schema(:foo).should == Hash
139
+
140
+ data[:foo] = {:a => 1}
141
+ data[:foo].should == {:a => 1}
142
+ data.schema(:foo).should == {Symbol => Fixnum}
143
+ end
144
+
145
+ it "should not override schema if explicitly declarement exists" do
146
+ data[:foo] = Hash
147
+ data[:foo] = {}
148
+ data.schema(:foo).should == Hash
149
+
150
+ data[:foo] = {:a => 1}
151
+ data[:foo].should == {:a => 1}
152
+ data.schema(:foo).should == Hash
153
+ end
154
+
155
+ it "raise TypeError when re-declarement causes type mismatch" do
156
+ data[:foo] = Numeric
157
+ data[:foo] = 0.5
158
+ lambda {
159
+ data[:foo] = Fixnum
160
+ }.should raise_error(TypeError)
94
161
  end
95
162
  end
96
163
 
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe Typed::Schema do
4
+ describe ".schema?" do
5
+ delegate :schema?, :to => "Typed::Schema"
6
+
7
+ it "should return true for Class,Module" do
8
+ schema?(Class ).should == true
9
+ schema?(Module).should == true
10
+ schema?(Array ).should == true
11
+ schema?(Hash ).should == true
12
+ schema?(Fixnum).should == true
13
+ end
14
+
15
+ it "should return false for [],{}" do
16
+ schema?([]).should == false
17
+ schema?({}).should == false
18
+ end
19
+
20
+ it "should return true for [Class,Module,...]" do
21
+ schema?([Array ]).should == true
22
+ schema?([Hash ]).should == true
23
+ schema?([Object]).should == true
24
+ end
25
+
26
+ it "should return true for {(Class,Module) => (Class,Module)}" do
27
+ schema?({String => Fixnum}).should == true
28
+ schema?({Hash => Array }).should == true
29
+ end
30
+
31
+ it "should return false for instances" do
32
+ schema?(1).should == false
33
+ schema?([1]).should == false
34
+ schema?({:a => 2}).should == false
35
+ end
36
+ end
37
+ end
data/typed.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_dependency "activesupport"
22
- s.add_dependency "must", ">= 0.2.5"
22
+ s.add_dependency "must", ">= 0.2.6"
23
23
 
24
24
  s.add_development_dependency "rspec"
25
25
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typed
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
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-02-10 00:00:00 +09:00
18
+ date: 2012-02-13 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -40,12 +40,12 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- hash: 29
43
+ hash: 27
44
44
  segments:
45
45
  - 0
46
46
  - 2
47
- - 5
48
- version: 0.2.5
47
+ - 6
48
+ version: 0.2.6
49
49
  type: :runtime
50
50
  version_requirements: *id002
51
51
  - !ruby/object:Gem::Dependency
@@ -82,6 +82,7 @@ files:
82
82
  - lib/typed/schema.rb
83
83
  - lib/typed/version.rb
84
84
  - spec/hash_spec.rb
85
+ - spec/schema_spec.rb
85
86
  - spec/spec_helper.rb
86
87
  - typed.gemspec
87
88
  has_rdoc: true