rubyless 0.1.0 → 0.2.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/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