Ruby 中类似 Elixir 的管道来处理集合

问题描述 投票:0回答:2

在 Elixir 中,有一个很棒的管道操作符,其工作方式如下:

"hello, world!"
  |> String.split(" ")
  |> Enum.map(&String.capitalize/1)
  |> Enum.join

在 Ruby 中我们可以使用类似的语法:

"hello, world!"
  .split(" ")
  .map(&:capitalize)
  .join

仅当为对象本身定义了所有这些方法时,它才有效。如果需要调用一些本地方法,我们应该使用类似:

.map { |el| URI.parse(el) }

但是如果我们想要进行一些集合处理(不是单个元素),例如GZIP压缩:

chars = text
  .downcase
  .chars

compressed = GZipped.new(chars).bytes

但是链条断了!

我找到了一些链接,但看起来不太好:

在我看来,有这样的东西会很棒:

text
  .split
  .pipe(URI.method(:parse))
  .map(&:to_s)
  .join
  .pipe(GZIPped)
  .pipe(Base64.method(:encode))

在 Ruby 中构建此类管道的最佳方法是什么?

更新1

这是一个例子

class Dedup
  def initialize(obj)
    @obj = obj
  end

  def each
    Enumerator.new do |y|
      prev = nil

      @obj.each do |el|
        if el != prev
          y << el
          prev = el
        end
      end
    end
  end
end


expect(
  "1 1 1 2 2 3"
    .split
    .then { |obj| Dedup.new(obj).each }
    .to_a
).to eq [1, 2, 3]

这种链接看起来丑陋且难以阅读。

比较:

expect(
  "1 1 1 2 2 3"
    .split
    .pipe(Dedup)
    .to_a
).to eq [1, 2, 3]
arrays ruby functional-programming pipe elixir
2个回答
4
投票

已经有这样的方法了,至少从 Ruby 2.5 开始 -

yield_self
,在 Ruby 2.6 中别名为
then
。您可以对任何响应
&
的对象使用
to_proc
运算符来传递它而不是块。

text
  .split
  .map(&URI.method(:parse)) # URI#parse expects a string, not an array
  .map(&:to_s)
  .join
  .then(&GZIPped) # not sure what GZIPped is - I'll assume it has .to_proc method
  .then(&Base64.method(:encode))

(我可能应该提到上面的代码实际上不会工作,老实说我不知道它会做什么 - 为什么要分割一个字符串,将它们转换为网址,然后再返回字符串?唯一的事情就是to 是要提高 id 其中一个子字符串不是有效的字符串?但是然后您尝试将结果字符串作为 gzip 压缩文件读取...我假设我误解了代码中的某些内容)

更高级的东西 - 我在 Elixir 中非常喜欢的一件事是将方法与剩余参数链接在一起的选项。这也可以在 ruby 中模拟,但需要一些工作并好好思考是否值得:

module MyMath
  module_function
  
  UNDEFINED = Object.new

  def add(a, b = UNDEFINED)
    if b == UNDEFINED
      return ->(num) { add(a, num) }
    end
    a + b
  end
end

MyMath.add(2,5) #=> 7
[1,2,5,9].map(&MyMath.add(5)] #=> [6,7,10,14]

0
投票

我不知道这对你的情况是否有帮助,但是 Greg Navis 发表了“9 Lines of Ruby 中的 Elixir-style Pipelines”,这肯定与这个普遍问题相关。

© www.soinside.com 2019 - 2024. All rights reserved.