sbyc 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +21 -0
- data/lib/sbyc.rb +10 -2
- data/lib/sbyc/codetree/ast_node.rb +7 -3
- data/lib/sbyc/codetree/proc_parser.rb +2 -1
- data/lib/sbyc/type_system.rb +8 -0
- data/lib/sbyc/type_system/contract.rb +42 -0
- data/lib/sbyc/type_system/errors.rb +6 -0
- data/lib/sbyc/type_system/ruby.rb +135 -0
- data/test/spec/documentation/type_system/example.spec +21 -0
- data/test/spec/unit/sbyc/codetree/ast_node/coerce.spec +9 -0
- data/test/spec/unit/sbyc/codetree/parse.spec +27 -0
- data/test/spec/unit/sbyc/type_system/ruby/coerce.spec +97 -0
- data/test/spec/unit/sbyc/type_system/ruby/parse_literal.spec +26 -0
- data/test/spec/unit/sbyc/type_system/ruby/to_literal.spec +116 -0
- data/test/spec/unit/sbyc/type_system/ruby/type_of.spec +16 -0
- metadata +13 -4
data/README.textile
CHANGED
@@ -26,6 +26,27 @@ Marshal.dump(code)
|
|
26
26
|
|
27
27
|
"Learn more about CodeTree":http://blambeau.github.com/sbyc/codetree.html
|
28
28
|
|
29
|
+
h2. TypeSystem
|
30
|
+
|
31
|
+
This part of SByC implements a TypeSystem abstraction. A type is simply collection of values. A type system is to generate and parse literals and to coerce from String values.
|
32
|
+
|
33
|
+
<pre>
|
34
|
+
TypeSystem::Ruby::type_of(-125)
|
35
|
+
# => Fixnum
|
36
|
+
|
37
|
+
lit = TypeSystem::Ruby::to_literal(-125)
|
38
|
+
# => "-125"
|
39
|
+
|
40
|
+
TypeSystem::Ruby::parse_literal("-125")
|
41
|
+
# => -125
|
42
|
+
|
43
|
+
TypeSystem::Ruby::coerce('-125', Integer)
|
44
|
+
# => -125
|
45
|
+
</pre>
|
46
|
+
|
47
|
+
"Learn more about TypeSystem":http://blambeau.github.com/sbyc/type_system.html
|
48
|
+
|
49
|
+
|
29
50
|
h2. INSTALL
|
30
51
|
|
31
52
|
bc. gem install sbyc
|
data/lib/sbyc.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
module SByC
|
2
2
|
|
3
3
|
# Version
|
4
|
-
VERSION = "0.1.
|
4
|
+
VERSION = "0.1.3".freeze
|
5
5
|
|
6
6
|
# Provides tools around functional source code trees.
|
7
7
|
module CodeTree
|
8
8
|
|
9
9
|
end # module CodeTree
|
10
|
+
|
11
|
+
# Provides tools around type system abstractions
|
12
|
+
module TypeSystem
|
13
|
+
|
14
|
+
end # module CodeTree
|
10
15
|
|
11
16
|
end # module SByC
|
12
17
|
|
13
18
|
CodeTree = ::SByC::CodeTree
|
14
|
-
require 'sbyc/codetree'
|
19
|
+
require 'sbyc/codetree'
|
20
|
+
|
21
|
+
TypeSystem = ::SByC::TypeSystem
|
22
|
+
require 'sbyc/type_system'
|
@@ -121,10 +121,14 @@ module CodeTree
|
|
121
121
|
arg
|
122
122
|
when Array
|
123
123
|
name, children = arg
|
124
|
-
if name
|
125
|
-
|
124
|
+
if name.kind_of?(Symbol) and children.kind_of?(Array)
|
125
|
+
if name == :_ and children.size == 1
|
126
|
+
AstNode.new(:_, children)
|
127
|
+
else
|
128
|
+
AstNode.new(name, children.collect{|c| AstNode.coerce(c)})
|
129
|
+
end
|
126
130
|
else
|
127
|
-
AstNode.new(
|
131
|
+
AstNode.new(:_, [ arg ])
|
128
132
|
end
|
129
133
|
else
|
130
134
|
AstNode.new(:_, [ arg ])
|
@@ -89,7 +89,8 @@ module CodeTree
|
|
89
89
|
collector = options[:multiline] ? Collector.new : nil
|
90
90
|
e = case block.arity
|
91
91
|
when -1, 0
|
92
|
-
Expr.new(nil, nil, collector)
|
92
|
+
expr = Expr.new(nil, nil, collector)
|
93
|
+
expr.instance_eval(&block)
|
93
94
|
when 1
|
94
95
|
block.call(Expr.new(nil, nil, collector))
|
95
96
|
else
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module TypeSystem
|
2
|
+
#
|
3
|
+
# Defines the abstract contract that a TypeSystem should implement.
|
4
|
+
#
|
5
|
+
module Contract
|
6
|
+
|
7
|
+
#
|
8
|
+
# Returns the type of a value
|
9
|
+
#
|
10
|
+
def type_of(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Converts _value_ to a literal and returns it.
|
15
|
+
#
|
16
|
+
# This method should always be such that:
|
17
|
+
# v == parse_literal(to_literal(v))
|
18
|
+
#
|
19
|
+
# @raise NoSuchLiteralError if value cannot be expressed as a literal
|
20
|
+
#
|
21
|
+
def to_literal(value)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Parse _str_ value literal and returns real value.
|
26
|
+
#
|
27
|
+
# @raise InvalidValueLiteralError if str does not look like a valid
|
28
|
+
# value literal
|
29
|
+
#
|
30
|
+
def parse_literal(str)
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Coerces a string to a given class.
|
35
|
+
#
|
36
|
+
# @raise CoercionError if something goes wrong
|
37
|
+
#
|
38
|
+
def coerce(str, clazz)
|
39
|
+
end
|
40
|
+
|
41
|
+
end # module Contract
|
42
|
+
end # module TypeSystem
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
module TypeSystem
|
4
|
+
#
|
5
|
+
# Implements a basic TypeSystem that mimics Ruby's type system.
|
6
|
+
#
|
7
|
+
module Ruby
|
8
|
+
|
9
|
+
# Methods
|
10
|
+
module Methods
|
11
|
+
|
12
|
+
# Ruby classes for which value.inspect will work for returning
|
13
|
+
# a valid literal
|
14
|
+
SAFE_LITERAL_CLASSES = {}
|
15
|
+
[NilClass, TrueClass, FalseClass,
|
16
|
+
Fixnum, Bignum,
|
17
|
+
Float,
|
18
|
+
String,
|
19
|
+
Symbol,
|
20
|
+
Class,
|
21
|
+
Module,
|
22
|
+
Regexp].each{|c| SAFE_LITERAL_CLASSES[c] = true}
|
23
|
+
|
24
|
+
#
|
25
|
+
# Returns value.class
|
26
|
+
#
|
27
|
+
# @see TypeSystem::Contract#type_of
|
28
|
+
#
|
29
|
+
def type_of(value)
|
30
|
+
value.class
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Converts _value_ to a ruby literal and returns it.
|
35
|
+
#
|
36
|
+
# Behavior of the algorithm when th value cannot be recognized depends
|
37
|
+
# on the :fallback option:
|
38
|
+
# * when set to :fail, it raises a NoSuchLiteralError
|
39
|
+
# * when set to :inspect, it returns <code>value.inspect</code>
|
40
|
+
# * when set to :marshal it uses <code>Marshal::dump(value)</code>
|
41
|
+
# * when set to :json it uses <code>JSON::generate(value)</code>
|
42
|
+
#
|
43
|
+
# @see TypeSystem::Contract#to_literal(value)
|
44
|
+
#
|
45
|
+
def to_literal(value, options = {:fallback => :fail})
|
46
|
+
if value.respond_to?(:to_ruby_literal)
|
47
|
+
value.to_ruby_literal
|
48
|
+
elsif value == (1.0/0)
|
49
|
+
return '(1.0/0)'
|
50
|
+
elsif value == -(1.0/0)
|
51
|
+
return '(-1.0/0)'
|
52
|
+
elsif SAFE_LITERAL_CLASSES.key?(type_of(value))
|
53
|
+
value.inspect
|
54
|
+
elsif value.kind_of?(Array)
|
55
|
+
"[" + value.collect{|v| to_literal(v, options)}.join(', ') + "]"
|
56
|
+
elsif value.kind_of?(Hash)
|
57
|
+
"{" + value.collect{|pair| "#{to_literal(pair[0], options)} => #{to_literal(pair[1], options)}"}.join(', ') + "}"
|
58
|
+
elsif value.kind_of?(Date)
|
59
|
+
"Date::parse(#{value.to_s.inspect})"
|
60
|
+
elsif value.kind_of?(Time)
|
61
|
+
"Time::parse(#{value.inspect.inspect})"
|
62
|
+
else
|
63
|
+
case options[:fallback]
|
64
|
+
when :inspect
|
65
|
+
value.inspect
|
66
|
+
when :marshal
|
67
|
+
"Marshal::load(#{Marshal::dump(value).inspect})"
|
68
|
+
when :json
|
69
|
+
require 'json'
|
70
|
+
JSON::generate(value)
|
71
|
+
when :fail, nil
|
72
|
+
raise NoSuchLiteralError, "Unable to convert #{value.inspect} to a ruby literal"
|
73
|
+
else
|
74
|
+
raise ArgumentError, "Invalid fallback option #{options[:fallback]}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Returns result of Kernel.eval(str)
|
81
|
+
#
|
82
|
+
# @see TypeSystem::Contract#parse_literal(str)
|
83
|
+
#
|
84
|
+
def parse_literal(str)
|
85
|
+
Kernel.eval(str)
|
86
|
+
rescue Exception => ex
|
87
|
+
raise TypeSystem::InvalidValueLiteralError, "Invalid ruby value literal #{str.inspect}", ex.backtrace
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Coerces a string to a given class.
|
92
|
+
#
|
93
|
+
# @see TypeSystem::Contract#coerce(str)
|
94
|
+
#
|
95
|
+
def coerce(str, clazz)
|
96
|
+
if clazz == NilClass
|
97
|
+
return nil if str.empty? or str == "nil"
|
98
|
+
elsif clazz == TrueClass
|
99
|
+
return true if str == "true"
|
100
|
+
elsif clazz == FalseClass
|
101
|
+
return false if str == "false"
|
102
|
+
elsif [Fixnum, Bignum, Integer].include?(clazz)
|
103
|
+
if str =~ /^[-+]?[0-9]+$/
|
104
|
+
i = str.to_i
|
105
|
+
return i if i.kind_of?(clazz)
|
106
|
+
end
|
107
|
+
elsif clazz == Float
|
108
|
+
if str =~ /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/
|
109
|
+
return str.to_f
|
110
|
+
end
|
111
|
+
elsif clazz == String
|
112
|
+
return str
|
113
|
+
elsif clazz == Symbol
|
114
|
+
return str.to_sym
|
115
|
+
elsif clazz == Class or clazz == Module
|
116
|
+
parts, current = str.split("::"), Kernel
|
117
|
+
parts.each{|part| current = current.const_get(part.to_sym)}
|
118
|
+
return current if current.kind_of?(clazz)
|
119
|
+
elsif clazz == Regexp
|
120
|
+
return Regexp::compile(str)
|
121
|
+
elsif clazz.respond_to?(:parse)
|
122
|
+
return clazz.parse(str)
|
123
|
+
end
|
124
|
+
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}"
|
125
|
+
rescue TypeSystem::CoercionError
|
126
|
+
raise
|
127
|
+
rescue StandardError => ex
|
128
|
+
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}: #{ex.message}"
|
129
|
+
end
|
130
|
+
|
131
|
+
end # module Methods
|
132
|
+
extend(Methods)
|
133
|
+
|
134
|
+
end # class Ruby
|
135
|
+
end # module TypeSystem
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
describe "Gh-Pages documentation: type_system/home.redcloth" do
|
4
|
+
|
5
|
+
describe "What is said in README" do
|
6
|
+
specify{
|
7
|
+
TypeSystem::Ruby::type_of(-125).should == Fixnum
|
8
|
+
# => Fixnum
|
9
|
+
|
10
|
+
lit = TypeSystem::Ruby::to_literal(-125).should == "-125"
|
11
|
+
# => "-125"
|
12
|
+
|
13
|
+
TypeSystem::Ruby::parse_literal("-125").should == -125
|
14
|
+
# => -125
|
15
|
+
|
16
|
+
TypeSystem::Ruby::coerce('-125', Integer).should == -125
|
17
|
+
# => -125
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -57,4 +57,13 @@ describe "CodeTree::AstNode#coerce" do
|
|
57
57
|
}
|
58
58
|
end
|
59
59
|
|
60
|
+
context("with array a single literal") do
|
61
|
+
subject { CodeTree::AstNode.coerce([{:id => 1}, {:id => 2}]) }
|
62
|
+
specify {
|
63
|
+
subject.should be_kind_of(CodeTree::AstNode)
|
64
|
+
subject.leaf?.should be_true
|
65
|
+
subject.literal.should == [{:id => 1}, {:id => 2}]
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
60
69
|
end
|
@@ -28,5 +28,32 @@ describe "CodeTree::parse" do
|
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
31
|
+
context "when called with an array of hashes as parameter" do
|
32
|
+
subject{ CodeTree::parse{
|
33
|
+
insert [{:id => 1}, {:id => 2}]
|
34
|
+
}}
|
35
|
+
specify{
|
36
|
+
subject.should be_kind_of(CodeTree::AstNode)
|
37
|
+
subject.name.should == :insert
|
38
|
+
subject.children[0].should be_kind_of(CodeTree::AstNode)
|
39
|
+
subject.children[0].literal.should == [{:id => 1}, {:id => 2}]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when called with an array of hashes as parameter" do
|
44
|
+
subject{ CodeTree::parse{
|
45
|
+
(key! :table_name, [:col1, :col2])
|
46
|
+
}}
|
47
|
+
specify{
|
48
|
+
subject.should be_kind_of(CodeTree::AstNode)
|
49
|
+
subject.name.should == :key!
|
50
|
+
subject.children[0].should be_kind_of(CodeTree::AstNode)
|
51
|
+
subject.children[0].literal.should == :table_name
|
52
|
+
subject.children[1].should be_kind_of(CodeTree::AstNode)
|
53
|
+
subject.children[1].leaf?.should be_true
|
54
|
+
subject.children[1].literal.should == [:col1, :col2]
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
31
58
|
end
|
32
59
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.expand_path('../../../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
|
4
|
+
describe "TypeSystem::Ruby#coerce" do
|
5
|
+
|
6
|
+
##################################################################################
|
7
|
+
### SAFE CLASSES REPRESENTORS
|
8
|
+
##################################################################################
|
9
|
+
|
10
|
+
safe_representors = {
|
11
|
+
NilClass => [ nil ],
|
12
|
+
TrueClass => [ true ],
|
13
|
+
FalseClass => [ false ],
|
14
|
+
Fixnum => [ -(2**(0.size * 8 - 2)), -1, 0, 1, 10, (2**(0.size * 8 - 2) - 1)],
|
15
|
+
Bignum => [ -(2**(0.size * 8 - 2)) - 1, (2**(0.size * 8 - 2)) ],
|
16
|
+
Float => [ -0.10, 0.0, 0.10 ],
|
17
|
+
String => ['', 'hello'],
|
18
|
+
Symbol => [ :hello, :"s-b-y-c", :"12" ],
|
19
|
+
Class => [ Integer, ::Struct::Tms ],
|
20
|
+
Module => [ Kernel, TypeSystem, TypeSystem::Ruby ],
|
21
|
+
Regexp => [ /a-z/, /^$/, /\s*/, /[a-z]{15}/ ]
|
22
|
+
}
|
23
|
+
|
24
|
+
safe_representors.each_pair do |clazz, values|
|
25
|
+
values.each do |value|
|
26
|
+
describe "When coercing #{value} to a #{clazz}" do
|
27
|
+
it "should return #{value}" do
|
28
|
+
str = value.kind_of?(Regexp) ? value.inspect[1..-2] : value.to_s
|
29
|
+
TypeSystem::Ruby::coerce(str, clazz).should == value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
##################################################################################
|
37
|
+
### User defined objects
|
38
|
+
##################################################################################
|
39
|
+
class TypeSystem::Ruby::Bar
|
40
|
+
attr_accessor :id
|
41
|
+
def initialize(id = 1); @id = id; end
|
42
|
+
def ==(other); other.kind_of?(TypeSystem::Ruby::Bar) and other.id == id; end
|
43
|
+
def self.parse(str)
|
44
|
+
TypeSystem::Ruby::Bar.new(TypeSystem::Ruby::coerce(str, Integer))
|
45
|
+
end
|
46
|
+
def inspect
|
47
|
+
id.inspect
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "when called with a user-defined class that respond to parse" do
|
52
|
+
|
53
|
+
subject{ TypeSystem::Ruby::coerce(str, TypeSystem::Ruby::Bar) }
|
54
|
+
|
55
|
+
describe "when given a valid value" do
|
56
|
+
let(:value){ TypeSystem::Ruby::Bar.new(10) }
|
57
|
+
let(:str){ value.inspect }
|
58
|
+
it{ should == value }
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "when given an invalid values" do
|
62
|
+
let(:str){ "hello" }
|
63
|
+
specify{
|
64
|
+
lambda{ subject }.should raise_error(TypeSystem::CoercionError)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
##################################################################################
|
72
|
+
### Invalid values
|
73
|
+
##################################################################################
|
74
|
+
|
75
|
+
invalid_values = {
|
76
|
+
NilClass => [ "hello", "false" ],
|
77
|
+
TrueClass => [ "false", "nil" ],
|
78
|
+
FalseClass => [ "true", "nil" ],
|
79
|
+
Fixnum => [ "hello", "1hello", "hello1", "1.0" ],
|
80
|
+
Bignum => [ "hello", "1hello", "hello1", "1.0" ],
|
81
|
+
Float => [ "hello", "1hello", "hello1", "1.0qsjh" ],
|
82
|
+
Class => [ "hello" ],
|
83
|
+
Module => [ "hello" ],
|
84
|
+
Regexp => [ "[a-" ]
|
85
|
+
}
|
86
|
+
|
87
|
+
invalid_values.each_pair do |clazz, values|
|
88
|
+
values.each do |value|
|
89
|
+
describe "When coercing #{value} to a #{clazz}" do
|
90
|
+
it "should raise an exception" do
|
91
|
+
lambda{ TypeSystem::Ruby::coerce(value, clazz) }.should raise_error(TypeSystem::CoercionError)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
|
4
|
+
describe "TypeSystem::Ruby#parse_literal" do
|
5
|
+
|
6
|
+
describe "when called on a String value" do
|
7
|
+
subject{ TypeSystem::Ruby.parse_literal("'string'") }
|
8
|
+
it{ should == 'string' }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when called on a Fixnum value" do
|
12
|
+
subject{ TypeSystem::Ruby.parse_literal('10') }
|
13
|
+
it{ should == 10 }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when called on true" do
|
17
|
+
subject{ TypeSystem::Ruby.parse_literal('true') }
|
18
|
+
it{ should == true }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "when called on false" do
|
22
|
+
subject{ TypeSystem::Ruby.parse_literal('false') }
|
23
|
+
it{ should == false }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.expand_path('../../../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
|
4
|
+
describe "TypeSystem::Ruby#to_literal" do
|
5
|
+
|
6
|
+
##################################################################################
|
7
|
+
### SAFE CLASSES REPRESENTORS
|
8
|
+
##################################################################################
|
9
|
+
|
10
|
+
safe_representors = {
|
11
|
+
NilClass => [ nil ],
|
12
|
+
TrueClass => [ true ],
|
13
|
+
FalseClass => [ false ],
|
14
|
+
Fixnum => [ -(2**(0.size * 8 - 2)), -1, 0, 1, 10, (2**(0.size * 8 - 2) - 1)],
|
15
|
+
Bignum => [ -(2**(0.size * 8 - 2)) - 1, (2**(0.size * 8 - 2)) ],
|
16
|
+
Float => [ -0.10, 0.0, 0.10 ],
|
17
|
+
String => ['', 'hello'],
|
18
|
+
Symbol => [ :hello, :"s-b-y-c", :"12" ],
|
19
|
+
Class => [ Integer, ::Struct::Tms ],
|
20
|
+
Module => [ Kernel, TypeSystem, TypeSystem::Ruby ],
|
21
|
+
Regexp => [ /a-z/, /^$/, /\s*/, /[a-z]{15}/ ]
|
22
|
+
}
|
23
|
+
|
24
|
+
TypeSystem::Ruby::Methods::SAFE_LITERAL_CLASSES.keys.each do |clazz|
|
25
|
+
describe("SAFE_LITERAL_CLASS #{clazz} is covered by spec tests") do
|
26
|
+
subject{ safe_representors.key?(clazz) }
|
27
|
+
it{ should be_true }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
safe_representors.each_pair{|clazz, values|
|
32
|
+
values.each do |value|
|
33
|
+
describe("Safe representor #{value} is of good type #{clazz} natively") do
|
34
|
+
subject{ value.class }
|
35
|
+
it{ should == clazz }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe("Safe representor #{value} is of good type #{clazz} through Ruby::type_of") do
|
39
|
+
subject{ TypeSystem::Ruby::type_of(value) }
|
40
|
+
it{ should == clazz }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe("to_literal on safe representor #{clazz} / #{value} is equal to inspect") do
|
44
|
+
subject{ TypeSystem::Ruby::to_literal(value) }
|
45
|
+
it{ should == value.inspect }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe("to_literal invariant is respected on safe representor #{clazz} / #{value}") do
|
49
|
+
subject{ TypeSystem::Ruby::parse_literal(TypeSystem::Ruby::to_literal(value)) }
|
50
|
+
it{ should == value }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
}
|
54
|
+
|
55
|
+
##################################################################################
|
56
|
+
### SPECIAL VALUES
|
57
|
+
##################################################################################
|
58
|
+
|
59
|
+
special_values = [
|
60
|
+
1.0/0, -1.0/0,
|
61
|
+
Time::parse(Time.now.inspect), Date::parse(Date.today.to_s)
|
62
|
+
]
|
63
|
+
|
64
|
+
special_values.each{|value|
|
65
|
+
describe("When called on special value #{value}") do
|
66
|
+
subject{ TypeSystem::Ruby::parse_literal(TypeSystem::Ruby::to_literal(value)) }
|
67
|
+
it{ should == value }
|
68
|
+
end
|
69
|
+
}
|
70
|
+
|
71
|
+
##################################################################################
|
72
|
+
### ARRAY AND HASH
|
73
|
+
##################################################################################
|
74
|
+
|
75
|
+
describe "When called on an array with safe class instances" do
|
76
|
+
let(:value){ (safe_representors.values + special_values).flatten }
|
77
|
+
subject{ TypeSystem::Ruby::parse_literal(TypeSystem::Ruby::to_literal(value)) }
|
78
|
+
it{ should == value }
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "When called on a hash with safe class instances" do
|
82
|
+
let(:value){ safe_representors }
|
83
|
+
subject{ TypeSystem::Ruby::parse_literal(TypeSystem::Ruby::to_literal(value)) }
|
84
|
+
it{ should == value }
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
##################################################################################
|
89
|
+
### User defined objects
|
90
|
+
##################################################################################
|
91
|
+
|
92
|
+
class TypeSystem::Ruby::Foo
|
93
|
+
attr_accessor :id
|
94
|
+
def initialize(id = 1); @id = id; end
|
95
|
+
def ==(other); other.kind_of?(TypeSystem::Ruby::Foo) and other.id == id; end
|
96
|
+
def inspect
|
97
|
+
"TypeSystem::Ruby::Foo.new(#{id.inspect})"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
non_failing_fallbacks = [:inspect, :marshal]
|
102
|
+
non_failing_fallbacks.each do |fallback|
|
103
|
+
describe "When called on a user-defined object with a #{fallback.inspect} fallback option" do
|
104
|
+
let(:value){ TypeSystem::Ruby::Foo.new(10) }
|
105
|
+
subject{ TypeSystem::Ruby::parse_literal(TypeSystem::Ruby::to_literal(value, :fallback => fallback)) }
|
106
|
+
it{ should == value }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'When called on a user-defined object with a :fail fallback option' do
|
111
|
+
let(:value){ TypeSystem::Ruby::Foo.new(10) }
|
112
|
+
subject{ Kernel::lambda{ TypeSystem::Ruby::to_literal(value, :fallback => :fail) } }
|
113
|
+
it{ should raise_error(TypeSystem::NoSuchLiteralError) }
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../../../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
|
4
|
+
describe "TypeSystem::Ruby#type_of" do
|
5
|
+
|
6
|
+
describe "when called on a String value" do
|
7
|
+
subject{ TypeSystem::Ruby.type_of("string") }
|
8
|
+
it{ should == String }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when called on a Fixnum value" do
|
12
|
+
subject{ TypeSystem::Ruby.type_of(10) }
|
13
|
+
it{ should == Fixnum }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sbyc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 3
|
10
|
+
version: 0.1.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bernard Lambeau
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-07-19 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -51,6 +51,10 @@ files:
|
|
51
51
|
- lib/sbyc/codetree/rewriting/match.rb
|
52
52
|
- lib/sbyc/codetree/rewriting.rb
|
53
53
|
- lib/sbyc/codetree.rb
|
54
|
+
- lib/sbyc/type_system/contract.rb
|
55
|
+
- lib/sbyc/type_system/errors.rb
|
56
|
+
- lib/sbyc/type_system/ruby.rb
|
57
|
+
- lib/sbyc/type_system.rb
|
54
58
|
- lib/sbyc.rb
|
55
59
|
- test/spec/documentation/codetree/production.spec
|
56
60
|
- test/spec/documentation/readme/assumptions.spec
|
@@ -60,6 +64,7 @@ files:
|
|
60
64
|
- test/spec/documentation/readme/semantics.spec
|
61
65
|
- test/spec/documentation/readme/synopsis.spec
|
62
66
|
- test/spec/documentation/readme/syntax.spec
|
67
|
+
- test/spec/documentation/type_system/example.spec
|
63
68
|
- test/spec/spec_helper.rb
|
64
69
|
- test/spec/test_all.rb
|
65
70
|
- test/spec/unit/sbyc/codetree/ast_node/code_inject.spec
|
@@ -108,6 +113,10 @@ files:
|
|
108
113
|
- test/spec/unit/sbyc/codetree/rewriting/match/apply.spec
|
109
114
|
- test/spec/unit/sbyc/codetree/rewriting/match/coerce.spec
|
110
115
|
- test/spec/unit/sbyc/codetree/rewriting/match/matches.spec
|
116
|
+
- test/spec/unit/sbyc/type_system/ruby/coerce.spec
|
117
|
+
- test/spec/unit/sbyc/type_system/ruby/parse_literal.spec
|
118
|
+
- test/spec/unit/sbyc/type_system/ruby/to_literal.spec
|
119
|
+
- test/spec/unit/sbyc/type_system/ruby/type_of.spec
|
111
120
|
- README.textile
|
112
121
|
- LICENCE.textile
|
113
122
|
has_rdoc: true
|