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 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