DRY模块必需的元编程?

时间:2011-10-31 21:57:17

标签: ruby-on-rails ruby metaprogramming maintenance

我将应用程序中的代码命名为练习。通过“运动”,我的意思完全是为了好玩。假设示例角色PerformerManager代表必须与帮助方法一起定义的20个角色中的2个。

class Role
  module Performer
    extend ActiveSupport::Concern

    module InstanceMethods
      def performer?(id = @current_user_id)
        true unless self.roles.where(user_id: id, name: 'Performer').empty?
      end

      def make_performer(id = @current_user_id)
        self.roles.new(user_id: id, name: 'Performer')
      end
    end

  end

  module Manager
    extend ActiveSupport::Concern

    module InstanceMethods
      def manager?(id = @current_user_id)
        true unless self.roles.where(user_id: id, name: 'Manager').empty?
      end

      def make_manager(id = @current_user_id)
        self.roles.new(user_id: id, name: 'Manager')
      end
    end

  end
end

根据需要将选择角色混合到其他模块中。每个模块都混合了一组不同的角色,

class Group
  module Roles
    extend ActiveSupport::Concern

    included do
      include Role::Manager
      include Role::Performer
      before_create :make_creator_manager

      protected
        def make_creator_manager
          make_manager @current_user_id if @current_user_id
        end
    end

  end
end

然后通过多态关联与个体模型相关联。

class Group < ActiveRecord::Base
  include Group::Roles
  attr_accessor :current_user_id
  has_many :roles, as: :restrictable
end

我可以用闭包来干掉方法的内容,但由于方法的名称也遵循一种模式,metaprogramming会更有意义吗? ruby example

元编程在红宝石中是否足够普遍,无论谁(理论上)接管这个项目都能够毫无困难地维护它?


编辑1:角色迁移可能与此讨论相关

class CreateRoles < ActiveRecord::Migration
  def change
    create_table :roles do |t|
      t.belongs_to :user
      t.references :restrictable, polymorphic: true
      t.string :name

      t.timestamps
    end
    add_index :roles, :user_id
    add_index :roles, [:restrictable_id, :restrictable_type]
  end
end

2 个答案:

答案 0 :(得分:1)

这很常见,但它是否可维护更多地与您提供的文档和开发人员的心态有关。

理想情况下,元编程会消失在应用程序中,很少需要触及。为此,它会做同样的事情 - 做出特定于角色的方法。元编程本身有多大可能需要维护?

只要有一条路径来自“嘿,那个功能来自哪里?”对于注入功能的代码,我认为这很好,特别是因为此功能的“元”范围非常有限。

我看到的唯一潜在问题是需要明确定义法律角色名称的样子,并确保它显然是什么方法名称,如果它不是简单的alpha字符,它将映射到哪个。

答案 1 :(得分:0)

看起来真的很复杂,你确定没有更简单的方法吗?

首先,看起来像STI(单表继承)或只是常规oo继承(如果你没有使用活动记录)会更合适:

user.type?(Manager)代替manager?(user_id)

user.update_attributes(:type => 'Manager')代替make_manager(user_id)

如果您要进行元编程,我现在会使用它来修改method_missing以将上述方法转发到user.manager?user.make_manager!