rubyless 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.2.0 2009-06-02
2
+
3
+ * 1 major enhancement:
4
+ * Added support for ActiveRecord attributes
5
+
6
+ * 2 minor enhancement:
7
+ * Better documentation
8
+ * Removed eval (this means safe methods are globally declared)
9
+
1
10
  == 0.1.0 2009-06-02
2
11
 
3
12
  * 1 major enhancement:
data/README.rdoc CHANGED
@@ -35,10 +35,15 @@ return 'nil' instead of the declared output, you need to wrap your final ruby 'e
35
35
  safe_method_for String, [:==, String] => RubyLess::Boolean
36
36
  safe_method_for String, [:to_s] => String
37
37
 
38
- You can also redefine 'safe_method?' for any class or for the main helper in order to do some more complicated renaming. Note
38
+ You can also redefine 'safe_method_type' for any class or for the main helper in order to do some more complicated renaming. Note
39
39
  also that you should add ':nil => true' declaration to any method that could return a nil value so that RubyLess can render
40
40
  code that will not break during runtime (adding nil checking in the form of "foo ? foo.name : nil").
41
41
 
42
+ Or you can group all declarations in a single place with 'safe_method_for':
43
+
44
+ RubyLess::SafeClass.safe_method_for Dummy, :prev => {:class => Dummy, :method => 'previous', :nil => true},
45
+ :node => lambda {|h| {:class => h.context[:node_class], :method => h.context[:node]}}
46
+
42
47
  You can now parse some ruby code:
43
48
 
44
49
  RubyLess.translate("!prev.ancestor?(main) && !node.ancestor?(main)", self)
@@ -53,8 +58,7 @@ You can now parse some ruby code:
53
58
  RubyLess.translate("log_info(spouse, spouse.name)", self)
54
59
  => "(var1.spouse ? log_info(var1.spouse, var1.spouse.name) : nil)"
55
60
 
56
- Since most of the code in SafeClass is string evaluated (to scope class variables), there is not much to parse for rdoc. You
57
- can look at the tests for an idea of how to declare things. If you have more questions, ask on zena's mailing list:
61
+ You can look at the tests for an idea of how to declare things. If you have more questions, ask on zena's mailing list:
58
62
 
59
63
  http://zenadmin.org/community
60
64
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require "rubygems"
2
2
  require "rake/gempackagetask"
3
3
  require "rake/rdoctask"
4
- require "lib/RubyLess"
4
+ require "lib/rubyless"
5
5
 
6
6
  task :default => :test
7
7
 
@@ -0,0 +1,39 @@
1
+ require 'safe_class'
2
+
3
+ module RubyLess
4
+
5
+ class Boolean
6
+ end
7
+
8
+ class Number
9
+ include SafeClass
10
+ safe_method( [:==, Number] => Boolean, [:< , Number] => Boolean, [:> , Number] => Boolean, [:<=, Number] => Boolean, [:>=, Number] => Boolean,
11
+ [:- , Number] => Number, [:+ , Number] => Number, [:* , Number] => Number, [:/ , Number] => Number,
12
+ [:% , Number] => Number, [:"-@"] => Number )
13
+ end
14
+
15
+
16
+ class Missing
17
+ [:==, :< , :> , :<=, :>=, :"?"].each do |sym|
18
+ define_method(sym) do |arg|
19
+ false
20
+ end
21
+ end
22
+
23
+ def to_s
24
+ ''
25
+ end
26
+
27
+ def nil?
28
+ true
29
+ end
30
+
31
+ def method_missing(*meth)
32
+ self
33
+ end
34
+ end
35
+
36
+ Nil = Missing.new
37
+
38
+
39
+ end
@@ -1,113 +1,11 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
1
  require 'rubygems'
5
2
  require 'parse_tree'
