rubyless 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/lib/ruby_less.rb +4 -4
- data/lib/ruby_less/basic_types.rb +0 -1
- data/lib/ruby_less/info.rb +1 -1
- data/lib/ruby_less/processor.rb +9 -10
- data/lib/ruby_less/safe_class.rb +8 -16
- data/rubyless.gemspec +2 -2
- data/test/RubyLess_test.rb +14 -14
- data/test/mock/dummy_class.rb +9 -0
- metadata +3 -3
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.7.0 2010-09-13
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
* Warning: changed RubyLess.translate to use (helper, code) instead of (code, helper).
|
5
|
+
* Enable contextual method resolution by passing the receiver in method resolution.
|
6
|
+
* Enable translation starting with a TypedString: RubyLess.translate(typed_string, method).
|
7
|
+
|
1
8
|
== 0.6.0 2010-07-22
|
2
9
|
|
3
10
|
* Major enhancements
|
data/lib/ruby_less.rb
CHANGED
@@ -22,8 +22,8 @@ module RubyLess
|
|
22
22
|
SafeClass.safe_method_type_for(klass, signature)
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.translate(
|
26
|
-
RubyLessProcessor.translate(
|
25
|
+
def self.translate(receiver, string)
|
26
|
+
RubyLessProcessor.translate(receiver, string)
|
27
27
|
rescue Exception => err
|
28
28
|
if err.kind_of?(RubyLess::Error)
|
29
29
|
raise err
|
@@ -32,9 +32,9 @@ module RubyLess
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def self.translate_string(
|
35
|
+
def self.translate_string(receiver, string)
|
36
36
|
if string =~ /\#\{/
|
37
|
-
translate("%Q{#{string}}"
|
37
|
+
translate(receiver, "%Q{#{string}}")
|
38
38
|
else
|
39
39
|
TypedString.new(string.inspect, :class => String, :literal => string)
|
40
40
|
end
|
@@ -11,7 +11,6 @@ end
|
|
11
11
|
class StringDictionary
|
12
12
|
include RubyLess
|
13
13
|
safe_method ['[]', Symbol] => {:class => String, :nil => true}
|
14
|
-
disable_safe_read # ?
|
15
14
|
end
|
16
15
|
|
17
16
|
RubyLess::SafeClass.safe_literal_class Fixnum => Number, Float => Number, Symbol => Symbol, Regexp => Regexp
|
data/lib/ruby_less/info.rb
CHANGED
data/lib/ruby_less/processor.rb
CHANGED
@@ -9,9 +9,9 @@ module RubyLess
|
|
9
9
|
INFIX_OPERATOR = ['<=>', '==', '<', '>', '<=', '>=', '-', '+', '*', '/', '%']
|
10
10
|
PREFIX_OPERATOR = ['-@']
|
11
11
|
|
12
|
-
def self.translate(
|
12
|
+
def self.translate(receiver, string)
|
13
13
|
if sexp = RubyParser.new.parse(string)
|
14
|
-
self.new(
|
14
|
+
self.new(receiver).process(sexp)
|
15
15
|
elsif string.size == 0
|
16
16
|
''
|
17
17
|
else
|
@@ -85,17 +85,15 @@ module RubyLess
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def process_call(exp)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# receiver = t("(#{receiver})", receiver.klass) if
|
92
|
-
# Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
|
88
|
+
unless receiver = process(exp.shift)
|
89
|
+
receiver = @helper.kind_of?(TypedString) ? @helper : nil
|
90
|
+
end
|
93
91
|
|
94
92
|
method_call(receiver, exp)
|
95
93
|
end
|
96
94
|
|
97
95
|
def process_fcall(exp)
|
98
|
-
method_call(nil, exp)
|
96
|
+
method_call(@helper.kind_of?(TypedString) ? @helper : nil, exp)
|
99
97
|
end
|
100
98
|
|
101
99
|
def process_arglist(exp)
|
@@ -125,9 +123,10 @@ module RubyLess
|
|
125
123
|
t "[#{list * ','}]", res.opts.merge(:literal => nil)
|
126
124
|
end
|
127
125
|
|
126
|
+
# Is this used ?
|
128
127
|
def process_vcall(exp)
|
129
128
|
var_name = exp.shift
|
130
|
-
unless opts = get_method([var_name]
|
129
|
+
unless opts = get_method(nil, [var_name])
|
131
130
|
raise RubyLess::Error.new("Unknown variable or method '#{var_name}'.")
|
132
131
|
end
|
133
132
|
method = opts[:method]
|
@@ -328,7 +327,7 @@ module RubyLess
|
|
328
327
|
def get_method(receiver, signature)
|
329
328
|
klass = receiver ? receiver.klass : @helper
|
330
329
|
|
331
|
-
type = klass.respond_to?(:safe_method_type) ? klass.safe_method_type(signature) : SafeClass.safe_method_type_for(klass, signature)
|
330
|
+
type = klass.respond_to?(:safe_method_type) ? klass.safe_method_type(signature, receiver) : SafeClass.safe_method_type_for(klass, signature)
|
332
331
|
|
333
332
|
if type.nil?
|
334
333
|
# We try to match with the superclass of the arguments
|
data/lib/ruby_less/safe_class.rb
CHANGED
@@ -176,7 +176,7 @@ module RubyLess
|
|
176
176
|
end
|
177
177
|
|
178
178
|
# Return the type if the given signature corresponds to a safe method for the class.
|
179
|
-
def safe_method_type(signature)
|
179
|
+
def safe_method_type(signature, receiver = nil)
|
180
180
|
SafeClass.safe_method_type_for(self, signature)
|
181
181
|
end
|
182
182
|
|
@@ -184,43 +184,35 @@ module RubyLess
|
|
184
184
|
def safe_class?
|
185
185
|
true
|
186
186
|
end
|
187
|
-
|
188
|
-
# Use this if you want to disable 'safe_read'. This is useful if you provided
|
189
|
-
# a mock as return type signature.
|
190
|
-
def disable_safe_read
|
191
|
-
undef_method(:safe_read)
|
192
|
-
end
|
193
187
|
end # ClassMethods
|
194
188
|
|
195
189
|
def self.included(base)
|
196
190
|
base.extend ClassMethods
|
197
191
|
end # included
|
198
192
|
|
199
|
-
|
200
193
|
# Return the type if the given signature corresponds to a safe method for the object's class.
|
201
|
-
def safe_method_type(signature)
|
194
|
+
def safe_method_type(signature, receiver = nil)
|
202
195
|
if type = SafeClass.safe_method_type_for(self.class, signature)
|
203
196
|
type[:class].kind_of?(Symbol) ? self.send(type[:class], signature) : type
|
204
197
|
end
|
205
198
|
end
|
206
199
|
|
207
|
-
# Safe
|
208
|
-
#
|
209
|
-
|
210
|
-
|
211
|
-
return "'#{key}' not readable" unless type = self.class.safe_method_type([key])
|
200
|
+
# Safe dynamic method dispatching when the method is not known during compile time. Currently this
|
201
|
+
# only works for methods without arguments.
|
202
|
+
def safe_send(method)
|
203
|
+
return nil unless type = self.class.safe_method_type([method])
|
212
204
|
self.send(type[:method])
|
213
205
|
end
|
214
206
|
|
215
207
|
# Evaluate a RubyLess expression. This is just like 'eval' but with safe method checking and typing.
|
216
208
|
def safe_eval(code)
|
217
|
-
ruby = RubyLessProcessor.translate(
|
209
|
+
ruby = RubyLessProcessor.translate(self, code)
|
218
210
|
eval(ruby)
|
219
211
|
end
|
220
212
|
|
221
213
|
# Evaluate a RubyLess expression. This is just like 'eval' but with safe method checking and typing.
|
222
214
|
def safe_eval_string(code)
|
223
|
-
ruby = RubyLess.translate_string(
|
215
|
+
ruby = RubyLess.translate_string(self, code)
|
224
216
|
eval(ruby)
|
225
217
|
end
|
226
218
|
|
data/rubyless.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rubyless}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.7.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gaspard Bucher"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-09-14}
|
13
13
|
s.description = %q{RubyLess is an interpreter for "safe ruby". The idea is to transform some "unsafe" ruby code into safe, type checked ruby, eventually rewriting some variables or methods.}
|
14
14
|
s.email = %q{gaspard@teti.ch}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/RubyLess_test.rb
CHANGED
@@ -59,7 +59,7 @@ class RubyLessTest < Test::Unit::TestCase
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# Example to dynamically rewrite method calls during compilation
|
62
|
-
def safe_method_type(signature)
|
62
|
+
def safe_method_type(signature, receiver = nil)
|
63
63
|
unless res = super
|
64
64
|
if signature == ['prepend_test', Number]
|
65
65
|
res ={:class => Number, :prepend_args => RubyLess::TypedString.new('10', :class => Number), :method => 'add'}
|
@@ -120,14 +120,9 @@ class RubyLessTest < Test::Unit::TestCase
|
|
120
120
|
"[#{obj.name}] #{msg}"
|
121
121
|
end
|
122
122
|
|
123
|
-
def
|
124
|
-
assert_equal 10, Dummy.new.
|
125
|
-
assert_equal
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_disable_safe_read
|
129
|
-
assert Dummy.instance_methods.include?('safe_read')
|
130
|
-
assert !StringDictionary.instance_methods.include?('safe_read')
|
123
|
+
def test_safe_send
|
124
|
+
assert_equal 10, Dummy.new.safe_send('id')
|
125
|
+
assert_equal nil, Dummy.new.safe_send('rm')
|
131
126
|
end
|
132
127
|
|
133
128
|
def test_safe_method_type
|
@@ -136,6 +131,11 @@ class RubyLessTest < Test::Unit::TestCase
|
|
136
131
|
assert_equal type_should_be, type
|
137
132
|
end
|
138
133
|
|
134
|
+
def test_translate_with_typed_string
|
135
|
+
typed_string = RubyLess::TypedString.new('marsupilami', :class => SubDummy, :message => 'Hello')
|
136
|
+
assert_equal "marsupilami.says('Hello')", RubyLess.translate(typed_string, 'talk')
|
137
|
+
end
|
138
|
+
|
139
139
|
def yt_do_test(file, test, context = yt_get('context',file,test))
|
140
140
|
@@test_strings[file][test].keys.each do |key|
|
141
141
|
next if ['src', 'context', 'str'].include?(key)
|
@@ -148,9 +148,9 @@ class RubyLessTest < Test::Unit::TestCase
|
|
148
148
|
if source = yt_get('str', file, test)
|
149
149
|
case key
|
150
150
|
when 'tem'
|
151
|
-
source ? RubyLess.translate_string(
|
151
|
+
source ? RubyLess.translate_string(self, source) : yt_get('tem', file, test)
|
152
152
|
when 'res'
|
153
|
-
eval(source ? RubyLess.translate_string(
|
153
|
+
eval(source ? RubyLess.translate_string(self, source) : yt_get('tem', file, test)).to_s
|
154
154
|
when 'sxp'
|
155
155
|
RubyParser.new.parse(source).inspect
|
156
156
|
else
|
@@ -159,10 +159,10 @@ class RubyLessTest < Test::Unit::TestCase
|
|
159
159
|
elsif source = yt_get('src', file, test)
|
160
160
|
case key
|
161
161
|
when 'tem'
|
162
|
-
source ? RubyLess.translate(
|
162
|
+
source ? RubyLess.translate(self, source) : yt_get('tem', file, test)
|
163
163
|
when 'res'
|
164
|
-
res = RubyLess.translate(
|
165
|
-
eval(source ? RubyLess.translate(
|
164
|
+
res = RubyLess.translate(self, source)
|
165
|
+
eval(source ? RubyLess.translate(self, source) : yt_get('tem', file, test)).to_s
|
166
166
|
when 'sxp'
|
167
167
|
RubyParser.new.parse(source).inspect
|
168
168
|
else
|
data/test/mock/dummy_class.rb
CHANGED
@@ -44,8 +44,17 @@ class Dummy < RubyLess::ActiveRecordMock
|
|
44
44
|
}
|
45
45
|
end
|
46
46
|
# Mock Property ================= ]
|
47
|
+
|
47
48
|
safe_property :dog_name, :dog_age
|
48
49
|
|
50
|
+
def self.safe_method_type(signature, receiver = nil)
|
51
|
+
if signature == ['talk']
|
52
|
+
{:class => String, :method => "says('#{receiver.opts[:message]}')"}
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
49
58
|
def width(opts = {})
|
50
59
|
return 'nice!' if opts['nice']
|
51
60
|
"mode: #{(opts[:mode] || 'none')}, type: #{(opts[:type] || 'none')}"
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 7
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.7.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Gaspard Bucher
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-09-14 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|