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