可重复使用的代码块 - Ruby 块、过程、Lambda
Reusable Code Chunks - Ruby Blocks, Procs, Lambdas
ruby 的新手。写了一个程序,现在正在尝试元编程。如您所见,我有下面的代码。已标明常用语句。我如何将这些写在一个地方并一次又一次地使用它们。
这些语句是循环的一部分。所以就像我只想能够插入语句一样。尝试了一个似乎有效的过程。但是还没有真正理解它。行话让我明白了。
我应该认真阅读什么以及什么是好的来源。
有3个循环要做。循环的开始因条件而异,每个循环中只有一个语句不同。我怎么写这个清洁和干燥
@ids.each do |key, ids|
key_ids = []
case key
when :flows then next
when :morals
ids.each_with_index do |id, index|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id #Common B
relation[:values] = S(@ids[:values][index])
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
when :values
ids.flatten.uniq.each do |id|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id; #Common B
ids.each_with_index { |array, index| !array.include?(id) ? relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) : () }
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
else
ids.each do |id|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id #Common B
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
end
!key_ids.empty? ? TaleRelation.where(for: key , key => key_ids).each { |activerecord| activerecord[:state] = nil; @stack << activerecord } : ()
end
你问的是block和yield。
它是这样工作的:
def add_with_extra(a, b)
c = a + b
d = yield(c)
c + d
end
# > add_with_extra(3, 5) { |c| c * 2 }
# => 24
# > add_with_extra(3, 5) { |c| c / 2 }
# => 12
但在你的情况下它看起来像这样:
case key
when :morals
ids.each_with_index do |id, index|
do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id|
relation[:values] = S(@ids[:values][index])
end
end
when :values
ids.flatten.uniq.each do |id|
do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id|
ids.each_with_index { |array, index| relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id }
end
end
else
ids.each do |id|
do_processing(ids, basic_relation, key_ids, key, id, index)
end
end
这不是很好读和理解。相反,我建议进行一些重构:
def prepare_relation(basic_relation, key, id)
relation = basic_relation.dup
relation[:for] = key
relation[key] = id
relation
end
def add_to_stack(relation, key_ids, key, id)
@stack << relation
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id }
end
basic_relation = {for: nil, state: nil}
@objects.each_key { |key| basic_relation[key] = nil unless key == :flows }
basic_relation.merge!(ids_string)
@ids.each do |key, ids|
next if key == :flows
key_ids = []
lookup_ids = key == :values ? ids.flatten.uniq : ids
lookup_ids.each_with_index do |id, index|
relation = prepare_relation(basic_relation, key, id)
relation[:values] = S(@ids[:values][index]) if key == :morals
if key == :values
ids.each_with_index do |array, index|
relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id
end
end
add_to_stack(relation, key_ids, key, id)
end
unless key_ids.empty?
TaleRelation.where(for: key , key: key_ids).each do |activerecord|
activerecord[:state] = nil
@stack << activerecord
end
end
end
这里我概括了你的主要区别switch
:
when :morals
ids.each_with_index do |id, index|
...
when :values
ids.flatten.uniq.each do |id|
...
else
ids.each do |id|
真正的区别仅在于 :values 的情况,因为 each_with_index
也适用于最后一种情况——我们只是不会使用索引。
然后不常见的变成简单的两个if:
relation[:values] = S(@ids[:values][index]) if key == :morals
if key == :values
ids.each_with_index do |array, index|
relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id
end
end
P.S。您不应该调用方法 A 或 S。方法名称必须小写并且应该有意义。
ruby 的新手。写了一个程序,现在正在尝试元编程。如您所见,我有下面的代码。已标明常用语句。我如何将这些写在一个地方并一次又一次地使用它们。 这些语句是循环的一部分。所以就像我只想能够插入语句一样。尝试了一个似乎有效的过程。但是还没有真正理解它。行话让我明白了。 我应该认真阅读什么以及什么是好的来源。 有3个循环要做。循环的开始因条件而异,每个循环中只有一个语句不同。我怎么写这个清洁和干燥
@ids.each do |key, ids|
key_ids = []
case key
when :flows then next
when :morals
ids.each_with_index do |id, index|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id #Common B
relation[:values] = S(@ids[:values][index])
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
when :values
ids.flatten.uniq.each do |id|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id; #Common B
ids.each_with_index { |array, index| !array.include?(id) ? relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) : () }
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
else
ids.each do |id|
relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A
relation.merge!(ids_string); relation[:for] = key; relation[key] = id #Common B
@stack << relation #Common C
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D
end
end
!key_ids.empty? ? TaleRelation.where(for: key , key => key_ids).each { |activerecord| activerecord[:state] = nil; @stack << activerecord } : ()
end
你问的是block和yield。 它是这样工作的:
def add_with_extra(a, b)
c = a + b
d = yield(c)
c + d
end
# > add_with_extra(3, 5) { |c| c * 2 }
# => 24
# > add_with_extra(3, 5) { |c| c / 2 }
# => 12
但在你的情况下它看起来像这样:
case key
when :morals
ids.each_with_index do |id, index|
do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id|
relation[:values] = S(@ids[:values][index])
end
end
when :values
ids.flatten.uniq.each do |id|
do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id|
ids.each_with_index { |array, index| relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id }
end
end
else
ids.each do |id|
do_processing(ids, basic_relation, key_ids, key, id, index)
end
end
这不是很好读和理解。相反,我建议进行一些重构:
def prepare_relation(basic_relation, key, id)
relation = basic_relation.dup
relation[:for] = key
relation[key] = id
relation
end
def add_to_stack(relation, key_ids, key, id)
@stack << relation
key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id }
end
basic_relation = {for: nil, state: nil}
@objects.each_key { |key| basic_relation[key] = nil unless key == :flows }
basic_relation.merge!(ids_string)
@ids.each do |key, ids|
next if key == :flows
key_ids = []
lookup_ids = key == :values ? ids.flatten.uniq : ids
lookup_ids.each_with_index do |id, index|
relation = prepare_relation(basic_relation, key, id)
relation[:values] = S(@ids[:values][index]) if key == :morals
if key == :values
ids.each_with_index do |array, index|
relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id
end
end
add_to_stack(relation, key_ids, key, id)
end
unless key_ids.empty?
TaleRelation.where(for: key , key: key_ids).each do |activerecord|
activerecord[:state] = nil
@stack << activerecord
end
end
end
这里我概括了你的主要区别switch
:
when :morals
ids.each_with_index do |id, index|
...
when :values
ids.flatten.uniq.each do |id|
...
else
ids.each do |id|
真正的区别仅在于 :values 的情况,因为 each_with_index
也适用于最后一种情况——我们只是不会使用索引。
然后不常见的变成简单的两个if:
relation[:values] = S(@ids[:values][index]) if key == :morals
if key == :values
ids.each_with_index do |array, index|
relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id
end
end
P.S。您不应该调用方法 A 或 S。方法名称必须小写并且应该有意义。