typisch 0.1.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.md +55 -0
- data/lib/typisch/boolean.rb +13 -0
- data/lib/typisch/constructor.rb +112 -0
- data/lib/typisch/datetime.rb +41 -0
- data/lib/typisch/dsl.rb +242 -0
- data/lib/typisch/errors.rb +11 -0
- data/lib/typisch/meta.rb +57 -0
- data/lib/typisch/named_placeholder.rb +67 -0
- data/lib/typisch/null.rb +17 -0
- data/lib/typisch/numeric.rb +80 -0
- data/lib/typisch/object.rb +72 -0
- data/lib/typisch/poset_algorithms.rb +18 -0
- data/lib/typisch/registry.rb +146 -0
- data/lib/typisch/sequence.rb +107 -0
- data/lib/typisch/serialization.rb +80 -0
- data/lib/typisch/string.rb +69 -0
- data/lib/typisch/subtyping.rb +64 -0
- data/lib/typisch/tuple.rb +74 -0
- data/lib/typisch/type.rb +138 -0
- data/lib/typisch/type_checking.rb +12 -0
- data/lib/typisch/typed.rb +133 -0
- data/lib/typisch/union.rb +75 -0
- data/lib/typisch/version.rb +3 -0
- data/lib/typisch.rb +34 -0
- metadata +166 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
class Typisch::Type
|
2
|
+
class Tuple < Constructor
|
3
|
+
class << self
|
4
|
+
def top_type(overall_top)
|
5
|
+
new()
|
6
|
+
end
|
7
|
+
|
8
|
+
def check_subtype(x, y, &recursively_check_subtype)
|
9
|
+
if x.length >= y.length
|
10
|
+
(0...y.length).all? {|i| recursively_check_subtype[x[i], y[i]]}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# This l.u.b. isn't as tight as it could be;
|
15
|
+
# (Int, Int) union (Bool, Bool) is a strict subset of
|
16
|
+
# (Int union Bool, Int union Bool), see eg (1, true).
|
17
|
+
#
|
18
|
+
# It makes life simpler to do it this way though;
|
19
|
+
# if you want to keep the distinction, try using
|
20
|
+
# Object types with different type tags.
|
21
|
+
def least_upper_bounds_for_union(*tuples)
|
22
|
+
min_length = tuples.map(&:length).min
|
23
|
+
unions = Array.new(min_length) do |i|
|
24
|
+
Type::Union.union(*tuples.map {|t| t[i]})
|
25
|
+
end
|
26
|
+
[new(*unions)]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(*types)
|
32
|
+
@types = types
|
33
|
+
end
|
34
|
+
|
35
|
+
# For now we're only allowing Array as a tuple.
|
36
|
+
# We could allow any Enumerable, say, but a tuple is really not supposed to be
|
37
|
+
# in any way a lazy data structure, it's something of fixed (usually short) length.
|
38
|
+
def check_type(instance, &recursively_check_type)
|
39
|
+
::Array === instance &&
|
40
|
+
instance.length == @types.length &&
|
41
|
+
@types.zip(instance).all?(&recursively_check_type)
|
42
|
+
end
|
43
|
+
|
44
|
+
def shallow_check_type(instance)
|
45
|
+
::Array === instance && instance.length == @types.length
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
attr_reader :types
|
50
|
+
alias :subexpression_types :types
|
51
|
+
|
52
|
+
def length
|
53
|
+
@types.length
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](n)
|
57
|
+
@types[n]
|
58
|
+
end
|
59
|
+
|
60
|
+
def tag
|
61
|
+
"Tuple"
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_string(depth, indent)
|
65
|
+
next_indent = "#{indent} "
|
66
|
+
types = @types.map {|t| t.to_s(depth+1, next_indent)}
|
67
|
+
"tuple(\n#{next_indent}#{types.join(",\n#{next_indent}")}\n#{indent})"
|
68
|
+
end
|
69
|
+
|
70
|
+
def canonicalize!
|
71
|
+
@types.map!(&:target)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/typisch/type.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# Base class for types, with some convenience methods.
|
2
|
+
#
|
3
|
+
# Note: since most of the algorithms on types (subtyping, union, intersection, ...)
|
4
|
+
# operate on pairs of types, we don't use methods on the actual type subclasses very much,
|
5
|
+
# since polymorphic dispatch on just one of the pair of types isn't much use in terms
|
6
|
+
# of extensibility.
|
7
|
+
#
|
8
|
+
# Instead the actual Type classes themselves are kept fairly lightweight, with the algorithms
|
9
|
+
# implemented separately in class methods.
|
10
|
+
class Typisch::Type
|
11
|
+
def <=(other)
|
12
|
+
Typisch::Type.subtype?(self, other)
|
13
|
+
end
|
14
|
+
|
15
|
+
def <(other)
|
16
|
+
self <= other && !(self >= other)
|
17
|
+
end
|
18
|
+
|
19
|
+
# N.B. equality is based on the subtyping algorithm. So, we cannot rely on
|
20
|
+
# using == on types inside any methods used in the subtyping algorithm.
|
21
|
+
# We must rely only on .equal? instance equality instead.
|
22
|
+
#
|
23
|
+
# Note that we have *not* overridden hash and eql? to be compatible with
|
24
|
+
# this subtyping-based equality, since it's not easy to find a unique
|
25
|
+
# representative of the equivalence class on which to base a hash function.
|
26
|
+
#
|
27
|
+
# This means that hash lookup of types will remain based on instance
|
28
|
+
# equality, and can safely be used inside the subtyping logic without
|
29
|
+
# busting the stack
|
30
|
+
def ==(other)
|
31
|
+
self <= other && self >= other
|
32
|
+
end
|
33
|
+
|
34
|
+
def >=(other)
|
35
|
+
other <= self
|
36
|
+
end
|
37
|
+
|
38
|
+
def >(other)
|
39
|
+
other < self
|
40
|
+
end
|
41
|
+
|
42
|
+
def <=>(other)
|
43
|
+
if other <= self
|
44
|
+
self <= other ? 0 : 1
|
45
|
+
else
|
46
|
+
self <= other ? -1 : nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
"#<Type: #{to_s}>"
|
53
|
+
end
|
54
|
+
|
55
|
+
# overridden on the Placeholder proxy wrapper, otherwise points at self
|
56
|
+
def target; self; end
|
57
|
+
|
58
|
+
def to_s(depth=0, indent='')
|
59
|
+
return @name.inspect if depth > 0 && @name
|
60
|
+
return "..." if depth > 3 # MAX_DEPTH
|
61
|
+
to_string(depth, indent)
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_string(depth, indent)
|
65
|
+
raise NotImplementedError
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :name
|
69
|
+
def name=(name)
|
70
|
+
raise "name already set" if @name
|
71
|
+
@name = name
|
72
|
+
end
|
73
|
+
private :name=
|
74
|
+
|
75
|
+
# types may be annotated with a hash of arbitrary stuff.
|
76
|
+
# could use this to document them, or to add instructions for
|
77
|
+
# other tools which do type-directed metaprogramming.
|
78
|
+
|
79
|
+
def annotations
|
80
|
+
@annotations ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def annotations=(annotations)
|
84
|
+
@annotations = annotations
|
85
|
+
end
|
86
|
+
|
87
|
+
# For convenience. Type::Constructor will implement this as [self], whereas
|
88
|
+
# Type::Union will implement it as its full list of alternative constructor types.
|
89
|
+
def alternative_types
|
90
|
+
raise NotImplementedError
|
91
|
+
end
|
92
|
+
|
93
|
+
# should return a list of any subexpressions which are themselves types.
|
94
|
+
# used by any generic type-graph-traversing logic.
|
95
|
+
def subexpression_types
|
96
|
+
[]
|
97
|
+
end
|
98
|
+
|
99
|
+
# should update any references to subexpression types to point at their true
|
100
|
+
# target, eliminating any NamedPlaceholder wrappers.
|
101
|
+
def canonicalize!
|
102
|
+
end
|
103
|
+
|
104
|
+
# Does this type make any use of recursion / is it an 'infinite' type?
|
105
|
+
def recursive?(found_so_far={})
|
106
|
+
found_so_far[self] or begin
|
107
|
+
found_so_far[self] = true
|
108
|
+
result = subexpression_types.any? {|t| t.recursive?(found_so_far)}
|
109
|
+
# subexpression_types.each {|t| raise t.inspect if t.recursive?(found_so_far)}
|
110
|
+
found_so_far.delete(self)
|
111
|
+
result
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# should check the type of this instance, but only 'one level deep', ie
|
116
|
+
# typically just check its type tag without recursively type-checking
|
117
|
+
# any child objects.
|
118
|
+
def shallow_check_type(instance)
|
119
|
+
raise NotImplementedError
|
120
|
+
end
|
121
|
+
|
122
|
+
# returns a version of this type which excludes null.
|
123
|
+
# generally will be self, except when a union type which includes null.
|
124
|
+
def excluding_null
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# Inidividual type subclasses must implement this. If they need to
|
131
|
+
# perform some recursive typecheck, eg on child objects of the object
|
132
|
+
# they're validating, they should call the supplied recursively_check_type
|
133
|
+
# block to do so, rather than calling === directly.
|
134
|
+
def check_type(instance, &recursively_check_type)
|
135
|
+
raise NotImplementedError
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Typisch::Type
|
2
|
+
|
3
|
+
# This uses essentially the same corecursive algorithm used for subtyping.
|
4
|
+
# Just this time we're comparing with a possible instance rather than a possible
|
5
|
+
# subtype.
|
6
|
+
def ===(instance, already_checked={})
|
7
|
+
return true if already_checked[[self, instance]]
|
8
|
+
already_checked[[self, instance]] = true
|
9
|
+
check_type(instance) {|u,v| u.===(v, already_checked)}
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Typisch
|
2
|
+
|
3
|
+
# A module which classes or modules can be extended with in order
|
4
|
+
# to help register an object type for that class or module, associate
|
5
|
+
# it with the class, and auto-define attributes on the class for the
|
6
|
+
# properties of its type.
|
7
|
+
#
|
8
|
+
# To be used like so:
|
9
|
+
#
|
10
|
+
# class Foo
|
11
|
+
# include Typisch::Typed
|
12
|
+
# register_type do
|
13
|
+
# property :foo, :bar
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
module Typed
|
18
|
+
def self.included(klass)
|
19
|
+
super
|
20
|
+
klass.send(:extend, ClassMethods)
|
21
|
+
end
|
22
|
+
|
23
|
+
def type
|
24
|
+
self.class.type
|
25
|
+
end
|
26
|
+
|
27
|
+
def type_check(full_check=false)
|
28
|
+
if full_check
|
29
|
+
self.class.type === self or raise TypeError, "failed to type-check"
|
30
|
+
else
|
31
|
+
self.class.type.property_names.each {|a| type_check_property(a, false)}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def type_check_property(name, full_check=false)
|
36
|
+
type = self.class.type_of(name) or raise NameError, "no typed property #{name} in #{self.class}"
|
37
|
+
value = send(name)
|
38
|
+
if full_check
|
39
|
+
type === send(value)
|
40
|
+
else
|
41
|
+
type.shallow_check_type(value)
|
42
|
+
end or raise TypeError, "property #{name} was expected to be of type #{type}, got instance of #{value.class}"
|
43
|
+
end
|
44
|
+
|
45
|
+
module ClassMethods
|
46
|
+
def type
|
47
|
+
@type || raise("Forgot to register_type for Typisch::Typed class")
|
48
|
+
end
|
49
|
+
|
50
|
+
def type_of(property_name)
|
51
|
+
type[property_name]
|
52
|
+
end
|
53
|
+
|
54
|
+
def version_types
|
55
|
+
@version_types ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def versions
|
59
|
+
version_types.keys
|
60
|
+
end
|
61
|
+
|
62
|
+
def version_type(key)
|
63
|
+
version_types[key]
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def register_type(in_registry = Typisch.global_registry, derive_from_type=nil, &block)
|
68
|
+
raise "Type already registered for #{self}" if @type
|
69
|
+
|
70
|
+
# a pox on instance_eval's scoping rules :(
|
71
|
+
callback = method(:type_available); klass = self; type = nil
|
72
|
+
in_registry.register do
|
73
|
+
type = _object(klass, {}, derive_from_type, &block)
|
74
|
+
klass.send(:instance_variable_set, :@type, type)
|
75
|
+
in_registry.register_type(:"#{klass}", type, &callback)
|
76
|
+
in_registry.register_type_for_class(klass, type)
|
77
|
+
end
|
78
|
+
type
|
79
|
+
end
|
80
|
+
|
81
|
+
def register_version_type(version, in_registry = Typisch.global_registry, &block)
|
82
|
+
raise "should register_type before register_version_type" unless @type
|
83
|
+
|
84
|
+
callback = method(:type_available); klass = self; type = nil
|
85
|
+
derive_from_type = @type
|
86
|
+
in_registry.register do
|
87
|
+
type = _object(klass, {}, derive_from_type, &block)
|
88
|
+
klass.version_types[version] = type
|
89
|
+
in_registry.register_type(:"#{klass}__#{version}", type, &callback)
|
90
|
+
in_registry.register_type_for_class(klass, type)
|
91
|
+
end
|
92
|
+
type
|
93
|
+
end
|
94
|
+
|
95
|
+
# Called once the type which you registered is available in a fully canonicalized form
|
96
|
+
# (so eg any forward declarations to types defined in other still-to-be-required classes,
|
97
|
+
# will have been resolved at this point).
|
98
|
+
#
|
99
|
+
# By default declares an attr_accessor for each property, and aliases it with a ? on the
|
100
|
+
# end if it's a boolean property. Override if you want to do something different.
|
101
|
+
def type_available
|
102
|
+
type.property_names_to_types.map do |name, type|
|
103
|
+
attr_accessor(name) unless method_defined?(name)
|
104
|
+
alias_method(:"#{name}?", name) if type.excluding_null.is_a?(Type::Boolean)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def register_subtype(in_registry = Typisch.global_registry, &block)
|
109
|
+
raise "Type already registered for #{self}" if @type
|
110
|
+
raise "register_subtype: superclass was not typed" unless superclass < Typed
|
111
|
+
supertype = superclass.send(:type)
|
112
|
+
callback = method(:type_available); klass = self; type = nil
|
113
|
+
in_registry.register do
|
114
|
+
type = derived_from(supertype, klass) do
|
115
|
+
instance_eval(&block)
|
116
|
+
derive_all_properties
|
117
|
+
end
|
118
|
+
klass.send(:instance_variable_set, :@type, type)
|
119
|
+
in_registry.register_type(:"#{klass}", type, &callback)
|
120
|
+
in_registry.register_type_for_class(klass, type)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Typisch::TypedStruct
|
127
|
+
include Typisch::Typed
|
128
|
+
|
129
|
+
def initialize(properties={})
|
130
|
+
properties.each {|p,v| instance_variable_set("@#{p}", v)}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Typisch
|
2
|
+
class Type::Union < Type
|
3
|
+
attr_reader :alternative_types
|
4
|
+
alias :subexpression_types :alternative_types
|
5
|
+
|
6
|
+
def initialize(*alternative_types)
|
7
|
+
@alternative_types = alternative_types
|
8
|
+
end
|
9
|
+
|
10
|
+
def check_type(instance, &recursively_check_type)
|
11
|
+
type = @alternative_types.find {|t| t.shallow_check_type(instance)}
|
12
|
+
type && recursively_check_type[type, instance]
|
13
|
+
end
|
14
|
+
|
15
|
+
def shallow_check_type(instance)
|
16
|
+
@alternative_types.any? {|t| t.shallow_check_type(instance)}
|
17
|
+
end
|
18
|
+
|
19
|
+
def excluding_null
|
20
|
+
types = @alternative_types.reject {|t| Type::Null === t}
|
21
|
+
types.length == 1 ? types.first : Type::Union.new(*types)
|
22
|
+
end
|
23
|
+
|
24
|
+
def canonicalize!
|
25
|
+
@alternative_types.map!(&:target)
|
26
|
+
|
27
|
+
unless @alternative_types.all? {|t| Type::Constructor === t} &&
|
28
|
+
(tags = @alternative_types.map(&:tag)).uniq.length == tags.length
|
29
|
+
raise TypeDeclarationError, "the types in a Union must be constructor types with different tags"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_string(depth, indent)
|
34
|
+
next_indent = "#{indent} "
|
35
|
+
types = @alternative_types.map {|t| t.to_s(depth+1, next_indent)}
|
36
|
+
"union(\n#{next_indent}#{types.join(",\n#{next_indent}")}\n#{indent})"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# The Nothing (or 'bottom') type is just an empty Union:
|
42
|
+
class Type::Nothing < Type::Union
|
43
|
+
def initialize
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s(*); @name.inspect; end
|
48
|
+
|
49
|
+
INSTANCE = new
|
50
|
+
class << self; private :new; end
|
51
|
+
Registry.register_global_type(:nothing, INSTANCE)
|
52
|
+
end
|
53
|
+
|
54
|
+
# The Any (or 'top') type is just a union of all the top types of the various Type::Constructor
|
55
|
+
# subclasses:
|
56
|
+
class Type::Any < Type::Union
|
57
|
+
def initialize
|
58
|
+
super(*Constructor::CONSTRUCTOR_TYPE_SUBCLASSES.map {|klass| klass.top_type(self)})
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s(*); @name.inspect; end
|
62
|
+
|
63
|
+
def canonicalize!; end
|
64
|
+
|
65
|
+
# skip some unnecessary work checking different alternatives, since we know everything
|
66
|
+
# works here:
|
67
|
+
def check_type(instance)
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
INSTANCE = new
|
72
|
+
class << self; private :new; end
|
73
|
+
Registry.register_global_type(:any, INSTANCE)
|
74
|
+
end
|
75
|
+
end
|
data/lib/typisch.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Typisch
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
require 'typisch/type'
|
7
|
+
require 'typisch/constructor'
|
8
|
+
|
9
|
+
require 'typisch/dsl'
|
10
|
+
require 'typisch/registry'
|
11
|
+
require 'typisch/named_placeholder'
|
12
|
+
|
13
|
+
require 'typisch/boolean'
|
14
|
+
require 'typisch/null'
|
15
|
+
require 'typisch/numeric'
|
16
|
+
require 'typisch/string'
|
17
|
+
require 'typisch/datetime'
|
18
|
+
|
19
|
+
require 'typisch/tuple'
|
20
|
+
require 'typisch/object'
|
21
|
+
|
22
|
+
require 'typisch/sequence'
|
23
|
+
require 'typisch/constructor'
|
24
|
+
|
25
|
+
require 'typisch/union'
|
26
|
+
|
27
|
+
require 'typisch/subtyping'
|
28
|
+
require 'typisch/type_checking'
|
29
|
+
require 'typisch/poset_algorithms'
|
30
|
+
require 'typisch/errors'
|
31
|
+
|
32
|
+
require 'typisch/meta'
|
33
|
+
|
34
|
+
require 'typisch/typed'
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: typisch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 5
|
10
|
+
version: 0.1.5
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Matthew Willson
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-14 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: autotest
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: minitest
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 11
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
version: 2.1.0
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: mocha
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 35
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
- 9
|
63
|
+
- 12
|
64
|
+
version: 0.9.12
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rcov
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 41
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
- 9
|
79
|
+
- 9
|
80
|
+
version: 0.9.9
|
81
|
+
type: :development
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
type: :development
|
96
|
+
version_requirements: *id005
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- matthew@playlouder.com
|
100
|
+
executables: []
|
101
|
+
|
102
|
+
extensions: []
|
103
|
+
|
104
|
+
extra_rdoc_files: []
|
105
|
+
|
106
|
+
files:
|
107
|
+
- lib/typisch/boolean.rb
|
108
|
+
- lib/typisch/constructor.rb
|
109
|
+
- lib/typisch/datetime.rb
|
110
|
+
- lib/typisch/dsl.rb
|
111
|
+
- lib/typisch/errors.rb
|
112
|
+
- lib/typisch/meta.rb
|
113
|
+
- lib/typisch/named_placeholder.rb
|
114
|
+
- lib/typisch/null.rb
|
115
|
+
- lib/typisch/numeric.rb
|
116
|
+
- lib/typisch/object.rb
|
117
|
+
- lib/typisch/poset_algorithms.rb
|
118
|
+
- lib/typisch/registry.rb
|
119
|
+
- lib/typisch/sequence.rb
|
120
|
+
- lib/typisch/serialization.rb
|
121
|
+
- lib/typisch/string.rb
|
122
|
+
- lib/typisch/subtyping.rb
|
123
|
+
- lib/typisch/tuple.rb
|
124
|
+
- lib/typisch/type.rb
|
125
|
+
- lib/typisch/type_checking.rb
|
126
|
+
- lib/typisch/typed.rb
|
127
|
+
- lib/typisch/union.rb
|
128
|
+
- lib/typisch/version.rb
|
129
|
+
- lib/typisch.rb
|
130
|
+
- README.md
|
131
|
+
has_rdoc: true
|
132
|
+
homepage:
|
133
|
+
licenses: []
|
134
|
+
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
hash: 3
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
version: "0"
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
hash: 3
|
155
|
+
segments:
|
156
|
+
- 0
|
157
|
+
version: "0"
|
158
|
+
requirements: []
|
159
|
+
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 1.3.7
|
162
|
+
signing_key:
|
163
|
+
specification_version: 3
|
164
|
+
summary: A schema language / type system / validation framework, for semi-structured data and for data in dynamic languages
|
165
|
+
test_files: []
|
166
|
+
|