我一直是直接给出返回的数据... 比如我用 HTTPClient 的 get 或是 post 方法,我直接把这些方法换掉,然后根据参数返回预先设置好的数据..
@badboy 我直接写个文件里了,这里东西懒的写 Gem 了,这个不折腾了,我感觉痛苦了。。
应该是我这种做法有问题,就这样算了,以后想到更好的方法再说。。
@badboy 我也怀疑我的需求有问题。。。
不过暂时想不到别的方法来做,只好乱搞了。。
@badboy 然后这样就和我问题里写的一个实现差不了多少了(请看本贴最后的更新内容),initialize 挂了 而且你这里如果是 C < B 的话,B 的模块不会自动加上来的,嘿嘿
@badboy 你真的是转圈圈了。。 请把 extend 改成 include,虽然这个关系不大,最重要的是在 B 和 C 中定义一个方法,然后让模块中的方法来覆盖他
@badboy 这样每个类里在结束都要加 load_config_module 这一句,如我标题所示,我想知道怎么知道这个类结束了,然后自动做这个操作。。。。
@badboy 谢谢你的解答,不过这样还是不能覆盖掉类下面原的方法,如:
class Object
def self.load_config_module
CONFIG[self.to_s].each do |module_name|
eval("include #{module_name}")
end if CONFIG && CONFIG[self.to_s]
end
end
#类
class A
def a
puts 'a-a'
end
load_config_module
end
class B < A
load_config_module
def a
puts 'b-a'
end
end
A.new.a
B.new.a
A 还是输出 a-a,B 输出了 b-b
感觉是我表述的不清楚。。
求更优美的解决方案。。 哈哈
主要就是后面再也不能定义已经被移除的方法了,然后,再来一个 include 相同的方法会覆盖了,不过这样我项目里暂时没什么问题。。 弄好其它的测试还是得多写写了
@wppurking 这样弄起来发现问题确实会很后,怕以后出了问题,不知道哪里找去。。 现在我的实现
module ProjectExt
def inherited(cls)
project_name = get_project_name
ext_project_module(project_name, cls)
cls.class_eval do
def self.method_added(method_name)
remove_method(method_name) if _included_modules_has_method?(method_name)
end
define_singleton_method "_included_modules_has_method?" do |method_name|
self.included_modules.each do |m|
next unless m.to_s =~ /^#{project_name}\:\:/
return true if m.instance_methods(false).include?(method_name)
end
return false
end
end
super
end
def ext_project_module(project_name, cls)
return unless project_name && project_name.safe_constantize
project_controller_name = project_name + "::" + cls.to_s
project_controller = project_controller_name.safe_constantize
return unless project_controller && project_controller_name == project_controller.to_s
cls.send(:include, project_controller)
end
def set_project_name(name)
@project_name = name.classify
end
def get_project_name
@project_name ||= (APP_CONFIG["project"] || "").classify
end
end
然后,测试
# encoding: utf-8
require 'spec_helper'
module M
module B
def a; 'ext-a'; end
end
end
class A
extend ProjectExt
set_project_name("m")
end
class B < A
def a; 'a'; end
def b; 'b'; end
end
class C
def a; 'a'; end
end
module M2
def a; 'other-a'; end
def b; 'other-b'; end
def c; 'other-c'; end
end
describe ProjectExt do
it '自动加载扩展模块,使用扩展模块的方法代替掉原有方法' do
B.new.a.should == "ext-a"
end
it '其它模块引入情况' do
class ::B
# 因为有M::B,所以这里定义不了
def a; 'a'; end
include M2
end
# 因为M2在M::B后面,所以这里会先找到M2中的函数
B.new.a.should == 'other-a'
B.new.b.should == 'b'
B.new.c.should == 'other-c'
end
it '引入非目标扩展模块不受影响' do
C.send :include, M2
C.new.a.should == 'a'
C.new.b.should == 'other-b'
C.new.c.should == 'other-c'
end
end
虽然 问题多,不过暂时在我项目上还不会有影响,先用着
@wppurking 恩,还好这项目我接手后都写了测试,改完可以运行下测试就知道有问题没,不然改后 BUG 出来又不知道什么情况了,哈哈
或是扩展 ruby 的核心什么的来实现??这个我真不知道了。。
@wppurking 这样移除方法,我还得写个判断,只有名字是 Xx::Yyy 下的模块有这个方法我才弄掉这个方法,这样就不怕别的模块来了我也把方法删了。。
绕了一圈,感觉应该差不多了,不过最初的那个如果知道一个类定义完了,这个问题还不知道,不知道有没有回调。。。
@wppurking 这个。。。确实的暴力,不过我一直都是用暴力解决的,我现在用 A 的 initialize 来实现,这样每次 new 都会 extend,至于 extend 为什么可以用,这个我真不知道,我在 Rails 里可以,直接开 irb 试不可以。。。
现在遇到的问题是:
class A
def initialize
# self.send(:extend, module)
end
end
class B < A
end
class C < B
end
# =========
module AM
module B
end
module C
end
end
然后我 C.new 时,只能管不到 B 了
看了你的实现我又学到新方法了,B 里的 include M 应该可以直接在 A 里做了,通过 inherited 回调来为 A 的所有继承者来 include 对应的模块,如果模块中有这个方法就移除类里的这个方法
接着试验去。。
难道是做了特殊的处理? 有点怀疑。。
以前我做过的事,rails 中的 before_filter 来弄
def load_project_module(project)
project_module_name = project.classify
return unless project_module_name.safe_constantize
controller_name = (params[:controller] + "_controller").classify
project_controller_name = project_module_name + "::" + controller_name
project_controller = project_controller_name.safe_constantize
return unless project_controller && project_controller_name == project_controller.to_s
self.send(:extend, project_controller)
end
这个在 Controller 里面确实去调用 extend 里的方法了,这个我真不知道是为什么。。 因为我刚刚试了下一个对象 extend 一个模块是不能覆盖掉已经有的方法。。 不知道什么情况,看来回公司后又要把 Ruby 元编程拿来看看了。。
@wppurking 这样是可以实现,不过每个模块要查找自己有定义的方法,然后 included 的时候再替换,最后就是那个 include M 要每个继承自 A 的类都要加上
我想要每个继承自 A 的类自动找到对应的模块然后加上。比如:B => M, B1 => M1....
就是只修改 A 这个类来实现
感觉是不是我想法有问题。。。。。。
@kenshin54 恩多谢,我先弄弄看
@jjym 怎么做?我没看懂,真不好意思
有很多个 B,B1,B2 的,不同的还得 include 对应的模块,前提是有那个模块在,我总不能一个个去写吧。。
我现在正在给 A 写个 initialize,然后里面 self.send(:extend, M)
试验试验。。。
@badboy 关键是我在什么时候 include。。。 上那我代码里那个,a 方法被 B 的覆盖了,我想要的是模块 M 覆盖类 B 的 a 方法
@badboy 怎么用?
或者教我用其他方法解决呃。。
前提是现在的代码不用做过多改变。。
直接国定假的放...
来打酱油。。。
再用个框架来做更好,比如 backbone,感觉做交互很爽的
我是开始工作时公司用的就是 rubyOnRails 用了两年了,现在发现我开始爱上 ruby 了。。。
bundle 不是可以把 gem 安装到项目里面吗?