Fluent Interfaces in Ruby

In the last month I had to write a lot of Java and I found that interesting concept of fluent interfaces, where instead if writing a big constructor, you have expressive getters and setters for every attribute. I wrote a post about how to implement such a fluent interface in Ruby http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
But now I wonder if fluent interfaces are really a thing in Ruby, because of all the syntactic sugar the language already provides. What do you think?

I hope it is appropriate to ask this question in this mailing list. I am pretty new to all those mailing lists and this is my first contribution.

Cheers
Tim

What pros can fluent interface provide in Ruby?

···

On 14 Jul 2015, at 17:21, Tim Kächele <mail@timkaechele.me> wrote:

In the last month I had to write a lot of Java and I found that interesting concept of fluent interfaces, where instead if writing a big constructor, you have expressive getters and setters for every attribute. I wrote a post about how to implement such a fluent interface in Ruby http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
But now I wonder if fluent interfaces are really a thing in Ruby, because of all the syntactic sugar the language already provides. What do you think?

I hope it is appropriate to ask this question in this mailing list. I am pretty new to all those mailing lists and this is my first contribution.

Cheers
Tim

In the last month I had to write a lot of Java and I found that
interesting concept of fluent interfaces, where instead if writing a big
constructor, you have expressive getters and setters for every attribute. I
wrote a post about how to implement such a fluent interface in Ruby
http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
But now I wonder if fluent interfaces are really a thing in Ruby, because
of all the syntactic sugar the language already provides. What do you think?

At least for your Point I would simply use a Struct:

$ ./x.rb
#<struct Point x=1, y=2>
#<struct Point x=1, y=2>
#<struct Point x=1, y=2>
$ cat x.rb
#!/usr/bin/ruby

Point = Struct.new :x, :y

def Point(x, y = Point)
  if y.equal? Point
    Point.new(*Point.members.map {|m| x[m]})
  else
    Point.new(x, y)
  end
end

p Point[1,2]
p Point(1, 2)
p Point(x: 1, y: 2)

For me that is expressive enough. Even without defining Point() what the
Struct generated class provides is pretty good (the first one with the
square brackets).

I hope it is appropriate to ask this question in this mailing list. I am
pretty new to all those mailing lists and this is my first contribution.

That is totally appropriate. Actually, I find these types of posts are the
more interesting ones so please keep them coming! :slight_smile:

Kind regards

robert

···

On Tue, Jul 14, 2015 at 9:21 AM, Tim Kächele <mail@timkaechele.me> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/

I got it. Thanx Tim, Frederic.

···

On Tue 14 Jul 2015 at 22:27 Frederic Branczyk <fbranczyk@gmail.com> wrote:

I basically only use a fluent interface or the builder pattern, if I have
multiple optional arguments. In those cases, I make the required attributes
part of the constructor and the other attributes are set by the
fluent-interface/builder pattern.

On Tue, Jul 14, 2015 at 2:13 PM, Tim Kächele <mail@timkaechele.me> wrote:

Well it's not really handy if you use it with classes that don't have many
attributes. But currently I work on
a gem that allows to generate SVG with Ruby and I found it more than just
helpful to write code like this

    Polygon.from(0, 0).to(1, 1).to(3,
5).fill("#fff").stroke_width(2).stroke_color("#fff").to_svg

I am still somehow not sure if I completely like it. I find it an
interesting
concept that can provide an expressive
api, without the need to write lots of code or to use blocks. Yet it
doesn't
feel native in Ruby.

> Dmitry Shvetsov <shvetsovdm@gmail.com> hat am 14. Juli 2015 um 13:29
> geschrieben:
>
> What pros can fluent interface provide in Ruby?
>
> > On 14 Jul 2015, at 17:21, Tim Kächele <mail@timkaechele.me> wrote:
> >
> > In the last month I had to write a lot of Java and I found that
interesting
> > concept of fluent interfaces, where instead if writing a big
constructor,
> > you have expressive getters and setters for every attribute. I wrote
a post
> > about how to implement such a fluent interface in Ruby
> > http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
> > But now I wonder if fluent interfaces are really a thing in Ruby,
because of
> > all the syntactic sugar the language already provides. What do you
think?
> >
> > I hope it is appropriate to ask this question in this mailing list. I
am
> > pretty new to all those mailing lists and this is my first
contribution.
> >
> > Cheers
> > Tim

