langrove 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. data/.rspec +1 -0
  2. data/.rvmrc +62 -0
  3. data/.watchr +27 -0
  4. data/Gemfile +16 -0
  5. data/Gemfile.lock +61 -0
  6. data/Rakefile +24 -0
  7. data/functional/.gitignore +1 -0
  8. data/functional/bin/datagram +6 -0
  9. data/functional/config/.gitignore +0 -0
  10. data/functional/config/boot.rb +64 -0
  11. data/functional/config/daemons.yml +12 -0
  12. data/functional/config/environment.rb +28 -0
  13. data/functional/config/environments/development.rb +0 -0
  14. data/functional/config/environments/production.rb +0 -0
  15. data/functional/config/environments/test.rb +0 -0
  16. data/functional/lib/daemon/datagram.rb +21 -0
  17. data/functional/lib/handler/socket_to_file.rb +36 -0
  18. data/functional/lib/protocol/socket_to_file.rb +55 -0
  19. data/functional/libexec/daemon.rb +68 -0
  20. data/functional/log/.gitignore +3 -0
  21. data/functional/tmp/README +1 -0
  22. data/lib/langrove/_base.rb +26 -0
  23. data/lib/langrove/adaptor/base.rb +3 -0
  24. data/lib/langrove/adaptor/datagram.rb +27 -0
  25. data/lib/langrove/adaptor_base.rb +89 -0
  26. data/lib/langrove/client/base.rb +2 -0
  27. data/lib/langrove/client/datagram.rb +25 -0
  28. data/lib/langrove/client_base.rb +114 -0
  29. data/lib/langrove/daemon/base.rb +2 -0
  30. data/lib/langrove/daemon_base.rb +175 -0
  31. data/lib/langrove/ext/class_loader.rb +148 -0
  32. data/lib/langrove/ext/config_item.rb +34 -0
  33. data/lib/langrove/ext/config_loader.rb +16 -0
  34. data/lib/langrove/ext/fake_logger.rb +8 -0
  35. data/lib/langrove/ext/persistable.rb +103 -0
  36. data/lib/langrove/ext/string.rb +35 -0
  37. data/lib/langrove/ext.rb +7 -0
  38. data/lib/langrove/handler/base.rb +2 -0
  39. data/lib/langrove/handler_base.rb +141 -0
  40. data/lib/langrove/protocol/base.rb +2 -0
  41. data/lib/langrove/protocol/syslog.rb +32 -0
  42. data/lib/langrove/protocol_base.rb +32 -0
  43. data/lib/langrove/version.rb +3 -0
  44. data/lib/langrove.rb +1 -0
  45. data/spec/functional/daemon/datagram_spec.rb +115 -0
  46. data/spec/langrove/adaptor/datagram_spec.rb +6 -0
  47. data/spec/langrove/adaptor_base_spec.rb +48 -0
  48. data/spec/langrove/client/datagram_spec.rb +1 -0
  49. data/spec/langrove/client_base_spec.rb +5 -0
  50. data/spec/langrove/daemon_base_spec.rb +101 -0
  51. data/spec/langrove/ext/class_loader_spec.rb +83 -0
  52. data/spec/langrove/ext/config_item_spec.rb +81 -0
  53. data/spec/langrove/ext/config_loader_spec.rb +5 -0
  54. data/spec/langrove/ext/fake_logger_spec.rb +0 -0
  55. data/spec/langrove/ext/persistable_spec.rb +117 -0
  56. data/spec/langrove/ext/string_spec.rb +16 -0
  57. data/spec/langrove/handler_base_spec.rb +57 -0
  58. data/spec/langrove/protocol/syslog_spec.rb +45 -0
  59. data/spec/langrove/protocol_base_spec.rb +6 -0
  60. data/spec/todo_spec.rb +12 -0
  61. data/tmp/README +2 -0
  62. metadata +200 -0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.2-p0@langrove"
