This exercise covers the following topics.
clobber
versus clean
Notice how little code there is in bin/sinatra
.
Compare this to a REST service implemented using Java's HttpServlet
class,
Spring MVC, or Apache CXF!
As short as it is, however, some redundancy probably exists.
Use your passing tests as a safety net to DRY up your code.
Here are some hints:
content_types = { 'html' => 'text/html', 'xml' => 'text/xml', 'json' => 'application/json' }
/statistics.html
,
/statistics.xml
, and /statistics.json
:
get '/statistics.*' do ... end
get '/statistics.*' do scheme = request.scheme # -> "http" host = request.host # -> "localhost" for example port = request.port # -> "8080" for example path = request.path # -> "/statistics.html" for example ... end
Two ways to accomplish the same thing:
my_object.its_method() my_object.send("its_method")
Examples enable users to quickly grasp how your software works.
In contrast to production code in the lib
directory,
example files in the examples
directory should not
correspond to class names.
Instead, their names should describe what they do.
Unlike the executables in bin
,
the names of example files usually have a .rb
extension.
Create a new directory called examples
and insert the
following into a new file examples/basic_api_usage.rb
#!/usr/bin/env ruby # Basic extensions to Ruby's Array class. $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' require 'statowl/extensions' puts [1,2,3,4].mean # -> 2.5 puts [1,2,3,4,5].median # -> 3 puts [1,2,3,4].variance # -> 1.25 puts [1,2,3,4].standard_deviation # -> 1.118033988749895 puts puts [1,2,3,4].statistics_as_text puts puts [1,2,3,4].statistics_as_html puts puts [1,2,3,4].statistics_as_xml puts puts [1,2,3,4].statistics_as_json
The $LOAD_PATH
line is important, because users
often like to run the examples without fully installing the project's
RubyGem, as in
cd examples ruby basic_api_usage.rb
Make the file executable and test it:
chmod +x examples/basic_api_usage.rb examples/basic_api_usage.rb
In preparation for packaging,
remove the links to the test code status pages from the README.rdoc
file.
Only RDOC pages will deploy with the packaged gem.
There are several ways to package a gem.
A very popular approach uses the gem
command.
Try the following from your project's working directory:
gem build statowl.gemspec
You should now have statowl-0.0.1.gem
in your working directory.
This works for any project that conforms to Ruby conventions and it is worthwhile to
verify that users can package your gem this way.
Remove statowl-0.0.1.gem
and take a look at the currently valid Rake tasks,
some of which you created in your Rakefile
and
others that are set up by default.
rake --tasks
The clean
task cleans out directories and removes any files
that were generated as part of the build process
but are not part of the final deliverable.
The documentation mentions .o
files,
which are not created by a pure Ruby project.
If you execute rake clean
and examine your directories
then you will notice that nothing really happens.
The clobber
task is similar to clean
but more
aggressive. In particular, it removes the pkg
directory
that the package
task creates.
To include Aruba's temporary directory tmp
,
add the following to Rakefile
:
CLOBBER.include 'tmp'
Also in your Rakefile
, add steps to Gem::PackageTask
to execute rake yard
and to create archived versions
prior to packaging the project as a RubyGem:
Gem::PackageTask.new(spec) do |pkg| pkg.need_tar = true pkg.need_tar_gz = true pkg.need_tar_bz2 = true pkg.need_zip = true end task :package => :yard
Execute the following to be sure that it removes any existing pkg
directory and packages your gem as pkg/statowl-0.0.1.gem
:
rake clobber rake package
List the files in the pkg
directory to check that the archived
files were created. Which compression technique produced the smallest file?
Add a new Rake task called deploy
that deploys your gem
locally using the shell command
gem install pkg/statowl-0.0.1.gem
Hints
lib/statowl/version.rb
and
it should be namespaced.
ls -l
seven times and
echos the results to stdout
:
puts 'ls -l' # use backticks, not single quotes! puts %x{ ls -l } puts %x[ ls -l ] puts %x( ls -l ) puts %x< ls -l > system("ls -l") exec("ls -l") # also terminates the current process puts "I'm dead!" # never reached
lib/statowl/version.rb
:
require 'statowl' desc 'Give the Statowl version' task :version do puts Statowl::VERSION end
Make the deploy
dependent on the package
task:
... task :deploy => :package ...
Execute the new task and ensure that Statowl gem was installed:
rake clobber rake deploy gem list | grep statowl
You should now be able to execute your command line app using the installed
gem. This is how the users of your gem wil invoke your executable.
You use bundle exec
only to execute uninstalled code.
Try these commands:
statowl help statowl help all echo '1,2,3,4' | statowl all echo '1,2,3,4' | statowl -f html all echo '1,2,3,4' | statowl -f xml all echo '1,2,3,4' | statowl -f json all
Now execute sinatra
and point your browser to
http://localhost:8080/statistics.html?numbers=1,2,3,4
Take a look at Gemfile.lock
to see how dependencies were resolved.
A dependency marked >=3.1.5
means any version greater or equal to
3.1.5. A dependency marked ~>3.1.5
is "pessimistic" and equivalent to
>=3.1.5 AND <4.0.0
.
It is common practice to guarantee that API interfaces do not change in minor releases.
Accordingly, an API change requires an increment of the major version number.
Note the simplecov version number.
If you wanted to express some pessimism about future API changes in simplecov,
you could modify your dependency in statowl.gemspec
like this:
s.add_development_dependency('simplecov', '~>0.9.1')
The "PLATFORM" in Gemfile.lock
may be "ruby," which means C Ruby (MRI) on Rubinious
but not Windows. Other possibilities include "jruby," "mri" (same as "ruby" but not Rubinious),
"rbx" (same as "ruby" but not MRI), and various Windows configurations.
The exclamation point after your project name indicates that the gem comes from your local
working directory.
Completely uninstall the StatOwl gem so that it does not conflict with further development:
gem uninstall statowl
In this exercise you refactored your Sinatra routes by removing redundancy.
You wrote "quick start" examples for users of your StatOwl API.
You then configured your Rakefile
to package and deploy your project as a RubyGem.
Finally, you installed your gem.
Ruby can appear to be magic. This is facilitated by a focus on easy installation and use. Rubyists use convention over configuration so that README files are short. They include examples and they test and test and test to make sure the product works as expected. This is the Ruby way!
In the next exercise you will learn how Behavior Driven Development can be used for database applications.
Copyright © 2005-2022 Amp Books LLC All Rights Reserved