em-langrove 0.0.4.5

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/bin/langrove +3 -0
  8. data/functional/config/boot.rb +64 -0
  9. data/functional/config/daemons.yml +13 -0
  10. data/functional/config/environment.rb +28 -0
  11. data/functional/config/environments/development.rb +0 -0
  12. data/functional/config/environments/production.rb +0 -0
  13. data/functional/config/environments/test.rb +0 -0
  14. data/functional/lib/client/socket_to_file.rb +47 -0
  15. data/functional/lib/daemon/datagram.rb +21 -0
  16. data/functional/lib/protocol/socket_to_file.rb +55 -0
  17. data/functional/libexec/daemon.rb +68 -0
  18. data/functional/tmp/README +1 -0
  19. data/lib/langrove/_base.rb +28 -0
  20. data/lib/langrove/adaptor/base.rb +2 -0
  21. data/lib/langrove/adaptor_base.rb +116 -0
  22. data/lib/langrove/client/base.rb +2 -0
  23. data/lib/langrove/client/datagram.rb +25 -0
  24. data/lib/langrove/client_base.rb +92 -0
  25. data/lib/langrove/daemon/base.rb +2 -0
  26. data/lib/langrove/daemon_base.rb +281 -0
  27. data/lib/langrove/ext/class_loader.rb +148 -0
  28. data/lib/langrove/ext/config_item.rb +34 -0
  29. data/lib/langrove/ext/config_loader.rb +16 -0
  30. data/lib/langrove/ext/fake_logger.rb +8 -0
  31. data/lib/langrove/ext/find.rb +90 -0
  32. data/lib/langrove/ext/persistable.rb +103 -0
  33. data/lib/langrove/ext/string.rb +35 -0
  34. data/lib/langrove/ext.rb +7 -0
  35. data/lib/langrove/handler/base.rb +2 -0
  36. data/lib/langrove/handler_base.rb +148 -0
  37. data/lib/langrove/job/base.rb +1 -0
  38. data/lib/langrove/job_base.rb +24 -0
  39. data/lib/langrove/protocol/base.rb +2 -0
  40. data/lib/langrove/protocol/syslog.rb +32 -0
  41. data/lib/langrove/protocol_base.rb +32 -0
  42. data/lib/langrove/version.rb +3 -0
  43. data/lib/langrove.rb +1 -0
  44. data/spec/functional/daemon/datagram_spec.rb +121 -0
  45. data/spec/langrove/adaptor_base_spec.rb +63 -0
  46. data/spec/langrove/client/datagram_spec.rb +1 -0
  47. data/spec/langrove/client_base_spec.rb +5 -0
  48. data/spec/langrove/daemon_base_spec.rb +154 -0
  49. data/spec/langrove/ext/class_loader_spec.rb +83 -0
  50. data/spec/langrove/ext/config_item_spec.rb +81 -0
  51. data/spec/langrove/ext/config_loader_spec.rb +5 -0
  52. data/spec/langrove/ext/fake_logger_spec.rb +0 -0
  53. data/spec/langrove/ext/find_spec.rb +53 -0
  54. data/spec/langrove/ext/persistable_spec.rb +117 -0
  55. data/spec/langrove/ext/string_spec.rb +16 -0
  56. data/spec/langrove/handler_base_spec.rb +103 -0
  57. data/spec/langrove/job_base_spec.rb +28 -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 +203 -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 em-langrove.gemspec"
