4

I have read about Fluent APIs, where code can be made to read like English, but I can't seem to find any examples of them, as I would like to find out whether they are a reasonable way to make an easy to use interface to a system by non full time programmers. Does anyone have any examples of a fluent interface?

Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
yazz.com
  • 57,320
  • 66
  • 234
  • 385

5 Answers5

5

Couple of examples below in C#. Used by non-programmers? Well, decide for yourself, I'd say probably not - they're designed for coders and you need to know the syntax. But then this is C#, there are better examples in Ruby and other languages with much more readable, english-like syntax.

You'd might want to also look at external DSLs (domain specific languages). (Fluent APIs are considered internal DSLs).

NUnit:

Assert.That(result, Is.EqualTo(10));

Ninject:

Bind<IDataAccess>()
                .To<Db4oDataAccess>()
                .WithConstructorArgument("fileName", "dbFile.db");

Rhino Mocks:

repository.Expect(x => x.LoadUserList()).Return(users);

Here's some Ruby from RSpec:

@account.balance.should eql(Money.new(0, :dollars))

However, bear in mind that these examples are aimed at programmers, it is possible to get much more human-readable code if non-programmers are the target audience, especially with Ruby and the like.

Grant Crofton
  • 8,895
  • 5
  • 28
  • 38
2

Here is a pretty good example:

http://www.google.com/codesearch/p?hl=en#CICsffyVkoc/trunk/src/ShouldIt.Clr/Fluent/Be.cs&q=lang:c%23%20Fluent&d=3

What you should do when developing your own fluent interface or DSL (Domain Specific Language) as it also is called, is to write tests first. Write tests on how you want it to behave.

var q = Question.For(Site.StackOverflow)
           .WithTags("inteface", "fluent")
           .WithTitle("Are there any fluent interafces?");

And then start coding away.

Mikael Östberg
  • 16,982
  • 6
  • 61
  • 79
2

I am the developer of jOOQ, which ships with a fluent API to dynamically construct typesafe SQL queries. An example:

create.select(FIRST_NAME, LAST_NAME, count())
      .from(AUTHORS)
      .join(BOOKS)
      .using(AUTHOR_ID)
      .groupBy(FIRST_NAME, LAST_NAME)
      .orderBy(LAST_NAME);

The underlying SQL query is "hidden" behind a number of interfaces that model every "step" involved in query creation. This means, .select(Field...) returns an interface providing access to the .from(Table) method, which in turn returns an interface providing access to the .join(Table) method, etc.

SQL is actually a DSL which is external to Java. With jOOQ (or any other fluent API), SQL can be "internalised" into Java to a certain extent. Unlike with an external DSL, some SQL-specific constructs are hard to be mapped to an internal DSL in Java. An example for this is aliasing.

See more documentation here:

http://www.jooq.org/manual/DSL/

Update:

In the mean time, I actually ran across another highly interesting fluent API used to construct RTF files from Java. Some example code:

rtf().section(
   p( "first paragraph" ),
   p( tab(),
      " second par ",
      bold( "with something in bold" ),
      text( " and " ),
      italic( underline( "italic underline" ) )     
    )  
).out( out );

See more here:

http://code.google.com/p/jrtf/

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
1

I created a library of fluent assertions for .NET: Should Assertion Library (scroll down to see the fluent examples).

StructureMap has a very sophisticated Fluent DSL for configuration.

FluentNHibernate is pretty good. It replaces XML based mapping with a fluent DSL.

C# (and other static languages) have a very nice advantage for Fluent APIs of supporting code completion (e.g. Intellisense) to guide the user through composing what they intend.

The downside, with C# anyway, is that language cruft gets in the way. For example, you will often see things like Should().Not.Be.Null() where you would rather see Should.Not.Be.Null.

Tim Scott
  • 15,106
  • 9
  • 65
  • 79
0

fluentAOP

An AOP (Aspect-Oriented Programming) library that allows to implement aspects utilizing a fluent API. fluentAOP is primarily designed to simplify the adoption and use of AOP in .NET. It does not require XML files, attributes or any other kind of configuration. In contrast to most AOP implementations, its interception semantics exclusively rely on strongly-typed method definitions and a fluent API.

Code example:

