Brooke Kuhlmann
June 17, 2024
420

# Ruby Function Composition

Ruby elegantly blends both Functional Programming and Object Oriented design patterns together with minimal effort. In this talk, I'll combine both of these design patterns by briefly walking you through the fundamentals of functional composition, appling monads, and finally wrapping all of this up in a nice transactional pipeline object composed of multiple -- fault tolerant -- steps for building robust architectures. You'll learn a lot and walk away with new patterns to apply to your own code base.

June 17, 2024

## Transcript

1. ### Ruby Function Composition Brooke Kuhlmann g(f(x)) f(x) x A B

C f g alchemists.io

5. ### Pipeable Dry Monads Ruby Overview Fundamentals Railway Pattern Fault tolerent

pipelines alchemists.io

8. ### en.wikipedia.org/wiki/Function_composition_(computer_science) What "[F]unction composition is an act or mechanism to

combine simple functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole." -- Wikipedia alchemists.io

21. ### History Ruby 2.6.0 Methods: #>> #<< (forward composition) (backward composition)

alchemists.io/articles/ruby_function_composition alchemists.io
22. ### History Ruby 2.6.0 Methods: Proc Method #>> #<< Objects: (forward

composition) (backward composition) alchemists.io/articles/ruby_function_composition alchemists.io

27. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m m m m m 3| | | | | | | | | | | Procs alchemists.io/articles/ruby_function_composition alchemists.io
28. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m m m m m 3| | | | | | | | | | | Procs alchemists.io/articles/ruby_function_composition alchemists.io
29. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m m m m m 3| | | | | | | | | | | m m m m m m m m m m m c c c c c # # # # # Procs alchemists.io/articles/ruby_function_composition alchemists.io
30. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m m m m m 3| | | | | | | | | | | m m m m m m m m m m m c c c c c # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Procs alchemists.io/articles/ruby_function_composition alchemists.io
31. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m m m m m 3| | | | | | | | | | | m m m m m m m m m m m c c c c c # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # Procs alchemists.io/articles/ruby_function_composition alchemists.io
32. ### Fundamentals multiplier = proc { |number, by = 3| number

* by } multiplier.class # Proc multiplier.inspect # #<Proc:0x00000001059b5248 (irb):22> multiplier.call 3 # 9 multiplier.call 3, 10 # 30 Procs alchemists.io/articles/ruby_function_composition alchemists.io

34. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
35. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
36. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 m m m m m m m m m m m c c c c c # # # # # Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
37. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 m m m m m m m m m m m c c c c c # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
38. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 m m m m m m m m m m m c c c c c # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
39. ### Fundamentals m m m m m m m m m

m m m m m m m m m m m m m m 3 m m m m m m m m m m m c c c c c # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io
40. ### Fundamentals multiplier = -> number, by = 3 { number

* by } multiplier.class # Proc multiplier.inspect # "#<Proc:0x0000000104ba68a0 (irb):19 (lambda)>" multiplier.call 3 # 9 multiplier.call 3, 10 # 30 Lam bdas alchemists.io/articles/ruby_function_composition alchemists.io

42. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) M ethods alchemists.io/articles/ruby_function_composition alchemists.io
43. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) M ethods alchemists.io/articles/ruby_function_composition alchemists.io
44. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) M ethods alchemists.io/articles/ruby_function_composition alchemists.io
45. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m M ethods alchemists.io/articles/ruby_function_composition alchemists.io
46. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m M ethods alchemists.io/articles/ruby_function_composition alchemists.io
47. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
48. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
49. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
50. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
51. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # m m m m m m m m m m m m m m m 3, 1 1 # # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
52. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # m m m m m m m m m m m m m m m 3, 1 1 # # # f f f f f f f f f f f f f f f f f f f f f f f f f f f M ethods alchemists.io/articles/ruby_function_composition alchemists.io
53. ### Fundamentals C C C C C C C C C

C C C C C C C C C C C C d d d d d d d .m m m m m m m m ( ( ( ( ( ( ( ( ( ( ( 3) ) ) ) ) ) ) ) ) ) ) ) m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # m m m m m m m m m m m m m m m 3, 1 1 # # # f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f c c c c c # # # # # M ethods alchemists.io/articles/ruby_function_composition alchemists.io
54. ### Fundamentals Calculate = Module.new { def self.multiply(number, by = 3)