6
- require 'SafeClass'
7
- =begin rdoc
8
- =end
9
- module RubyLess
10
- VERSION = '0.1.0'
11
-
12
- def self.translate(string, helper)
13
- RubyLessProcessor.translate(string, helper)
14
- end
15
-
16
- class Boolean
17
- end
18
-
19
- class Number
20
- include SafeClass
21
- safe_method( [:==, Number] => Boolean, [:< , Number] => Boolean, [:> , Number] => Boolean, [:<=, Number] => Boolean, [:>=, Number] => Boolean,
22
- [:- , Number] => Number, [:+ , Number] => Number, [:* , Number] => Number, [:/ , Number] => Number,
23
- [:% , Number] => Number, [:"-@"] => Number )
24
- end
25
-
26
-
27
- class Missing
28
- [:==, :< , :> , :<=, :>=, :"?"].each do |sym|
29
- define_method(sym) do |arg|
30
- false
31
- end
32
- end
33
-
34
- def to_s
35
- ''
36
- end
37
-
38
- def nil?
39
- true
40
- end
41
-
42
- def method_missing(*meth)
43
- self
44
- end
45
- end
46
-
47
- Nil = Missing.new
48
-
49
- class TypedString < String
50
- attr_reader :klass, :opts
51
3
 
52
- def initialize(content = "", opts = nil)
53
- opts ||= {:class => String}
54
- replace(content)
55
- @opts = opts.dup
56
- if could_be_nil? && !@opts[:cond]
57
- @opts[:cond] = [self.to_s]
58
- end
59
- end
60
-
61
- def klass
62
- @opts[:class]
63
- end
64
-
65
- def could_be_nil?
66
- @opts[:nil]
67
- end
68
-
69
- # condition when 'could_be_nil' comes from a different method then the last one:
70
- # var1.spouse.name == ''
71
- # "var1.spouse" would be the condition that inserted 'could_be_nil?'.
72
- def cond
73
- @opts[:cond]
74
- end
75
-
76
- # raw result without nil checking:
77
- # "var1.spouse.name" instead of "(var1.spouse ? var1.spouse.name : nil)"
78
- def raw
79
- @opts[:raw] || self.to_s
80
- end
81
-
82
- def <<(typed_string)
83
- append_opts(typed_string)
84
- if self.empty?
85
- replace(typed_string.raw)
86
- else
87
- replace("#{self.raw}, #{typed_string.raw}")
88
- end
89
- end
90
-
91
- def append_opts(typed_string)
92
- if self.empty?
93
- @opts = typed_string.opts.dup
94
- else
95
- if klass.kind_of?(Array)
96
- klass << typed_string.klass
97
- else
98
- @opts[:class] = [klass, typed_string.klass]
99
- end
100
- append_cond(typed_string.cond) if typed_string.could_be_nil?
101
- end
102
- end
103
-
104
- def append_cond(condition)
105
- @opts[:cond] ||= []
106
- @opts[:cond] += [condition].flatten
107
- @opts[:cond].uniq!
108
- end
109
- end
4
+ require 'basic_types'
5
+ require 'typed_string'
6
+ require 'safe_class'
110
7
 
8
+ module RubyLess
111
9
  class RubyLessProcessor < SexpProcessor
112
10
  attr_reader :ruby
113
11
 
@@ -172,7 +70,7 @@ module RubyLess
172
70
  def process_arglist(exp)
173
71
  code = t("")
174
72
  until exp.empty? do
175
- code << process(exp.shift)
73
+ code.append_argument(process(exp.shift))
176
74
  end
177
75
  code
178
76
  end
@@ -296,7 +194,7 @@ module RubyLess
296
194
  end
297
195
 
298
196
  def get_method(signature, receiver, is_method = true)
299
- res = receiver.respond_to?(:safe_method?) ? receiver.safe_method?(signature) : @helper.class.safe_method_for?(receiver, signature)
197
+ res = receiver.respond_to?(:safe_method_type) ? receiver.safe_method_type(signature) : SafeClass.safe_method_type_for(receiver, signature)
300
198
  res = res.call(@helper) if res.kind_of?(Proc)
301
199
  res
302
200
  end
