rubyless 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.8.3
2
+
3
+ * Major enhancements
4
+ * Better support for literal Arrays.
5
+ * Support for Hash methods and Hash literals.
6
+
7
+ * Minor enhancements
8
+ * Added some methods for basic types.
9
+ * Fixed a bug where evaluated string would be altered.
10
+ * Added support for true and false classes.
11
+
1
12
  == 0.8.2 2011-01-15
2
13
 
3
14
  * Minor enhancements
@@ -18,7 +18,9 @@ RubyLess::SafeClass.safe_method_for( Number,
18
18
  [:==, Number] => Boolean, [:< , Number] => Boolean, [:> , Number] => Boolean,
19
19
  [:<=, Number] => Boolean, [:>=, Number] => Boolean, [:- , Number] => Number,
20
20
  [:+ , Number] => Number, [:* , Number] => Number, [:/ , Number] => Number,
21
- [:% , Number] => Number, [:"-@"] => Number
21
+ [:% , Number] => Number, [:"-@"] => Number,
22
+ :to_f => Number,
23
+ :to_i => Number
22
24
  )
23
25
 
24
26
  RubyLess::SafeClass.safe_method_for( Time,
@@ -33,7 +35,9 @@ RubyLess::SafeClass.safe_method_for( String,
33
35
 
34
36
  RubyLess::SafeClass.safe_method_for( NilClass,
35
37
  [:==, String] => Boolean,
36
- [:==, Number] => Boolean
38
+ [:==, Number] => Boolean,
39
+ :to_f => Number,
40
+ :to_i => Number
37
41
  )
38
42
 
39
43
  RubyLess::SafeClass.safe_method_for( Array,
@@ -1,3 +1,3 @@
1
1
  module RubyLess
2
- VERSION = '0.8.2'
2
+ VERSION = '0.8.3'
3
3
  end
@@ -11,7 +11,11 @@ module RubyLess
11
11
 
12
12
  def self.translate(receiver, string)
13
13
  if sexp = RubyParser.new.parse(string)
14
- self.new(receiver).process(sexp)
14
+ res = self.new(receiver).process(sexp)
15
+ if res.klass.kind_of?(Hash)
16
+ res.opts[:class] = Hash
17
+ end
18
+ res
15
19
  elsif string.size == 0
16
20
  ''
17
21
  else
@@ -52,6 +56,14 @@ module RubyLess
52
56
  end
53
57
  end
54
58
 
59
+ def process_true(*args)
60
+ t 'true', {:class => Boolean, :literal => true}
61
+ end
62
+
63
+ def process_false(*args)
64
+ t 'false', {:class => Boolean, :literal => false}
65
+ end
66
+
55
67
  def process_and(exp)
56
68
  t "(#{process(exp.shift)} and #{process(exp.shift)})", Boolean
57
69
  end
@@ -118,7 +130,7 @@ module RubyLess
118
130
  list << res
119
131
  end
120
132
 
121
- res.opts[:class] = Array
133
+ res.opts[:class] = [content_class] # Array
122
134
  res.opts[:elem] = content_class
123
135
  t "[#{list * ','}]", res.opts.merge(:literal => nil)
124
136
  end
@@ -229,7 +241,18 @@ module RubyLess
229
241
  cond = []
230
242
  end
231
243
 
232
- opts = get_method(receiver, signature)
244
+ if receiver && receiver.klass.kind_of?(Hash)
245
+ # resolve now
246
+ if signature.first == '[]' && klass = receiver.klass[args.literal]
247
+ return receiver.hash[args.literal]
248
+ else
249
+ # safe_method_type on Hash... ?
250
+ receiver = TypedString.new(receiver, Hash)
251
+ opts = get_method(receiver, signature)
252
+ end
253
+ else
254
+ opts = get_method(receiver, signature)
255
+ end
233
256
 
234
257
  # method type can rewrite receiver
235
258
  if opts[:receiver]
@@ -354,11 +377,15 @@ module RubyLess
354
377
  def get_method(receiver, signature)
355
378
  klass = receiver ? receiver.klass : @helper
356
379
 
357
- type = klass.respond_to?(:safe_method_type) ? klass.safe_method_type(signature, receiver) : SafeClass.safe_method_type_for(klass, signature)
358
-
359
- if type.nil?
360
- # We try to match with the superclass of the arguments
380
+ if klass.respond_to?(:safe_method_type)
381
+ type = klass.safe_method_type(signature, receiver)
382
+ elsif klass.kind_of?(Array)
383
+ unless type = SafeClass.safe_method_type_for(Array, signature)
384
+ raise RubyLess::NoMethodError.new(receiver, "[#{klass}]", signature)
385
+ end
386
+ elsif type = SafeClass.safe_method_type_for(klass, signature)
361
387
  end
388
+
362
389
  raise RubyLess::NoMethodError.new(receiver, klass, signature) if !type || type[:class].kind_of?(Symbol) # we cannot send: no object.
363
390
 
364
391
  type[:class].kind_of?(Proc) ? type[:class].call(@helper, receiver ? receiver.klass : @helper, signature) : type
@@ -13,32 +13,35 @@ module RubyLess
13
13
  # Return method type (options) if the given signature is a safe method for the class.
14
14
  def self.safe_method_type_for(klass, signature)
15
15
  if klass.kind_of?(Array)
16
- return safe_method_type_for(Array, signature)
17
- end
18
-
19
- # Signature might be ['name', {:mode => String, :type => Number}].
20
- # build signature arguments
21
-
22
- # Replace all hashes in signature by Hash class and check for arguments
23
- signature_args = []
24
- signature = signature.map do |s|
25
- if s.kind_of?(Hash)
26
- signature_args << s
27
- Hash
28
- else
29
- signature_args << nil
30
- s
16
+ safe_method_type_for(Array, signature)
17
+ elsif klass.kind_of?(Hash)
18
+ nil # literal hash resolved in processor
19
+ klass = Hash
20
+ else
21
+ # Signature might be ['name', {:mode => String, :type => Number}].
22
+ # build signature arguments
23
+
24
+ # Replace all hashes in signature by Hash class and check for arguments
25
+ signature_args = []
26
+ signature = signature.map do |s|
27
+ if s.kind_of?(Hash)
28
+ signature_args << s
29
+ Hash
30
+ else
31
+ signature_args << nil
32
+ s
33
+ end
31
34
  end
32
- end
33
35
 
34
- # Find safe method in all ancestry
35
- klass.ancestors.each do |ancestor|
36
- # FIXME: find a way to optimize this search !
37
- if type = safe_method_with_hash_args(ancestor, signature, signature_args)
38
- return type
36
+ # Find safe method in all ancestry
37
+ klass.ancestors.each do |ancestor|
38
+ # FIXME: find a way to optimize this search !
39
+ if type = safe_method_with_hash_args(ancestor, signature, signature_args)
40
+ return type
41
+ end
39
42
  end
43
+ nil
40
44
  end
41
- nil
42
45
  end
43
46
 
44
47
  def self.literal_class_for(klass)
data/rubyless.gemspec CHANGED
@@ -1,78 +1,75 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rubyless}
8
- s.version = "0.8.2"
8
+ s.version = "0.8.3"
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{2011-01-15}
12
+ s.date = %q{2011-06-15}
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 = [
16
16
  "README.rdoc",
17
- "TODO"
17
+ "TODO"
18
18
  ]
19
19
  s.files = [
20
- ".gitignore",
21
- "History.txt",
22
- "README.rdoc",
23
- "Rakefile",
24
- "TODO",
25
- "lib/ruby_less.rb",
26
- "lib/ruby_less/basic_types.rb",
27
- "lib/ruby_less/error.rb",
28
- "lib/ruby_less/info.rb",
29
- "lib/ruby_less/no_method_error.rb",
30
- "lib/ruby_less/processor.rb",
31
- "lib/ruby_less/safe_class.rb",
32
- "lib/ruby_less/signature_hash.rb",
33
- "lib/ruby_less/syntax_error.rb",
34
- "lib/ruby_less/typed_method.rb",
35
- "lib/ruby_less/typed_string.rb",
36
- "lib/rubyless.rb",
37
- "rails/init.rb",
38
- "rubyless.gemspec",
39
- "test/RubyLess/active_record.yml",
40
- "test/RubyLess/basic.yml",
41
- "test/RubyLess/errors.yml",
42
- "test/RubyLess/hash.yml",
43
- "test/RubyLess/string.yml",
44
- "test/RubyLess/time.yml",
45
- "test/RubyLess_test.rb",
46
- "test/mock/active_record_mock.rb",
47
- "test/mock/dummy_class.rb",
48
- "test/mock/dummy_module.rb",
49
- "test/mock/property_column.rb",
50
- "test/safe_class_test.rb",
51
- "test/signature_hash_test.rb",
52
- "test/test_helper.rb",
53
- "test/typed_method_test.rb",
54
- "test/typed_string_test.rb"
20
+ "History.txt",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "TODO",
24
+ "lib/ruby_less.rb",
25
+ "lib/ruby_less/basic_types.rb",
26
+ "lib/ruby_less/error.rb",
27
+ "lib/ruby_less/info.rb",
28
+ "lib/ruby_less/no_method_error.rb",
29
+ "lib/ruby_less/processor.rb",
30
+ "lib/ruby_less/safe_class.rb",
31
+ "lib/ruby_less/signature_hash.rb",
32
+ "lib/ruby_less/syntax_error.rb",
33
+ "lib/ruby_less/typed_method.rb",
34
+ "lib/ruby_less/typed_string.rb",
35
+ "lib/rubyless.rb",
36
+ "rails/init.rb",
37
+ "rubyless.gemspec",
38
+ "test/RubyLess/active_record.yml",
39
+ "test/RubyLess/basic.yml",
40
+ "test/RubyLess/errors.yml",
41
+ "test/RubyLess/hash.yml",
42
+ "test/RubyLess/string.yml",
43
+ "test/RubyLess/time.yml",
44
+ "test/RubyLess_test.rb",
45
+ "test/mock/active_record_mock.rb",
46
+ "test/mock/dummy_class.rb",
47
+ "test/mock/dummy_module.rb",
48
+ "test/mock/property_column.rb",
49
+ "test/safe_class_test.rb",
50
+ "test/signature_hash_test.rb",
51
+ "test/test_helper.rb",
52
+ "test/typed_method_test.rb",
53
+ "test/typed_string_test.rb"
55
54
  ]
56
55
  s.homepage = %q{http://zenadmin.org/546}
57
- s.rdoc_options = ["--charset=UTF-8"]
58
56
  s.require_paths = ["lib"]
59
- s.rubygems_version = %q{1.3.7}
57
+ s.rubygems_version = %q{1.6.1}
60
58
  s.summary = %q{RubyLess is an interpreter for "safe ruby"}
61
59
  s.test_files = [
60
+ "test/RubyLess_test.rb",
62
61
  "test/mock/active_record_mock.rb",
63
- "test/mock/dummy_class.rb",
64
- "test/mock/dummy_module.rb",
65
- "test/mock/property_column.rb",
66
- "test/RubyLess_test.rb",
67
- "test/safe_class_test.rb",
68
- "test/signature_hash_test.rb",
69
- "test/test_helper.rb",
70
- "test/typed_method_test.rb",
71
- "test/typed_string_test.rb"
62
+ "test/mock/dummy_class.rb",
63
+ "test/mock/dummy_module.rb",
64
+ "test/mock/property_column.rb",
65
+ "test/safe_class_test.rb",
66
+ "test/signature_hash_test.rb",
67
+ "test/test_helper.rb",
68
+ "test/typed_method_test.rb",
69
+ "test/typed_string_test.rb"
72
70
  ]
73
71
 
74
72
  if s.respond_to? :specification_version then
75
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
76
73
  s.specification_version = 3
77
74
 
78
75
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
@@ -164,10 +164,6 @@ accept_nil_in_no_nil:
164
164
  src: "no_nil(accept_nil(dictionary[:foo]))"
165
165
  tem: "no_nil(accept_nil(get_dict[:foo]))"
166
166
 
167
- parse_array:
168
- src: "[3, 6]"
169
- tem: '[3,6]'
170
-
171
167
  noop_method:
172
168
  src: 'no_op("hello")'
173
169
  tem: '("hello")'
@@ -222,4 +218,24 @@ map_allowed_method:
222
218
 
223
219
  map_forbidden_method:
224
220
  src: "%w{45 52}.map(:foo)"
225
- tem: "unknown method 'map(:foo)' for '[\"45\",\"52\"]' of type Array."
221
+ tem: "unknown method 'map(:foo)' for '[\"45\",\"52\"]' of type [String]."
222
+
223
+ eval_true:
224
+ src: "true"
225
+ tem: "true"
226
+
227
+ eval_false:
228
+ src: "false"
229
+ tem: "false"
230
+
231
+ number_array:
232
+ src: "[3, 6]"
233
+ tem: '[3,6]'
234
+
235
+ string_array:
236
+ src: "%w{foo bar}.join(',')"
237
+ res: 'foo,bar'
238
+
239
+ array_bad_method:
240
+ src: "%w{foo bar}.plop(',')"
241
+ res: "unknown method 'plop(String)' for '[\"foo\",\"bar\"]' of type [String]."
@@ -2,6 +2,14 @@ parse_hash:
2
2
  src: "{'one' => 1, 2 => 'two'}"
3
3
  tem: "{\"one\" => 1, 2 => \"two\"}"
4
4
 
5
+ literal_on_hash:
6
+ src: "{'one' => 1, 2 => 'two'}['one'] + 2"
7
+ tem: "(1+2)"
8
+
9
+ method_on_hash:
10
+ src: "{'one' => 1, 2 => 'two'}.to_param"
11
+ tem: "{\"one\" => 1, 2 => \"two\"}.to_param"
12
+
5
13
  hash_access:
6
14
  src: "dictionary[:key]"
7
15
  tem: "get_dict[:key]"
@@ -22,7 +22,7 @@ class RubyLessTest < Test::Unit::TestCase
22
22
  end
23
23
  res = RubyLess::TypedString.new(res, :class => [type[:class]])
24
24
  else
25
- raise RubyLess::NoMethodError.new(receiver.raw, receiver.klass, ['map', method])
25
+ raise RubyLess::NoMethodError.new(receiver.raw, "[#{receiver.klass}]", ['map', method])
26
26
  end
27
27
  else
28
28
  # should never happen
@@ -55,6 +55,10 @@ class RubyLessTest < Test::Unit::TestCase
55
55
 
56
56
  safe_method_for Array, [:map, Symbol] => {:method => 'nil', :class => nil, :pre_processor => self.map_proc}
57
57
 
58
+ safe_method_for Array, [:join, String] => {:method => 'join', :class => String, :pre_processor => true}
59
+
60
+ safe_method_for Hash, :to_param => String
61
+
58
62
  safe_method_for String, :upcase => {:class => String, :pre_processor => true}
59
63
 
60
64
  safe_method_for Time, [:strftime, String] => String
@@ -169,6 +173,20 @@ class RubyLessTest < Test::Unit::TestCase
169
173
  assert_equal "marsupilami.says('Hello')", RubyLess.translate(typed_string, 'talk')
170
174
  end
171
175
 
176
+ def test_literal_hash_type
177
+ # Out of RubyLess::Processor, type is Hash, not {:foo => TypedString}.
178
+ typed_string = RubyLess.translate(self, %q{{:foo => 'bar'}})
179
+ assert_equal Hash, typed_string.klass
180
+ end
181
+
182
+ def test_should_not_alter_input_string
183
+ orig_str = 'contact where id #{params[:foo]} in site'
184
+ str = orig_str.dup
185
+ RubyLess.translate(self, str)
186
+ rescue RubyLess::Error => err
187
+ assert_equal orig_str, str
188
+ end
189
+
172
190
  def yt_do_test(file, test, context = yt_get('context',file,test))
173
191
  @@test_strings[file][test].keys.each do |key|
174
192
  next if ['src', 'context', 'str'].include?(key)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyless
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
5
- prerelease: false
4
+ hash: 57
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 2
10
- version: 0.8.2
9
+ - 3
10
+ version: 0.8.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Gaspard Bucher
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-15 00:00:00 +01:00
18
+ date: 2011-06-15 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -90,7 +90,6 @@ extra_rdoc_files:
90
90
  - README.rdoc
91
91
  - TODO
92
92
  files:
93
- - .gitignore
94
93
  - History.txt
95
94
  - README.rdoc
96
95
  - Rakefile
@@ -130,8 +129,8 @@ homepage: http://zenadmin.org/546
130
129
  licenses: []
131
130
 
132
131
  post_install_message:
133
- rdoc_options:
134
- - --charset=UTF-8
132
+ rdoc_options: []
133
+
135
134
  require_paths:
136
135
  - lib
137
136
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -155,16 +154,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
154
  requirements: []
156
155
 
157
156
  rubyforge_project:
158
- rubygems_version: 1.3.7
157
+ rubygems_version: 1.6.1
159
158
  signing_key:
160
159
  specification_version: 3
161
160
  summary: RubyLess is an interpreter for "safe ruby"
162
161
  test_files:
162
+ - test/RubyLess_test.rb
163
163
  - test/mock/active_record_mock.rb
164
164
  - test/mock/dummy_class.rb
165
165
  - test/mock/dummy_module.rb
166
166
  - test/mock/property_column.rb
167
- - test/RubyLess_test.rb
168
167
  - test/safe_class_test.rb
169
168
  - test/signature_hash_test.rb
170
169
  - test/test_helper.rb
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- pkg
2
- rdoc
3
- *.gem
4
- coverage