代码之家  ›  专栏  ›  技术社区  ›  t6d

带模块的Ruby核心扩展

  •  1
  • t6d  · 技术社区  · 16 年前

    基本上我有两个模块: CoreExtensions::CamelcasedJsonString …::CamelcasedJsonSymbol . 后者优先于后者 Symbol#to_s ,以便该方法返回 String CamelcasedJsonString . 这就是我尝试应用扩展实例特定的原因。

    符号#至#美国

    require 'rubygems' if RUBY_VERSION < '1.9'
    require 'spec'
    
    module CoreExtensions
    
      module CamelcasedJsonString; end
    
      module CamelcasedJsonSymbol
    
        alias to_s_before_core_extension to_s
        def to_s(*args)
          to_s_before_core_extension(*args).extend(CamelcasedJsonString)
        end
    
      end
      ::Symbol.send :include, CamelcasedJsonSymbol
    
    end
    
    describe Symbol do
    
      subject { :chunky_bacon }
    
      it "should be a CamelcasedJsonSymbol" do
        subject.should be_a(CoreExtensions::CamelcasedJsonSymbol)
      end
    
      it "should respond to #to_s_before_core_extension" do
        subject.should respond_to(:to_s_before_core_extension)
      end
    
      specify "#to_s should return a CamelcasedJsonString" do
        subject.to_s.should be_a(CoreExtensions::CamelcasedJsonString)
      end
    
    end
    

    但是,以下示例有效:

    require 'rubygems' if RUBY_VERSION < '1.9'
    require 'spec'
    
    module CoreExtensions
      module CamelcasedJsonString; end
    end
    
    class Symbol
      alias to_s_before_core_extension to_s
      def to_s(*args)
        to_s_before_core_extension(*args).extend(CoreExtensions::CamelcasedJsonString)
      end
    end
    
    describe Symbol do
    
      subject { :chunky_bacon }
    
      it "should respond to #to_s_before_core_extension" do
        subject.should respond_to(:to_s_before_core_extension)
      end
    
      specify "#to_s should return a CamelcasedJsonString" do
        subject.to_s.should be_a(CoreExtensions::CamelcasedJsonString)
      end
    
    end
    

    更新:2010年1月24日

    我的问题的背景是,我试图转换一个巨大的嵌套哈希 Symbol 典型的下划线符号。使用JSON的JavaScript库 data希望键是camelcase表示法中的字符串。我以为 凌驾 Symbol#to_json 方法可能是最简单的方法。但那 从那以后就没有工作了 Hash#to_json 先打电话 #to_s 然后呢 #to_json 在每把钥匙上。因此,我认为这可能是一个扩展的解决方案 返回的所有字符串 符号#至#美国 具有覆盖 #到u json 方法返回具有 A. #到u json 方法,该方法以camelcase表示法返回自身。

    我不确定是否有一个简单的方法来修补猴子补丁 散列到json .

    如果有人想了解我正在使用的JSON实现,下面是链接: http://github.com/flori/json/blob/master/lib/json/pure/generator.rb

    2 回复  |  直到 16 年前
        1
  •  2
  •   Marc-André Lafortune    16 年前

    第一个没有,因为include所做的只是将模块添加到包含的模块列表中。只有当类本身没有定义特定的方法,或者该方法调用super时,才会调用这些函数。所以你的代码永远不会被调用。

    如果要使用模块,必须使用 included 回拨:

      module CamelcasedJsonSymbol
        def self.included(base)
          base.class_eval do
            alias_method_chain :to_s, :camelcase_json
          end
        end
    
        def to_s_with_camelcase_json(*args)
          to_s_without_camelcase_json(*args).extend(CamelcasedJsonString)
        end
      end
    

    alias_method_chain

    这是技术上的答案。

    从更务实的角度来看,你应该重新思考这一点。像这样反复扩展字符串是不好的,这将对大多数实现造成巨大的性能消耗(例如,它会清除MRI上的整个方法缓存),并且是一种巨大的代码气味。


    #to_json #to_s ,例如:

    { :chunky_bacon => "good" }.to_json(:camelize => true)
    

    我的第一个想法是去monkeypatch Symbol#to_json

    module CamelizeKeys
      def self.included(base)
        base.class_eval do
          alias_method_chain :to_json, :camelize_option
        end
      end
    
      def to_json_with_camelize_option(*args)
        if args.empty? || !args.first[:camelize]
          to_json_without_camelize_option(*args)
        else
          pairs = map do |key, value|
            "#{key.to_s.camelize.to_json(*args)}: #{value.to_json(*args)}"
          end
          "{" << pairs.join(",\n") << "}"
        end
      end
    end
    
        2
  •  0
  •   Wayne Conrad    16 年前

    这看起来有点复杂。我可能不明白你想要实现什么,但是像这样的事情呢?

    #!/usr/bin/ruby1.8
    
    class Symbol
    
      alias_method :old_to_s, :to_s
      def to_s(*args)
        if args == [:upcase]
          old_to_s.upcase
        else
          old_to_s(*args)
        end
      end
    
    end
    
    puts :foo                   # => foo
    puts :foo.to_s(:upcase)     # => FOO
    

    和部分规格:

    describe :Symbol do
    
      it "should return the symbol as a string when to_s is called" do
        :foo.to_s.should eql 'foo'
      end
    
      it "should delegate to the original Symbol.to_s method when to_s is called with unknown arguments" do
        # Yeah, wish I knew how to test that
      end
    
      it "should return the symbol name as uppercase when to_s(:upcase) is called" do
        :foo.to_s(:upcase).should eql "FOO"
      end
    
    end
    
    推荐文章