= number * by } multiplier = Calculate.method :multiply multiplier.class # Method multiplier.inspect # "#<Method: Calculate.multiply(number, by=...) (irb):1>" multiplier.call 3 # 9 multiplier.call 3, 10 # 30 function = multiplier.to_proc function.class # Proc function.inspect # #<Proc:0x0000000104906f78 (lambda)> M ethods alchemists.io/articles/ruby_function_composition alchemists.io
55. ### Fundamentals Calculate = Module.new { def self.multiply(number, by = 3)

= number * by } multiplier = Calculate.method :multiply multiplier.class # Method multiplier.inspect # "#<Method: Calculate.multiply(number, by=...) (irb):1>" multiplier.call 3 # 9 multiplier.call 3, 10 # 30 function = multiplier.to_proc function.class # Proc function.inspect # #<Proc:0x0000000104906f78 (lambda)> M ethods alchemists.io/articles/ruby_function_composition alchemists.io

57. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e C lasses alchemists.io/articles/ruby_function_composition alchemists.io
58. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e C lasses alchemists.io/articles/ruby_function_composition alchemists.io
59. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e C lasses alchemists.io/articles/ruby_function_composition alchemists.io
60. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e m m m m m m m m m m m m m m m m m m m m m m m m m C lasses alchemists.io/articles/ruby_function_composition alchemists.io
61. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # # # # # C lasses alchemists.io/articles/ruby_function_composition alchemists.io
62. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # C lasses alchemists.io/articles/ruby_function_composition alchemists.io
63. ### Fundamentals c c c c c d d d 3

@ @ @ e e e d d d c c c c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( p p p p p p p e e e m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m c c c c c # # # # # # # # # # # m m m m m m m m m m m m m m m m m m # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # m m m m m m m m m m m m m m m 3 # # C lasses alchemists.io/articles/ruby_function_composition alchemists.io
64. ### Fundamentals class Multiplier def initialize by = 3 @by =

by end def call(number) = number * by private attr_reader :by end multiplier = Multiplier.new multiplier.class # Multiplier multiplier.inspect # "#<Multiplier:0x0000000103761908 @by=3>" multiplier.call 3 # 9 Multiplier.new(10).call 3 # 30 C lasses alchemists.io/articles/ruby_function_composition alchemists.io
65. ### Fundamentals class Multiplier def initialize by = 3 @by =

by end def call(number) = number * by private attr_reader :by end multiplier = Multiplier.new multiplier.class # Multiplier multiplier.inspect # "#<Multiplier:0x0000000103761908 @by=3>" multiplier.call 3 # 9 Multiplier.new(10).call 3 # 30 C lasses alchemists.io/articles/ruby_function_composition alchemists.io

75. ### Composition module Composable def >>(other) = method(:call) >> other def

<<(other) = method(:call) << other def call = fail NoMethodError, "`#{self.class.name}##{__method__}` must be implemented." end alchemists.io/articles/ruby_function_composition alchemists.io
76. ### Composition module Composable def >>(other) = method(:call) >> other def

<<(other) = method(:call) << other def call = fail NoMethodError, "`#{self.class.name}##{__method__}` must be implemented." end alchemists.io/articles/ruby_function_composition alchemists.io
77. ### Composition module Composable def >>(other) = method(:call) >> other def

<<(other) = method(:call) << other def call = fail NoMethodError, "`#{self.class.name}##{__method__}` must be implemented." end Pipeable alchemists.io/articles/ruby_function_composition alchemists.io

79. ### Composition class Divider include Composable def initialize by = 3

@by = by end def call(number) = number / by private attr_reader :by end Class alchemists.io/articles/ruby_function_composition alchemists.io
80. ### Composition class Divider include Composable def initialize by = 3

@by = by end def call(number) = number / by private attr_reader :by end Class alchemists.io/articles/ruby_function_composition alchemists.io

82. ### Composition module Calculate def self.multiply(number, by = 3) = number

* by end Method alchemists.io/articles/ruby_function_composition alchemists.io

84. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply alchemists.io/articles/ruby_function_composition alchemists.io
85. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply Proc alchemists.io/articles/ruby_function_composition alchemists.io
86. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply Proc Lambda alchemists.io/articles/ruby_function_composition alchemists.io
87. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply Proc Lambda Class alchemists.io/articles/ruby_function_composition alchemists.io
88. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply Proc Lambda Class Method alchemists.io/articles/ruby_function_composition alchemists.io
89. ### Composition adder = proc { |number, by = 3| number

+ by } subtracter = -> number, by = 3 { number - by } divider = Divider.new multiplier = Calculate.method :multiply Proc Lambda Class Method Composable alchemists.io/articles/ruby_function_composition alchemists.io
90. ### Composition multiplier (method) subtractor (lambda) adder (proc) divider (class) >>

