sbyc 0.1.1 → 0.1.3
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.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
|