data/lib/rubyless.rb ADDED
@@ -0,0 +1,14 @@
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.2.0'
10
+
11
+ def self.translate(string, helper)
12
+ RubyLessProcessor.translate(string, helper)
13
+ end
14
+ end
data/lib/safe_class.rb ADDED
@@ -0,0 +1,140 @@
1
+ module RubyLess
2
+ module SafeClass
3
+ @@_safe_methods ||= {} # defined for each class
4
+ @@_safe_methods_all ||= {} # full list with inherited attributes
5
+
6
+ # List of safe methods for a specific class.
7
+ def self.safe_methods_for(klass)
8
+ @@_safe_methods_all[klass] ||= build_safe_methods_list(klass)
9
+ end
10
+
11
+ # Return method type (options) if the given signature is a safe method for the class.
12
+ def self.safe_method_type_for(klass, signature)
13
+ if res = safe_methods_for(klass)[signature]
14
+ res.dup
15
+ else
16
+ nil
17
+ end
18
+ end
19
+
20
+ # Declare a safe method for a given class
21
+ def self.safe_method_for(klass, hash)
22
+ list = (@@_safe_methods[klass] ||= {})
23
+ hash.each do |k,v|
24
+ k = [k] unless k.kind_of?(Array)
25
+ v = {:class => v} unless v.kind_of?(Hash) || v.kind_of?(Proc)
26
+ list[k] = v
27
+ end
28
+ end
29
+
30
+ def self.included(base)
31
+ base.class_eval do
32
+
33
+ # Declare a safe method through a hash of either
34
+ # signature => return type
35
+ # or
36
+ # signature => options
37
+ # or
38
+ # signature => lambda {|h| ... }
39
+ #
40
+ # The lambda expression will be called with @helper as argument during compilation.
41
+ #
42
+ # The signature can be either a single symbol or an array containing the method name and type arguments like:
43
+ # [:strftime, Time, String]
44
+ #
45
+ # The return type can be a string with the class name or a class.
46
+ #
47
+ # Options are:
48
+ # :class the return type (class name)
49
+ # :nil set this to true if the method could return nil
50
+ def self.safe_method(hash)
51
+ list = (@@_safe_methods[self] ||= {})
52
+ hash.each do |k,v|
53
+ k = [k] unless k.kind_of?(Array)
54
+ v = {:class => v} unless v.kind_of?(Hash) || v.kind_of?(Proc)
55
+ list[k] = v
56
+ end
57
+ end
58
+
59
+ # Declare a safe method to access a list of attributes.
60
+ # This method should only be used when the class is linked with a database table and provides
61
+ # proper introspection to detect types and the possibility of NULL values.
62
+ def self.safe_attribute(*attributes)
63
+ attributes.each do |att|
64
+ if col = columns_hash[att.to_s]
65
+ opts = {}
66
+ opts[:nil] = col.default.nil?
67
+ if col.number?
68
+ opts[:class] = RubyLess::Number
69
+ elsif col.text?
70
+ opts[:class] = String
71
+ elsif att.to_s =~ /_at$/
72
+ opts[:class] = Time
73
+ else
74
+ raise "Could not declare safe_method for '#{att}': could not guess return type"
75
+ end
76
+ safe_method att.to_sym => opts
77
+ else
78
+ puts "Warning: could not declare safe_attribute '#{att}' (No column with this name found in class #{self})"
79
+ end
80
+ end
81
+ end
82
+
83
+ # Declare a safe method for a given class
84
+ def self.safe_method_for(klass, signature)
85
+ SafeClass.safe_method_for(klass, signature)
86
+ end
87
+
88
+ # Hash of all safe methods defined for the class.
89
+ def self.safe_methods
90
+ SafeClass.safe_methods_for(self)
91
+ end
92
+
93
+ # Return true if the given signature corresponds to a safe method for the class.
94
+ def self.safe_method_type(signature)
95
+ if res = SafeClass.safe_method_type_for(self, signature)
96
+ res.dup
97
+ else
98
+ nil
99
+ end
100
+ end
101
+
102
+ # Return the method type (options) if the given signature is a safe method for the class.
103
+ def safe_method_type(signature)
104
+ self.class.safe_method_type(signature)
105
+ end
106
+ end # base.class_eval
107
+ end # included
108
+
109
+ private
110
+ def self.build_safe_methods_list(klass)
111
+ list = klass.superclass.respond_to?(:safe_methods) ? klass.superclass.safe_methods : {}
112
+ (@@_safe_methods[klass] || {}).map do |signature, return_value|
113
+ if return_value.kind_of?(Hash)
114
+ return_value[:class] = parse_class(return_value[:class])
115
+ elsif !return_value.kind_of?(Proc)
116
+ return_value = {:class => return_value}
117
+ end
118
+ signature.map! {|e| parse_class(e)}
119
+ list[signature] = return_value
120
+ end
121
+ list
122
+ end
123
+
124
+ def self.parse_class(klass)
125
+ if klass.kind_of?(Array)
126
+ if klass[0].kind_of?(String)
127
+ [Module::const_get(klass[0])]
128
+ else
129
+ klass
130
+ end
131
+ else
132
+ if klass.kind_of?(String)
133
+ Module::const_get(klass)
134
+ else
135
+ klass
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,71 @@
1
+ module RubyLess
2
+
3
+ # This is a special kind of string containing ruby code that retains some information from the
4
+ # elements that compose it.
5
+ class TypedString < String
6
+ attr_reader :klass, :opts
7
+
8
+ def initialize(content = "", opts = nil)
9
+ opts ||= {:class => String}
10
+ replace(content)
11
+ @opts = opts.dup
12
+ if could_be_nil? && !@opts[:cond]
13
+ @opts[:cond] = [self.to_s]
14
+ end
15
+ end
16
+
17
+ # Resulting class of the evaluated ruby code if it is not nil.
18
+ def klass
19
+ @opts[:class]
20
+ end
21
+
22
+ # Returns true if the evaluation of the ruby code represented by the string could be 'nil'.
23
+ def could_be_nil?
24
+ @opts[:nil]
25
+ end
26
+
27
+ # Condition that could yield a nil result in the whole expression.
28
+ # For example in the following expression:
29
+ # var1.spouse.name == ''
30
+ # "var1.spouse" would be the condition that could yield 'nil'.
31
+ def cond
32
+ @opts[:cond]
33
+ end
34
+
35
+ # raw result without nil checking:
36
+ # "var1.spouse.name" instead of "(var1.spouse ? var1.spouse.name : nil)"
37
+ def raw
38
+ @opts[:raw] || self.to_s
39
+ end
40
+
41
+ # Append a typed string to build an argument list
42
+ def append_argument(typed_string)
43
+ append_opts(typed_string)
44
+ if self.empty?
45
+ replace(typed_string.raw)
46
+ else
47
+ replace("#{self.raw}, #{typed_string.raw}")
48
+ end
49
+ end
50
+
51
+ private
52
+ def append_opts(typed_string)
53
+ if self.empty?
54
+ @opts = typed_string.opts.dup
55
+ else
56
+ if klass.kind_of?(Array)
57
+ klass << typed_string.klass
58
+ else
59
+ @opts[:class] = [klass, typed_string.klass]
60
+ end
61
+ append_cond(typed_string.cond) if typed_string.could_be_nil?
62
+ end
63
+ end
64
+
65
+ def append_cond(condition)
66
+ @opts[:cond] ||= []
67
+ @opts[:cond] += [condition].flatten
68
+ @opts[:cond].uniq!
69
+ end
70
+ end
71
+ end
data/rubyless.gemspec CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{rubyless}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Gaspard Bucher"]
9
9
  s.date = %q{2009-06-02}