>> >> alchemists.io/articles/ruby_function_composition alchemists.io
91. ### Composition multiplier (method) subtractor (lambda) adder (proc) divider (class) >>

>> >> alchemists.io/articles/ruby_function_composition alchemists.io

93. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 alchemists.io/articles/ruby_function_composition alchemists.io
94. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 Forward composition alchemists.io/articles/ruby_function_composition alchemists.io
95. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 Forward composition Backward composition alchemists.io/articles/ruby_function_composition alchemists.io
96. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 alchemists.io/articles/ruby_function_composition alchemists.io
97. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 alchemists.io/articles/ruby_function_composition alchemists.io
98. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 alchemists.io/articles/ruby_function_composition alchemists.io
99. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 alchemists.io/articles/ruby_function_composition alchemists.io
100. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 1 alchemists.io/articles/ruby_function_composition alchemists.io
101. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 1 alchemists.io/articles/ruby_function_composition alchemists.io
102. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 1 alchemists.io/articles/ruby_function_composition alchemists.io
103. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 1 2 alchemists.io/articles/ruby_function_composition alchemists.io
104. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 (10 + 3) * 3 = 39 📖 1 2 alchemists.io/articles/ruby_function_composition alchemists.io
105. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 alchemists.io/articles/ruby_function_composition alchemists.io
106. ### Composition (adder >> multiplier).call 10 # 39 (multiplier << adder).call

10 # 39 ⭐ alchemists.io/articles/ruby_function_composition alchemists.io

108. ### Composition (adder >> multiplier >> subtracter >> divider).call 10 #

12 (divider << subtracter << multiplier << adder).call 10 # 12 alchemists.io/articles/ruby_function_composition alchemists.io
109. ### Composition (adder >> multiplier >> subtracter >> divider).call 10 #

12 (divider << subtracter << multiplier << adder).call 10 # 12 (((10 + 3) * 3) - 3) / 3 = 12 alchemists.io/articles/ruby_function_composition alchemists.io
110. ### Composition (adder >> multiplier >> subtracter >> divider).call 10 #

12 (divider << subtracter << multiplier << adder).call 10 # 12 (((10 + 3) * 3) - 3) / 3 = 12 alchemists.io/articles/ruby_function_composition alchemists.io
111. ### Composition (adder >> multiplier >> subtracter >> divider).call 10 #

12 (divider << subtracter << multiplier << adder).call 10 # 12 (((10 + 3) * 3) - 3) / 3 = 12 alchemists.io/articles/ruby_function_composition alchemists.io

113. ### Composition a a a a a a a a a

a a a a a a a a a a a a a a a a a a a a a a a a a alchemists.io/articles/ruby_function_composition alchemists.io
114. ### Composition a a a a a a a a a

a a a a a a a a a a a a a a a a a a a a a a a a a s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s alchemists.io/articles/ruby_function_composition alchemists.io
115. ### Composition a a a a a a a a a

a a a a a a a a a a a a a a a a a a a a a a a a a s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a alchemists.io/articles/ruby_function_composition alchemists.io

117. ### Composition add_and_multiply = adder >> multiplier subtract_and_divide = subtracter >>

