edi 0.1.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 (129) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +4 -0
  7. data/Guardfile +47 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +129 -0
  10. data/Rakefile +11 -0
  11. data/bin/edi +12 -0
  12. data/edi.gemspec +40 -0
  13. data/features/fact_service.feature +7 -0
  14. data/features/giphy_service.feature +43 -0
  15. data/features/i_heart_quotes_service.feature +21 -0
  16. data/features/step_definitions/fact_service_steps.rb +7 -0
  17. data/features/step_definitions/giphy_steps.rb +3 -0
  18. data/features/step_definitions/server_steps.rb +3 -0
  19. data/features/step_definitions/tweet_that_steps.rb +19 -0
  20. data/features/step_definitions/weather_steps.rb +3 -0
  21. data/features/support/env.rb +37 -0
  22. data/features/support/hooks.rb +1 -0
  23. data/features/support/vcr_cassettes/Fact_Service/EDI_responds_with_a_random_fact.yml +53 -0
  24. data/features/support/vcr_cassettes/Fact_Service/Jarvis_responds_with_a_random_fact.yml +52 -0
  25. data/features/support/vcr_cassettes/Giphy_Service/Bacon.yml +58 -0
  26. data/features/support/vcr_cassettes/Giphy_Service/Cat_GIF_-_Cat_Wording.yml +58 -0
  27. data/features/support/vcr_cassettes/Giphy_Service/Cat_GIF_-_Kitty_Wording.yml +58 -0
  28. data/features/support/vcr_cassettes/Giphy_Service/Cat_GIF_-_Kitty_Wording_-_Case_Insensitive.yml +58 -0
  29. data/features/support/vcr_cassettes/Giphy_Service/Plain_old_GIF.yml +58 -0
  30. data/features/support/vcr_cassettes/Giphy_Service/Sloth.yml +58 -0
  31. data/features/support/vcr_cassettes/Giphy_Service/Trippy.yml +58 -0
  32. data/features/support/vcr_cassettes/I_Heart_Quotes/A_Random_Quote.yml +44 -0
  33. data/features/support/vcr_cassettes/I_Heart_Quotes/A_Simpsons_Quote.yml +44 -0
  34. data/features/support/vcr_cassettes/I_Heart_Quotes/A_Star_Wars_Quote.yml +44 -0
  35. data/features/support/vcr_cassettes/Tweet_that/Post_the_last_message_to_twitter.yml +211 -0
  36. data/features/support/vcr_cassettes/Weather_Service/Use_a_specified_location.yml +86 -0
  37. data/features/support/vcr_cassettes/Weather_Service/Use_default_location.yml +86 -0
  38. data/features/tweet_that_service.feature +14 -0
  39. data/features/weather_service.feature +21 -0
  40. data/lib/edi.rb +53 -0
  41. data/lib/edi/api/response.rb +22 -0
  42. data/lib/edi/application.rb +39 -0
  43. data/lib/edi/cli.rb +61 -0
  44. data/lib/edi/configuration.rb +26 -0
  45. data/lib/edi/core_ext.rb +1 -0
  46. data/lib/edi/core_ext/symbol.rb +7 -0
  47. data/lib/edi/exceptions.rb +8 -0
  48. data/lib/edi/http_utilities.rb +40 -0
  49. data/lib/edi/interpreter.rb +32 -0
  50. data/lib/edi/refinements.rb +1 -0
  51. data/lib/edi/refinements/zip_refinement.rb +11 -0
  52. data/lib/edi/scheduler.rb +21 -0
  53. data/lib/edi/server.rb +45 -0
  54. data/lib/edi/service.rb +89 -0
  55. data/lib/edi/services.rb +9 -0
  56. data/lib/edi/services/dice.rb +25 -0
  57. data/lib/edi/services/eightball.rb +38 -0
  58. data/lib/edi/services/fact.rb +7 -0
  59. data/lib/edi/services/giphy.rb +38 -0
  60. data/lib/edi/services/i_heart_quotes.rb +29 -0
  61. data/lib/edi/services/img_flip.rb +69 -0
  62. data/lib/edi/services/img_flip_memes/afraid_to_ask.rb +17 -0
  63. data/lib/edi/services/img_flip_memes/and_its_gone.rb +17 -0
  64. data/lib/edi/services/img_flip_memes/base_meme.rb +57 -0
  65. data/lib/edi/services/img_flip_memes/everywhere.rb +15 -0
  66. data/lib/edi/services/img_flip_memes/gonna_have_a_bad_time.rb +17 -0
  67. data/lib/edi/services/img_flip_memes/most_interesting_man.rb +13 -0
  68. data/lib/edi/services/img_flip_memes/not_sure_if.rb +13 -0
  69. data/lib/edi/services/img_flip_memes/one_does_not_simply.rb +17 -0
  70. data/lib/edi/services/img_flip_memes/overly_attached_girlfriend.rb +13 -0
  71. data/lib/edi/services/img_flip_memes/picard.rb +13 -0
  72. data/lib/edi/services/img_flip_memes/success_kid.rb +13 -0
  73. data/lib/edi/services/img_flip_memes/sudden_clarity.rb +13 -0
  74. data/lib/edi/services/img_flip_memes/what_if_i_told_you.rb +17 -0
  75. data/lib/edi/services/img_flip_memes/willy_wonka.rb +13 -0
  76. data/lib/edi/services/img_flip_memes/y_u_no.rb +17 -0
  77. data/lib/edi/services/null_service.rb +5 -0
  78. data/lib/edi/services/tweet_that.rb +68 -0
  79. data/lib/edi/services/weather.rb +42 -0
  80. data/lib/edi/slack.rb +1 -0
  81. data/lib/edi/slack/message.rb +17 -0
  82. data/lib/edi/test_support/cucumber.rb +1 -0
  83. data/lib/edi/test_support/test_support.rb +27 -0
  84. data/lib/edi/utilities/array_responder.rb +16 -0
  85. data/lib/edi/version.rb +3 -0
  86. data/spec/edi/edi_spec.rb +29 -0
  87. data/spec/edi/interpreter_spec.rb +61 -0
  88. data/spec/edi/server_spec.rb +20 -0
  89. data/spec/edi/service_spec.rb +112 -0
  90. data/spec/services/dice_spec.rb +22 -0
  91. data/spec/services/eightball_spec.rb +9 -0
  92. data/spec/services/fact_spec.rb +7 -0
  93. data/spec/services/giphy_spec.rb +46 -0
  94. data/spec/services/i_heart_quotes_spec.rb +50 -0
  95. data/spec/services/img_flip_spec.rb +89 -0
  96. data/spec/services/null_service_spec.rb +3 -0
  97. data/spec/services/tweet_that_spec.rb +18 -0
  98. data/spec/services/weather_spec.rb +17 -0
  99. data/spec/spec_helper.rb +51 -0
  100. data/spec/support/fixtures/vcr_cassettes/fact.yml +57 -0
  101. data/spec/support/fixtures/vcr_cassettes/giphy.yml +513 -0
  102. data/spec/support/fixtures/vcr_cassettes/i_heart_quotes.yml +222 -0
  103. data/spec/support/fixtures/vcr_cassettes/img_flip_afraid_to_ask.yml +54 -0
  104. data/spec/support/fixtures/vcr_cassettes/img_flip_and_its_gone.yml +54 -0
  105. data/spec/support/fixtures/vcr_cassettes/img_flip_everywhere.yml +54 -0
  106. data/spec/support/fixtures/vcr_cassettes/img_flip_gonna_have_a_bad_time.yml +54 -0
  107. data/spec/support/fixtures/vcr_cassettes/img_flip_most_interesting_man.yml +54 -0
  108. data/spec/support/fixtures/vcr_cassettes/img_flip_not_sure_if.yml +54 -0
  109. data/spec/support/fixtures/vcr_cassettes/img_flip_one_does_not_simply.yml +54 -0
  110. data/spec/support/fixtures/vcr_cassettes/img_flip_overly_attached_girlfriend.yml +54 -0
  111. data/spec/support/fixtures/vcr_cassettes/img_flip_picard.yml +54 -0
  112. data/spec/support/fixtures/vcr_cassettes/img_flip_success_kid.yml +54 -0
  113. data/spec/support/fixtures/vcr_cassettes/img_flip_sudden_clarity.yml +54 -0
  114. data/spec/support/fixtures/vcr_cassettes/img_flip_what_if_I_told_you.yml +54 -0
  115. data/spec/support/fixtures/vcr_cassettes/img_flip_willy_wonka.yml +54 -0
  116. data/spec/support/fixtures/vcr_cassettes/img_flip_y_u_no.yml +54 -0
  117. data/spec/support/fixtures/vcr_cassettes/tweet_that.yml +189 -0
  118. data/spec/support/fixtures/vcr_cassettes/weather.yml +346 -0
  119. data/spec/support/shared_contexts/server.rb +9 -0
  120. data/spec/support/shared_contexts/service.rb +10 -0
  121. data/templates/project/Gemfile +7 -0
  122. data/templates/project/bot/server.rb +6 -0
  123. data/templates/project/bot/services/.gitkeep +0 -0
  124. data/templates/project/config.ru +2 -0
  125. data/templates/project/config/.gitkeep +0 -0
  126. data/templates/project/config/environment.rb +12 -0
  127. data/templates/project/config/initializers/.gitkeep +0 -0
  128. data/templates/services/%name%.rb.tt +5 -0
  129. metadata +514 -0
