Tutorial #1. Creating Services
The sources for this tutorial may be found in the tutorial/01 directory of the Copland distribution.
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.
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.
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.
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
require 'copland' registry = Copland::Registry.build adder = registry.service( "tutorial.Adder" ) puts adder.add( "5", 7 )
#buildmethod 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
Once the registry has been initialized, you can query it for services. In this case, we ask the registry for the
tutorial.Adderservice (i.e., the
Adderservice that exists in the
tutorialpackage). Copland then returns this service.
Lastly, we invoke the
#addmethod and print the result. And it just works!
This tutorial demonstrated a few things:
- Copland services are just plain-ol’ Ruby objects.
- Package descriptors are just YAML files
- 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.