Well it's not really handy if you use it with classes that don't have many
attributes. But currently I work on
a gem that allows to generate SVG with Ruby and I found it more than just
helpful to write code like this

    Polygon.from(0, 0).to(1, 1).to(3,
5).fill("#fff").stroke_width(2).stroke_color("#fff").to_svg

I am still somehow not sure if I completely like it. I find it an interesting
concept that can provide an expressive
api, without the need to write lots of code or to use blocks. Yet it doesn't
feel native in Ruby.

···

Dmitry Shvetsov <shvetsovdm@gmail.com> hat am 14. Juli 2015 um 13:29
geschrieben:

What pros can fluent interface provide in Ruby?

> On 14 Jul 2015, at 17:21, Tim Kächele <mail@timkaechele.me> wrote:
>
> In the last month I had to write a lot of Java and I found that interesting
> concept of fluent interfaces, where instead if writing a big constructor,
> you have expressive getters and setters for every attribute. I wrote a post
> about how to implement such a fluent interface in Ruby
> http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
> But now I wonder if fluent interfaces are really a thing in Ruby, because of
> all the syntactic sugar the language already provides. What do you think?
>
> I hope it is appropriate to ask this question in this mailing list. I am
> pretty new to all those mailing lists and this is my first contribution.
>
> Cheers
> Tim

I basically only use a fluent interface or the builder pattern, if I have
multiple optional arguments. In those cases, I make the required attributes
part of the constructor and the other attributes are set by the
fluent-interface/builder pattern.

···

On Tue, Jul 14, 2015 at 2:13 PM, Tim Kächele <mail@timkaechele.me> wrote:

Well it's not really handy if you use it with classes that don't have many
attributes. But currently I work on
a gem that allows to generate SVG with Ruby and I found it more than just
helpful to write code like this

    Polygon.from(0, 0).to(1, 1).to(3,
5).fill("#fff").stroke_width(2).stroke_color("#fff").to_svg

I am still somehow not sure if I completely like it. I find it an
interesting
concept that can provide an expressive
api, without the need to write lots of code or to use blocks. Yet it
doesn't
feel native in Ruby.

> Dmitry Shvetsov <shvetsovdm@gmail.com> hat am 14. Juli 2015 um 13:29
> geschrieben:
>
> What pros can fluent interface provide in Ruby?
>
> > On 14 Jul 2015, at 17:21, Tim Kächele <mail@timkaechele.me> wrote:
> >
> > In the last month I had to write a lot of Java and I found that
interesting
> > concept of fluent interfaces, where instead if writing a big
constructor,
> > you have expressive getters and setters for every attribute. I wrote a
post
> > about how to implement such a fluent interface in Ruby
> > http://blog.timkaechele.me/2015/07/12/fluent-interfaces-in-ruby.html
> > But now I wonder if fluent interfaces are really a thing in Ruby,
because of
> > all the syntactic sugar the language already provides. What do you
think?
> >
> > I hope it is appropriate to ask this question in this mailing list. I
am
> > pretty new to all those mailing lists and this is my first
contribution.
> >
> > Cheers
> > Tim

Isn't a fluent interface what RSpec uses?

···

On Tue, Jul 14, 2015 at 7:13 AM, Tim Kächele <mail@timkaechele.me> wrote:

I am still somehow not sure if I completely like it. I find it an interesting
concept that can provide an expressive
api, without the need to write lots of code or to use blocks. Yet it doesn't
feel native in Ruby.

You're right that the "Point" example probably does not need a fluent
interface. However, coming from the C++ world, I found them extremly useful
for more complex cases.