divider add_multiply_subtract_and_divide = add_and_multiply >> subtract_and_divide add_multiply_subtract_and_divide.call 10 # 12 (((10 + 3) * 3) - 3) / 3 = 12 alchemists.io/articles/ruby_function_composition alchemists.io

119. ### Composition (adder >> multiplier).call 10 # 39 (adder << multiplier).call

10 # 33 Order of operations matters! alchemists.io/articles/ruby_function_composition alchemists.io

121. ### Composition (adder >> Divider.new(0) >> multiplier).call 10 # ZeroDivisionError: divided

by 0 Any error will halt the operation. alchemists.io/articles/ruby_function_composition alchemists.io

134. ### ✅ ❌ ✅ ✅ Success Success Success Pipeline (Railway Pattern)

alchemists.io alchemists.io/projects/pipeable
135. ### ✅ ❌ ✅ ✅ Success Success Success Failure Failure Failure

Pipeline (Railway Pattern) alchemists.io alchemists.io/projects/pipeable
136. ### ✅ ❌ ✅ ✅ Success Success Success Failure Failure Failure

Pipeline No Exceptions! (Railway Pattern) alchemists.io alchemists.io/projects/pipeable

149. ### Dry Monads dry-rb.org/gems/dry-monads Success Failure ✅ ❌ Ok Err Union

Composite alchemists.io

153. ### Pipeable require "bundler/inline" gemfile true do source "https://rubygems.org" gem "amazing_print"

gem "debug" gem "http" gem "dry-monads" gem "pipeable" end Install alchemists.io/articles/ruby_function_composition alchemists.io
154. ### Pipeable require "bundler/inline" gemfile true do source "https://rubygems.org" gem "amazing_print"

gem "debug" gem "http" gem "dry-monads" gem "pipeable" end Install alchemists.io/articles/ruby_function_composition alchemists.io
155. ### Pipeable require "bundler/inline" gemfile true do source "https://rubygems.org" gem "amazing_print"

gem "debug" gem "http" gem "dry-monads" gem "pipeable" end Install alchemists.io/articles/ruby_function_composition alchemists.io
156. ### Pipeable require "bundler/inline" gemfile true do source "https://rubygems.org" gem "amazing_print"

gem "debug" gem "http" gem "dry-monads" gem "pipeable" end Install alchemists.io/articles/ruby_function_composition alchemists.io
157. ### Pipeable require "bundler/inline" gemfile true do source "https://rubygems.org" gem "amazing_print"

gem "debug" gem "http" gem "dry-monads" gem "pipeable" end Install alchemists.io/articles/ruby_function_composition alchemists.io

159. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
160. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
161. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
162. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
163. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
164. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
165. ### class Pinger include Pipeable def initialize client: HTTP @client =

client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
166. ### Pipeable class Pinger include Pipeable def initialize client: HTTP @client

= client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation alchemists.io/articles/ruby_function_composition alchemists.io
167. ### Pipeable class Pinger include Pipeable def initialize client: HTTP @client

= client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation Domain Speci fi c Language (DSL) alchemists.io/articles/ruby_function_composition alchemists.io
168. ### Pipeable class Pinger include Pipeable def initialize client: HTTP @client

= client end def call url pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report end end Im plem entation Domain Speci fi c Language (DSL) alchemists.io/articles/ruby_function_composition alchemists.io

170. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
171. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates 🎗:get alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
172. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates Monad alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
173. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
174. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates Function Map alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
175. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
176. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
177. ### class Pinger include Pipeable # ... private attr_reader :client def

get result result.fmap { |url| client.timeout(1).get url } rescue HTTP::TimeoutError => error Failure error.message end end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable

179. ### class Pinger include Pipeable # ... private # ... def

report(result) = result.fmap { |status| status == 200 ? "Site is up!" : status } end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
180. ### class Pinger include Pipeable # ... private # ... def

report(result) = result.fmap { |status| status == 200 ? "Site is up!" : status } end Privates 🎗:report alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
181. ### class Pinger include Pipeable # ... private # ... def

report(result) = result.fmap { |status| status == 200 ? "Site is up!" : status } end Privates Monad alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
182. ### class Pinger include Pipeable # ... private # ... def

