Using External Libraries

When building your app, you don’t want to reinvent the wheel. More often than not, parts of your functionality are already covered by existing Crystal packages or libraries. Commonly called shards, they’re the equivalent of gems in the Ruby world.

shards is also the name of the application that manages the dependencies of a project, like bundler in Ruby. How can you instruct your app to load one or more external shards?

Your app can list its dependencies in the file shard.yml (for Rubyists: the gemfile), which we’ll take a closer look at now. At the start of a project, it looks like this:

 name: ​mineral
 version: ​0.1.0
 
 authors:
  ​- Your-Name <your-email-address>
 
 targets:
  mineral:
  main: ​src/mineral.​cr
 
 crystal: ​0.22.0
 
 license: ​MIT

It lists the startup file of the app, together with some general info. To add external packages, we need a new dependencies section.

Adding a Shard

Let’s see how this works by adding a logging feature to our app, the katip logger developed by Güven Cenan. To keep our code short and clean, we’ll work in a project mineral_log, which copies the code from project mineral.

There are two steps to add a shard to a project.

First, let’s edit shard.yml in the root folder of mineral_log, add the following, and then save:

 dependencies:
  katip:
  github: guvencenanguvenal/katip

Each external library is a dependency specified with its name and the link on GitHub to fetch its source code, so there’s no need for a central Crystal repository. Beneath the link, you can also specify a specific version to use:

 version: 0.1.2

Crystal won’t typically change versions on you silently, but specifying the version explicitly may help other maintainers see what you did. If, on the other hand, you need the latest changes, use this:

 branch: master

Next, you need to install the library and add it to the current project. Go to the root folder and do: $ crystal shards, or even shorter: $ shards.

This produces the following output:

 Updating https://github.com/guvencenanguvenal/katip.git
 Installing katip (version: 0.1.0)

If the shard you’re adding also depended on other shards, they’ll also be installed. You can see which shards were installed with:

$ shards list

which in our case produces:

 Shards installed:
  * katip (0.1.0)

If you look inside the project structure, you can see what was created:

  • A lib folder, containing a subfolder for each of the installed dependencies. Note that the source code is installed, not the executables.

  • A hidden folder, .shards, containing a Git subfolder for each of the installed dependencies.

  • A shard.lock text file, listing all of the installed shards and their version.

Changed Dependencies

images/aside-icons/tip.png

The requirements of one of the dependencies might change, perhaps because you need other versions of the shards on which your app depends. Check this with $ shards check. If everything is okay, this gives the message: “Dependencies are satisfied.” If not, run the command $ shards update.

Now that the shard is properly installed, you can start using it. First, you have to tell your app to load its code. Do this by adding the following at the start of src/mineral_log.cr:

 require "katip"

As you saw in Combining Files with Require, this will look for its source inside the lib folder.

Including the shard is just the start of the work to integrate it. Katip also needs some configuration code before it can run, like:

 LOGGER = Katip::Logger.​new
 
 LOGGER.​configure​ ​do​ |config|
  config.​loglevel​ = Katip::LogLevel::DEBUG
  config.​logclassification​ = Katip::LogClassification::DATE_DAY
  config.​path​ = ​"src/katip/logfiles"
  config.​info​.​description​ = ​"This is the Mineral Log project."
  config.​info​.​project​ = ​"Mineral Log."
  config.​info​.​version​ = MineralLog::VERSION ​# project version
 end

Note how we create the logger object as a constant LOGGER, so we can access it in the module MineralLog and the class Mineral.

Now we’re all set and done, and we can start adding logging messages—For example, at startup, when creating a Mineral object, when calling to_csv, and so on:

 module​ ​MineralLog
  LOGGER.​info​(​"app mineral_log is started!"​)
 
  min1 = Mineral.​new​(101, ​"gold"​, ​"cubic"​)
  puts min1.​to_csv
 end
 
 class​ Mineral
  getter id, name
  property crystal_struct
 def​ ​initialize​(@id : Int32, @name : String, @crystal_struct : String)
  LOGGER.​debug​(​"A new mineral is created!"​)
 end
 
 def​ ​initialize​(@id : Int32, logger)
  @name = ​"rock"
  @crystal_struct = ​"unknown"
  LOGGER.​debug​(​"A new default mineral is created!"​)
 end
 
 def​ ​to_s
  puts ​"This is a mineral with id ​​#{​id​}​​ and is called ​​#{​name​}​​ "
  puts ​"It has ​​#{​crystal_struct​}​​ as crystal structure"
 end
 
 def​ ​to_csv
  LOGGER.​debug​(​"to_csv method is called"​)
 "​​#{​id​}​​,​​#{​name​}​​,​​#{​crystal_struct​}​​"
 end
 end

Now you can find the logfile in src/katip/logfiles/*.json. Use the logviewer by starting up mineral_log/lib/katip/katipviewer.html in a browser:

images/managing_projects/katip_viewer.png

Katip offers info, warn, debug, error, and fatal messages, so you can choose what to log and when to view it.

No Shared Dependencies

images/aside-icons/tip.png

In Crystal, each app has its own source copy of the shards on which it depends. These are compiled into the production executable. There are no shared dependencies, as long as the code is purely Crystal. This has several advantages:

  • No dependency hell: no problems with shard versions out of sync! You know with which versions your app works, and shard.lock makes sure these versions are used.

  • When you delete an app, you also delete all dependencies without leaving code behind.

  • If there’s a problem with a dependency, you can debug it and even change it without impacting other applications.

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.168.8