10
10
  s.email = %q{gaspard@teti.ch}
11
11
  s.extra_rdoc_files = ["README.rdoc"]
12
- s.files = ["History.txt", "Rakefile", "README.rdoc", "rubyless.gemspec", "test/mock", "test/mock/dummy_class.rb", "test/RubyLess", "test/RubyLess/basic.yml", "test/RubyLess/errors.yml", "test/RubyLess_test.rb", "test/test_helper.rb", "lib/RubyLess.rb", "lib/SafeClass.rb"]
12
+ s.files = ["History.txt", "Rakefile", "README.rdoc", "rubyless.gemspec", "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", "lib/basic_types.rb", "lib/processor.rb", "lib/rubyless.rb", "lib/safe_class.rb", "lib/typed_string.rb"]
13
13
  s.has_rdoc = true
14
14
  s.homepage = %q{http://zenadmin.org/546}
15
15
  s.rdoc_options = ["--main", "README.rdoc"]
@@ -0,0 +1,19 @@
1
+ time_type_from_columns:
2
+ src: 'log_at.strftime("%Y")'
3
+ tem: "(var1.log_at ? var1.log_at.strftime(\"%Y\") : nil)"
4
+
5
+ text_type_from_columns:
6
+ src: 'birth.strftime(format)'
7
+ tem: "Date.parse('2009-06-02 18:44').strftime(var1.format)"
8
+ res: '02.06.2009'
9
+
10
+ number_type_from_columns:
11
+ src: "age + 15"
12
+ tem: "(var1.age+15)"
13
+ res: "20"
14
+
15
+ number_type_from_columns_no_default:
16
+ src: "friend_id + 15"
17
+ tem: "(var1.friend_id ? (var1.friend_id+15) : nil)"
18
+ res: ""
19
+
@@ -7,16 +7,16 @@ numbers:
7
7
  tem: "((var1.zip>45) and ((3>-var1.zip) or (3+3)))"
8
8
 
9
9
  global_method:
10
- src: "strftime(now, '%Y')"
11
- tem: "strftime(Time.now, \"%Y\")"
10
+ src: "now.strftime('%Y')"
11
+ tem: "Time.now.strftime(\"%Y\")"
12
12
 
13
13
  dynamic_string:
14
- src: "strftime(now, \"#{name}\")"
15
- tem: "strftime(Time.now, \"#{var1.name}\")"
14
+ src: "now.strftime(\"#{name}\")"
15
+ tem: "Time.now.strftime(\"#{var1.name}\")"
16
16
 
17
17
  dynamic_string_again:
18
- src: "strftime(now, \"#{name}\")"
19
- tem: "strftime(Time.now, \"#{var1.name}\")"
18
+ src: "now.strftime(\"#{name}\")"
19
+ tem: "Time.now.strftime(\"#{var1.name}\")"
20
20
 
21
21
  rewrite_variables:
22
22
  src: "!prev.ancestor?(main) && !node.ancestor?(main)"
@@ -11,6 +11,10 @@ zero_div:
11
11
  tem: "(1/(var1.zip-10) rescue nil)"
12
12
  res: ""
13
13
 
14
- no_looping:
14
+ looping:
15
15
  src: "while(true) do puts 'flood' end"
16
- res: 'Bug! Unknown node-type :while to RubyLess::RubyLessProcessor'
16
+ res: 'Bug! Unknown node-type :while to RubyLess::RubyLessProcessor'
17
+
18
+ add_two_strings:
19
+ src: "name + 14"
20
+ res: "'var1.name' does not respond to '+(14)'."
@@ -1,3 +1,4 @@
1
+ require 'date'
1
2
  require File.dirname(__FILE__) + '/test_helper.rb'
2
3
 
3
4
  class SimpleHelper < Test::Unit::TestCase
@@ -7,17 +8,19 @@ class SimpleHelper < Test::Unit::TestCase
7
8
  safe_method :prev => {:class => Dummy, :method => 'previous'}
8
9
  safe_method :main => {:class => Dummy, :method => '@node'}
9
10
  safe_method :node => lambda {|h| {:class => h.context[:node_class], :method => h.context[:node]}}
10
- safe_method :now => {:class => Time, :method => 'Time.now'}
11
- safe_method [:strftime, Time, String] => String
11
+ safe_method :now => {:class => Time, :method => "Time.now"}
12
+ safe_method :birth => {:class => Time, :method => "Date.parse('2009-06-02 18:44')"}
12
13
  safe_method [:vowel_count, String] => RubyLess::Number
13
14
  safe_method [:log_info, Dummy, String] => String
14
15
  safe_method_for String, [:==, String] => RubyLess::Boolean
15
16
  safe_method_for String, [:to_s] => String
17
+ safe_method_for Time, [:strftime, String] => String
16
18
 
17
- def safe_method?(signature)
18
- unless res = self.class.safe_method?(signature)
19
+ # Example to dynamically rewrite method calls during compilation
20
+ def safe_method_type(signature)
21
+ unless res = self.class.safe_method_type(signature)
19
22
  # try to execute method in the current var "var.method"
20
- if res = context[:node_class].safe_method?(signature)
23
+ if res = context[:node_class].safe_method_type(signature)
21
24
  res = res.call(self) if res.kind_of?(Proc)
22
25
  res[:method] = "#{context[:node]}.#{res[:method] || signature[0]}"
23
26
  end
@@ -0,0 +1,37 @@
1
+ module RubyLess
2
+ class ColumnMock
3
+ def initialize(opts = {})
4
+ @opts = opts
5
+ end
6
+
7
+ def default
8
+ @opts[:default]
9
+ end
10
+
11
+ def text?
12
+ @opts[:text]
13
+ end
14
+
15
+ def number?
16
+ @opts[:number]
17
+ end
18
+ end
19
+
20
+ class ActiveRecordMock
21
+ COLUMNS = {
22
+ 'format' => ColumnMock.new(:default => '%d.%m.%Y', :text => true),
23
+ 'age' => ColumnMock.new(:default => 5, :number => true),
24
+ 'friend_id' => ColumnMock.new(:number => true),
25
+ 'log_at' => ColumnMock.new,
26
+ }
27
+ def self.columns_hash
28
+ COLUMNS
29
+ end
30
+
31
+ COLUMNS.each do |k, v|
32
+ define_method(k) do
33
+ v.default
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,15 +1,19 @@
1
- class Dummy
1
+ require File.dirname(__FILE__) + '/active_record_mock'
2
+
3
+ class Dummy < RubyLess::ActiveRecordMock
2
4
  attr_reader :name
3
5
  include RubyLess::SafeClass
4
6
 
5
7
  safe_method [:ancestor?, Dummy] => RubyLess::Boolean
6
- safe_method :parent => {:class => 'Dummy', :special_option => 'foobar'}
7
- safe_method :children => ['Dummy']
8
- safe_method :project => 'Dummy'
9
- safe_method :spouse => {:class => 'Dummy', :nil => true}
10
- safe_method :husband => {:class => 'Dummy', :nil => true}
11
- safe_method :id => {:class => RubyLess::Number, :method => :zip}
12
- safe_method :name => String
8
+ safe_method :parent => {:class => 'Dummy', :special_option => 'foobar'},
9
+ :children => ['Dummy'],
10
+ :project => 'Dummy',
11
+ :spouse => {:class => 'Dummy', :nil => true},
12
+ :husband => {:class => 'Dummy', :nil => true},
13
+ :id => {:class => RubyLess::Number, :method => :zip},
14
+ :name => String
15
+
16
+ safe_attribute :age, :friend_id, :log_at, :format
13
17
 
14
18
  def initialize(name = 'dummy')
15
19
  @name = name
data/test/test_helper.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'stringio'
2
2
  require 'test/unit'
3
- require File.dirname(__FILE__) + '/../lib/RubyLess'
3
+ require File.dirname(__FILE__) + '/../lib/rubyless'
4
4
  require File.dirname(__FILE__) + '/mock/dummy_class'
5
5
  require 'rubygems'
6
6
  require 'yamltest'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyless
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gaspard Bucher
@@ -27,14 +27,19 @@ files:
27
27
  - README.rdoc
28
28
  - rubyless.gemspec
29
29
  - test/mock
30
+ - test/mock/active_record_mock.rb
30
31
  - test/mock/dummy_class.rb
31
32
  - test/RubyLess
33
+ - test/RubyLess/active_record.yml
32
34
  - test/RubyLess/basic.yml
33
35
  - test/RubyLess/errors.yml
34
36
  - test/RubyLess_test.rb
35
37
  - test/test_helper.rb
36
- - lib/RubyLess.rb
37
- - lib/SafeClass.rb
38
+ - lib/basic_types.rb
39
+ - lib/processor.rb
40
+ - lib/rubyless.rb
41
+ - lib/safe_class.rb
42
+ - lib/typed_string.rb
38
43
  has_rdoc: true
39
44
  homepage: http://zenadmin.org/546
40
45
  post_install_message:
data/lib/SafeClass.rb DELETED
@@ -1,98 +0,0 @@
1
- module RubyLess
2
- module SafeClass
3
- def self.included(base)
4
- # add all methods from the module "AddActsAsMethod" to the 'base' module
5
- base.class_eval <<-END
6
- @@_safe_methods ||= {} # defined for each class
7
- @@_safe_methods_all ||= {} # full list with inherited attributes
8
-
9
- def self.safe_method(hash)
10
- list = (@@_safe_methods[self] ||= {})
11
- hash.each do |k,v|
12
- k = [k] unless k.kind_of?(Array)
13
- v = {:class => v} unless v.kind_of?(Hash) || v.kind_of?(Proc)
14
- list[k] = v
15
- end
16
- end
17
-
18
- def self.safe_methods
19
- safe_methods_for(self)
20
- end
21
-
22
- def self.safe_methods_for(klass)
23
- @@_safe_methods_all[klass] ||= build_safe_methods_list(klass)
24
- end
25
-
26
- def self.build_safe_methods_list(klass)
27
- list = klass.superclass.respond_to?(:safe_methods) ? klass.superclass.safe_methods : {}
28
- (@@_safe_methods[klass] || {}).map do |signature, return_value|
29
- if return_value.kind_of?(Hash)
30
- return_value[:class] = parse_class(return_value[:class])
31
- elsif !return_value.kind_of?(Proc)
32
- return_value = {:class => return_value}
33
- end
34
- signature.map! {|e| parse_class(e)}
35
- list[signature] = return_value
36
- end
37
- list
38
- end
39
-
40
- def self.safe_method?(signature)
41
- if res = safe_methods[signature]
42
- res.dup
43
- else
44
- nil
45
- end
46
- end
47
-
48
- def self.safe_method_for?(klass, signature)
49
- if res = safe_methods_for(klass)[signature]
50
- res.dup
51
- else
52
- nil
53
- end
54
- end
55
-
56
- def safe_method?(signature)
57
- self.class.safe_methods[signature]
58
- end
59
-
60
- def self.safe_method_for(klass, hash)
61
- list = (@@_safe_methods[klass] ||= {})
62
- hash.each do |k,v|
63
- k = [k] unless k.kind_of?(Array)
64
- v = {:class => v} unless v.kind_of?(Hash) || v.kind_of?(Proc)
65
- list[k] = v
66
- end
67
- end
68
-
69
- def self.parse_class(klass)
70
- if klass.kind_of?(Array)
71
- if klass[0].kind_of?(String)
72
- [Module::const_get(klass[0])]
73
- else
74
- klass
75
- end
76
- else
77
- if klass.kind_of?(String)
78
- Module::const_get(klass)
79
- else
80
- klass
81
- end
82
- end
83
- end
84
-
85
- def self.safe_attribute?(sym)
86
- column_names.include?(sym) || zafu_readable?(sym) || safe_attribute_list.include?(sym.to_s)
87
- end
88
-
89
- def self.zafu_readable?(sym)
90
- if sym.to_s =~ /(.*)_zips?$/
91
- return true if self.ancestors.include?(Node) && RelationProxy.find_by_role($1.singularize)
92
- end
93
- self.zafu_readable_attributes.include?(sym.to_s)
94
- end
95
- END
96
- end
97
- end
98
- end