For example, my implementation of a specific ANN training method [1] looks
like this:

    trainingAlgorithm
            .populationSize(50)
            .eliteSize(5)
            .maxNoSuccessEpochs(INT_MAX)
            .startTTL(500)
            .gradientWeight(3.0)
            .ebmin(1e-2)
            .ebmax(2.0)
            .successWeight(0.1);

I would love to see this in Ruby in the same way as, for example, Moose added
OOP convenience to Perl.

Cheers!
  Eric

[1] http://www.informatik.tu-freiberg.de/prof2/publikationen/EMERGING_2014_ann-evol-train.pdf

···

On Thursday 16 July 2015 18:44:59, Robert Klemme <shortcutter@googlemail.com> wrote:

At least for your Point I would simply use a Struct:

Hello,

  In Ruby you may use a block e.g.

trainingAlgorithm
            .populationSize(50)
            .eliteSize(5)
            .maxNoSuccessEpochs(INT_MAX)
            .startTTL(500)
            .gradientWeight(3.0)
            .ebmin(1e-2)
            .ebmax(2.0)
            .successWeight(0.1);

  becomes something like:

training_algorithm do
        population_size = 50
        elite_size = 5
        max_no_success_epochs = INT_MAX
        start_ttl = 500
        gradient_weight = 3.0
        ebmin = 1e-2
        ebmax = 2.0
        success_weight = 0.1
   end

  Keep it simple :wink: Cheers.

Gerald Bauer <gerald.bauer@gmail.com> writes:

  becomes something like:

training_algorithm do
        population_size = 50
        elite_size = 5
        max_no_success_epochs = INT_MAX
        start_ttl = 500
        gradient_weight = 3.0
        ebmin = 1e-2
        ebmax = 2.0
        success_weight = 0.1
   end

This won’t work, because the assignments are treated as local
variables. You need to either pass in the receiver as an explicit
argument to the block like this:

    training_algorithm do |params|
      params.population_size = 50
      params.elite_size = 5
      # ...
    end

Or you need to fiddle with “self” (using #instance_eval under the hood)
and leave off the assignment such that the statements are treated as
method calls instead.

    training_algorithm do
      population_size 50
      elite_size 5
      # ...
    end

The former version defeats the point of a special interface pattern, you
could then just go without the block version. The second one is actually
quite nice; for a real-life example have a look at the Prawn PDF
library[1] which uses this.

Valete,
Marvin

[1]: http://prawnpdf.org/

···

--
#!/sbin/quintus
Blog: http://www.guelkerdev.de

GnuPG key: F1D8799FBCC8BC4F

Prawn is also featured in "Eloquent Ruby" [1], and for a good reason. (I would
always recommend this book, it is great!) This way gives us an interface plus
a DSL-like way to use it. I'd like to see it combined with the Moose approach,
so that this snipped would become a reality:

    class REvol < TrainingAlgorithm
        has population_size: {
            isa: Integer,
            is: :rw,
            required: true,
            on_update: {|prev, new| raise "Eek, must be >0!" if new <= 0 }
         }
         has elite_size: {
             isa: Integer,
             is: :rw,
             default: ->{ this.population_size / 10 }
         }

         # ...
    end

    REvol.new do
        population_size 500
        elite_size 10
    end.train my_network

Perhaps I'll give it a shot as a C extension along the lines of MooseX [2].

Cheers
  Eric

[1] Olsen, Russ. Eloquent Ruby. http://eloquentruby.com/
[2] Tiago Peczenyj. MooseX. GitHub - peczenyj/MooseX: MooseX - a new DSL for object creation in Ruby

···

On Friday 17 July 2015 09:58:32, Quintus <quintus@quintilianus.eu> wrote:

Or you need to fiddle with “self” (using #instance_eval under the hood)
and leave off the assignment such that the statements are treated as
method calls instead.

    training_algorithm do
      population_size 50
      elite_size 5
      # ...
    end

The former version defeats the point of a special interface pattern, you
could then just go without the block version. The second one is actually
quite nice; for a real-life example have a look at the Prawn PDF
library[1] which uses this.