// Note: line indented to improve readability
var foo = new Proxy<Foo>()
   .Target( new Foo() )
   .InterceptMethod ( f => f.Go() )
   .OnBefore(()=> Console.Write(“Hello World!”) )
   .Save();

// Result: every time Go() is called a “Hello World!” message is previously printed.
foo.Go();

Should Assertion Library

The Should Assertion Library provides a set of extension methods for test assertions for AAA and BDD style tests. It provides assertions only, and as a result it is Test runner agnostic. The assertions are a direct fork of the xUnit test assertions. This project was born because test runners Should be independent of the the assertions!

Code example:

var numbers = new List<int> { 1, 1, 2, 3 };
numbers.Should().Contain.Any(x => x == 1);
numbers
    .Should().Count.AtLeast(1)
    .Should().Count.NoMoreThan(5)
    .Should().Count.Exactly(4)
    .Should().Contain.One(x => x > 2);

Fluent Assertions

Fluent Assertions is a set of .NET extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style test. We currently use it in all our internal and client projects, and it is used in many open-source projects. It runs on .NET 3.5, 4.0 and 4.5 (Desktop and Windows Store), Silverlight 4 and 5 and Windows Phon…

Code example:

var theObject = "whatever";
theObject.Should().BeOfType<String>("because a {0} is set", typeof(String));
theObject.Should().NotBeNull();

FluentValidation

A small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your business objects.

Code example:

public CustomerValidator()
{
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
}

TNValidate

TNValidate is a fluent validation library for .Net. It enables you to write validation logic in a way that somewhat resembles natural language. This is not only intended to make it a little easier for developers to scan, but also means non-programmers have a better chance of being able to understand and modify the constraints being placed on data.

Code example:

// Basic validation.
Validate.That(Email, "Email address").IsEmail();

// Chaining a couple of rules.
Validate.That(Name, "Name").IsLongerThan(3).IsShorterThan(100);

Fluent.NET

The Fluent.NET library introduces extension methods to make .NET code easier to read and more fluid to write.

Code example:

var x = Sequence.Create<int>(0, i => i);
var pair = KeyValuePair.Create(1, "Hello World");

var strings = new[] { "This", "is", "a" } .AsEnumerable();
strings = strings.With("test");

Fluent NHibernate

Fluent, XML-less, compile safe, automated, convention-based mappings for NHibernate.

Code example:

public class CatMap : ClassMap<Cat>
{
  public CatMap()
  {
    Id(x => x.Id);
    Map(x => x.Name)
      .Length(16)
      .Not.Nullable();
    Map(x => x.Sex);
    References(x => x.Mate);
    HasMany(x => x.Kittens);
  }
}

Fluent Configuration API

It is possible to programmatically manipulate the default configuration classes used by Enterprise Library for the core, instrumentation, and all of the application blocks. The fluent interface exposed by Enterprise Library is designed to facilitate this process. The fluent interface can be used for all of the configurable features of instrumentation and for all of the Enterprise Library application blocks with the exception of the Validation and Policy Injection Application Blocks.

Code example:

var builder = new ConfigurationSourceBuilder();

builder.ConfigureInstrumentation()
       .ForApplicationInstance("MyApp")
         .EnableLogging()
         .EnablePerformanceCounters();

Fluent Automation

Simple, fluent DSL for automating web applications.

Code example:

Test.Run("KnockoutJS Cart Editor", I => {
    I.Open("http://knockoutjs.com/examples/cartEditor.html");
    I.Select("Motorcycles").From(".liveExample tr select:eq(0)"); // Select by value/text
    I.Select(2).From(".liveExample tr select:eq(1)"); // Select by index
    I.Enter(6).In(".liveExample td.quantity input:eq(0)");
    I.Expect.Text("$197.70").In(".liveExample tr span:eq(1)");

FluentDateTime

Allows you to write cleaner DateTime expressions and operation.

Code example:

DateTime.Now - 1.Weeks() - 3.Days() + 14.Minutes();
DateTime.Now + 5.Years();
3.Days().Ago();
2.Days().Since(DateTime.Now);
DateTime.Now.NextDay();
DateTime.Now.NextYear();
DateTime.Now.PreviousYear();
DateTime.Now.WeekAfter();
DateTime.Now.Midnight();
DateTime.Now.Noon();
DateTime.Now.SetTime(11, 55, 0);
Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73