2016-09-11 12 views
1

在我学习ruby & rails的旅程中,我继续安装Rubocop。到目前为止,我的代码以ruby方式重构是非常有帮助的,但现在我认为我已经在这个无助的案例中遇到了困难。考虑下面的方法来创建一个新的实体,我正在寻找一种方式来重构它使Rubocop停在我大声喊叫:如何重构方法来降低RuboCop的ABCsize

  1. 线长
  2. 指派分支条件的大小(目前26.02/15)

,我能想到的就目前而言,除了禁止那些警察OFC的唯一的事,其实是分手了的模型分成两个较小的(说的基本信息和财务),并相应设置它们,但我会产生这样的印象,即这会将复杂性从创建方法中移出并放到其他地方,因为我需要记住创建这两者相关实体等。任何提示都是值得欢迎的。

def create_store_information(store, meta) 
    user = @datasource.user 
    user.store_informations.create!(
    name: store['name'], 
    description: store['description'], 
    status: 1, 
    url: store['URL'].downcase, 
    store_version: store['version'], 
    api_version: store['wc_version'], 
    timezone: meta['timezone'], 
    currency: meta['currency'], 
    currency_format: meta['currency_format'], 
    currency_position: meta['currency_position'], 
    thousand_separator: meta['thousand_separator'], 
    decimal_separator: meta['decimal_separator'], 
    price_num_decimals: meta['price_num_decimals'], 
    tax_included: cast_to_bool(meta['tax_included']), 
    weight_unit: meta['weight_unit'], 
    dimension_unit: meta['dimension_unit'], 
    ssl_enabled: cast_to_bool(meta['ssl_enabled']), 
    permalinks_enabled: cast_to_bool(meta['permalinks_enabled']), 
    generate_password: cast_to_bool(meta['generate_password']), 
    user: user 
) 
end 

编辑: 根据要求,我附加来自不同类创建store_information的第二样品。

def create_store_information(store, meta) 
    user = @datasource.user 
    user.store_informations.create!(
    name: store['id'], 
    description: store['name'], 
    status: 1, 
    url: store['domain'].downcase, 
    store_version: '1.0', 
    api_version: '1.0', 
    timezone: meta['timezone'], 
    currency: meta['currency'], 
    currency_format: meta['money_format'], 
    currency_position: '', # not applicable 
    thousand_separator: '', # not applicable, take from user's locale 
    decimal_separator: '', # not applicable, take from user's locale 
    price_num_decimals: '', # not applicable, take from user's locale 
    tax_included: cast_to_bool(meta['taxes_included']), 
    weight_unit: nil, # not applicable 
    dimension_unit: nil, # not applicable 
    ssl_enabled: cast_to_bool(meta['force_ssl']), 
    permalinks_enabled: true, 
    generate_password: false, 
    user: user 
) 
end 
+0

也许会喜欢的东西'store.slice(*%W [名称描述...])合并(meta.slice(*%重量快乐[。时区货币...]))'。然后将数据清理('store ['URL'],downcase'等)推送到'user.store_informations'模型中。 –

+0

也许,但它会提高整体代码的可读性?猜不是:) – Rafal

+0

可能不是,但我倾向于忽略这些愚蠢的工具和他们的教条shenanigans :) –

回答

1

这只是1条建议中的很多可能性。

您可以使用Ruby的元编程功能来动态发送方法。 meta对象的字段很容易分配user.store_informations,因为字段匹配1为1. 对于store对象也是可能的,但它不会那么简单。

您可以将字段的数组类定义中:

CAST_TO_BOOL = %w(
    tax_included 
    ssl_enabled 
    permalinks_enabled 
    generate_password 
).freeze 

META_FIELDS = %w(
    timezone 
    currency 
    currency_format 
    currency_position 
    thousand_separator 
    decimal_separator 
    price_num_decimals 
    tax_included 
    weight_unit 
    dimension_unit 
    ssl_enabled 
    permalinks_enabled 
    generate_password 
).freeze 

,那么你可以定义哪些动态设置的user.store_informations

private 

def set_meta_fields_to_store_information(user) 
    META_FIELDS.each do |field| 
    if CAST_TO_BOOL.include? field 
     user.store_informations.__send__ "#{f}=" { cast_to_bool(meta[field]) } 
     next 
    end 
    user.store_informations.__send__ "#{f}=" { meta[field] } 
    end 
end 

meta领域,那么你可以一个私有方法请拨打该方法:

def create_store_information(store, meta) 
    user = @datasource.user 
    user.store_informations.new(
    name: store['name'], 
    description: store['description'], 
    status: 1, 
    url: store['URL'].downcase, 
    store_version: store['version'], 
    api_version: store['wc_version'], 
    user: user 
) 
    set_meta_fields_to_store_information(user) 
    user.save! 
end 

编辑#2

关于用不同类别的对象填充字段;

解决这个问题的一种方法是定义一个方法,根据商店的类别为您分配字段。 但是,如果你有数千个不同的商店,这可能不会是最佳的。

class StoreA; end 
class StoreB; end 
class StoreC; end 

则:

# you could also use dynamic method dispatching here instead: 

def set_store_information_to_user(store, user) 
    case store 
    when StoreA 
    assign_store_a_method(store, user) 
    when StoreB 
    assign_store_b_method(store, user) 
    when StoreC 
    assign_store_c_method(store, user) 
    end 
end 

private 
def assign_store_a_method(store, user); end 
def assign_store_b_method(store, user); end 
def assign_store_c_method(store, user); end 
+0

感谢您的建议。当然,这里就是这种情况,因为在给定样本中映射确实是一对一的,但我们很容易想象到情况并非总是如此。取决于查询哪个商店,商店和元哈希可以完全不同。任何其他选项? – Rafal

+0

如果你可以用一个不同'store'和'meta'对象的例子来编辑你的问题,那将是我的荣幸! – Shiyason

+0

当然,我编辑了这个问题。 – Rafal