typestrict 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,26 @@
1
+ === 0.0.4 / 2010-08-03
2
+
3
+ * 1 major enhancement
4
+
5
+ * Renamed package to typestrict
6
+
7
+
8
+ === 0.0.3 / 2010-08-03
9
+
10
+ * 1 major enhancement
11
+
12
+ * Introduced TypeError and verbose output - now displays list of errors caught and raises single Strict::TypeError
13
+
14
+ === 0.0.2 / 2010-08-03
15
+
16
+ * 1 major enhancement
17
+
18
+ * Gemify
19
+
20
+
21
+ === 0.0.1 / 2010-08-02
22
+
23
+ * 1 major enhancement
24
+
25
+ * Birthday!
26
+
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README
4
+ README.txt
5
+ Rakefile
6
+ bin/typestrict
7
+ lib/typestrict.rb
8
+ test/test_strict.rb
data/README ADDED
@@ -0,0 +1,89 @@
1
+ strict is a rudimentary static typesystem for ruby objects - it includes easy validation of individual ruby objects and Hash sets.
2
+
3
+ For an example of validation:
4
+
5
+ require 'typestrict'
6
+
7
+ class Rectangle
8
+ include Strict
9
+
10
+ def initialize(p)
11
+
12
+ validate_map!({
13
+ :width => :natural_number,
14
+ :height => :natural_number,
15
+ :float => :boolean
16
+ }, p)
17
+
18
+ @width = p[:width]
19
+ @height = p[:height]
20
+ @float = p[:float]
21
+ end
22
+
23
+ def set_dimensions(dimensions)
24
+ validate_map!({
25
+ :width => :natural_number,
26
+ :height => :natural_number
27
+ }, dimensions) #checks for the presence + validity of all declared parameters
28
+
29
+ @height = dimensions[:height]
30
+ @width = dimensions[:width]
31
+ end
32
+
33
+ def scale_height(scale_coefficent)
34
+ enforce!(:float, scale_coefficent)
35
+ return scale_coefficent*@height #alays valid
36
+ end
37
+ end
38
+
39
+ Strict defines a number of 'super-types', currently which are:
40
+ :natural_number
41
+ :float
42
+ :boolean
43
+ :string_array
44
+ :numeric_array
45
+ :float_array
46
+ :integer_array
47
+ :hex_color_string
48
+
49
+ Strict simply implements an extendable static type-checker over dynamic ruby objects. For an example of validation with troublesome datasets:
50
+
51
+ #enforce!(:string_array, ["one", "two", 3, "four"])
52
+ #./strict.rb:3:in `enforce_primitive!': 3 must be of type String (RuntimeError)
53
+
54
+ type_matrix = {
55
+ :fruit => [:apple, :orange, :banana],
56
+ :height => :natural_number,
57
+ :width => :float,
58
+ :broken => :boolean
59
+ }
60
+
61
+ invalid_data = {
62
+ :fruit => :pear,
63
+ :height => -1,
64
+ :width => 100,
65
+ :broken => 1}
66
+
67
+
68
+ validate_map!(type_matrix, invalid_data)
69
+ #./strict.rb:27:in `enforce_weak_primitives!': 1 must be of one of the types of [TrueClass, FalseClass] (RuntimeError)
70
+ #./strict.rb:3:in `enforce_primitive!': 10 must be of type Float (RuntimeError)
71
+ #./strict.rb:38:in `enforce!': pear should take on a value within [:apple, :orange, :banana] (RuntimeError)
72
+ #./strict.rb:53:in `enforce!': -1 must be > 0 (RuntimeError)
73
+
74
+ A valid dataset for this type_matrix would be:
75
+
76
+ valid_data = {
77
+ :fruit => :apple,
78
+ :height => 200,
79
+ :width => 100.011,
80
+ :broken => true
81
+ }
82
+
83
+ validate_map!(type_matrix, invalid_data) # => all checks pass
84
+
85
+ TODO
86
+ ----
87
+ Implement generic handler for super-types
88
+ Performance analysis
89
+ Implement low-level?
data/README.txt ADDED
@@ -0,0 +1,72 @@
1
+ = strict
2
+
3
+ * http://www.raeez.com/strict
4
+
5
+ == DESCRIPTION:
6
+
7
+ Strict implements a traditional static type-system over dynamic ruby objects. Strict is designed to help debug simple type errors.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ Implements a Static typesystem over Object
12
+ Support for ruby Primitives (strict subsets, weak subsets etc.)
13
+ Support for user-defined types
14
+
15
+ == SYNOPSIS:
16
+
17
+ def add_nums(a, b)
18
+ enforce!(:numeric, a)
19
+ enforce!(:numeric, b)
20
+ return a + b
21
+ end
22
+
23
+ def launch_rocket(params)
24
+ enforce_map!({
25
+ :destination => [:moon, :mars, :saturn, :jupiter, :iss],
26
+ :rocket_type => [:appollo, :space_x],
27
+ :fuel_litres => :numeric,
28
+ :mission_id => :string}, params)
29
+ ... #launch the rocket
30
+ end
31
+
32
+ == REQUIREMENTS:
33
+
34
+ none
35
+
36
+ == INSTALL:
37
+
38
+ sudo gem install strict
39
+
40
+ == DEVELOPERS:
41
+
42
+ After checking out the source, run:
43
+
44
+ $ rake
45
+
46
+ This task will install any missing dependencies, run the tests/specs,
47
+ and generate the RDoc.
48
+
49
+ == LICENSE:
50
+
51
+ (The MIT License)
52
+
53
+ Copyright (c) 2010 FIX
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ 'Software'), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
69
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
70
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
71
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
72
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require 'lib/typestrict'
4
+
5
+ Hoe.spec 'Strict' do
6
+ self.name = 'typestrict'
7
+ self.version = Strict::VERSION
8
+ self.author = 'Raeez Lorgat'
9
+ self.description = 'Static typesystem for ruby'
10
+ self.email = 'raeez@mit.edu'
11
+ self.summary = 'Strict implements a static typesystem over dynamic ruby objects'
12
+ self.url = 'http://www.raeez.com/strict'
13
+ end
14
+
15
+ desc "Release and publish documentation"
16
+ task :repubdoc => [:release, :publish_docs]
data/bin/typestrict ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
data/lib/typestrict.rb ADDED
@@ -0,0 +1,159 @@
1
+ module Strict
2
+ VERSION = '0.0.4'
3
+
4
+ class TypeError < Exception
5
+ attr :errors
6
+ def initialize(error_list)
7
+ enforce!(:string_array, error_list, 'lib/strict')
8
+ @errors = error_list
9
+ end
10
+
11
+ def inspect
12
+ msg = "TypeError#{@errors.size > 1 ? "s" : ""} caught:\n"
13
+ @errors.each do |e|
14
+ msg += "#{e}\n"
15
+ end
16
+ return msg
17
+ end
18
+ end
19
+
20
+ @@errors = []
21
+ @@raise_exception = true
22
+
23
+ def setmode_raise!
24
+ @@errors = []
25
+ @@raise_exception = true
26
+ end
27
+
28
+ def setmode_catch!
29
+ @@errors = []
30
+ @@raise_exception = false
31
+ end
32
+
33
+ def catch_error error
34
+ @@errors << error
35
+ t = TypeError.new([error])
36
+ raise(t, t.inspect, caller) if @@raise_exception
37
+ end
38
+
39
+ def raise_hell!
40
+ t = TypeError.new(@@errors)
41
+ raise(t, t.inspect, caller) if @@errors.size > 0
42
+ end
43
+
44
+ def header(context, data)
45
+ "#{context}; #{data.class.inspect}::#{data.inspect}"
46
+ end
47
+
48
+ def enforce_primitive!(type, data, context="Value")
49
+ catch_error "#{header(context, data)} must be of type #{type}" unless (data.is_a? type and type.is_a? Class)
50
+ return data
51
+ end
52
+
53
+ def enforce_strict_primitives!(types, data, context="Value")
54
+ enforce_primitive!(Array, types, 'lib/strict')
55
+ types.each {|type| enforce_primitive!(Object, type, 'lib/strict')}
56
+ types.each do |type|
57
+ enforce_primitive!(type, data, context)
58
+ end
59
+ return data
60
+ end
61
+
62
+ def enforce_weak_primitives!(types, data, context="Value")
63
+ enforce_primitive!(Array, types, 'lib/strict')
64
+ types.each {|type| enforce_primitive!(Object, type, 'lib/strict')}
65
+
66
+ match_found = false
67
+ types.each do |type|
68
+ begin
69
+ s = @@errors.size
70
+ enforce_primitive!(type, data, context)
71
+ match_found = true unless s != @@errors.size
72
+ rescue
73
+ next
74
+ end
75
+ end
76
+ catch_error "#{header(context, data)} must be of one of the types of #{types.inspect}" unless match_found
77
+ return data
78
+ end
79
+
80
+ def enforce_non_nil!(obj, context="Value")
81
+ catch_error "#{context}: Object is nil!" if obj.nil?
82
+ return obj
83
+ end
84
+
85
+ def enforce!(supertype, data, context="Value") #write a more generic handler, for new types?
86
+ enforce_non_nil!(data, context)
87
+
88
+ if supertype.is_a? Array #enumeration of values
89
+ catch_error "#{header(context, data)} should take on a value within #{supertype.inspect}" unless supertype.include? data
90
+
91
+ else if supertype.is_a? Symbol #distinct type
92
+ case supertype
93
+ when :string
94
+ enforce_primitive!(String, data, context)
95
+ catch_error "#{header(context, data)} can't be empty string" unless (data.size > 0)
96
+
97
+ when :hex_color
98
+ enforce!(:string, data, context)
99
+ catch_error "#{header(context, data)} must be six characters long" unless (data.size == 6)
100
+ data.upcase.each_byte {|c| catch_error "#{header(context, data)} must contain only hexadecimal characters" unless ((48 <= c and c <= 57) or (65 <= c and c <= 70))}
101
+
102
+ when :natural_number
103
+ enforce_primitive!(Fixnum, data, context)
104
+ catch_error "#{header(context, data)} must be > 0" unless (data > 0)
105
+
106
+ when :integer
107
+ enforce_primitive!(Fixnum, data, context)
108
+
109
+ when :numeric
110
+ enforce_primitive!(Numeric, data, context)
111
+
112
+ when :boolean
113
+ enforce_weak_primitives!([TrueClass, FalseClass], data, context)
114
+
115
+ when :float
116
+ enforce_primitive!(Float, data, context)
117
+
118
+ when :string_array
119
+ enforce_primitive!(Array, data, context)
120
+ data.each {|item| enforce_primitive!(String, item, context)}
121
+
122
+ when :numeric_array
123
+ enforce_primitive!(Array, data, context)
124
+ data.each {|item| enforce_primitive!(Numeric, item, context)}
125
+
126
+ when :float_array
127
+ enforce_primitive!(Array, data, context)
128
+ data.each {|item| enforce_primitive!(Float, item, context)}
129
+
130
+ when :integer_array
131
+ enforce_primitive!(Array, data, context)
132
+ data.each {|item| enforce_primitive!(Fixnum, item, context)}
133
+
134
+ else
135
+ catch_error "undefined symbol-supertype encountered: #{supertype.inspect}"
136
+ end
137
+ end
138
+ end
139
+ return data
140
+ end
141
+
142
+ def enforce_map!(matrix, map)
143
+ enforce_primitive!(Hash, matrix, "lib/strict")
144
+ enforce_primitive!(Hash, map, "lib/strict")
145
+
146
+ setmode_catch!
147
+
148
+ matrix.each do |param, type|
149
+ if map.has_key? param
150
+ enforce!(type, map[param], "map[#{param.inspect}]")
151
+ else
152
+ catch_error "map: missing required param: #{param.inspect}"
153
+ end
154
+ end
155
+ raise_hell!
156
+ setmode_raise!
157
+ return map
158
+ end
159
+ end
@@ -0,0 +1,8 @@
1
+ require "test/unit"
2
+ require "typestrict"
3
+
4
+ class TestStrict < Test::Unit::TestCase
5
+ def test_sanity
6
+ puts "no tests implemented!"
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typestrict
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 4
10
+ version: 0.0.4
11
+ platform: ruby
12
+ authors:
13
+ - Raeez Lorgat
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-03 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rubyforge
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ - 0
33
+ - 4
34
+ version: 2.0.4
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: hoe
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 21
46
+ segments:
47
+ - 2
48
+ - 6
49
+ - 1
50
+ version: 2.6.1
51
+ type: :development
52
+ version_requirements: *id002
53
+ description: Static typesystem for ruby
54
+ email: raeez@mit.edu
55
+ executables:
56
+ - typestrict
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - History.txt
61
+ - Manifest.txt
62
+ - README.txt
63
+ files:
64
+ - History.txt
65
+ - Manifest.txt
66
+ - README
67
+ - README.txt
68
+ - Rakefile
69
+ - bin/typestrict
70
+ - lib/typestrict.rb
71
+ - test/test_strict.rb
72
+ has_rdoc: true
73
+ homepage: http://www.raeez.com/strict
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options:
78
+ - --main
79
+ - README.txt
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 3
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project: strict
103
+ rubygems_version: 1.3.7
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Strict implements a static typesystem over dynamic ruby objects
107
+ test_files:
108
+ - test/test_strict.rb