Show HN: Elixir/Unix style pipe operations in Ruby
github.comI quote one of the examples
"https://api.github.com/repos/ruby/ruby".pipe do
URI.parse
Net::HTTP.get
JSON.parse.fetch("stargazers_count")
yield_self { |n| "Ruby has #{n} stars" }
Kernel.puts
end
#=> Ruby has 15115 stars
Not having to type the |> like in Elixir is two shift keys less, which is good. I'm not sure about readability, because one has to spot the .pipe at the beginning of the block, but it shouldn't be a problem.Now, if we only had pattern matching with the exact syntax of Elixir and not some monstrosity I saw around in proposals and other languages...
Thanks for your feedback!
Check out this other proof of concept demonstrating ES6 style object destructuring in Ruby:
https://github.com/lendingHome/destruct
I think this same type of concept could be applied to port Elixir style pattern matching as well e.g.
data = { name: "John Smith", age: 35, prefs: { lang: "en", tz: "UTC", } } User = Pattern { name age prefs[lang] } user = User =~ data user.name user.age user.lang [data].map(&User) case object when Pattern { some attrs[:nested][real][deep, fields] } Pattern!.some Pattern!.real Pattern!.deep Pattern!.fields Pattern!.nested #=> NoMethodError end # or define "locals" by defining temporary methods on # the block receiver when the "then" block is evaluated case object when Pattern { some nested[data] }.then do puts some puts data endThanks. Destructuring is nice and I'll check your link.
I'm using Elixir's pattern matching also in function definitions, to do without ifs and switches. A trivial example with Elixir syntax (hopefully correct).
I'd like to have a pattern matching like that in Ruby as well. A more real world example:def div(a, 0), do: {:error, "can't divide by 0"} def div(a, 1), do: {:ok, a} def div(0, b), do: {:ok, 0} def div(a, b), do: {:ok, a/b}
Much more readable than having to write ifs inside the function/method.def something(%{"a" => %{"b" => b, "c" => c}}), do {:ok, b + c} def something(_), do {:error, "a didn't contain b and c"}All considered, I find Ruby a more pleasant language than Elixir because of syntax, verbosity, state keeping (probably unfair, because OO is made for that vs GenServers), deployment story. I'd like to keep using it for applications that can scale by adding processes, but pattern matching is a killer feature.
Pipelines are important in Elixir because it's functional. It would be a pain to code without them. Object oriented languages can somewhat pipeline by calling methods on results of previous methods, provided a consistent design of classes (each.map.uniq.sort). It seems that in Ruby it could remove lots of useless variables. A lot less head scratching to find sensible variable names, faster programming. I hope it gets into the language or that this gem gets popular.
Thanks! Agreed it feels like a good fit for Ruby as well!
RE the pattern matching stuff I think the destructuring concept could be applied to look something like:
Some shorthand to access `Pattern.last` e.g. "$~" for regex would make things even nicer!def div(*args) case args when Pattern{[a, 0]} then [:error, "can't divide by 0"] when Pattern{[a, 1]} then [:ok, Pattern.last.a] when Pattern{[0, b]} then [:ok, 0] when Pattern{[a, b]} then [:ok, Pattern.last.a / Pattern.last.b] end end def something(object) case object when Pattern{a[b, c]} then [:ok, Pattern.last.b + Pattern.last.c] else [:error, "a didn't contain b and c"] end end