rubyless 0.3.5 → 0.4.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/.gitignore +4 -0
- data/History.txt +31 -16
- data/{README.txt → README.rdoc} +3 -3
- data/Rakefile +47 -36
- data/lib/ruby_less/basic_types.rb +15 -0
- data/lib/ruby_less/error.rb +4 -0
- data/lib/ruby_less/info.rb +3 -0
- data/lib/ruby_less/no_method_error.rb +47 -0
- data/lib/{processor.rb → ruby_less/processor.rb} +62 -23
- data/lib/{safe_class.rb → ruby_less/safe_class.rb} +87 -38
- data/lib/ruby_less/signature_hash.rb +33 -0
- data/lib/ruby_less/syntax_error.rb +4 -0
- data/lib/{typed_string.rb → ruby_less/typed_string.rb} +3 -3
- data/lib/ruby_less.rb +27 -0
- data/lib/rubyless.rb +1 -14
- data/rails/init.rb +1 -0
- data/rubyless.gemspec +56 -13
- data/test/RubyLess/active_record.yml +4 -4
- data/test/RubyLess/basic.yml +56 -18
- data/test/RubyLess/errors.yml +11 -11
- data/test/RubyLess/string.yml +11 -0
- data/test/RubyLess_test.rb +54 -20
- data/test/mock/dummy_class.rb +28 -3
- data/test/mock/dummy_module.rb +8 -0
- data/test/mock/property_column.rb +21 -0
- data/test/safe_class_test.rb +16 -0
- data/test/signature_hash_test.rb +44 -0
- data/test/test_helper.rb +3 -1
- metadata +76 -39
- data/lib/basic_types.rb +0 -15
@@ -26,14 +26,14 @@ module RubyLess
|
|
26
26
|
|
27
27
|
# Condition that could yield a nil result in the whole expression.
|
28
28
|
# For example in the following expression:
|
29
|
-
#
|
30
|
-
# "
|
29
|
+
# node.spouse.name == ''
|
30
|
+
# "node.spouse" would be the condition that could yield 'nil'.
|
31
31
|
def cond
|
32
32
|
@opts[:cond]
|
33
33
|
end
|
34
34
|
|
35
35
|
# raw result without nil checking:
|
36
|
-
# "
|
36
|
+
# "node.spouse.name" instead of "(node.spouse ? node.spouse.name : nil)"
|
37
37
|
def raw
|
38
38
|
@opts[:raw] || self.to_s
|
39
39
|
end
|
data/lib/ruby_less.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
=end
|
3
|
+
require 'ruby_less/info'
|
4
|
+
require 'ruby_less/basic_types'
|
5
|
+
require 'ruby_less/signature_hash'
|
6
|
+
require 'ruby_less/error'
|
7
|
+
require 'ruby_less/no_method_error'
|
8
|
+
require 'ruby_less/syntax_error'
|
9
|
+
require 'ruby_less/typed_string'
|
10
|
+
require 'ruby_less/safe_class'
|
11
|
+
require 'ruby_less/processor'
|
12
|
+
|
13
|
+
module RubyLess
|
14
|
+
def self.translate(string, helper)
|
15
|
+
RubyLessProcessor.translate(string, helper)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.translate_string(string, helper)
|
19
|
+
if string =~ /\#\{/
|
20
|
+
::RubyLess.translate("%Q{#{string}}", helper)
|
21
|
+
else
|
22
|
+
string.inspect
|
23
|
+
end
|
24
|
+
rescue => err
|
25
|
+
raise ::RubyLess::Error.new("Error parsing string \"#{string}\": #{err.message.strip}")
|
26
|
+
end
|
27
|
+
end
|
data/lib/rubyless.rb
CHANGED
@@ -1,14 +1 @@
|
|
1
|
-
|
2
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
-
|
4
|
-
require 'processor'
|
5
|
-
|
6
|
-
=begin rdoc
|
7
|
-
=end
|
8
|
-
module RubyLess
|
9
|
-
VERSION = '0.3.5'
|
10
|
-
|
11
|
-
def self.translate(string, helper)
|
12
|
-
RubyLessProcessor.translate(string, helper)
|
13
|
-
end
|
14
|
-
end
|
1
|
+
require 'ruby_less'
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rubyless'
|
data/rubyless.gemspec
CHANGED
@@ -1,24 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{rubyless}
|
5
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Gaspard Bucher"]
|
9
|
-
s.date = %q{
|
10
|
-
s.description = %q{RubyLess is an interpreter for "safe ruby". The idea is to transform some "unsafe" ruby code into safe, type checked
|
11
|
-
ruby, eventually rewriting some variables or methods.}
|
12
|
+
s.date = %q{2010-03-21}
|
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.}
|
12
14
|
s.email = %q{gaspard@teti.ch}
|
13
|
-
s.extra_rdoc_files = [
|
14
|
-
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"History.txt",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"lib/ruby_less.rb",
|
24
|
+
"lib/ruby_less/basic_types.rb",
|
25
|
+
"lib/ruby_less/error.rb",
|
26
|
+
"lib/ruby_less/info.rb",
|
27
|
+
"lib/ruby_less/no_method_error.rb",
|
28
|
+
"lib/ruby_less/processor.rb",
|
29
|
+
"lib/ruby_less/safe_class.rb",
|
30
|
+
"lib/ruby_less/signature_hash.rb",
|
31
|
+
"lib/ruby_less/syntax_error.rb",
|
32
|
+
"lib/ruby_less/typed_string.rb",
|
33
|
+
"lib/rubyless.rb",
|
34
|
+
"rails/init.rb",
|
35
|
+
"rubyless.gemspec",
|
36
|
+
"test/RubyLess/active_record.yml",
|
37
|
+
"test/RubyLess/basic.yml",
|
38
|
+
"test/RubyLess/errors.yml",
|
39
|
+
"test/RubyLess/string.yml",
|
40
|
+
"test/RubyLess_test.rb",
|
41
|
+
"test/mock/active_record_mock.rb",
|
42
|
+
"test/mock/dummy_class.rb",
|
43
|
+
"test/mock/dummy_module.rb",
|
44
|
+
"test/mock/property_column.rb",
|
45
|
+
"test/safe_class_test.rb",
|
46
|
+
"test/signature_hash_test.rb",
|
47
|
+
"test/test_helper.rb"
|
48
|
+
]
|
15
49
|
s.homepage = %q{http://zenadmin.org/546}
|
16
|
-
s.rdoc_options = ["--
|
50
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
17
51
|
s.require_paths = ["lib"]
|
18
|
-
s.
|
19
|
-
s.rubygems_version = %q{1.3.5}
|
52
|
+
s.rubygems_version = %q{1.3.6}
|
20
53
|
s.summary = %q{RubyLess is an interpreter for "safe ruby"}
|
21
|
-
s.test_files = [
|
54
|
+
s.test_files = [
|
55
|
+
"test/mock/active_record_mock.rb",
|
56
|
+
"test/mock/dummy_class.rb",
|
57
|
+
"test/mock/dummy_module.rb",
|
58
|
+
"test/mock/property_column.rb",
|
59
|
+
"test/RubyLess_test.rb",
|
60
|
+
"test/safe_class_test.rb",
|
61
|
+
"test/signature_hash_test.rb",
|
62
|
+
"test/test_helper.rb"
|
63
|
+
]
|
22
64
|
|
23
65
|
if s.respond_to? :specification_version then
|
24
66
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -27,18 +69,19 @@ ruby, eventually rewriting some variables or methods.}
|
|
27
69
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
70
|
s.add_runtime_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
29
71
|
s.add_runtime_dependency(%q<sexp_processor>, [">= 3.0.1"])
|
30
|
-
s.add_development_dependency(%q<
|
72
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
31
73
|
s.add_development_dependency(%q<yamltest>, [">= 0.5.3"])
|
32
74
|
else
|
33
75
|
s.add_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
34
76
|
s.add_dependency(%q<sexp_processor>, [">= 3.0.1"])
|
35
|
-
s.add_dependency(%q<
|
77
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
36
78
|
s.add_dependency(%q<yamltest>, [">= 0.5.3"])
|
37
79
|
end
|
38
80
|
else
|
39
81
|
s.add_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
40
82
|
s.add_dependency(%q<sexp_processor>, [">= 3.0.1"])
|
41
|
-
s.add_dependency(%q<
|
83
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
42
84
|
s.add_dependency(%q<yamltest>, [">= 0.5.3"])
|
43
85
|
end
|
44
86
|
end
|
87
|
+
|
@@ -1,19 +1,19 @@
|
|
1
1
|
time_type_from_columns:
|
2
2
|
src: 'log_at.strftime("%Y")'
|
3
|
-
tem: "(
|
3
|
+
tem: "(node.log_at ? node.log_at.strftime(\"%Y\") : nil)"
|
4
4
|
|
5
5
|
text_type_from_columns:
|
6
6
|
src: 'birth.strftime(format)'
|
7
|
-
tem: "Date.parse('2009-06-02 18:44').strftime(
|
7
|
+
tem: "Date.parse('2009-06-02 18:44').strftime(node.format)"
|
8
8
|
res: '02.06.2009'
|
9
9
|
|
10
10
|
number_type_from_columns:
|
11
11
|
src: "age + 15"
|
12
|
-
tem: "(
|
12
|
+
tem: "(node.age+15)"
|
13
13
|
res: "20"
|
14
14
|
|
15
15
|
number_type_from_columns_no_default:
|
16
16
|
src: "friend_id + 15"
|
17
|
-
tem: "(
|
17
|
+
tem: "(node.friend_id ? (node.friend_id+15) : nil)"
|
18
18
|
res: ""
|
19
19
|
|
data/test/RubyLess/basic.yml
CHANGED
@@ -4,7 +4,7 @@ empty:
|
|
4
4
|
|
5
5
|
numbers:
|
6
6
|
src: "id > 45 and (3 > -id or 3+3)"
|
7
|
-
tem: "((
|
7
|
+
tem: "((node.zip>45) and ((3>-node.zip) or (3+3)))"
|
8
8
|
|
9
9
|
global_method:
|
10
10
|
src: "now.strftime('%Y')"
|
@@ -12,11 +12,11 @@ global_method:
|
|
12
12
|
|
13
13
|
dynamic_string:
|
14
14
|
src: "now.strftime(\"#{name}\")"
|
15
|
-
tem: "Time.now.strftime(\"#{
|
15
|
+
tem: "Time.now.strftime(\"#{node.name}\")"
|
16
16
|
|
17
17
|
dynamic_string_again:
|
18
18
|
src: "now.strftime(\"#{name}\")"
|
19
|
-
tem: "Time.now.strftime(\"#{
|
19
|
+
tem: "Time.now.strftime(\"#{node.name}\")"
|
20
20
|
|
21
21
|
symbol:
|
22
22
|
src: ":foobar"
|
@@ -28,34 +28,34 @@ hash_access:
|
|
28
28
|
|
29
29
|
rewrite_variables:
|
30
30
|
src: "!prev.ancestor?(main) && !node.ancestor?(main)"
|
31
|
-
tem: "(not previous.ancestor?(@node) and not
|
31
|
+
tem: "(not previous.ancestor?(@node) and not node.ancestor?(@node))"
|
32
32
|
|
33
33
|
method_can_return_nil:
|
34
34
|
src: "spouse.name"
|
35
|
-
tem: "(
|
35
|
+
tem: "(node.spouse ? node.spouse.name : nil)"
|
36
36
|
|
37
37
|
method_on_method_can_return_nil:
|
38
38
|
src: "spouse.name == 'yo'"
|
39
|
-
tem: "(
|
39
|
+
tem: "(node.spouse ? (node.spouse.name==\"yo\") : nil)"
|
40
40
|
res: ""
|
41
41
|
|
42
42
|
nil_greater_then:
|
43
43
|
src: "spouse.id > 1"
|
44
|
-
tem: "(
|
44
|
+
tem: "(node.spouse ? (node.spouse.zip>1) : nil)"
|
45
45
|
|
46
46
|
nil_ternary_op:
|
47
47
|
src: "spouse ? 'foo' : 'bar'"
|
48
|
-
tem: "
|
48
|
+
tem: "node.spouse ? \"foo\" : \"bar\""
|
49
49
|
res: 'bar'
|
50
50
|
|
51
51
|
nested_ternary_op:
|
52
52
|
src: "spouse.name == 'Adam' ? 'man' : 'not a man'"
|
53
|
-
tem: "(
|
53
|
+
tem: "(node.spouse ? (node.spouse.name==\"Adam\") : nil) ? \"man\" : \"not a man\""
|
54
54
|
res: "not a man"
|
55
55
|
|
56
56
|
method_on_method:
|
57
57
|
src: "project.name.to_s"
|
58
|
-
tem: "
|
58
|
+
tem: "node.project.name.to_s"
|
59
59
|
res: 'project'
|
60
60
|
|
61
61
|
comp_ternary_op:
|
@@ -65,24 +65,24 @@ comp_ternary_op:
|
|
65
65
|
|
66
66
|
method_ternary_op:
|
67
67
|
src: "id > 2 ? 'foo' : 'bar'"
|
68
|
-
tem: "(
|
68
|
+
tem: "(node.zip>2) ? \"foo\" : \"bar\""
|
69
69
|
res: "foo"
|
70
70
|
|
71
71
|
method_argument_can_be_nil:
|
72
72
|
src: "vowel_count(spouse.name)"
|
73
|
-
tem: "(
|
73
|
+
tem: "(node.spouse ? vowel_count(node.spouse.name) : nil)"
|
74
74
|
|
75
75
|
multi_arg_method_argument_can_be_nil:
|
76
76
|
src: "log_info(spouse, 'foobar')"
|
77
|
-
tem: "(
|
77
|
+
tem: "(node.spouse ? log_info(node.spouse, \"foobar\") : nil)"
|
78
78
|
|
79
79
|
multi_arg_method_arguments_can_be_nil:
|
80
80
|
src: "log_info(husband, spouse.name)"
|
81
|
-
tem: "((
|
81
|
+
tem: "((node.husband && node.spouse) ? log_info(node.husband, node.spouse.name) : nil)"
|
82
82
|
|
83
83
|
multi_arg_method_arguments_can_be_nil_same_condition:
|
84
84
|
src: "log_info(spouse, spouse.name)"
|
85
|
-
tem: "(
|
85
|
+
tem: "(node.spouse ? log_info(node.spouse, node.spouse.name) : nil)"
|
86
86
|
|
87
87
|
literal_argument_for_method:
|
88
88
|
src: "vowel_count('ruby')"
|
@@ -94,10 +94,48 @@ safe_method_defined_as_symbol:
|
|
94
94
|
|
95
95
|
optional_arguments:
|
96
96
|
src: "width(:mode => 'pv')"
|
97
|
-
tem: "
|
97
|
+
tem: "node.width({:mode => \"pv\"})"
|
98
98
|
res: "mode: pv, type: none"
|
99
99
|
|
100
|
+
optional_arguments:
|
101
|
+
src: "width"
|
102
|
+
tem: "node.width"
|
103
|
+
res: "mode: none, type: none"
|
104
|
+
|
100
105
|
optional_arguments_string:
|
101
106
|
src: "width('nice' => 1 == 1)"
|
102
|
-
tem: "
|
103
|
-
res: "nice!"
|
107
|
+
tem: "node.width({\"nice\" => (1==1)})"
|
108
|
+
res: "nice!"
|
109
|
+
|
110
|
+
module_method:
|
111
|
+
src: "maze"
|
112
|
+
tem: "node.mazette"
|
113
|
+
res: "Mazette !"
|
114
|
+
|
115
|
+
regexp:
|
116
|
+
src: "maze.gsub(/ette/,'o')"
|
117
|
+
tem: "node.mazette.gsub(/ette/, \"o\")"
|
118
|
+
res: "Mazo !"
|
119
|
+
|
120
|
+
instance_variable:
|
121
|
+
src: "@foo.maze"
|
122
|
+
tem: "node.mazette"
|
123
|
+
res: "Mazette !"
|
124
|
+
|
125
|
+
prepend_arg:
|
126
|
+
src: "prepend_test(4)"
|
127
|
+
tem: "add(10, 4)"
|
128
|
+
res: "14"
|
129
|
+
|
130
|
+
safe_property:
|
131
|
+
src: "dog_name"
|
132
|
+
tem: "node.prop['dog_name']"
|
133
|
+
res: "Biscotte"
|
134
|
+
|
135
|
+
match_on_subclass:
|
136
|
+
src: "log_info(sub, 'hello')"
|
137
|
+
tem: "log_info(sub, \"hello\")"
|
138
|
+
|
139
|
+
optional_argument_subclass:
|
140
|
+
src: "width(:mode => str)"
|
141
|
+
tem: "node.width({:mode => str})"
|
data/test/RubyLess/errors.yml
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
unknown_global_method:
|
2
2
|
src: "system('echo date')"
|
3
|
-
res: "
|
3
|
+
res: "(RubyLessTest): unknown method 'system(String)'."
|
4
4
|
|
5
5
|
bad_argument_types:
|
6
6
|
src: "strftime(34,'ffoo')"
|
7
|
-
res: "
|
7
|
+
res: "(RubyLessTest): unknown method 'strftime(Number, String)'."
|
8
8
|
|
9
9
|
zero_div:
|
10
10
|
src: "1/(id-10)"
|
11
|
-
tem: "(1/(
|
11
|
+
tem: "(1/(node.zip-10) rescue nil)"
|
12
12
|
res: ""
|
13
13
|
|
14
14
|
looping:
|
15
15
|
src: "while(true) do puts 'flood' end"
|
16
|
-
res: '
|
16
|
+
res: "'while' not available in RubyLess."
|
17
17
|
|
18
18
|
add_two_strings:
|
19
19
|
src: "name + 14"
|
20
|
-
res: "
|
20
|
+
res: "node.name (String): unknown method '+(Number)'."
|
21
21
|
|
22
22
|
two_arguments_in_hash:
|
23
23
|
src: "dictionary[:one, :two]"
|
24
|
-
res: "
|
24
|
+
res: "get_dict (StringDictionary): unknown method '[](Symbol, Symbol)'."
|
25
25
|
|
26
26
|
number_argument:
|
27
27
|
src: "dictionary[43]"
|
28
|
-
res: "
|
28
|
+
res: "get_dict (StringDictionary): unknown method '[](Number)'."
|
29
29
|
|
30
30
|
string_argument:
|
31
31
|
src: "dictionary[spouse.name]"
|
32
|
-
res: "
|
32
|
+
res: "get_dict (StringDictionary): unknown method '[](String)'."
|
33
33
|
|
34
34
|
symbol_type_not_used_out_of_helper:
|
35
35
|
src: "node.foo"
|
36
|
-
tem: "
|
36
|
+
tem: "node (Dummy): unknown method 'foo()'."
|
37
37
|
|
38
38
|
optional_arguments_with_dynamic_string:
|
39
39
|
src: "spouse.width(\"nice#{spouse.name}\" => 'pv')"
|
@@ -42,8 +42,8 @@ optional_arguments_with_dynamic_string:
|
|
42
42
|
|
43
43
|
optional_arguments_bad_type:
|
44
44
|
src: "width(:mode => 12)"
|
45
|
-
res: "
|
45
|
+
res: "(RubyLessTest): unknown method 'width(:mode=>Number)'."
|
46
46
|
|
47
47
|
optional_arguments_bad_argument:
|
48
48
|
src: "width(:xyz => 'pv')"
|
49
|
-
res: "
|
49
|
+
res: "(RubyLessTest): unknown method 'width(:xyz=>String)'."
|
data/test/RubyLess_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
-
require
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
4
|
class StringDictionary
|
5
5
|
include RubyLess::SafeClass
|
@@ -7,6 +7,10 @@ class StringDictionary
|
|
7
7
|
disable_safe_read
|
8
8
|
end
|
9
9
|
|
10
|
+
# Used to test sub-classes in optional arguments
|
11
|
+
class SubString < String
|
12
|
+
end
|
13
|
+
|
10
14
|
class RubyLessTest < Test::Unit::TestCase
|
11
15
|
attr_reader :context
|
12
16
|
yamltest :src_from_title => false
|
@@ -22,13 +26,19 @@ class RubyLessTest < Test::Unit::TestCase
|
|
22
26
|
safe_method :foo => :contextual_method, :bar => :contextual_method
|
23
27
|
safe_method_for String, [:==, String] => Boolean
|
24
28
|
safe_method_for String, [:to_s] => String
|
29
|
+
safe_method_for String, [:gsub, Regexp, String] => String
|
25
30
|
safe_method_for Time, [:strftime, String] => String
|
31
|
+
safe_method :@foo => {:class => Dummy, :method => "node"}
|
32
|
+
safe_method :sub => SubDummy
|
33
|
+
safe_method :str => SubString
|
26
34
|
|
27
35
|
# Example to dynamically rewrite method calls during compilation
|
28
36
|
def safe_method_type(signature)
|
29
37
|
unless res = super
|
30
|
-
|
31
|
-
|
38
|
+
if signature == ['prepend_test', Number]
|
39
|
+
res ={:class => Number, :prepend_args => RubyLess::TypedString.new('10', :class => Number), :method => 'add'}
|
40
|
+
elsif res = context[:node_class].safe_method_type(signature)
|
41
|
+
# try to execute method in the current var "var.method"
|
32
42
|
res = res.call(self, signature) if res.kind_of?(Proc)
|
33
43
|
res = res.merge(:method => "#{context[:node]}.#{res[:method] || signature[0]}")
|
34
44
|
end
|
@@ -40,10 +50,22 @@ class RubyLessTest < Test::Unit::TestCase
|
|
40
50
|
{:method => "contextual_#{signature[0]}", :class => String}
|
41
51
|
end
|
42
52
|
|
43
|
-
def
|
53
|
+
def node
|
44
54
|
Dummy.new
|
45
55
|
end
|
46
56
|
|
57
|
+
def sub
|
58
|
+
SubDummy.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def str
|
62
|
+
"str"
|
63
|
+
end
|
64
|
+
|
65
|
+
def add(a,b)
|
66
|
+
a+b
|
67
|
+
end
|
68
|
+
|
47
69
|
def vowel_count(str)
|
48
70
|
str.tr('^aeiouy', '').size
|
49
71
|
end
|
@@ -70,28 +92,40 @@ class RubyLessTest < Test::Unit::TestCase
|
|
70
92
|
|
71
93
|
def yt_do_test(file, test, context = yt_get('context',file,test))
|
72
94
|
@@test_strings[file][test].keys.each do |key|
|
73
|
-
next if ['src', 'context'].include?(key)
|
95
|
+
next if ['src', 'context', 'str'].include?(key)
|
74
96
|
yt_assert yt_get(key,file,test), parse(key, file, test, context)
|
75
97
|
end
|
76
98
|
end
|
77
99
|
|
78
100
|
def parse(key, file, test, opts)
|
79
|
-
@context = {:node => '
|
80
|
-
source = yt_get('
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
101
|
+
@context = {:node => 'node', :node_class => Dummy}
|
102
|
+
if source = yt_get('str', file, test)
|
103
|
+
case key
|
104
|
+
when 'tem'
|
105
|
+
source ? RubyLess.translate_string(source, self) : yt_get('tem', file, test)
|
106
|
+
when 'res'
|
107
|
+
eval(source ? RubyLess.translate_string(source, self) : yt_get('tem', file, test)).to_s
|
108
|
+
when 'sxp'
|
109
|
+
RubyParser.new.parse(source).inspect
|
110
|
+
else
|
111
|
+
"Unknown key '#{key}'. Should be 'tem' or 'res'."
|
112
|
+
end
|
113
|
+
elsif source = yt_get('src', file, test)
|
114
|
+
case key
|
115
|
+
when 'tem'
|
116
|
+
source ? RubyLess.translate(source, self) : yt_get('tem', file, test)
|
117
|
+
when 'res'
|
118
|
+
res = RubyLess.translate(source, self)
|
119
|
+
eval(source ? RubyLess.translate(source, self) : yt_get('tem', file, test)).to_s
|
120
|
+
when 'sxp'
|
121
|
+
RubyParser.new.parse(source).inspect
|
122
|
+
else
|
123
|
+
"Unknown key '#{key}'. Should be 'tem' or 'res'."
|
124
|
+
end
|
91
125
|
end
|
92
|
-
rescue => err
|
93
|
-
#puts "\n\n#{err.message}"
|
94
|
-
#puts err.backtrace
|
126
|
+
rescue RubyLess::Error => err
|
127
|
+
# puts "\n\n#{err.message}"
|
128
|
+
# puts err.backtrace
|
95
129
|
err.message
|
96
130
|
end
|
97
131
|
|
data/test/mock/dummy_class.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/active_record_mock'
|
2
|
+
require File.dirname(__FILE__) + '/dummy_module'
|
3
|
+
require File.dirname(__FILE__) + '/property_column'
|
2
4
|
|
3
5
|
class Dummy < RubyLess::ActiveRecordMock
|
4
|
-
|
6
|
+
include DummyModule
|
5
7
|
include RubyLess::SafeClass
|
6
8
|
|
9
|
+
attr_reader :name
|
10
|
+
|
7
11
|
safe_method [:ancestor?, Dummy] => Boolean
|
8
12
|
safe_method :parent => {:class => 'Dummy', :special_option => 'foobar'},
|
9
13
|
:children => ['Dummy'],
|
@@ -12,7 +16,8 @@ class Dummy < RubyLess::ActiveRecordMock
|
|
12
16
|
:id => {:class => Number, :method => :zip},
|
13
17
|
:name => String,
|
14
18
|
:foo => :bar,
|
15
|
-
[:width, {:mode => String, :type => String, 'nice' => Boolean}]
|
19
|
+
[:width, {:mode => String, :type => String, 'nice' => Boolean}] => String,
|
20
|
+
[:width] => String
|
16
21
|
safe_context :spouse => 'Dummy',
|
17
22
|
:husband => {:class => 'Dummy', :context => {:clever => 'no'}}
|
18
23
|
|
@@ -22,6 +27,23 @@ class Dummy < RubyLess::ActiveRecordMock
|
|
22
27
|
@name = name
|
23
28
|
end
|
24
29
|
|
30
|
+
# Mock Property ================= [
|
31
|
+
def self.schema; self; end
|
32
|
+
def self.columns
|
33
|
+
{
|
34
|
+
'dog_name' => MockPropertyColumn.new('dog_name', nil, :string),
|
35
|
+
'dog_age' => MockPropertyColumn.new('dog_age', 0, :number),
|
36
|
+
}
|
37
|
+
end
|
38
|
+
def prop
|
39
|
+
{
|
40
|
+
'dog_name' => 'Biscotte',
|
41
|
+
'dog_age' => 6,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
# Mock Property ================= ]
|
45
|
+
safe_property :dog_name, :dog_age
|
46
|
+
|
25
47
|
def width(opts = {})
|
26
48
|
return 'nice!' if opts['nice']
|
27
49
|
"mode: #{(opts[:mode] || 'none')}, type: #{(opts[:type] || 'none')}"
|
@@ -48,4 +70,7 @@ class Dummy < RubyLess::ActiveRecordMock
|
|
48
70
|
def zip
|
49
71
|
10
|
50
72
|
end
|
51
|
-
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class SubDummy < Dummy
|
76
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class MockPropertyColumn
|
2
|
+
attr_reader :name, :default, :klass
|
3
|
+
def initialize(name, default, type)
|
4
|
+
case type
|
5
|
+
when :string
|
6
|
+
@klass = String
|
7
|
+
when :number
|
8
|
+
@klass = Number
|
9
|
+
end
|
10
|
+
@name = name
|
11
|
+
@default = default
|
12
|
+
end
|
13
|
+
|
14
|
+
def number?
|
15
|
+
@klass == Number
|
16
|
+
end
|
17
|
+
|
18
|
+
def text?
|
19
|
+
@klass == String
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SafeClassTest < Test::Unit::TestCase
|
4
|
+
class SubString < String
|
5
|
+
end
|
6
|
+
|
7
|
+
context 'A safe model' do
|
8
|
+
subject do
|
9
|
+
Dummy
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'have an associated SignatureHash for safe methods' do
|
13
|
+
assert_kind_of RubyLess::SignatureHash, Dummy.safe_methods
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|