• 我一直是直接给出返回的数据... 比如我用 HTTPClient 的 get 或是 post 方法,我直接把这些方法换掉,然后根据参数返回预先设置好的数据..

  • @badboy 我直接写个文件里了,这里东西懒的写 Gem 了,这个不折腾了,我感觉痛苦了。。

    应该是我这种做法有问题,就这样算了,以后想到更好的方法再说。。

  • @badboy 我也怀疑我的需求有问题。。。

    不过暂时想不到别的方法来做,只好乱搞了。。

  • @badboy 然后这样就和我问题里写的一个实现差不了多少了(请看本贴最后的更新内容),initialize 挂了 而且你这里如果是 C < B 的话,B 的模块不会自动加上来的,嘿嘿

  • @badboy 你给的是

    class B < A
    end
    
    class C < A
    end
    

    两个类都是空的

  • @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 怎么用?

  • 或者教我用其他方法解决呃。。

    前提是现在的代码不用做过多改变。。

  • 八卦一下:你放假了吗 at 2013年02月04日

    直接国定假的放...

  • 来打酱油。。。

  • 再用个框架来做更好,比如 backbone,感觉做交互很爽的

  • 我是开始工作时公司用的就是 rubyOnRails 用了两年了,现在发现我开始爱上 ruby 了。。。

  • cancan 的配置 at 2012年11月24日

    @clark 恩,谢谢,但或许是我英文烂到不能再烂了吧,看资料都借用工具半翻译的看,哈哈

    我发现光看没感觉啊,还是要有时间再去写写,这个周末要加班。。。

    另外谢谢大家了,嘿嘿

  • bundle 不是可以把 gem 安装到项目里面吗?