8
+ sh "gem push em-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
data/bin/langrove ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts "warbel"
@@ -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,13 @@
1
+ :daemons:
2
+ datagram:
3
+ :periodic: 5
4
+ :protocol:
5
+ :class: SocketToFile
6
+ :adaptor:
7
+ :iface: 127.0.0.1
8
+ :port: 12701
9
+ :transport: udp
10
+ :client:
11
+ :class: SocketToFile
12
+ :handler:
13
+ :collection: Base
@@ -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 = :debug
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,47 @@
1
+ #
2
+ # Define a Client by extending LanGrove::Handler::Client
3
+ # and extending the functions:
4
+ #
5
+ # 1. <YourClass>.receive( decoded_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 Daemon
10
+ #
11
+ # # 2. <YourClass>.transmit
12
+ # #
13
+
14
+ require 'langrove'
15
+
16
+ module Client
17
+
18
+ class SocketToFile < LanGrove::Client::Base
19
+
20
+ def periodic
21
+
22
+ #
23
+ # OVERRIDE
24
+ #
25
+ # To perform activities on the periodic ticker.
26
+ #
27
+ @logger.debug( "#{self}.periodic" )
28
+
29
+ end
30
+
31
+ def receive( data )
32
+
33
+ @logger.debug( "#{self}.receive: #{data}" )
34
+
35
+ File.open( data[:filename], 'w' ) do |f|
36
+
37
+ f.write( data[:content] )
38
+
39
+ end
40
+
41
+ @logger.debug "Wrote data: '#{data[ :content ]}' to file: '#{ data[ :filename ]}'"
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -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,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.debug( "#{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 @@
1
+ Certain test write files into here
@@ -0,0 +1,28 @@
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
+ module Job; end
14
+
15
+ module LanGrove
16
+
17
+ class DaemonConfigException < Exception; end
18
+
19
+ end
20
+
21
+ require 'langrove/ext'
22
+
23
+ require 'langrove/daemon/base'
24
+ require 'langrove/adaptor/base'
25
+ require 'langrove/handler/base'
26
+ require 'langrove/protocol/base'
27
+ require 'langrove/client/base'
28
+ require 'langrove/job/base'
@@ -0,0 +1,2 @@
1
+ module LanGrove::Adaptor; end
2
+ require 'langrove/adaptor_base'
@@ -0,0 +1,116 @@
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
+ @transport = :tcp
15
+ @iface = '127.0.0.1'
16
+ @port = 12701
17
+
18
+ @iface = @config[ :iface ] if @config.has_key? :iface
19
+ @port = @config[ :port ] if @config.has_key? :port
20
+ @transport = @config[ :transport ].to_sym if @config.has_key? :transport
21
+
22
+ #
23
+ # Assign the call signature for the EventMachine server
24
+ #
25
+ @em_server_call = case @transport
26
+
27
+ when :tcp
28
+
29
+ :start_server
30
+
31
+ when :udp
32
+
33
+ :open_datagram_socket
34
+
35
+ else
36
+
37
+ :start_server
38
+
39
+ end
40
+
41
+ end
42
+
43
+ def listen( client, protocol, handler )
44
+
45
+ #
46
+ # <client> = {
47
+ #
48
+ # :class => <loaded class constant>
49
+ # :config => <client's branch of config>
50
+ #
51
+ # }
52
+ #
53
+ # <protocol> = { ...the same, but protocolic }
54
+ #
55
+ #
56
+
57
+ @logger.info "starting listen at UDP #{@iface}:#{@port}"
58
+
59
+ EventMachine::send( @em_server_call, @iface, @port,
60
+
61
+ client[:class] ) do | client_connected |
62
+
63
+ #
64
+ # @em_server_call as:
65
+ #
66
+ # udp - EM::open_datagram_socket, yields an instance of
67
+ # client[:class] into here on bind to the port
68
+ #
69
+ # ie. at starting to listen
70
+ #
71
+ # unverified: ? If more than 1 datagram source is
72
+ # transmitting to here - will there still
73
+ # still be only ONE EM:Connection instance?
74
+ #
75
+ # tcp - EM::start_server yields an new instance of client[:class]
76
+ # with every connecting socket pair.
77
+ #
78
+ # ie. On socket pair binding - so each remote client will
79
+ # have it's own associated instance of a client[:class]
80
+ # running in the machine.
81
+ #
82
+
83
+
84
+ #
85
+ # Initialize the client with the (application layer) Protocol
86
+ #
87
+
88
+ client_connected.logger = @logger
89
+
90
+ client_connected.config = client[ :config ]
91
+
92
+ client_connected.protocol = protocol[ :class ]\
93
+
94
+ .new( protocol[ :config ], @logger )
95
+
96
+ @logger.info( "TODO: make a reference to the Client on the Handler" )
97
+
98
+ #
99
+ # Bi-Directionally bind the Client and Handler
100
+ #
101
+ handler.connect( client_connected )
102
+ client_connected.handler = handler
103
+
104
+ #
105
+ # Client is ready and running inside the reactor
106
+ #
107
+ # EM::start_server will yield again on the next connect.
108
+ #
109
+
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ 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