report(result) = result.fmap { |status| status == 200 ? "Site is up!" : status } end Privates alchemists.io/articles/ruby_function_composition alchemists.io Pipeable

184. ### include Dry::Monads[:result] url = "https://xkcd.com" case Pinger.new.call(url) in Success(message) then

puts "Success: #{message}" in Failure(error) then puts "Site is down or invalid. Reason: #{error}" end Execution alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
185. ### include Dry::Monads[:result] url = "https://xkcd.com" case Pinger.new.call(url) in Success(message) then

puts "Success: #{message}" in Failure(error) then puts "Site is down or invalid. Reason: #{error}" end Execution alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
186. ### include Dry::Monads[:result] url = "https://xkcd.com" case Pinger.new.call(url) in Success(message) then

puts "Success: #{message}" in Failure(error) then puts "Site is down or invalid. Reason: #{error}" end Execution Input alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
187. ### include Dry::Monads[:result] url = "https://xkcd.com" case Pinger.new.call(url) in Success(message) then

puts "Success: #{message}" in Failure(error) then puts "Site is down or invalid. Reason: #{error}" end Execution Pipe alchemists.io/articles/ruby_function_composition alchemists.io Pipeable
188. ### include Dry::Monads[:result] url = "https://xkcd.com" case Pinger.new.call(url) in Success(message) then

puts "Success: #{message}" in Failure(error) then puts "Site is down or invalid. Reason: #{error}" end Execution alchemists.io/articles/ruby_function_composition alchemists.io Pipeable

192. ### Checking: https://xkcd.com... Success: Site is up! Input: https://xkcd.com Success alchemists.io/articles/ruby_function_composition

alchemists.io Pipeable

194. ### Checking: http://xkcd.com... Site is down or invalid. Reason: http://xkcd.com Input:

http://xkcd.com Failure alchemists.io/articles/ruby_function_composition alchemists.io Pipeable

196. ### Checking: https://www.unknown.com... Site is down or invalid. Reason: Timed out

after using the allocated 1 seconds. Input: https://www.unknown.com Failure alchemists.io/articles/ruby_function_composition alchemists.io Pipeable

200. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report alchemists.io alchemists.io/projects/pipeable Pipeable
201. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report alchemists.io alchemists.io/projects/pipeable Pipeable
202. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). alchemists.io alchemists.io/projects/pipeable Pipeable
203. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). Print info to the console. alchemists.io alchemists.io/projects/pipeable Pipeable
204. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). Print info to the console. Check if the URL is secure. alchemists.io alchemists.io/projects/pipeable Pipeable
205. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). Print info to the console. Check if the URL is secure. Make the HTTP GET request. alchemists.io alchemists.io/projects/pipeable Pipeable
206. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). Print info to the console. Check if the URL is secure. Make the HTTP GET request. Ask the HTTP response for status. alchemists.io alchemists.io/projects/pipeable Pipeable
207. ### pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status),

:report The URL (raw input). Print info to the console. Check if the URL is secure. Make the HTTP GET request. Ask the HTTP response for status. Report the HTTP status. alchemists.io alchemists.io/projects/pipeable Pipeable
208. ### Pipe pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get,

as(:status), :report alchemists.io alchemists.io/projects/pipeable Pipeable
209. ### Pipe :get url tee check as :report ↓ ↓ ↓

↓ ↓ pipe url, tee(Kernel, :puts, "Checking: #{url}..."), check(/\Ahttps/, :match?), :get, as(:status), :report alchemists.io alchemists.io/projects/pipeable Pipeable
210. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ alchemists.io alchemists.io/projects/pipeable
211. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Input alchemists.io alchemists.io/projects/pipeable
212. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Step Step Step Step Step alchemists.io alchemists.io/projects/pipeable

214. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Pipe alchemists.io alchemists.io/projects/pipeable
215. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Pipe alchemists.io alchemists.io/projects/pipeable
216. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Pipe alchemists.io alchemists.io/projects/pipeable
217. ### Architecture :get url tee check as :report ↓ ↓ ↓

↓ ↓ Pipe alchemists.io alchemists.io/projects/pipeable