8
+
9
+ #
10
+ # Uncomment following line if you want options to be set only for given project.
11
+ #
12
+ # PROJECT_JRUBY_OPTS=( --1.9 )
13
+
14
+ #
15
+ # First we attempt to load the desired environment directly from the environment
16
+ # file. This is very fast and efficient compared to running through the entire
17
+ # CLI and selector. If you want feedback on which environment was used then
18
+ # insert the word 'use' after --create as this triggers verbose mode.
19
+ #
20
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
22
+ then
23
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
24
+
25
+ if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
26
+ then
27
+ . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
28
+ fi
29
+ else
30
+ # If the environment file has not yet been created, use the RVM CLI to select.
31
+ if ! rvm --create use "$environment_id"
32
+ then
33
+ echo "Failed to create RVM environment '${environment_id}'."
34
+ return 1
35
+ fi
36
+ fi
37
+
38
+ #
39
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
40
+ # it be automatically loaded. Uncomment the following and adjust the filename if
41
+ # necessary.
42
+ #
43
+ # filename=".gems"
44
+ # if [[ -s "$filename" ]]
45
+ # then
46
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
47
+ # fi
48
+
49
+ # If you use bundler, this might be useful to you:
50
+ # if command -v bundle && [[ -s Gemfile ]]
51
+ # then
52
+ # bundle install
53
+ # fi
54
+
55
+ if [[ $- == *i* ]] # check for interactive shells
56
+ then
57
+ echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
58
+ else
59
+ echo "Using: $GEM_HOME" # don't use colors in interactive shells
60
+ fi
61
+
62
+
data/.watchr ADDED
@@ -0,0 +1,27 @@
1
+ def run_spec(file)
2
+ unless File.exist?(file)
3
+ puts "#{file} does not exist"
4
+ return
5
+ end
6
+
7
+ puts "Running #{file}"
8
+ system "rspec #{file}"
9
+ puts
10
+ end
11
+
12
+ watch("spec/.*/*_spec.rb") do |match|
13
+ run_spec match[0]
14
+ end
15
+
16
+ watch("(.*/*).rb") do |match|
17
+ file = match[1]
18
+ file.gsub!('lib/','')
19
+ file.gsub!('spec/','')
20
+ file.sub!('_spec','')
21
+ puts "====#{file}==="
22
+ if /demo/.match(match[0]) then
23
+ run_spec %{spec/#{file}_spec.rb}
24
+ next
25
+ end
26
+ run_spec %{spec/#{file}_spec.rb}
27
+ end
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source :gemcutter
2
+ source "http://rubygems.org"
3
+
4
+ gem 'watchr'
5
+ gem 'rspec'
6
+
7
+ # daemon-kit
8
+ gem 'daemon-kit'
9
+ gem 'eventmachine'
10
+ gem 'em-http-request'
11
+ gem 'awesome_print'
12
+
13
+ gem 'eventmachine_httpserver'
14
+
15
+ gem 'resque'
16
+ gem 'rake'
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ remote: http://rubygems.org/
4
+ specs:
5
+ addressable (2.2.7)
6
+ awesome_print (1.0.2)
7
+ daemon-kit (0.1.8.2)
8
+ eventmachine (>= 0.12.10)
9
+ safely (>= 0.3.1)
10
+ diff-lcs (1.1.3)
11
+ em-http-request (0.3.0)
12
+ addressable (>= 2.0.0)
13
+ escape_utils
14
+ eventmachine (>= 0.12.9)
15
+ escape_utils (0.2.4)
16
+ eventmachine (0.12.10)
17
+ eventmachine_httpserver (0.2.1)
18
+ multi_json (1.3.2)
19
+ rack (1.4.1)
20
+ rack-protection (1.2.0)
21
+ rack
22
+ rake (0.8.7)
23
+ redis (2.2.2)
24
+ redis-namespace (1.0.3)
25
+ redis (< 3.0.0)
26
+ resque (1.20.0)
27
+ multi_json (~> 1.0)
28
+ redis-namespace (~> 1.0.2)
29
+ sinatra (>= 0.9.2)
30
+ vegas (~> 0.1.2)
31
+ rspec (2.9.0)
32
+ rspec-core (~> 2.9.0)
33
+ rspec-expectations (~> 2.9.0)
34
+ rspec-mocks (~> 2.9.0)
35
+ rspec-core (2.9.0)
36
+ rspec-expectations (2.9.1)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.9.0)
39
+ safely (0.3.1)
40
+ sinatra (1.3.2)
41
+ rack (~> 1.3, >= 1.3.6)
42
+ rack-protection (~> 1.2)
43
+ tilt (~> 1.3, >= 1.3.3)
44
+ tilt (1.3.3)
45
+ vegas (0.1.11)
46
+ rack (>= 1.0.0)
47
+ watchr (0.7)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ awesome_print
54
+ daemon-kit
55
+ em-http-request
56
+ eventmachine
57
+ eventmachine_httpserver
58
+ rake
59
+ resque
60
+ rspec
61
+ watchr
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift 'lib'
2
+
3
+ desc "Publish a new version to ruby-gems.org"
4
+ task :publish do
5
+ require 'langrove/version'
6
+
7
+ sh "gem build langrove.gemspec"
8
+ sh "gem push langrove-#{LanGrove::Version}.gem"
9
+
10
+ sh "git tag v#{LanGrove::Version}"
11
+ sh "git push origin v#{LanGrove::Version}"
12
+ sh "git push origin master"
13
+ sh "git clean -fd"
14
+
15
+ # exec "rake documentation"
16
+
17
+ end
18
+
19
+ desc "Push to github"
20
+ task :push_world do
21
+
22
+ puts "TODO"
23
+
24
+ end
@@ -0,0 +1 @@
1
+ tmp/*.*
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ DAEMON_ROOT = File.expand_path('../../../functional/', __FILE__)
4
+ DAEMON_NAME = File.basename $0
5
+ require File.expand_path('../../config/environment', __FILE__)
6
+ DaemonKit::Application.exec( DAEMON_ROOT + '/libexec/daemon.rb' )
File without changes
@@ -0,0 +1,64 @@
1
+ # Don't change this file!
2
+ # Configure your daemon in config/environment.rb
3
+
4
+ DAEMON_ROOT = "#{File.expand_path(File.dirname(__FILE__))}/.." unless defined?( DAEMON_ROOT )
5
+
6
+ require "rubygems"
7
+ require "bundler/setup"
8
+
9
+ module DaemonKit
10
+ class << self
11
+ def boot!
12
+ unless booted?
13
+ pick_boot.run
14
+ end
15
+ end
16
+
17
+ def booted?
18
+ defined? DaemonKit::Initializer
19
+ end
20
+
21
+ def pick_boot
22
+ (vendor_kit? ? VendorBoot : GemBoot).new
23
+ end
24
+
25
+ def vendor_kit?
26
+ File.exists?( "#{DAEMON_ROOT}/vendor/daemon-kit" )
27
+ end
28
+ end
29
+
30
+ class Boot
31
+ def run
32
+ load_initializer
33
+ DaemonKit::Initializer.run
34
+ end
35
+ end
36
+
37
+ class VendorBoot < Boot
38
+ def load_initializer
39
+ require "#{DAEMON_ROOT}/vendor/daemon-kit/lib/daemon_kit/initializer"
40
+ end
41
+ end
42
+
43
+ class GemBoot < Boot
44
+ def load_initializer
45
+ begin
46
+ require 'rubygems' unless defined?( ::Gem )
47
+ gem 'daemon-kit'
48
+ require 'daemon_kit/initializer'
49
+ rescue ::Gem::LoadError => e
50
+ msg = <<EOF
51
+
52
+ You are missing the daemon-kit gem. Please install the following gem:
53
+
54
+ sudo gem install daemon-kit
55
+
56
+ EOF
57
+ $stderr.puts msg
58
+ exit 1
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ DaemonKit.boot!
@@ -0,0 +1,12 @@
1
+ :daemons:
2
+ datagram:
3
+ :periodic: 5
4
+ :adaptor:
5
+ :connection: Datagram
6
+ :iface: 127.0.0.1
7
+ :port: 12701
8
+ :client:
9
+ :class: Datagram
10
+ :handler:
11
+ :collection: SocketToFile
12
+ :protocol: SocketToFile
@@ -0,0 +1,28 @@
1
+ ENV["TZ"] = "ZA"
2
+ #ENV['DAEMON_ENV'] ||= 'production'
3
+
4
+ # Boot up
5
+ require File.join(File.dirname(__FILE__), 'boot')
6
+
7
+ # Auto-require default libraries.
8
+ Bundler.require :default, DaemonKit.env
9
+
10
+ DaemonKit::Initializer.run do |config|
11
+
12
+ config.daemon_name = DAEMON_NAME
13
+
14
+ # Force the daemon to be killed after X seconds from asking it to
15
+ # config.force_kill_wait = 30
16
+
17
+ # Log backraces when a thread/daemon dies (Recommended)
18
+ config.backtraces = true
19
+
20
+ #
21
+ # TODO: move log level into per daemon config
22
+ #
23
+ #config.log_level = :debug
24
+ config.log_level = :info
25
+ #config.log_level = :warn
26
+ #config.log_level = :error
27
+
28
+ end
File without changes
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ class Datagram < LanGrove::Daemon::Base
2
+
3
+ #
4
+ # Consider tossing this dependancy.
5
+ #
6
+ # Not entirely certain this layer in the abstraction
7
+ # will be useful.
8
+ #
9
+ # Except, by
10
+ #
11
+ # << using this layer in the abstraction >>
12
+ #
13
+ #
14
+ # the eval "require 'module/class_name.rb'" in the
15
+ # langrove/ext/class_loader could possibly be avoided
16
+ # if the implementation requires all necessary modules
17
+ # ahead of starting the daemon.
18
+ #
19
+ #
20
+
21
+ end
@@ -0,0 +1,36 @@
1
+ #
2
+ # Define a Handler by extending LanGrove::Handler::Base
3
+ # and extending the functions:
4
+ #
5
+ # 1. <YourClass>.receive( data )
6
+ #
7
+ # Data arriving from the Adaptor will arrive into
8
+ # this function having already been decoded by the
9
+ # configured Protocol for this Handler
10
+ #
11
+ # # 2. <YourClass>.transmit
12
+ # #
13
+
14
+ require 'langrove'
15
+
16
+ module Handler
17
+
18
+ class SocketToFile < LanGrove::Handler::Base
19
+
20
+ def receive( data )
21
+
22
+ @logger.info( "#{self}.receive: #{data}" )
23
+
24
+ File.open( data[:filename], 'w' ) do |f|
25
+
26
+ f.write( data[:content] )
27
+
28
+ end
29
+
30
+ @logger.info "Wrote data: '#{data[ :content ]}' to file: '#{ data[ :filename ]}'"
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,55 @@
1
+ #
2
+ # Define a Protocol by extending LanGrove::Protocol::Base
3
+ # and extending the functions:
4
+ #
5
+ # 1. <YourClass>.decode( data )
6
+ #
7
+ # Data arriving from the Adaptor will be passed to
8
+ # the config assigned protocol. The Handler will
9
+ # be expecting decoded data in the form of a Hash
10
+ #
11
+ # SPECIFICALLY: One of the keys should correspond
12
+ # to the :route_by in the config.
13
+ #
14
+ # # 2. <YourClass>.encode( .. )
15
+ # #
16
+
17
+
18
+ require 'langrove'
19
+
20
+ module Protocol
21
+
22
+ #
23
+ # Module is only necessary if you choose to
24
+ # structure associations of class by name.
25
+ #
26
+ # eg.
27
+ #
28
+ # Protocol::SocketToFile
29
+ # Handler::SocketToFile
30
+ #
31
+
32
+ class SocketToFile < LanGrove::Protocol::Base
33
+
34
+ def decode( data )
35
+
36
+ #
37
+ # OVERRIDE
38
+ #
39
+ # Becasuse your protocol
40
+ #
41
+
42
+ @logger.info( "#{self}.decode: #{data}" ) unless @logger.nil?
43
+
44
+ {
45
+
46
+ :filename => data.split('|')[0],
47
+ :content => data.split('|',2)[1]
48
+
49
+ }
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,68 @@
1
+ require 'langrove'
2
+
3
+ CLASS_NAME = DAEMON_NAME.camelize
4
+ CONFIG_FILE = "#{DAEMON_ROOT}/config/daemons.yml"
5
+ CONFIG_HASH = LanGrove::ConfigLoader.yaml( CONFIG_FILE )
6
+
7
+ daemon = nil
8
+
9
+ DaemonKit::Application.running! do |config|
10
+
11
+ DaemonKit.logger.info "Spawing #{DAEMON_NAME} at pidfile #{config.pid_file}"
12
+
13
+ #
14
+ # setup signal traps
15
+ #
16
+ config.trap( 'TERM', Proc.new {
17
+
18
+ #
19
+ # Handle stop signal from os
20
+ #
21
+ daemon.stop_daemon
22
+
23
+ } )
24
+
25
+ config.trap( 'INT', Proc.new {
26
+
27
+ #
28
+ # Handle ^C from user (eg. developer) running un-daemonized
29
+ #
30
+ daemon.stop_daemon
31
+
32
+ } )
33
+
34
+ #
35
+ # Have not yet '''suitably''' succeeded in getting a sigHUP
36
+ # into a daemon with the monit/daemonkit combo yet....
37
+ #
38
+ # grumbles...
39
+ #
40
+ config.trap( 'HUP', Proc.new {
41
+
42
+ #
43
+ # Handle reload
44
+ #
45
+ daemon.reload_daemon
46
+
47
+ } )
48
+
49
+ #
50
+ # Latebind the daemon class
51
+ #
52
+ # TODO: see about tossing the libexec
53
+ # or modifying class loader to enable
54
+ # alternate load path to allow this pattern:
55
+ #
56
+ # daemon = LanGrove::ClassLoader.create( {
57
+ #
58
+ # :module => 'Daemon',
59
+ # :class => DAEMON_NAME.camelize
60
+ #
61
+ # } ).new( CONFIG_HASH, DAEMON_NAME, DaemonKit.logger )
62
+ #
63
+
64
+ require "daemon/#{DAEMON_NAME}"
65
+ daemon = Object.const_get( CLASS_NAME ).new( CONFIG_HASH, DAEMON_NAME, DaemonKit.logger )
66
+ daemon.run
67
+
68
+ end
@@ -0,0 +1,3 @@
1
+ *.log
2
+ *.pid
3
+ *.yml
@@ -0,0 +1 @@
1
+ Certain test write files into here
@@ -0,0 +1,26 @@
1
+ #$LOAD_PATH.unshift 'langrove' unless $LOAD_PATH.include?( 'langrove' )
2
+
3
+ #$LOAD_PATH.inspect
4
+
5
+ #
6
+ # For the implementation client
7
+ #
8
+ module Adaptor; end
9
+ module Client; end
10
+ module Daemon; end
11
+ module Handler; end
12
+ module Protocol; end
13
+
14
+ module LanGrove
15
+
16
+ class DaemonConfigException < Exception; end
17
+
18
+ end
19
+
20
+ require 'langrove/ext'
21
+
22
+ require 'langrove/daemon/base'
23
+ require 'langrove/adaptor/base'
24
+ require 'langrove/handler/base'
25
+ require 'langrove/protocol/base'
26
+ require 'langrove/client/base'
@@ -0,0 +1,3 @@
1
+ module LanGrove::Adaptor; end
2
+ require 'langrove/adaptor_base'
3
+ require 'langrove/adaptor/datagram'
@@ -0,0 +1,27 @@
1
+ require 'langrove/adaptor/base'
2
+
3
+ module LanGrove::Adaptor
4
+
5
+ class Datagram < Base
6
+
7
+ def listen( handler, protocol )
8
+
9
+ @logger.info "starting listen at UDP #{@iface}:#{@port}"
10
+
11
+ EventMachine::open_datagram_socket( @iface, @port,
12
+
13
+ @client ) do |client|
14
+
15
+ @logger.info "client assign handler: #{handler}"
16
+ client.handler = handler
17
+
18
+ @logger.info "client instanciate protocol: #{protocol}"
19
+ client.protocol = protocol.new( nil, @logger )
20
+
21
+ @logger.info "client assign config: #{@client_config}"
22
+ client.config = @client_config.clone
23
+
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,89 @@
1
+ require 'eventmachine'
2
+
3
+ require 'langrove'
4
+
5
+ module LanGrove::Adaptor
6
+
7
+ class Base
8
+
9
+ def initialize( config, logger )
10
+
11
+ @config = config
12
+ @logger = logger
13
+
14
+ @iface = '127.0.0.1'
15
+ @port = 12701
16
+
17
+ @iface = @config[ :iface ] if @config.has_key? :iface
18
+ @port = @config[ :port ] if @config.has_key? :port
19
+
20
+ if @config.has_key? :connector then
21
+
22
+ #
23
+ # TODO: may need to override default connection handler
24
+ #
25
+
26
+ end
27
+
28
+ #
29
+ # initialize the client specified in config
30
+ #
31
+ # daemons:
32
+ # name_of_daemon:
33
+ # adaptor:
34
+ # connection: TcpServer
35
+ # client:
36
+ # class: Client <---------
37
+ # handler:
38
+ # collection: CollectionOfClients
39
+ #
40
+ #
41
+
42
+ @logger.info "TODO: loading client is not tested"
43
+
44
+ client = nil
45
+
46
+ begin
47
+
48
+ #
49
+ # TODO: make this more informative on error
50
+ #
51
+
52
+ @client_config = @config[ :client ]
53
+ client = @client_config[ :class ]
54
+
55
+ rescue
56
+
57
+ error = "Missing config item(s) for adaptor: #{@config.inspect}"
58
+
59
+ @logger.error "EXIT: #{error}"
60
+
61
+ raise LanGrove::DaemonConfigException.new(
62
+
63
+ "Missing config item for daemon: #{@daemon_name}"
64
+
65
+ )
66
+
67
+ end
68
+
69
+ @logger.info "Load definition: Client::#{client}"
70
+
71
+ @client = LanGrove::ClassLoader.create( {
72
+
73
+ :module => 'Client',
74
+ :class => client
75
+
76
+ } )
77
+
78
+
79
+ end
80
+
81
+ def listen( handler, protocol )
82
+
83
+ raise LanGrove::DaemonConfigException.new( "NotYetExtended: undefined listen()" )
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,2 @@
1
+ module LanGrove::Client; end
2
+ require 'langrove/client_base'
@@ -0,0 +1,25 @@
1
+ module LanGrove
2
+
3
+ module Client
4
+
5
+ class Datagram < Base
6
+
7
+ def receive( data )
8
+
9
+ #
10
+ # Quick hack, datagram client routes
11
+ # data back to the Handler - to get
12
+ # back to friday position.
13
+ #
14
+ # But with the gem
15
+ #
16
+
17
+ @handler.receive( data )
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end