@@ -0,0 +1,15 @@
1
+ module ImgFlipMemes
2
+ class Everywhere < BaseMeme
3
+
4
+ def template_id
5
+ 347390
6
+ end
7
+
8
+ def tokenize
9
+ captures = text.match /#{trigger_word},? (?<text0>.+),(?<text1>.+ everywhere)?/i
10
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
11
+ true
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class GonnaHaveABadTime < BaseMeme
3
+ def template_id
4
+ 100951
5
+ end
6
+
7
+ def text1
8
+ "You're gonna have a bad time"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/#{trigger_word},? (?<text0>.+),? you're gonna have a bad time/i)
13
+ self.captures[:text0] = captures[:text0]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class MostInterestingMan < BaseMeme
3
+ def template_id
4
+ 61532
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/#{trigger_word}.+(?<text0>i don'?t always.+), (?<text1>but when I do.+)/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class NotSureIf < BaseMeme
3
+ def template_id
4
+ 61520
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/#{trigger_word}.+(?<text0>not sure if.+),(?<text1>.+)/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class OneDoesNotSimply < BaseMeme
3
+ def template_id
4
+ 61579
5
+ end
6
+
7
+ def text0
8
+ "One Does Not Simply"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/one does not simply(?<text1>.+)/i)
13
+ self.captures[:text1] = captures[:text1]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class OverlyAttachedGirlfriend < BaseMeme
3
+ def template_id
4
+ 100952
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/overly attached girlfriend(?<text0>.[^,]+),?(?<text1>.[^,]+)?/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class Picard < BaseMeme
3
+ def template_id
4
+ 245898
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/picard(?<text0>.[^,]+),?(?<text1>.[^,]+)?/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class SuccessKid < BaseMeme
3
+ def template_id
4
+ 61544
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/success kid(?<text0>.[^,]+),?(?<text1>.[^,]+)?/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class SuddenClarity < BaseMeme
3
+ def template_id
4
+ 100948
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/sudden clarity(?<text0>.[^,]+),?(?<text1>.[^,]+)?/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class WhatIfIToldYou < BaseMeme
3
+ def template_id
4
+ 100947
5
+ end
6
+
7
+ def text0
8
+ "What if I told you"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/what if i told you(?<text1>.+)/i)
13
+ self.captures[:text1] = captures[:text1]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module ImgFlipMemes
2
+ class WillyWonka < BaseMeme
3
+ def template_id
4
+ 61582
5
+ end
6
+
7
+ def tokenize
8
+ captures = text.match(/willy wonka(?<text0>.[^,]+),?(?<text1>.[^,]+)?/i)
9
+ self.captures[:text0], self.captures[:text1] = captures[:text0], captures[:text1]
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class YUNo < BaseMeme
3
+ def template_id
4
+ 61527
5
+ end
6
+
7
+ def text0
8
+ "Y U NO"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/y u no(?<text1>.+)/i)
13
+ self.captures[:text1] = captures[:text1]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ class NullService < EDI::Service
2
+ def run
3
+ EDI::ArrayResponder.new(EDI.config.default_response).respond
4
+ end
5
+ end
@@ -0,0 +1,68 @@
1
+ # Tweet
2
+ require 'twitter'
3
+ class TweetThat < EDI::Service
4
+ phrases "tweet that", "post that to twitter"
5
+ environment :slack_token,
6
+ :twitter_handle,
7
+ :twitter_consumer_key,
8
+ :twitter_consumer_secret,
9
+ :twitter_access_token,
10
+ :twitter_token_secret
11
+
12
+ before_invoke :get_last_message_from_slack
13
+ before_invoke :initialize_twitter
14
+
15
+ attr_accessor :last_message, :twitter_client, :tweet
16
+
17
+ def run
18
+ self.tweet = post_tweet
19
+ "Here you are, #{user_name}, #{link}"
20
+ end
21
+
22
+ private
23
+
24
+ def link
25
+ "https://twitter.com/#{twitter_handle}/status/#{self.tweet.id}"
26
+ end
27
+
28
+ def post_tweet
29
+ self.twitter_client.update self.last_message
30
+ end
31
+
32
+ def get_last_message_from_slack
33
+ self.last_message = EDI.get("#{host}#{endpoint}?#{request}").response["messages"][1]["text"]
34
+ end
35
+
36
+ def initialize_twitter
37
+ self.twitter_client = Twitter::REST::Client.new do |config|
38
+ config.consumer_key = twitter_consumer_key
39
+ config.consumer_secret = twitter_consumer_secret
40
+ config.access_token = twitter_access_token
41
+ config.access_token_secret = twitter_token_secret
42
+ end
43
+ end
44
+
45
+ def request
46
+ [token, channel, count].join("&")
47
+ end
48
+
49
+ def host
50
+ "https://slack.com/api/"
51
+ end
52
+
53
+ def endpoint
54
+ "channels.history"
55
+ end
56
+
57
+ def token
58
+ "token=#{slack_token}"
59
+ end
60
+
61
+ def channel
62
+ "channel=#{channel_id}"
63
+ end
64
+
65
+ def count
66
+ "count=2"
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ class Weather < EDI::Service
2
+ using ZipRefinement
3
+
4
+ phrases "weather"
5
+ before_invoke :determine_location
6
+ environment :default_location # Default Location Should be a zip code
7
+ attr_accessor :location, :zip_api_response, :temperature, :parsed_response
8
+
9
+ def run
10
+ self.response = EDI.get("http://api.openweathermap.org/data/2.5/weather?q=#{encoded_location}").response
11
+ calculate_temperature
12
+ self.response = "#{weather_description}. The temperature is currently #{temperature}"
13
+ end
14
+
15
+ private
16
+
17
+ def determine_location
18
+ self.location = if text.contains_zip?
19
+ lookup_zip(text.zip_code)
20
+ else
21
+ lookup_zip(default_location)
22
+ end
23
+ end
24
+
25
+ def encoded_location
26
+ EDI.encode_uri(@location)
27
+ end
28
+
29
+ def lookup_zip(zip)
30
+ zip_api_response = EDI.get("http://api.zippopotam.us/us/#{zip}").response["places"].first
31
+ "#{zip_api_response["place name"]}, #{zip_api_response["state abbreviation"]}"
32
+ end
33
+
34
+ def weather_description
35
+ self.response["weather"].first["description"].humanize
36
+ end
37
+
38
+ def calculate_temperature
39
+ self.temperature = (((self.response["main"]["temp"].to_i - 273.15) * 1.8) + 32).to_i
40
+ end
41
+
42
+ end
@@ -0,0 +1 @@
1
+ require 'edi/slack/message'
@@ -0,0 +1,17 @@
1
+ module Slack
2
+ class Message
3
+
4
+ attr_accessor :text, :channel_id, :team_id, :channel_name, :user_id, :user_name, :trigger_word
5
+
6
+ def initialize(params)
7
+ @text = params["text"]
8
+ @channel_id = params["channel_id"]
9
+ @team_id = params["team_id"]
10
+ @channel_name = params["channel_name"]
11
+ @user_id = params["user_id"]
12
+ @user_name = params["user_name"]
13
+ @trigger_word = params["trigger_word"]
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1 @@
1
+ require 'cucumber/rspec/doubles'
@@ -0,0 +1,27 @@
1
+ module EDI
2
+ module TestSupport
3
+ require 'rspec/mocks'
4
+
5
+ def slack_outgoing_message(options={text:"EDI, what's going on?"})
6
+ {
7
+ "team_id" => options[:team_id] || "T0001",
8
+ "channel_id" => options[:channel_id] || "BLAH",
9
+ "channel_name" => options[:channel_name] || "test",
10
+ "timestamp" => options[:timestamp] || "1355517523.000005",
11
+ "user_id" => options[:user_id] || "U2147483697",
12
+ "user_name" => options[:user_name] || "Steve",
13
+ "text" => options[:text],
14
+ "trigger_word" => options[:trigger_word] || "EDI"
15
+ }
16
+ end
17
+
18
+ def parsed_response(response)
19
+ JSON.parse(response.body)["text"]
20
+ end
21
+
22
+ def stub_env(hash)
23
+ stub_const('ENV', ENV.to_hash.merge(hash))
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module EDI
2
+ class ArrayResponder
3
+ attr_accessor :response
4
+
5
+ def initialize(response)
6
+ @response = response
7
+ end
8
+
9
+ def respond
10
+ case response
11
+ when String then [response]
12
+ when Array then response
13
+ end.sample
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module EDI
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EDI do
4
+
5
+ describe "Service Registry" do
6
+ it "Allows you to register a EDI::Service subclass" do
7
+ EDI.register_services(:test_service)
8
+ expect(EDI.services).to eq [:test_service]
9
+ end
10
+ it "Works with multiple classes" do
11
+ EDI.register_services :test_service, :other_test_service
12
+ expect(EDI.services).to eq [:test_service, :other_test_service]
13
+ end
14
+ end
15
+
16
+ describe "Utilities" do
17
+
18
+ it { expect(EDI.encode_uri("hello world")).to eq "hello%20world" }
19
+ it { expect(EDI.decode_uri("hello%20world")).to eq "hello world" }
20
+ end
21
+
22
+ describe "Environment" do
23
+ before { EDI.env = "production" }
24
+ it { expect(EDI.env).to eq "production" }
25
+ it { expect(EDI.env.production?).to eq true }
26
+ it { expect(EDI.env.test?).to eq false }
27
+ end
28
+
29
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EDI::Interpreter do
4
+ def message(params)
5
+ Slack::Message.new(slack_outgoing_message(params))
6
+ end
7
+
8
+ describe "Defaults to NullService" do
9
+ before { EDI.register_services :test_service }
10
+ subject { described_class.new(message text: "success kid") }
11
+ it { expect(subject.determine_service).to eq NullService }
12
+ end
13
+
14
+ describe "Routes Services based on the registered services phrases" do
15
+ before { service.phrases "success kid" }
16
+ before { EDI.register_services :test_service }
17
+ context "A Match" do
18
+ subject { described_class.new(message text: "success kid") }
19
+ it { expect(subject.determine_service).to eq service }
20
+ end
21
+ context "No Match" do
22
+ subject { described_class.new(message text: "blah") }
23
+ it { expect(subject.determine_service).to eq NullService }
24
+ end
25
+ context "Generated regex is case insensitive" do
26
+ subject { described_class.new(message text: "SUCCESS KID") }
27
+ it { expect(subject.determine_service).to eq service}
28
+ end
29
+ context "Multiple phrases route correctly" do
30
+ before(:each) { other_service.phrases "overly attached bot", "hello world" }
31
+ before { EDI.register_services :other_test_service }
32
+ it { expect(described_class.new(message text: "hello world").determine_service).to eq other_service }
33
+ it { expect(described_class.new(message text: "overly attached bot").determine_service).to eq other_service }
34
+ end
35
+ end
36
+
37
+ describe "Routes services based on the registered interpreter pattern" do
38
+ before { service.interpreter_pattern /success kid/i }
39
+ before { EDI.register_services :test_service }
40
+ context "A Match" do
41
+ subject { described_class.new(message text: "success kid") }
42
+ it { expect(subject.determine_service).to eq service }
43
+ end
44
+ context "No Match" do
45
+ subject { described_class.new(message text: "blah") }
46
+ it { expect(subject.determine_service).to eq NullService }
47
+ end
48
+ end
49
+
50
+ describe "Routes to the correct service" do
51
+ let(:correct_service) { service }
52
+ let(:incorrect_service) { other_service }
53
+ before { correct_service.interpreter_pattern /success kid/i }
54
+ before { incorrect_service.interpreter_pattern /overly attached chatbot/i }
55
+ before { EDI.register_services :test_service, :other_test_service }
56
+ context "Routes to Test Service" do
57
+ subject { described_class.new(message text: "success kid hello, world") }
58
+ it { expect(subject.determine_service).to eq correct_service }
59
+ end
60
+ end
61
+ end