rubyless 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- # var1.spouse.name == ''
30
- # "var1.spouse" would be the condition that could yield 'nil'.
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
- # "var1.spouse.name" instead of "(var1.spouse ? var1.spouse.name : nil)"
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
- $:.unshift(File.dirname(__FILE__)) unless
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.3.5"
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{2009-11-08}
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 = ["History.txt", "README.txt"]
14
- s.files = ["History.txt", "README.txt", "Rakefile", "rubyless.gemspec", "lib/basic_types.rb", "lib/processor.rb", "lib/rubyless.rb", "lib/safe_class.rb", "lib/typed_string.rb", "test/mock", "test/mock/active_record_mock.rb", "test/mock/dummy_class.rb", "test/RubyLess", "test/RubyLess/active_record.yml", "test/RubyLess/basic.yml", "test/RubyLess/errors.yml", "test/RubyLess_test.rb", "test/test_helper.rb"]
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 = ["--main", "README.txt"]
50
+ s.rdoc_options = ["--charset=UTF-8"]
17
51
  s.require_paths = ["lib"]
18
- s.rubyforge_project = %q{rubyless}
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 = ["test/test_helper.rb"]
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<bones>, [">= 2.5.1"])
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<bones>, [">= 2.5.1"])
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<bones>, [">= 2.5.1"])
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: "(var1.log_at ? var1.log_at.strftime(\"%Y\") : nil)"
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(var1.format)"
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: "(var1.age+15)"
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: "(var1.friend_id ? (var1.friend_id+15) : nil)"
17
+ tem: "(node.friend_id ? (node.friend_id+15) : nil)"
18
18
  res: ""
19
19
 
@@ -4,7 +4,7 @@ empty:
4
4
 
5
5
  numbers:
6
6
  src: "id > 45 and (3 > -id or 3+3)"
7
- tem: "((var1.zip>45) and ((3>-var1.zip) or (3+3)))"
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(\"#{var1.name}\")"
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(\"#{var1.name}\")"
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 var1.ancestor?(@node))"
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: "(var1.spouse ? var1.spouse.name : nil)"
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: "(var1.spouse ? (var1.spouse.name==\"yo\") : nil)"
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: "(var1.spouse ? (var1.spouse.zip>1) : nil)"
44
+ tem: "(node.spouse ? (node.spouse.zip>1) : nil)"
45
45
 
46
46
  nil_ternary_op:
47
47
  src: "spouse ? 'foo' : 'bar'"
48
- tem: "var1.spouse ? \"foo\" : \"bar\""
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: "(var1.spouse ? (var1.spouse.name==\"Adam\") : nil) ? \"man\" : \"not a man\""
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: "var1.project.name.to_s"
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: "(var1.zip>2) ? \"foo\" : \"bar\""
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: "(var1.spouse ? vowel_count(var1.spouse.name) : nil)"
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: "(var1.spouse ? log_info(var1.spouse, \"foobar\") : nil)"
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: "((var1.husband && var1.spouse) ? log_info(var1.husband, var1.spouse.name) : nil)"
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: "(var1.spouse ? log_info(var1.spouse, var1.spouse.name) : nil)"
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: "var1.width({:mode => \"pv\"})"
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: "var1.width({\"nice\" => (1==1)})"
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})"
@@ -1,39 +1,39 @@
1
1
  unknown_global_method:
2
2
  src: "system('echo date')"
3
- res: "Unknown method 'system(\"echo date\")'."
3
+ res: "(RubyLessTest): unknown method 'system(String)'."
4
4
 
5
5
  bad_argument_types:
6
6
  src: "strftime(34,'ffoo')"
7
- res: "Unknown method 'strftime(34, \"ffoo\")'."
7
+ res: "(RubyLessTest): unknown method 'strftime(Number, String)'."
8
8
 
9
9
  zero_div:
10
10
  src: "1/(id-10)"
11
- tem: "(1/(var1.zip-10) rescue nil)"
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: 'Bug! Unknown node-type :while to RubyLess::RubyLessProcessor'
16
+ res: "'while' not available in RubyLess."
17
17
 
18
18
  add_two_strings:
19
19
  src: "name + 14"
20
- res: "'var1.name' does not respond to '+(Number)'."
20
+ res: "node.name (String): unknown method '+(Number)'."
21
21
 
22
22
  two_arguments_in_hash:
23
23
  src: "dictionary[:one, :two]"
24
- res: "'get_dict' does not respond to '[](Symbol, Symbol)'."
24
+ res: "get_dict (StringDictionary): unknown method '[](Symbol, Symbol)'."
25
25
 
26
26
  number_argument:
27
27
  src: "dictionary[43]"
28
- res: "'get_dict' does not respond to '[](Number)'."
28
+ res: "get_dict (StringDictionary): unknown method '[](Number)'."
29
29
 
30
30
  string_argument:
31
31
  src: "dictionary[spouse.name]"
32
- res: "'get_dict' does not respond to '[](String)'."
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: "'var1' does not respond to 'foo()'."
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: "Unknown method 'width({:mode => 12})'."
45
+ res: "(RubyLessTest): unknown method 'width(:mode=>Number)'."
46
46
 
47
47
  optional_arguments_bad_argument:
48
48
  src: "width(:xyz => 'pv')"
49
- res: "Unknown method 'width({:xyz => \"pv\"})'."
49
+ res: "(RubyLessTest): unknown method 'width(:xyz=>String)'."
@@ -0,0 +1,11 @@
1
+ empty:
2
+ str: ""
3
+ tem: '""'
4
+
5
+ text:
6
+ str: "hello"
7
+ tem: '"hello"'
8
+
9
+ dynamic_string:
10
+ str: 'one #{name} two'
11
+ tem: '"one #{node.name} two"'
@@ -1,5 +1,5 @@
1
1
  require 'date'
2
- require File.dirname(__FILE__) + '/test_helper.rb'
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
- # try to execute method in the current var "var.method"
31
- if res = context[:node_class].safe_method_type(signature)
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 var1
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 => 'var1', :node_class => Dummy}
80
- source = yt_get('src', file, test)
81
- case key
82
- when 'tem'
83
- source ? RubyLess.translate(source, self) : yt_get('tem', file, test)
84
- when 'res'
85
- res = RubyLess.translate(source, self)
86
- eval(source ? RubyLess.translate(source, self) : yt_get('tem', file, test)).to_s
87
- when 'sxp'
88
- RubyParser.new.parse(source).inspect
89
- else
90
- "Unknown key '#{key}'. Should be 'tem' or 'res'."
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
 
@@ -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
- attr_reader :name
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}] => String
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,8 @@
1
+ module DummyModule
2
+ include RubyLess::SafeClass
3
+ safe_method :maze => {:class => String, :method => 'mazette'}
4
+
5
+ def mazette
6
+ "Mazette !"
7
+ end
8
+ 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