rubyless 0.8.2 → 0.8.3

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