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,45 @@
1
+ require 'sinatra'
2
+ require "sinatra/json"
3
+ require "sinatra/multi_route"
4
+ require 'json'
5
+
6
+ module EDI
7
+ class Server < Sinatra::Base
8
+ register Sinatra::MultiRoute
9
+
10
+ get "/" do
11
+ json text: EDI::ArrayResponder.new(EDI.config.hello_message).respond
12
+ end
13
+
14
+ route :get, :post, "/edi" do
15
+ message = Slack::Message.new(params)
16
+ service = EDI::Interpreter.new(message).determine_service.new(message)
17
+ begin
18
+ json text: run_service(service)
19
+ rescue EDI::UnfitEnvironmentException => e
20
+ json text: EDI::ArrayResponder.new(EDI.config.unfit_environment_response).respond
21
+ rescue EDI::ThirdPartyAPIFailure
22
+ json text: EDI::ArrayResponder.new(EDI.config.third_party_api_failure_respone).respond
23
+ rescue => e
24
+ json text: EDI::ArrayResponder.new(EDI.config.standard_error_response).respond
25
+ end
26
+ end
27
+
28
+ get "/keepalive" do
29
+ json text: "Blah"
30
+ end
31
+
32
+ def self.register_services(*args)
33
+ EDI.register_services *args
34
+ end
35
+
36
+ private
37
+
38
+ def run_service(service)
39
+ service.validate_environment
40
+ service.invoke
41
+ end
42
+
43
+ run! if app_file == $0
44
+ end
45
+ end
@@ -0,0 +1,89 @@
1
+ require 'hooks'
2
+ module EDI
3
+ class Service
4
+ include Hooks
5
+
6
+ attr_accessor :message, :response
7
+ def initialize(message)
8
+ @message = message
9
+ @response = ""
10
+ end
11
+
12
+ def method_missing(name, *args, &blk)
13
+ message.public_send(name, *args, &blk)
14
+ end
15
+
16
+ def run
17
+
18
+ end
19
+
20
+ def validate_environment
21
+ self.class.required_environment_variables.each do |v|
22
+ raise UnfitEnvironmentException unless (ENV[v] || ENV[v.downcase])
23
+ end
24
+ end
25
+
26
+ # Class Methods
27
+ class << self
28
+ attr_accessor :required_environment_variables, :pattern, :interpreter_phrases, :invoker
29
+ end
30
+
31
+ def self.phrases(*args)
32
+ @interpreter_phrases = args
33
+ reset_interpreter_pattern
34
+ end
35
+
36
+ def self.required_environment_variables
37
+ @required_environment_variables ||= []
38
+ end
39
+
40
+ def self.environment(*args)
41
+ args.each do |sym|
42
+ str = sym.to_s.upcase
43
+ send :define_method, sym do
44
+ ENV[str] || ENV[str.downcase]
45
+ end
46
+ required_environment_variables << str
47
+ end
48
+ end
49
+
50
+
51
+ def self.interpreter_pattern(pattern)
52
+ @pattern = pattern
53
+ end
54
+
55
+ def self.pattern
56
+ @pattern ||= concatenate_phrases_into_regex
57
+ end
58
+
59
+ # class MyService < EDI::Service
60
+ # invoke_with :post_tweet
61
+ #
62
+ # end
63
+ def self.invoke_with(method_name)
64
+ send :define_method, :invoke do
65
+ run_hook :before_invoke
66
+ self.response = send method_name
67
+ run_hook :after_invoke
68
+ self.response
69
+ end
70
+ end
71
+
72
+
73
+ private
74
+
75
+ def self.concatenate_phrases_into_regex
76
+ case self.interpreter_phrases
77
+ when Array then /#{self.interpreter_phrases.join("|")}/i
78
+ when String then /#{self.interpreter_phrases}/i
79
+ end
80
+ end
81
+
82
+ def self.reset_interpreter_pattern
83
+ @pattern = nil
84
+ end
85
+
86
+ invoke_with :run
87
+ define_hooks :before_invoke, :after_invoke
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ require 'edi/services/null_service'
2
+ require 'edi/services/dice'
3
+ require 'edi/services/eightball'
4
+ require 'edi/services/fact'
5
+ require 'edi/services/giphy'
6
+ require 'edi/services/i_heart_quotes'
7
+ require 'edi/services/weather'
8
+ require 'edi/services/tweet_that'
9
+ require 'edi/services/img_flip'
@@ -0,0 +1,25 @@
1
+ class Dice < EDI::Service
2
+ attr_accessor :dice_result
3
+ phrases "roll", "dice"
4
+ before_invoke :perform_roll
5
+
6
+ def run
7
+ "You got a #{dice_result}"
8
+ end
9
+
10
+ private
11
+
12
+ def perform_roll
13
+ input = extract_dice_expression.split("d").map(&:to_i)
14
+ self.dice_result = input[0].times.map{ roll input[1] }.inject(:+)
15
+ end
16
+
17
+ def extract_dice_expression
18
+ text[/(\d+[d]\d+)/]
19
+ end
20
+
21
+ def roll(sides)
22
+ Random.rand(sides)
23
+ end
24
+
25
+ end
@@ -0,0 +1,38 @@
1
+ class Eightball < EDI::Service
2
+
3
+ interpreter_pattern /\?$/
4
+
5
+ def run
6
+ responses.sample
7
+ end
8
+
9
+ private
10
+
11
+ def responses
12
+ [
13
+ "It is certain",
14
+ "It is decidedly so",
15
+ "Without a doubt",
16
+ "Yes definitely",
17
+ "You may rely on it",
18
+ "As I see it, yes",
19
+ "Most likely",
20
+ "Outlook good",
21
+ "Yes",
22
+ "Signs point to yes",
23
+ "Reply hazy try again",
24
+ "Ask again later",
25
+ "Better not tell you now",
26
+ "Cannot predict now",
27
+ "Concentrate and ask again",
28
+ "Don't count on it",
29
+ "My reply is no",
30
+ "My sources say no",
31
+ "Outlook not so good",
32
+ "Very doubtful",
33
+ "I dont even",
34
+ "NO",
35
+ "Seriously?"
36
+ ]
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ class Fact < EDI::Service
2
+ phrases "fact"
3
+
4
+ def run
5
+ EDI.get("http://numbersapi.com/random").unparsed_response
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ class Giphy < EDI::Service
2
+ phrases "gif"
3
+ environment :giphy_api_version, :giphy_api_key
4
+ before_invoke :build_request_url
5
+ attr_accessor :request_url
6
+ def run
7
+ EDI.get(request_url).response["data"]["image_url"]
8
+ end
9
+
10
+ private
11
+
12
+ def build_request_url
13
+ self.request_url = "#{host}#{endpoint}random?api_key=#{giphy_api_key}#{additional_params}"
14
+ end
15
+
16
+ def host
17
+ "http://api.giphy.com/"
18
+ end
19
+
20
+ def endpoint
21
+ "#{giphy_api_version}/gifs/"
22
+ end
23
+
24
+ def additional_params
25
+ case text
26
+ when /Cat|Kitty/i
27
+ "&tag=cat"
28
+ when /sloth/i
29
+ "&tag=sloth"
30
+ when /bacon/i
31
+ "&tag=bacon"
32
+ when /trippy/i
33
+ "&tag=trippy"
34
+ else
35
+ ""
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ class IHeartQuotes < EDI::Service
2
+ phrases "quote"
3
+ after_invoke :extract_quote
4
+
5
+ def run
6
+ EDI.get(request_url).response
7
+ end
8
+
9
+ private
10
+
11
+ def extract_quote
12
+ self.response = self.response["quote"].strip
13
+ end
14
+
15
+ def request_url
16
+ "http://iheartquotes.com/api/v1/random?format=json#{source}"
17
+ end
18
+
19
+ def source
20
+ case text
21
+ when /simpsons|homer/i
22
+ "&source=simpsons_homer"
23
+ when /star wars|luke|leia|vader/i
24
+ "&source=starwars"
25
+ else
26
+ ""
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,69 @@
1
+ require 'edi/services/img_flip_memes/base_meme'
2
+ # Require All Supported Memes
3
+ Dir[File.dirname(__FILE__) + '/img_flip_memes/*.rb'].each {|file| require file }
4
+
5
+ class ImgFlip < EDI::Service
6
+ interpreter_pattern /you're gonna have a bad time|
7
+ and it'?s gone|
8
+ afraid to ask|
9
+ sudden clarity|
10
+ success kid|
11
+ not sure if|
12
+ picard|
13
+ one does not simply|
14
+ y u no|
15
+ what if i told you|
16
+ willy wonka|
17
+ overly attached girlfriend|
18
+ everywhere|
19
+ i don'?t always.+but when i do'?/xi
20
+
21
+ environment :imgflip_user, :imgflip_password
22
+ before_invoke :create_meme
23
+
24
+ attr_accessor :meme_link
25
+
26
+ def run
27
+ "Here you go, #{user_name}\n\n#{meme_link}"
28
+ end
29
+
30
+ private
31
+
32
+ def meme_class
33
+ case text
34
+ when /success kid/i
35
+ ImgFlipMemes::SuccessKid
36
+ when /afraid to ask/i
37
+ ImgFlipMemes::AfraidToAsk
38
+ when /and it'?s gone/i
39
+ ImgFlipMemes::AndItsGone
40
+ when /everywhere/i
41
+ ImgFlipMemes::Everywhere
42
+ when /you're gonna have a bad time/i
43
+ ImgFlipMemes::GonnaHaveABadTime
44
+ when /i don'?t always.+but when i do/i
45
+ ImgFlipMemes::MostInterestingMan
46
+ when /not sure if/i
47
+ ImgFlipMemes::NotSureIf
48
+ when /one does not simply/i
49
+ ImgFlipMemes::OneDoesNotSimply
50
+ when /overly attached girlfriend/i
51
+ ImgFlipMemes::OverlyAttachedGirlfriend
52
+ when /picard/i
53
+ ImgFlipMemes::Picard
54
+ when /sudden clarity/i
55
+ ImgFlipMemes::SuddenClarity
56
+ when /what if I told you/i
57
+ ImgFlipMemes::WhatIfIToldYou
58
+ when /willy wonka/i
59
+ ImgFlipMemes::WillyWonka
60
+ when /y u no/i
61
+ ImgFlipMemes::YUNo
62
+ end
63
+ end
64
+
65
+ def create_meme
66
+ self.meme_link = meme_class.new(message, imgflip_user, imgflip_password).create_meme
67
+ end
68
+
69
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class AfraidToAsk < BaseMeme
3
+ def template_id
4
+ 24557067
5
+ end
6
+
7
+ def text1
8
+ "And at this point, I'm afraid to ask"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/#{trigger_word}(?<text0>.+),? and at this point/i)
13
+ self.captures[:text0] = captures[:text0]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ImgFlipMemes
2
+ class AndItsGone < BaseMeme
3
+ def template_id
4
+ 766986
5
+ end
6
+
7
+ def text1
8
+ "Annnnnnnd it's gone"
9
+ end
10
+
11
+ def tokenize
12
+ captures = text.match(/#{trigger_word},? (?<text0>.+)and it'?s gone/i)
13
+ self.captures[:text0] = captures[:text0]
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ module ImgFlipMemes
2
+ class BaseMeme
3
+ attr_accessor :message, :imgflip_user, :imgflip_password, :text0, :text1, :captures
4
+ def initialize(message, imgflip_user, imgflip_password)
5
+ @message = message
6
+ @imgflip_user = imgflip_user
7
+ @imgflip_password = imgflip_password
8
+ @captures = {}
9
+ end
10
+
11
+ def tokenize
12
+ end
13
+
14
+ def template_id
15
+ end
16
+
17
+ def create_meme
18
+ tokenize
19
+ trim_captures
20
+ body = {
21
+ template_id: template_id,
22
+ username: imgflip_user,
23
+ password: imgflip_password,
24
+ text0: text0,
25
+ text1: text1
26
+ }
27
+ response = EDI.post(url, body: body).response
28
+ unless response["success"]
29
+ raise EDI::ThirdPartyAPIFailure
30
+ else
31
+ response["data"]["url"]
32
+ end
33
+ end
34
+
35
+ def url
36
+ "https://api.imgflip.com/caption_image"
37
+ end
38
+
39
+ def text0
40
+ captures[:text0]
41
+ end
42
+
43
+ def text1
44
+ captures[:text1]
45
+ end
46
+
47
+ def trim_captures
48
+ self.captures[:text0] = self.captures[:text0].strip if self.captures[:text0]
49
+ self.captures[:text1] = self.captures[:text1].strip if self.captures[:text1]
50
+ end
51
+
52
+ def method_missing(name, *args, &block)
53
+ message.public_send(name, *args, &block)
54
+ end
55
+
56
+ end
57
+ end