Skip to content
This repository has been archived by the owner on Jan 1, 2020. It is now read-only.

Commit

Permalink
Document the Bsf::Database class
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffrey Jones committed May 27, 2013
1 parent 130df95 commit 5a29802
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions lib/bsf/database.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,58 @@
require 'sequel'

module Bsf

# This class acts as the gateway to the database. All database related access must be
# done via an instance of this class. It works by using the Sequel gem to create a
# connection to the database and forwarding messages to it using 'method_missing'
# meta-programming.
#
# Why wrap the connection instead of just using it directly? Good question. The answer
# is that we want the rest of the script to know as little about the datastore as
# possible. By wrapping it inside this class we isolate it from the rest of the script.
#
# But do we? As mentioned above we use method_missing meta-programming to forward
# messages to the Sequel gem. That means that whatever is using this class is using
# Sequel gem message calls (For example look at the {#populate_fund_data} private method
# in the # {Bsf::Scraper::Command} class ).
#
# For this class to do it's job properly we need to remove the meta-programming and
# create method calls that can be used by other classes. This way they are using THIS
# class's API and not the underlying Sequel gem's API.
#
# Therefore this class needs some more refactoring. A good example would be a
# {#get_all_funds} method that could be called by the above mentioned {#populate_fund_data}
#
# As well as acting as the gateway this class also includes one utility method to create
# a table to persist fund data.
class Database

# A new instance of {Bsf::Database}
#
# If the :database_host option is not set then the script will attempt to
# connect to a PostgreSQL instance on the local machine.
#
# @param [Hash] options
# @option options String :database_host (nil) The hostname or IP address of the PostgreSQL server
# @option options String :database_name The name of the database to use
# @option options String :database_user The PostgreSQL login role to use
# @option options String :database_password The PostgreSQL login role's password
def initialize(options)
connect_to_database(options)
end

# Create a PostgreSQL table called 'funds'
#
# Using the Sequel gem's migration features we will create a 'funds' table
# to persist the information we scrape.
#
# Note that many of the string fields have a length of 255 characters which is
# far more than we need. However better safe than sorry. The original script
# attempted to dynamically resize these fields but this is a case of premature
# optimization which complicated the code.
#
# The table will only hold 20,000 or so rows so we can live with a little wasted
# space for the simple code benefits it provides us.
def create_fund_table
@connection.create_table?(:funds) do
primary_key :id
Expand Down Expand Up @@ -35,12 +81,42 @@ def create_fund_table
end
end

# Send unknown methods to the underlying Sequel Connection
#
# Since the {Bsf::Database} class wraps the Sequel gem's connection to
# PostgreSQL any method calls which we do not understand are assumed
# to be Sequel commands.
#
# Therefore we will use ruby's 'method missing' meta-programming to catch
# all of these method calls and then send them to the Sequel connection
# which was created during initialization.
#
# This is a type of 'message forwarding' ( it is also quite often referred
# to, incorrectly, as 'Delegation'), For more in-depth research please read
# http://www.saturnflyer.com/blog/jim/2012/07/06/the-gang-of-four-is-wrong-and-you-dont-understand-delegation/
def method_missing(method, *args, &block)
@connection.send(method, *args, &block)
end

private

# Create a connection to PostgreSQL using the Sequel Gem
#
# We will create the connection hash using a few pre-defined
# options and getting the rest from the options hash.
#
# This connection will be stored in a local variable in the instance of
# this class. It can then be used to send commands to the database.
#
# For more information about connection options please read the Sequel
# gem's documentation.
#
#
# @param [Hash] options
# @option options String :database_host (nil) The hostname or IP address of the PostgreSQL server
# @option options String :database_name The name of the database to use
# @option options String :database_user The PostgreSQL login role to use
# @option options String :database_password The PostgreSQL login role's password
def connect_to_database(options)
connection_hash = {:adapter => 'postgres',
:database => options[:database_name],
Expand Down

0 comments on commit 5a29802

Please sign in to comment.