lib/delorean/base.rb in delorean_lang-0.3.2 vs lib/delorean/base.rb in delorean_lang-0.3.3

- old
+ new

@@ -5,66 +5,69 @@ # FIXME: the whitelist is quite hacky. It's currently difficult to # override it. A user will likely want to directly modify this # hash. The whole whitelist mechanism should be eventually # rethought. RUBY_WHITELIST = { - compact: [Array], - flatten: [Array, [Fixnum, nil]], - length: [[Array, String]], - max: [Array], - member: "member?", - member?: [Array, [Fixnum, String]], - reverse: [Array], - slice: [Array, Fixnum, Fixnum], - sort: [Array], - split: [String, String], - uniq: [Array], - sum: [Array], - zip: [Array, [Array, Array, Array]], - index: [Array, [Integer, Numeric, String, Array, Fixnum]], - product: [Array, Array], - first: [Enumerable, [nil, Fixnum]], + compact: [Array], + to_set: [Array], + flatten: [Array, [Fixnum, nil]], + length: [[Array, String]], + max: [Array], + member: "member?", + member?: [Array, [Fixnum, String]], + reverse: [Array], + slice: [Array, Fixnum, Fixnum], + sort: [Array], + split: [String, String], + uniq: [Array], + sum: [Array], + zip: [Array, [Array, Array, Array]], + index: [Array, [Integer, Numeric, String, Array, Fixnum]], + product: [Array, Array], + first: [Enumerable, [nil, Fixnum]], + intersection: [Set, Enumerable], + union: [Set, Enumerable], - keys: [Hash], - values: [Hash], - upcase: [String], - downcase: [String], - match: [String, [String], [nil, Fixnum]], + keys: [Hash], + values: [Hash], + upcase: [String], + downcase: [String], + match: [String, [String], [nil, Fixnum]], - hour: [[Date, Time, ActiveSupport::TimeWithZone]], - min: [[Date, Time, ActiveSupport::TimeWithZone, Array]], - sec: [[Date, Time, ActiveSupport::TimeWithZone]], - to_date: [[Date, Time, ActiveSupport::TimeWithZone]], + hour: [[Date, Time, ActiveSupport::TimeWithZone]], + min: [[Date, Time, ActiveSupport::TimeWithZone, Array]], + sec: [[Date, Time, ActiveSupport::TimeWithZone]], + to_date: [[Date, Time, ActiveSupport::TimeWithZone]], - month: [[Date, Time, ActiveSupport::TimeWithZone]], - day: [[Date, Time, ActiveSupport::TimeWithZone]], - year: [[Date, Time, ActiveSupport::TimeWithZone]], + month: [[Date, Time, ActiveSupport::TimeWithZone]], + day: [[Date, Time, ActiveSupport::TimeWithZone]], + year: [[Date, Time, ActiveSupport::TimeWithZone]], - next_month: [[Date, Time, ActiveSupport::TimeWithZone], - [nil, Fixnum], - ], - prev_month: [[Date, Time, ActiveSupport::TimeWithZone], - [nil, Fixnum], - ], + next_month: [[Date, Time, ActiveSupport::TimeWithZone], + [nil, Fixnum], + ], + prev_month: [[Date, Time, ActiveSupport::TimeWithZone], + [nil, Fixnum], + ], beginning_of_month: [[Date, Time, ActiveSupport::TimeWithZone]], end_of_month: [[Date, Time, ActiveSupport::TimeWithZone]], - next_day: [[Date, Time, ActiveSupport::TimeWithZone], - [nil, Fixnum], - ], - prev_day: [[Date, Time, ActiveSupport::TimeWithZone], - [nil, Fixnum], - ], + next_day: [[Date, Time, ActiveSupport::TimeWithZone], + [nil, Fixnum], + ], + prev_day: [[Date, Time, ActiveSupport::TimeWithZone], + [nil, Fixnum], + ], - to_i: [[Numeric, String]], - to_f: [[Numeric, String]], - to_d: [[Numeric, String]], - to_s: [Object], - abs: [Numeric], - round: [Numeric, [nil, Integer]], + to_i: [[Numeric, String]], + to_f: [[Numeric, String]], + to_d: [[Numeric, String]], + to_s: [Object], + abs: [Numeric], + round: [Numeric, [nil, Integer]], } module BaseModule class NodeCall < Struct.new(:_e, :engine, :node, :params) def evaluate(attr) @@ -108,28 +111,25 @@ return obj.read_attribute(attr) if klass.attribute_names.member? attr return obj.send(attr.to_sym) if klass.reflect_on_all_associations.map(&:name).member? attr.to_sym - - # FIXME: should call _instance_call for other types as well. - # Too lazy to implement this now. - begin - return _instance_call(obj, attr, []) - rescue - raise InvalidGetAttribute, "ActiveRecord lookup '#{attr}' on #{obj}" - end elsif obj.instance_of?(NodeCall) return obj.evaluate(attr) elsif obj.instance_of?(Hash) return obj[attr] if obj.member?(attr) return attr.is_a?(String) ? obj[attr.to_sym] : nil elsif obj.instance_of?(Class) && (obj < BaseClass) return obj.send((attr + POST).to_sym, _e) end - raise InvalidGetAttribute, - "bad attribute lookup '#{attr}' on <#{obj.class}> #{obj}" + + begin + return _instance_call(obj, attr, [], _e) + rescue + raise InvalidGetAttribute, + "bad attribute lookup '#{attr}' on <#{obj.class}> #{obj}" + end end ###################################################################### def self._index(obj, args, _e) @@ -154,11 +154,11 @@ ###################################################################### def self._sanitize_hash(_e) _e.each_with_object({}) do |(k,v), h| - h[k] = v if k =~ /\A[a-z][A-Za-z0-9_]*\z/ + h[k] = v if k.is_a?(Integer) || k =~ /\A[a-z][A-Za-z0-9_]*\z/ end end ###################################################################### @@ -180,22 +180,29 @@ NodeCall.new(_e, engine, node || self, params) end ###################################################################### - def self._instance_call(obj, method, args) + def self._instance_call(obj, method, args, _e) begin msg = method.to_sym rescue NoMethodError raise "bad method #{method}" end + # FIXME: this is pretty hacky -- should probably merge + # RUBY_WHITELIST and SIG mechanisms. + if obj.is_a?(Class) + _e[:_engine].parse_check_call_fn(method, args.count, obj) + return obj.send(msg, *args) + end + sig = RUBY_WHITELIST[msg] raise "no such method #{method}" unless sig # if sig is a string, then method mapped to another name - return _instance_call(obj, sig, args) if sig.is_a? String + return _instance_call(obj, sig, args, _e) if sig.is_a? String raise "too many args to #{method}" if args.length>(sig.length-1) arglist = [obj] + args