Tutorial #1. Creating Services

The sources for this tutorial may be found in the tutorial/01 directory of the Copland distribution.

Introduction

A “service” is just an object. A plain, old, vanilla-flavored Ruby object. It’s as simple as that. You create a Ruby object, define methods and attributes on it, put it in Copland, and voila! Instant service.

I’m assuming you already know how to create Ruby objects. (If not, you may want to check out a more basic tutorial.) This tutorial will show you how to plug those objects into Copland, and how to access them in your program.

Steps

  1. Implement the Service

    For this tutorial, we’ll create a service that adds two numbers and returns the result. Pretty basic, but easy to understand.

    So, first things first: let’s write a Ruby class that performs this operation:

      class Adder
    
        def add( a, b )
          a.to_f + b.to_f
        end
    
      end
    

    (Just to give this example a little more value, we’ll have it explicitly convert its operands to floats—it makes things a little more impressive.)

    Save your file as “tutorial.rb” and move on to the next step.

  2. Tell Copland About It

    Next, we need to tell Copland about our service. We’ll create a package descriptor file (called “package.yml”) in the same directory as our “tutorial.rb” file, and in it we’ll tell Copland the name of our service and what Ruby class implements it (among other things). This file is YAML-formatted, so if you’ve used YAML before, the format (at least) should look very familiar.

     ---
      id: tutorial
      description: This is the package for the Copland tutorials.
    
      service-points:
    
        Adder:
          description: A service for adding two numbers.
          implementor: tutorial/Adder
    

    (The ‘description’ elements are always optional… we’ve shown them here just to demonstrate how they are used, but in later tutorials we’ll leave them out, for clarity.)

    This descriptor creates a new package, called “tutorial”. In Copland, all services are defined within packages.
    The descriptor then defines a single service point, called Adder. (Service points are the definitions of services. You can think of it like this: just as an object is the instantiation of a class, so is a service the instantiation of a service point.) This service point is implemented by “tutorial/Adder”, which means that “tutorial” will be @require@d, and then “Adder” instantiated.

  3. Use the Service

    Lastly, we create a “main.rb” driver file which we’ll use to test our new service point. This driver will simply instantiate a registry, grab a reference to the new service, and then invoke our #add method:

      require 'copland'
    
      registry = Copland::Registry.build
    
      adder = registry.service( "tutorial.Adder" )
    
      puts adder.add( "5", 7 )
    

    The #build method of Copland::Registry will recursively search for package descriptor files. By default, it will search from the current directory (but you can specify a different directory by giving it as a parameter to #build).

    Once the registry has been initialized, you can query it for services. In this case, we ask the registry for the tutorial.Adder service (i.e., the Adder service that exists in the tutorial package). Copland then returns this service.

    Lastly, we invoke the #add method and print the result. And it just works!

Summary

This tutorial demonstrated a few things:

  1. Copland services are just plain-ol’ Ruby objects.
  2. Package descriptors are just YAML files
  3. Registry instantiation and querying services

Also, this tutorial used the simple implementor; all it did was accept a class name (and require path) and instantiate it. Although this is useful for simple services, it doesn’t give us the dependency injection that IoC containers are famous for. The next tutorial will show how to wire several services together automatically, using the complex implementor.