rubyless 0.6.0 → 0.7.0
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/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
|