Module: RubyLess::SafeClass

Defined in:
lib/ruby_less/safe_class.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.all_safe_methodsObject



54
55
56
# File 'lib/ruby_less/safe_class.rb', line 54

def self.all_safe_methods
  @@_safe_methods
end

.included(base) ⇒ Object

ClassMethods



198
199
200
# File 'lib/ruby_less/safe_class.rb', line 198

def self.included(base)
  base.extend ClassMethods
end

.literal_class_for(klass) ⇒ Object



46
47
48
# File 'lib/ruby_less/safe_class.rb', line 46

def self.literal_class_for(klass)
  @@_safe_literal_classes[klass]
end

.safe_literal_class(hash) ⇒ Object



50
51
52
# File 'lib/ruby_less/safe_class.rb', line 50

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)



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ruby_less/safe_class.rb', line 59

def self.safe_method_for(klass, methods_hash)
  # This is why defining new safe methods during runtime is BAD.
  @@_safe_methods_parsed = {} # rebuild all cache

  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.



13
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
# File 'lib/ruby_less/safe_class.rb', line 13

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



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ruby_less/safe_class.rb', line 86

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_methods_for(klass) ⇒ Object

List of safe methods for a specific class.



8
9
10
# File 'lib/ruby_less/safe_class.rb', line 8

def self.safe_methods_for(klass)
  @@_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.



217
218
219
220
# File 'lib/ruby_less/safe_class.rb', line 217

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.



223
224
225
226
# File 'lib/ruby_less/safe_class.rb', line 223

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.



203
204
205
206
207
# File 'lib/ruby_less/safe_class.rb', line 203

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.



211
212
213
214
# File 'lib/ruby_less/safe_class.rb', line 211

def safe_send(method)
  return nil unless type = self.class.safe_method_type([method])
  self.send(type[:method])
end