lib/classproxy/classproxy.rb in classproxy-0.7.4 vs lib/classproxy/classproxy.rb in classproxy-0.7.9
- old
+ new
@@ -30,14 +30,14 @@
# @example Store Github API name in a different attribute
# class GithubUser
# include ClassProxy
#
# fallback_fetch { |args| Octokit.user(args[:login]) }
- # after_fallback_fetch do |model, obj|
+ # after_fallback_fetch do |obj|
# # obj is what `fallback_fetch` returns
- # model.name = obj.name
- # model.login = obj.login
+ # self.name = obj.name
+ # self.login = obj.login
# end
#
# attr_accessor :name, :login
# end
def after_fallback_fetch(&block); @after_fallback_method = block; end
@@ -48,11 +48,11 @@
# @example Load method using uppercase
# class GithubUser
# include ClassProxy
#
# fallback_fetch { |args| Octokit.user(args[:login]) }
- # after_fallback_fetch { |model, obj| model.name = obj.name; model.login = obj.login }
+ # after_fallback_fetch { |obj| self.name = obj.name; self.login = obj.login }
#
# attr_accessor :name, :followers :login
#
# proxy_methods :name, :followers, uppercase_login: lambda { login.upcase }
# end
@@ -99,30 +99,38 @@
end
private
def run_fallback(args, _self=nil)
- fallback_obj = @fallback_fetch[args]
+ obj = _self || self.new
+ fallback_obj = obj.instance_exec args, &@fallback_fetch
+
# Use the after_fallback_method
- obj = _self || self.new
- @after_fallback_method[obj, fallback_obj] if @after_fallback_method.is_a?(Proc)
+ obj.instance_exec fallback_obj, &@after_fallback_method if @after_fallback_method.is_a? Proc
# Go through the keys of the return object and try to use setters
if fallback_obj and obj and fallback_obj.respond_to? :keys and fallback_obj.keys.respond_to? :each
fallback_obj.keys.each do |key|
- next unless obj.respond_to? "#{key}=" and obj.send(key) == nil
- obj.send("#{key}=", fallback_obj.send(key))
+ next unless obj.respond_to? "#{key}="
+
+ # check if its set to something else
+ get_method = obj.respond_to?("no_proxy_#{key}") ? "no_proxy_#{key}" : key
+ if obj.respond_to? get_method and obj.send(get_method) == nil
+ obj.send("#{key}=", fallback_obj.send(key))
+ end
end
end
return obj
end
def proxy_method(method_name, proc=nil)
self.class_eval do
- alias_method "no_proxy_#{method_name}".to_sym, method_name
+ unless self.instance_methods.include? "no_proxy_#{method_name}".to_sym
+ alias_method "no_proxy_#{method_name}".to_sym, method_name
+ end
define_method(method_name) do |*args|
# Use the no_proxy one first
v = self.send("no_proxy_#{method_name}".to_sym, *args)
@@ -131,13 +139,15 @@
# Since AR calls the getter method when using the setter method
# to establish the dirty attribute, since the getter is being replaced
# here and the setter is being used when appropriate, the @mutex_in_call_for
# prevents endless recursion.
- if v == nil and @mutex_in_call_for != method_name
- @mutex_in_call_for = method_name
+ @mutex_in_call_for ||= []
+ if v == nil and not @mutex_in_call_for.include? method_name
+ @mutex_in_call_for << method_name
method = "_run_fallback_#{method_name}".to_sym
+
if self.respond_to?(method)
v = if self.method(method).arity == 1
# Callback method is expecting to receive the fallback object
fallback_fetch_method = self.class.instance_variable_get(:@fallback_fetch)
fallback_obj = fallback_fetch_method[self]
@@ -146,25 +156,20 @@
# Callback method doesn't need the fallback object
self.send(method)
end
else
# This method has no callback, so just run the fallback
- args = {}
- (self.methods - self.class.methods).each do |key|
- next if key[-1] == '=' # don't run for set
- hkey = key.to_s.gsub(/^no_proxy_/, '')
- args[hkey.to_sym] = self.send(key)
- end
- self.class.send :run_fallback, args, self
+ args_class = ArgsClass.new(self)
+ self.class.send :run_fallback, args_class, self
# The value might have changed, so check here
v = self.send("no_proxy_#{method_name}".to_sym)
end
# Set the defaults when this class responds to the same method
self.send("#{method_name}=".to_sym, v) if v and self.respond_to?("#{method_name}=")
- @mutex_in_call_for = nil
+ @mutex_in_call_for.delete method_name
end
return v
end
end
@@ -175,6 +180,27 @@
end
def self.included(receiver)
receiver.extend ClassMethods
end
-end
+
+ # This class makes methods accessible as a hash key, useful to pass
+ # as a fallback_fetch argument
+ class ArgsClass < BasicObject
+ def initialize(object)
+ @target = object
+ end
+
+ def [](key)
+ @target.respond_to?(key) ? @target.send(key) : @target[key]
+ end
+
+ def inspect
+ "ArgsClass [#{@target.inspect}] " +
+ (@target.methods - @target.class.methods).join(', ')
+ end
+
+ def target
+ @target
+ end
+ end
+end
\ No newline at end of file