Module: RubyLess::SafeClass
- Defined in:
- lib/ruby_less/safe_class.rb
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
- .all_safe_methods ⇒ Object
- .build_safe_methods_list(klass) ⇒ Object
- .build_signature(key) ⇒ Object
-
.included(base) ⇒ Object
ClassMethods.
- .literal_class_for(klass) ⇒ Object
- .parse_class(klass) ⇒ Object
- .safe_literal_class(hash) ⇒ Object
-
.safe_method_for(klass, methods_hash) ⇒ Object
Declare a safe method for a given class ( same as #safe_method).
-
.safe_method_type_for(klass, signature) ⇒ Object
Return method type (options) if the given signature is a safe method for the class.
-
.safe_method_type_for_column(col, is_property = false) ⇒ Object
Return a safe type from a column.
- .safe_method_with_hash_args(klass, signature, hash_args) ⇒ Object
-
.safe_methods_for(klass) ⇒ Object
List of safe methods for a specific class.
Instance Method Summary collapse
-
#safe_eval(code) ⇒ Object
Evaluate a RubyLess expression.
-
#safe_eval_string(code) ⇒ Object
Evaluate a RubyLess expression.
-
#safe_method_type(signature, receiver = nil) ⇒ Object
Return the type if the given signature corresponds to a safe method for the object’s class.
-
#safe_send(method) ⇒ Object
Safe dynamic method dispatching when the method is not known during compile time.
Class Method Details
.all_safe_methods ⇒ Object
55 56 57 |
# File 'lib/ruby_less/safe_class.rb', line 55 def self.all_safe_methods @@_safe_methods end |
.build_safe_methods_list(klass) ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/ruby_less/safe_class.rb', line 243 def self.build_safe_methods_list(klass) list = SignatureHash.new (@@_safe_methods[klass] || {}).map do |signature, return_value| if return_value.kind_of?(Hash) return_value[:class] = parse_class(return_value[:class]) elsif return_value.kind_of?(Proc) || return_value.kind_of?(Symbol) # keep else return_value = {:class => return_value} end method = signature.shift signature = [method] + signature.map {|e| parse_class(e)} list[signature] = return_value.freeze end list end |
.build_signature(key) ⇒ Object
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/ruby_less/safe_class.rb', line 227 def self.build_signature(key) keys = key.kind_of?(Array) ? key : [key] keys[0] = keys[0].to_s hash_args = [] signature = keys.map do |k| if k.kind_of?(Hash) hash_args << k Hash else hash_args << nil k end end [signature, (hash_args.compact.empty? ? nil : hash_args)] end |
.included(base) ⇒ Object
ClassMethods
196 197 198 |
# File 'lib/ruby_less/safe_class.rb', line 196 def self.included(base) base.extend ClassMethods end |
.literal_class_for(klass) ⇒ Object
47 48 49 |
# File 'lib/ruby_less/safe_class.rb', line 47 def self.literal_class_for(klass) @@_safe_literal_classes[klass] end |
.parse_class(klass) ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/ruby_less/safe_class.rb', line 260 def self.parse_class(klass) if klass.kind_of?(Array) if klass[0].kind_of?(String) [Module::const_get(klass[0])] else klass end else if klass.kind_of?(String) Module::const_get(klass) else klass end end end |
.safe_literal_class(hash) ⇒ Object
51 52 53 |
# File 'lib/ruby_less/safe_class.rb', line 51 def self.safe_literal_class(hash) @@_safe_literal_classes.merge!(hash) end |
.safe_method_for(klass, methods_hash) ⇒ Object
Declare a safe method for a given class ( same as #safe_method)
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/ruby_less/safe_class.rb', line 60 def self.safe_method_for(klass, methods_hash) defaults = methods_hash.delete(:defaults) || {} list = (@@_safe_methods[klass] ||= {}) methods_hash.each do |signature, type| signature, hash_args = build_signature(signature) type = {:class => type} unless type.kind_of?(Hash) type = defaults.merge(type) type[:method] = type[:method] ? type[:method].to_s : signature.first.to_s if hash_args type[:hash_args] = hash_args list[signature] = type if hash_args.last.kind_of?(Hash) # Also build signature without last hash. This enables the common idiom # method(arg, arg, opts = {}) list[signature[0..-2]] = type.dup end else list[signature] = type end end end |
.safe_method_type_for(klass, signature) ⇒ Object
Return method type (options) if the given signature is a safe method for the class.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/ruby_less/safe_class.rb', line 14 def self.safe_method_type_for(klass, signature) if klass.kind_of?(Array) safe_method_type_for(Array, signature) elsif klass.kind_of?(Hash) nil # literal hash resolved in processor klass = Hash else # Signature might be ['name', {:mode => String, :type => Number}]. # build signature arguments # Replace all hashes in signature by Hash class and check for arguments signature_args = [] signature = signature.map do |s| if s.kind_of?(Hash) signature_args << s Hash else signature_args << nil s end end # Find safe method in all ancestry klass.ancestors.each do |ancestor| # FIXME: find a way to optimize this search ! if type = safe_method_with_hash_args(ancestor, signature, signature_args) return type end end nil end end |
.safe_method_type_for_column(col, is_property = false) ⇒ Object
Return a safe type from a column
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/ruby_less/safe_class.rb', line 84 def self.safe_method_type_for_column(col, is_property = false) opts = {} opts[:nil] = col.default.nil? if col.number? opts[:class] = Number elsif col.text? opts[:class] = String else opts[:class] = col.klass end if is_property opts[:method] = "prop['#{col.name.gsub("'",'')}']" else opts[:method] = col.name end opts end |
.safe_method_with_hash_args(klass, signature, hash_args) ⇒ Object
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/ruby_less/safe_class.rb', line 276 def self.safe_method_with_hash_args(klass, signature, hash_args) if type = safe_methods_for(klass)[signature] unless allowed_args = type[:hash_args] # All arguments allowed return type end # Verify arguments hash_args.each_with_index do |args, i| next unless args # verify for each position: ({:a => 3}, {:x => :y}) return nil unless allowed_args_for_position = allowed_args[i] args.each do |k,v| return nil unless v.ancestors.include?(allowed_args_for_position[k]) end end type else nil end end |
.safe_methods_for(klass) ⇒ Object
List of safe methods for a specific class.
8 9 10 11 |
# File 'lib/ruby_less/safe_class.rb', line 8 def self.safe_methods_for(klass) # Caching safe_methods_all is bad when modules are dynamically added / removed. @@_safe_methods_parsed[klass] ||= build_safe_methods_list(klass) end |
Instance Method Details
#safe_eval(code) ⇒ Object
Evaluate a RubyLess expression. This is just like ‘eval’ but with safe method checking and typing.
215 216 217 218 |
# File 'lib/ruby_less/safe_class.rb', line 215 def safe_eval(code) ruby = RubyLessProcessor.translate(self, code) eval(ruby) end |
#safe_eval_string(code) ⇒ Object
Evaluate a RubyLess expression. This is just like ‘eval’ but with safe method checking and typing.
221 222 223 224 |
# File 'lib/ruby_less/safe_class.rb', line 221 def safe_eval_string(code) ruby = RubyLess.translate_string(self, code) eval(ruby) end |
#safe_method_type(signature, receiver = nil) ⇒ Object
Return the type if the given signature corresponds to a safe method for the object’s class.
201 202 203 204 205 |
# File 'lib/ruby_less/safe_class.rb', line 201 def safe_method_type(signature, receiver = nil) if type = SafeClass.safe_method_type_for(self.class, signature) type[:class].kind_of?(Symbol) ? self.send(type[:class], signature) : type end end |
#safe_send(method) ⇒ Object
Safe dynamic method dispatching when the method is not known during compile time. Currently this only works for methods without arguments.
209 210 211 212 |
# File 'lib/ruby_less/safe_class.rb', line 209 def safe_send(method) return nil unless type = self.class.safe_method_type([method]) self.send(type[:method]) end |