Ruby中的“Namespaced”方法

时间:2014-09-09 05:59:13

标签: ruby namespaces grouping sections

有一个带有“命名空间”方法的类:

class MyOrder
  def add
  end

  def edit
  end
end

class MyCompany
  def list
  end
end

class MyDriver
  def add
  end

  def edit
  end
end

class MyAPI
  attr_reader :order, :company, :driver

  def initialize
    @order = MyOrder.new
    @company = MyCompany.new
    @driver = MyDriver.new
  end
end

我们的想法是将方法分组为几个部分来调用它们:

api = MyApi.new
api.order.add
api.company.list

有没有办法在不创建容器类的情况下对方法进行分组?

2 个答案:

答案 0 :(得分:1)

class MyAPI
  def initialize
    @namespace = []
  end
  def self.namespace sym
    define_method(sym){@namespace.push(sym); self}
  end
  namespace :order
  namespace :company
  namespace :driver
  def add
    case @namespace
    when [:order] then ...
    when [:driver] then ...
    else raise "invalid namespace"
    end
    @namespace = []
    self
  end
  def edit
    case @namespace
    when [:order] then ...
    when [:driver] then ...
    else raise "invalid namespace"
    end
    @namespace = []
    self
  end
  def list
    case @namespace
    when [:company] then ...
    else raise "invalid namespace"
    end
    @namespace = []
    self
  end
end

方法结尾处的self是让你能够像

那样进行链接
MyApi.new.order.add.company.list

如果您不需要这样做,则不需要self

答案 1 :(得分:0)

好的,我明白了,请尝试以下方法:

module MyApi
  [MyOrder, MyCompany, MyDriver].each do |klass|    
    names = klass.to_s.scan(/[A-Z][a-z]+/)

    funcname = names[1].downcase
    define_singleton_method(funcname) do 
      instance_variable_get("@#{funcname}") ||
      instance_variable_set("@#{funcname}", klass.new)
    end
  end
end

MyApi.order.add

如果您更喜欢order_add,那么:

module MyApi
  [MyOrder, MyCompany, MyDriver].each do |klass|    
    names = klass.to_s.scan(/[A-Z][a-z]+/)

    prefix_name = names[1].downcase

    klass.public_instance_methods(false).each do |method|
      funcname = "#{prefix_name}_#{method}"
      define_singleton_method(funcname) do |*args|
        @obj = instance_variable_get("@#{prefix_name}") ||
               instance_variable_set("@#{prefix_name}", klass.new)
        @obj.send(method, *args)
      end
    end
  end
end