Ruby 向命名空间中的字符串添加方法

Ruby 向命名空间中的字符串添加方法,ruby,metaprogramming,Ruby,Metaprogramming,我正在String上定义一些新方法。我需要确保这些方法不会与其他库中定义的方法冲突(作为参考,我创建了一个屈折因子,然后在字符串上添加了pluralize和singularize) 我的第一个想法是将新内容包装在一个模块中,如下所示: module MM class String def rev self.split('').reverse.join('') end end end class Test include MM def me(s)

我正在
String
上定义一些新方法。我需要确保这些方法不会与其他库中定义的方法冲突(作为参考,我创建了一个屈折因子,然后在
字符串上添加了
pluralize
singularize

我的第一个想法是将新内容包装在一个模块中,如下所示:

module MM
  class String
    def rev
      self.split('').reverse.join('')
    end
  end
end

class Test
  include MM

  def me(s)
    s.rev
  end
end

puts Test.new.me('this is a test')
但这当然行不通<代码>字符串#版本
保持未定义状态。我的代码中真正包含的是一个模块
MM
,除了内置的类型扩展之外,所有内容都包装在
MM
中。我的目标是让
String
具有类似
rev
单数化
复数化
的方法,但仅在该模块内,
MM

这似乎应该是可行的。但不知何故,我错过了秘密咒语,这将使它如此


如果有人能提供一些建议,我们将不胜感激。

还有另一种方法可以让字符串类保持分离。在你添加需求之前,它将是免费的

#my_string.rb
class String
  def rev
      self.split('').reverse.join('')
   end
end

#test.rb
class Test
  require 'F:\on going\New Site\Ruby\my_string.rb' # Assuming both these files are in the same folder


  def me(s)
    s.rev
  end
end


puts Test.new.me('this is a test')

还有另一种方法可以将字符串类分开。在你添加需求之前,它将是免费的

#my_string.rb
class String
  def rev
      self.split('').reverse.join('')
   end
end

#test.rb
class Test
  require 'F:\on going\New Site\Ruby\my_string.rb' # Assuming both these files are in the same folder


  def me(s)
    s.rev
  end
end


puts Test.new.me('this is a test')
你在寻找“改进”。它们是Ruby 2.0中的一个实验性特性,因此如果不使用2.0,您可能会运气不佳。我自己还没有使用过它们,但您的示例几乎就是改进的规范用例。使用
refine
using
关键字获得所需的行为:

module MM
  refine class String
    def rev
      self.split('').reverse.join('')
    end
  end
end

class Test
  using MM

  def me(s)
    s.rev
  end
end

puts Test.new.me('this is a test')
你在寻找“改进”。它们是Ruby 2.0中的一个实验性特性,因此如果不使用2.0,您可能会运气不佳。我自己还没有使用过它们,但您的示例几乎就是改进的规范用例。使用
refine
using
关键字获得所需的行为:

module MM
  refine class String
    def rev
      self.split('').reverse.join('')
    end
  end
end

class Test
  using MM

  def me(s)
    s.rev
  end
end

puts Test.new.me('this is a test')

如果没有细化,可以扩展单个字符串对象:

module StringHelper
  def rev
    self.split('').reverse.join('')
  end
end

class Test
  def me(s)
    s.extend(StringHelper).rev
  end
end
或子类字符串:

class StringPlus < String
  def rev
    self.split('').reverse.join('')
  end
  def self.[](s)
    new(s)
  end
end

class Test
  def me(s)
    StringPlus[s].rev
  end
end
class-StringPlus
缺少细化,您可以扩展单个字符串对象:

module StringHelper
  def rev
    self.split('').reverse.join('')
  end
end

class Test
  def me(s)
    s.extend(StringHelper).rev
  end
end
或子类字符串:

class StringPlus < String
  def rev
    self.split('').reverse.join('')
  end
  def self.[](s)
    new(s)
  end
end

class Test
  def me(s)
    StringPlus[s].rev
  end
end
class-StringPlus
作为一种在没有改进的情况下的解决方法,我发现这种方法是有效的:

# class String
#   def rev
#     puts "rev: #{self}"
#   end
# end

class String
  unless String.instance_methods.include?(:rev)
    def rev
      self.split('').reverse.join('')
    end
  end
end

class Test
  def me(s)
    s.rev
  end
end

puts Test.new.me('this is a test')

如果您取消注释
rev
的早期定义,则将遵循该定义,而不会覆盖该定义。这有点老套,取决于文件加载的顺序,但如果加载顺序受到控制,它确实会起作用。

在没有改进的情况下,作为一种解决方法,我发现这类事情是有效的:

# class String
#   def rev
#     puts "rev: #{self}"
#   end
# end

class String
  unless String.instance_methods.include?(:rev)
    def rev
      self.split('').reverse.join('')
    end
  end
end

class Test
  def me(s)
    s.rev
  end
end

puts Test.new.me('this is a test')

如果您取消注释
rev
的早期定义,则将遵循该定义,而不会覆盖该定义。这有点老套,取决于文件加载的顺序,但如果加载顺序得到控制,它确实会起作用。

我不完全确定我是否理解;您只想在您自己的类中扩展字符串?只想在我自己的模块中扩展字符串。我只需要避免这些影响到其他实现,反之亦然。我知道我可以重命名它们来解决这个问题,但这似乎是名称空间的设计目的;在类中动态定义/取消定义方法有些不同。如果您想在模块中定义方法并将它们放入字符串中,这与仅在特定范围内提供这些方法不同。我认为Ruby 2.0引入了一些新的monkey补丁功能,这些功能(可能)有助于解决这些问题。在Ruby 2.0下,您只能将monkey补丁放在全局空间中,这将影响所有类别(不符合您的要求);在ruby 2.0中,您可以使用下面答案中显示的
细化
,这是您唯一的选择,但我不能完全理解;您只想在您自己的类中扩展字符串?只想在我自己的模块中扩展字符串。我只需要避免这些影响到其他实现,反之亦然。我知道我可以重命名它们来解决这个问题,但这似乎是名称空间的设计目的;在类中动态定义/取消定义方法有些不同。如果您想在模块中定义方法并将它们放入字符串中,这与仅在特定范围内提供这些方法不同。我认为Ruby 2.0引入了一些新的monkey补丁功能,这些功能(可能)有助于解决这些问题。在Ruby 2.0下,您只能将monkey补丁放在全局空间中,这将影响所有类别(不符合您的要求);在ruby 2.0中,您可以使用下面答案中显示的
细化
,这是您唯一的选择为“这是一个测试”给出
命名方法错误:未定义的方法“rev”:String
这是因为
rev
没有被添加到
String
的方法中。方法“m”之所以有效,是因为它只是类
Test
上的一个实例方法。我希望
s.rev
起作用。gives
NoMethodError:this is test的未定义方法'rev':String
这是因为
rev
没有添加到
String
的方法中。方法“m”之所以有效,是因为它只是类
Test
上的一个实例方法。我想要
s.rev
工作。顺便说一句:这不行。我只是在几分钟前才发现这一点,当时我正在写你上面写的内容;-)它直到最近才开始工作,但在2.0.0-p0发布前不久,改进规范发生了变化。特别是,
using
被定义为顶级
main
对象的私有单例方法,这意味着它仅在顶级范围内可用。因此,优化总是应用于整个文件和所有模块