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 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(string, helper)
26
- RubyLessProcessor.translate(string, helper)
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(string, helper)
35
+ def self.translate_string(receiver, string)
36
36
  if string =~ /\#\{/
37
- translate("%Q{#{string}}", helper)
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
@@ -1,3 +1,3 @@
1
1
  module RubyLess
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -9,9 +9,9 @@ module RubyLess
9
9
  INFIX_OPERATOR = ['<=>', '==', '<', '>', '<=', '>=', '-', '+', '*', '/', '%']
10
10
  PREFIX_OPERATOR = ['-@']
11
11
 
12
- def self.translate(string, helper)
12
+ def self.translate(receiver, string)
13
13
  if sexp = RubyParser.new.parse(string)
14
- self.new(helper).process(sexp)
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
- receiver_node_type = exp.first.nil? ? nil : exp.first.first
89
- receiver = process exp.shift
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], @helper, false)
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
@@ -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 attribute reader used when 'safe_readable?' could not be called because the class
208
- # is not known during compile time.
209
- # FIXME: Is this used anymore ?
210
- def safe_read(key)
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(code, self)
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(code, self)
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.6.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-07-22}
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 = [
@@ -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 test_safe_read
124
- assert_equal 10, Dummy.new.safe_read('id')
125
- assert_equal "'rm' not readable", Dummy.new.safe_read('rm')
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(source, self) : yt_get('tem', file, test)
151
+ source ? RubyLess.translate_string(self, source) : yt_get('tem', file, test)
152
152
  when 'res'
153
- eval(source ? RubyLess.translate_string(source, self) : yt_get('tem', file, test)).to_s
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(source, self) : yt_get('tem', file, test)
162
+ source ? RubyLess.translate(self, source) : yt_get('tem', file, test)
163
163
  when 'res'
164
- res = RubyLess.translate(source, self)
165
- eval(source ? RubyLess.translate(source, self) : yt_get('tem', file, test)).to_s
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
@@ -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
- - 6
7
+ - 7
8
8
  - 0
9
- version: 0.6.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-07-22 00:00:00 +02:00
17
+ date: 2010-09-14 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency