slnky 0.8.3 → 0.9.0

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/bin/slnky +1 -0
  5. data/lib/slnky/cli/command.rb +78 -0
  6. data/lib/slnky/cli/generate.rb +3 -1
  7. data/lib/slnky/cli/service.rb +30 -0
  8. data/lib/slnky/cli.rb +4 -1
  9. data/lib/slnky/command/request.rb +7 -0
  10. data/lib/slnky/command/response.rb +43 -0
  11. data/lib/slnky/command.rb +100 -0
  12. data/lib/slnky/config.rb +69 -0
  13. data/lib/slnky/data.rb +14 -3
  14. data/lib/slnky/generator.rb +44 -18
  15. data/lib/slnky/log.rb +117 -0
  16. data/lib/slnky/service/subscriber.rb +57 -0
  17. data/lib/slnky/service/timer.rb +45 -0
  18. data/lib/slnky/service.rb +58 -96
  19. data/lib/slnky/system.rb +19 -0
  20. data/lib/slnky/template/service/.ruby-version +1 -0
  21. data/lib/slnky/template/service/config/deploy.rb.erb +3 -6
  22. data/lib/slnky/template/service/lib/slnky/NAME/client.rb.erb +11 -0
  23. data/lib/slnky/template/service/lib/slnky/NAME/command.rb.erb +15 -0
  24. data/lib/slnky/template/service/lib/slnky/NAME/mock.rb.erb +11 -0
  25. data/lib/slnky/template/service/lib/slnky/{service/NAME.rb.erb → NAME/service.rb.erb} +7 -4
  26. data/lib/slnky/template/service/lib/slnky/NAME.rb.erb +6 -0
  27. data/lib/slnky/template/service/service-slnky-NAME.erb +2 -2
  28. data/lib/slnky/template/service/spec/slnky/NAME/command_spec.rb.erb +17 -0
  29. data/lib/slnky/template/service/spec/slnky/NAME/service_spec.rb.erb +14 -0
  30. data/lib/slnky/template/service/spec/spec_helper.rb.erb +15 -4
  31. data/lib/slnky/template/service/test/commands/echo.json.erb +11 -0
  32. data/lib/slnky/template/service/test/config.yaml.erb +1 -1
  33. data/lib/slnky/transport.rb +98 -0
  34. data/lib/slnky/version.rb +1 -1
  35. data/lib/slnky.rb +15 -14
  36. data/slnky.gemspec +2 -0
  37. metadata +52 -8
  38. data/lib/slnky/service/exchanges.rb +0 -33
  39. data/lib/slnky/service/periodics.rb +0 -19
  40. data/lib/slnky/service/queues.rb +0 -27
  41. data/lib/slnky/service/subscriptions.rb +0 -27
  42. data/lib/slnky/template/service/spec/slnky/service/NAME_spec.rb.erb +0 -10
@@ -0,0 +1,57 @@
1
+ module Slnky
2
+ module Service
3
+ class << self
4
+ def subscriber
5
+ Slnky::Service::Subscriber.instance
6
+ end
7
+ end
8
+
9
+ class Subscriber
10
+ class << self
11
+ def instance
12
+ @instance ||= self.new
13
+ end
14
+ end
15
+
16
+ def initialize
17
+ @subscriptions = []
18
+ end
19
+
20
+ def handle(name, data)
21
+
22
+ end
23
+
24
+ def add(name, method)
25
+ @subscriptions << Slnky::Service::Subscription.new(name, method)
26
+ end
27
+
28
+ def list
29
+ @subscriptions
30
+ end
31
+
32
+ def each
33
+ @subscriptions.each do |sub|
34
+ yield sub.name, sub.method
35
+ end
36
+ end
37
+
38
+ def for(name)
39
+ @subscriptions.each do |sub|
40
+ if sub.name == name || File.fnmatch(sub.name, name)
41
+ yield sub.name, sub.method if block_given?
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ class Subscription
48
+ attr_reader :name
49
+ attr_reader :method
50
+
51
+ def initialize(name, method)
52
+ @name = name
53
+ @method = method
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,45 @@
1
+ module Slnky
2
+ module Service
3
+ class << self
4
+ def timers
5
+ Slnky::Service::Timer.instance
6
+ end
7
+ end
8
+
9
+ class Timer
10
+ class << self
11
+ def instance
12
+ @instance ||= self.new
13
+ end
14
+ end
15
+
16
+ def initialize
17
+ @timers = []
18
+ end
19
+
20
+ def add(seconds, method)
21
+ @timers << Slnky::Service::Periodic.new(seconds, method)
22
+ end
23
+
24
+ def list
25
+ @timers
26
+ end
27
+
28
+ def each
29
+ @timers.each do |t|
30
+ yield t.seconds, t.method
31
+ end
32
+ end
33
+ end
34
+
35
+ class Periodic
36
+ attr_reader :seconds
37
+ attr_reader :method
38
+
39
+ def initialize(seconds, method)
40
+ @seconds = seconds
41
+ @method = method
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/slnky/service.rb CHANGED
@@ -1,82 +1,70 @@
1
- require 'amqp'
2
- require 'open-uri'
3
- require 'json'
4
- require 'socket'
5
-
6
1
  require 'slnky/version'
7
2
  require 'slnky/message'
8
- require 'slnky/service/subscriptions'
9
- require 'slnky/service/periodics'
10
- require 'slnky/service/queues'
11
- require 'slnky/service/exchanges'
3
+ require 'slnky/service/subscriber'
4
+ require 'slnky/service/timer'
12
5
 
13
6
  module Slnky
14
7
  module Service
15
8
  class Base
16
9
  attr_reader :config
17
-
18
- def initialize(url, options={})
19
- @server = url
20
- @name = self.class.name.split('::').last.downcase
21
- @environment = options.delete(:env) || options.delete(:environment) || 'development'
22
- @config = load_config(options)
23
-
24
- @subscriptions = self.class.subscriptions || Slnky::Service::Subscriptions.new
25
- @periodics = self.class.periodics || Slnky::Service::Periodics.new
26
- @hostname = Socket.gethostname
27
- @ipaddress = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
10
+ attr_reader :subscriber
11
+ attr_reader :timers
12
+ attr_reader :name
13
+
14
+ def initialize
15
+ config.service = name
16
+ @environment = config.environment
17
+ @server_down = false
28
18
  end
29
19
 
30
20
  def start
31
- AMQP.start("amqp://#{config.rabbit.host}:#{config.rabbit.port}") do |connection|
32
- @channel = AMQP::Channel.new(connection)
33
- @channel.on_error do |ch, channel_close|
34
- raise "Channel-level exception: #{channel_close.reply_text}"
35
- end
36
-
37
- @exchanges = Slnky::Service::Exchanges.new(@channel)
38
- @exchanges.create('events')
39
- @exchanges.create('logs')
21
+ transport.start!(self) do |_|
22
+ log.info "running"
23
+ run
40
24
 
41
- @queues = Slnky::Service::Queues.new(@channel)
42
- @queues.create(@name, @exchanges['events'])
25
+ subscriber.add "slnky.#{name}.command", :handle_command
26
+ subscriber.add "slnky.help.command", :handle_command
27
+ subscriber.add "slnky.service.restart", :handle_restart
28
+ timers.add 5.seconds, :handle_heartbeat unless config.development?
43
29
 
44
- stopper = Proc.new do
45
- puts "#{Time.now}: stopping"
46
- connection.close { EventMachine.stop }
30
+ subscriber.each do |name, method|
31
+ log.info "subscribed to: #{name} -> #{self.class.name}.#{method}"
47
32
  end
33
+ end
34
+ end
48
35
 
49
- Signal.trap("INT", stopper)
50
- Signal.trap("TERM", stopper)
36
+ def handle_command(event, data)
37
+ if command
38
+ command.handle(event, data)
39
+ else
40
+ log.error "no comamnd support for #{name}"
41
+ end
42
+ end
51
43
 
52
- log :info, "running"
44
+ def handle_restart(name, data)
45
+ # if we get this event, just stop. upstart will start us again.
46
+ log.warn "received restart event"
47
+ transport.stop!('Restarted')
48
+ end
53
49
 
54
- run
50
+ def handle_heartbeat
51
+ return if @server_down
52
+ Slnky.heartbeat(name)
53
+ rescue => e
54
+ log.info "could not post heartbeat, server down? #{e.message}"
55
+ @server_down = true
56
+ end
55
57
 
56
- @subscriptions.each do |name, method|
57
- log :info, "subscribed to: #{name} -> #{self.class.name}.#{method}"
58
- end
58
+ def subscriber
59
+ @subscriber ||= Slnky::Service.subscriber
60
+ end
59
61
 
60
- @queues[@name].subscribe do |raw|
61
- message = parse(raw)
62
- event = message.name
63
- data = message.payload
64
- @subscriptions.for(event) do |name, method|
65
- self.send(method.to_sym, event, data)
66
- end
67
- if event == 'slnky.service.restart'
68
- # if we get this event, just stop. upstart will start us again.
69
- log :warn, "received restart event"
70
- stopper.call
71
- end
72
- end
62
+ def timers
63
+ @timers ||= Slnky::Service.timers
64
+ end
73
65
 
74
- @periodics.each do |seconds, method|
75
- EventMachine.add_periodic_timer(seconds) do
76
- self.send(method.to_sym)
77
- end
78
- end
79
- end
66
+ def name
67
+ @name ||= self.class.name.split('::')[1].downcase
80
68
  end
81
69
 
82
70
  protected
@@ -93,55 +81,29 @@ module Slnky
93
81
  Slnky::Message.parse(data)
94
82
  end
95
83
 
96
- def subscribe(name, method)
97
- raise "move this to class level, use methods instead of blocks"
98
- # @subscriptions.add(name, method)
84
+ def log
85
+ Slnky::Log.instance
99
86
  end
100
87
 
101
- def periodic(seconds, method)
102
- raise "move this to class level, use methods instead of blocks"
103
- # @periodics.add(seconds, method)
88
+ def config
89
+ Slnky.config
104
90
  end
105
91
 
106
- def log(level, message)
107
- data = {
108
- service: "#{@name}-#{$$}",
109
- level: level,
110
- hostname: @hostname,
111
- ipaddress: @ipaddress,
112
- message: "slnky.service.#{@name}: #{message}"
113
- }
114
- @exchanges['logs'].publish(msg(data)) if @exchanges && @exchanges['logs'] # only log to the exchange if it's created
115
- puts "%s [%6s] %s" % [Time.now, data[:level], data[:message]] if development? # log to the console if in development
92
+ def transport
93
+ @transport ||= Slnky::Transport.instance
116
94
  end
117
95
 
118
- def development?
119
- @environment == 'development'
120
- end
121
-
122
- def load_config(config)
123
- # if you specify config, it will not load from server
124
- # this is useful for testing, so you won't need to be running
125
- # a server locally or configure your development service to
126
- # talk to production server
127
- if !config || config.count == 0
128
- config = JSON.parse(open("#{@server}/configs/#{@name}") {|f| f.read })
129
- end
130
- DeepStruct.new(config)
96
+ def command
97
+ @command ||= "Slnky::#{name.capitalize}::Command".constantize.new rescue nil
131
98
  end
132
99
 
133
100
  class << self
134
- attr_reader :subscriptions
135
- attr_reader :periodics
136
-
137
101
  def subscribe(name, method)
138
- @subscriptions ||= Slnky::Service::Subscriptions.new
139
- @subscriptions.add(name, method)
102
+ Slnky::Service.subscriber.add(name, method)
140
103
  end
141
104
 
142
105
  def periodic(seconds, method)
143
- @periodics ||= Slnky::Service::Periodics.new
144
- @periodics.add(seconds, method)
106
+ Slnky::Service.timers.add(seconds, method)
145
107
  end
146
108
  alias_method :timer, :periodic
147
109
  end
@@ -0,0 +1,19 @@
1
+ require 'socket'
2
+
3
+ module Slnky
4
+ class System
5
+ class << self
6
+ def pid(service)
7
+ "#{ipaddress}/#{service}-#{$$}"
8
+ end
9
+
10
+ def hostname
11
+ @hostname ||= Socket.gethostname
12
+ end
13
+
14
+ def ipaddress
15
+ @ipaddress ||= Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ 2.2.2
@@ -1,17 +1,14 @@
1
1
  # config valid only for current version of Capistrano
2
2
  lock '3.4.0'
3
3
 
4
- set :application, '<%= dir %>'
5
- set :repo_url, 'git@github.com:something/<%= dir %>.git'
6
-
7
- rubyversion = File.read('.ruby-version').chomp
8
- rubygemset = File.read('.ruby-gemset').chomp
4
+ set :application, '<%= service %>'
5
+ set :repo_url, 'git@github.com:something/<%= service %>.git'
9
6
 
10
7
  set :deploy_to, "#{ENV['DEPLOY_DIR']}/#{fetch(:application)}#{fetch(:stage) == 'staging' ? '-stg' : ''}"
11
8
 
12
9
  set :keep_releases, 5
13
10
 
14
- set :rvm_ruby_version, "#{rubyversion}@#{rubygemset}" # Defaults to: 'default'
11
+ set :rvm_ruby_version, File.read('.ruby-version').chomp # Defaults to: 'default'
15
12
 
16
13
  # Default branch is :master
17
14
  # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
@@ -0,0 +1,11 @@
1
+ module Slnky
2
+ module <%= cap %>
3
+ class Client
4
+ def initialize(config)
5
+
6
+ end
7
+
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Slnky
2
+ module <%= cap %>
3
+ class Command < Slnky::Command::Base
4
+ attr_writer :client
5
+ def client
6
+ @client ||= Slnky::<%= cap %>::Client.new(config)
7
+ end
8
+
9
+ def echo(request, response)
10
+ args = request.arguments||[]
11
+ response.output = args.join(" ")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Slnky
2
+ module <%= cap %>
3
+ class Mock
4
+ def initialize(config)
5
+
6
+ end
7
+
8
+
9
+ end
10
+ end
11
+ end
@@ -1,8 +1,11 @@
1
- require 'slnky'
2
-
3
1
  module Slnky
4
- module Service
5
- class <%= name.capitalize %> < Base
2
+ module <%= cap %>
3
+ class Service < Slnky::Service::Base
4
+ attr_writer :client
5
+ def client
6
+ @client ||= Slnky::<%= cap %>::Client.new(config)
7
+ end
8
+
6
9
  subscribe 'slnky.service.test', :handler
7
10
  # you can also subscribe to heirarchies, this gets
8
11
  # all events under something.happened
@@ -0,0 +1,6 @@
1
+ require 'slnky'
2
+
3
+ require 'slnky/<%= name %>/client'
4
+ require 'slnky/<%= name %>/mock'
5
+ require 'slnky/<%= name %>/service'
6
+ require 'slnky/<%= name %>/command'
@@ -7,7 +7,7 @@ require 'rubygems'
7
7
  require 'bundler/setup'
8
8
  require 'dotenv'
9
9
  require 'daemons'
10
- require 'slnky/service/<%= name %>'
10
+ require 'slnky/<%= name %>'
11
11
  Dotenv.load
12
12
 
13
13
  env = ARGV[0]
@@ -15,4 +15,4 @@ env = ARGV[0]
15
15
  # Become a daemon
16
16
  # Daemons.daemonize if env == 'production'
17
17
 
18
- Slnky::Service::<%= name.capitalize %>.new(ENV['SLNKY_URL'], env: env).start
18
+ Slnky::<%= cap %>::Service.new(ENV['SLNKY_URL'], environment: env).start
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Slnky::<%= cap %>::Command do
4
+ subject do
5
+ s = described_class.new("http://localhost:3000", test_config)
6
+ s.client = Slnky::<%= cap %>::Mock.new(test_config)
7
+ s
8
+ end
9
+ let(:echo) { command('echo').payload }
10
+ let(:response) { Slnky::Command::Response.new() }
11
+
12
+ it 'handles echo' do
13
+ resp = response
14
+ expect(subject.echo(echo, resp)).not_to raise_error
15
+ expect(resp.output).to eq("test echo")
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Slnky::<%= cap %>::Service do
4
+ subject do
5
+ s = described_class.new("http://localhost:3000", test_config)
6
+ s.client = Slnky::<%= cap %>::Mock.new(test_config)
7
+ s
8
+ end
9
+ let(:test_event) { event_load('test')}
10
+
11
+ it 'handles event' do
12
+ expect(subject.handler(test_event.name, test_event.payload)).to eq(true)
13
+ end
14
+ end
@@ -1,6 +1,6 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'slnky'
3
- require 'slnky/service/<%= name %>'
3
+ require 'slnky/<%= name %>'
4
4
  require 'yaml'
5
5
  require 'erb'
6
6
  require 'tilt'
@@ -8,12 +8,21 @@ require 'tilt'
8
8
  require 'dotenv'
9
9
  @dotenv = Dotenv.load
10
10
 
11
- def event_load(name)
11
+ def event(name)
12
12
  @events ||= {}
13
13
  @events[name] ||= begin
14
14
  file = File.expand_path("../../test/events/#{name}.json", __FILE__)
15
15
  raise "file #{file} not found" unless File.exists?(file)
16
- Slnky::Message.new(JSON.parse(File.read(file)))
16
+ Slnky::Data.new(JSON.parse(File.read(file)))
17
+ end
18
+ end
19
+
20
+ def command(name)
21
+ @commands ||= {}
22
+ @commands[name] ||= begin
23
+ file = File.expand_path("../../test/commands/#{name}.json", __FILE__)
24
+ raise "file #{file} not found" unless File.exists?(file)
25
+ Slnky::Command::Request.new(JSON.parse(File.read(file)))
17
26
  end
18
27
  end
19
28
 
@@ -22,6 +31,8 @@ def test_config
22
31
  file = File.expand_path("../../test/config.yaml", __FILE__)
23
32
  template = Tilt::ERBTemplate.new(file)
24
33
  output = template.render(self, @dotenv)
25
- YAML.load(output)
34
+ cfg = Slnky::Data.new(YAML.load(output))
35
+ cfg.environment = 'test'
36
+ cfg
26
37
  end
27
38
  end
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "slnky.<%= name %>.command",
3
+ "payload": {
4
+ "command": "echo",
5
+ "args": [
6
+ "test",
7
+ "echo"
8
+ ],
9
+ "responder": "STDOUT"
10
+ }
11
+ }
@@ -1,5 +1,5 @@
1
1
  ---
2
- # config.yaml for Slnky::Service::<%= name.capitalize %>
2
+ # config.yaml for Slnky::<%= cap %>::Service
3
3
  # this file is processed through ERB, you can inject
4
4
  # values into the config from the environment, by specifying them
5
5
  # in the .env file
@@ -0,0 +1,98 @@
1
+ require 'amqp'
2
+
3
+ module Slnky
4
+ module Transport
5
+ class << self
6
+ def instance
7
+ @instance ||= begin
8
+ Slnky::Transport::Rabbit.new
9
+ end
10
+ end
11
+ end
12
+
13
+ class Rabbit
14
+ attr_reader :channel
15
+ attr_reader :exchanges
16
+ attr_reader :queues
17
+ attr_reader :stopper
18
+
19
+ def initialize
20
+ @config = Slnky.config
21
+ @host = @config.rabbit.host
22
+ @port = @config.rabbit.port
23
+ @url = "amqp://#{@host}:#{@port}"
24
+ @channel = nil
25
+ @exchanges = {}
26
+ @queues = {}
27
+ end
28
+
29
+ def start!(service, &block)
30
+ AMQP.start(@url) do |connection|
31
+ @connection = connection
32
+ @channel = AMQP::Channel.new(@connection)
33
+ @channel.on_error do |ch, channel_close|
34
+ raise "Channel-level exception: #{channel_close.reply_text}"
35
+ end
36
+
37
+ Signal.trap("INT", proc { self.stop!('Interrupted') })
38
+ Signal.trap("TERM", proc { self.stop!('Terminated') })
39
+
40
+ exchange('events', :fanout)
41
+ exchange('logs', :fanout)
42
+ exchange('response', :direct)
43
+ queue(service.name, 'events')
44
+
45
+ yield self if block_given?
46
+
47
+ if service.is_a?(Slnky::Service::Base)
48
+ queues.each do |name, queue|
49
+ queue.subscribe do |raw|
50
+ event = Slnky::Message.parse(raw)
51
+ service.subscriber.for(event.name) do |name, method|
52
+ service.send(method.to_sym, event.name, event.payload)
53
+ end
54
+ end
55
+ end
56
+
57
+ service.timers.each do |seconds, method|
58
+ EventMachine.add_periodic_timer(seconds) do
59
+ service.send(method.to_sym)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def stop!(msg=nil)
67
+ return unless @connection
68
+ puts "#{Time.now}: stopping (#{msg})" if msg
69
+ @connection.close { EventMachine.stop { exit } }
70
+ end
71
+
72
+ def exchange(desc, type)
73
+ raise 'attempting to create exchange without channel' unless @channel
74
+ name = "slnky.#{desc}"
75
+ @exchanges[desc] ||=
76
+ case type
77
+ when :fanout
78
+ @channel.fanout(name)
79
+ when :direct
80
+ @channel.direct(name)
81
+ else
82
+ raise "unknown exchange type: #{ex.type}"
83
+ end
84
+ end
85
+
86
+ def queue(desc, exchange, options={})
87
+ raise 'attempting to create queue without channel' unless @channel
88
+ name = "service.#{desc}.#{exchange}"
89
+ options = {
90
+ durable: true
91
+ }.merge(options)
92
+ routing = options.delete(:routing_key)
93
+ bindoptions = routing ? {routing_key: routing} : {}
94
+ @queues[desc] ||= @channel.queue(name, options).bind(@exchanges[exchange], bindoptions)
95
+ end
96
+ end
97
+ end
98
+ end
data/lib/slnky/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Slnky
2
- VERSION = "0.8.3"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/slnky.rb CHANGED
@@ -1,11 +1,17 @@
1
+ require 'rest_client'
2
+ require 'active_support/all'
3
+ require 'open-uri'
4
+ require 'json'
5
+
1
6
  require 'slnky/version'
2
7
  require 'slnky/data'
8
+ require 'slnky/config'
9
+ require 'slnky/log'
10
+ require 'slnky/system'
3
11
  require 'slnky/message'
4
12
  require 'slnky/service'
5
- require 'slnky/generator'
6
-
7
- require 'rest_client'
8
- require 'active_support/all'
13
+ require 'slnky/transport'
14
+ require 'slnky/command'
9
15
 
10
16
  module Slnky
11
17
  class << self
@@ -13,18 +19,13 @@ module Slnky
13
19
  Slnky::VERSION
14
20
  end
15
21
 
16
- def config
17
- load_config unless @config
18
- @config
19
- end
20
-
21
- def load_config(file='~/.slnky/config.yaml')
22
- path = File.expand_path(file)
23
- @config = Slnky::Data.new(YAML.load_file(path))
22
+ def heartbeat(name)
23
+ server = ENV['SLNKY_URL'] || Slnky.config.url
24
+ RestClient.post "#{server}/hooks/heartbeat", {name: name}, content_type: :json, accept: :json
24
25
  end
25
26
 
26
- def notify(msg, server=nil)
27
- server ||= config.slnky.url
27
+ def notify(msg)
28
+ server = self.config.url
28
29
  params = {name: msg.name, event: msg.to_h}
29
30
  RestClient.post "#{server}/hooks/notify", params.to_json, content_type: :json, accept: :json
30
31
  end
data/slnky.gemspec CHANGED
@@ -38,4 +38,6 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency 'tilt', '~> 2.0.2'
39
39
  spec.add_dependency 'eventmachine', '~> 1.0.9.1'
40
40
  spec.add_dependency 'rest-client', '~> 1.8.0'
41
+ spec.add_dependency 'docopt', '~> 0.5.0'
42
+ spec.add_dependency 'highline', '~> 1.7.8'
41
43
  end