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,86 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://api.zippopotam.us/us/43204
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Date:
22
+ - Sun, 22 Feb 2015 01:41:52 GMT
23
+ Server:
24
+ - Apache/2.4.7
25
+ Content-Length:
26
+ - '212'
27
+ X-Cache:
28
+ - hit
29
+ Charset:
30
+ - UTF-8
31
+ Vary:
32
+ - Accept-Encoding
33
+ Access-Control-Allow-Origin:
34
+ - "*"
35
+ Content-Type:
36
+ - application/json
37
+ body:
38
+ encoding: UTF-8
39
+ string: '{"post code": "43204", "country": "United States", "country abbreviation":
40
+ "US", "places": [{"place name": "Columbus", "longitude": "-83.078", "state":
41
+ "Ohio", "state abbreviation": "OH", "latitude": "39.9523"}]}'
42
+ http_version:
43
+ recorded_at: Sun, 22 Feb 2015 01:41:52 GMT
44
+ - request:
45
+ method: get
46
+ uri: http://api.openweathermap.org/data/2.5/weather?q=Columbus,%20OH
47
+ body:
48
+ encoding: US-ASCII
49
+ string: ''
50
+ headers:
51
+ Accept-Encoding:
52
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
53
+ Accept:
54
+ - "*/*"
55
+ User-Agent:
56
+ - Ruby
57
+ response:
58
+ status:
59
+ code: 200
60
+ message: OK
61
+ headers:
62
+ Server:
63
+ - nginx
64
+ Date:
65
+ - Sun, 22 Feb 2015 01:41:52 GMT
66
+ Content-Type:
67
+ - application/json; charset=utf-8
68
+ Transfer-Encoding:
69
+ - chunked
70
+ Connection:
71
+ - keep-alive
72
+ X-Source:
73
+ - back
74
+ Access-Control-Allow-Origin:
75
+ - "*"
76
+ Access-Control-Allow-Credentials:
77
+ - 'true'
78
+ Access-Control-Allow-Methods:
79
+ - GET, POST
80
+ body:
81
+ encoding: UTF-8
82
+ string: |
83
+ {"coord":{"lon":-83,"lat":39.96},"sys":{"message":0.0235,"country":"United States of America","sunrise":1424607278,"sunset":1424646972},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"base":"cmc stations","main":{"temp":277.284,"temp_min":277.284,"temp_max":277.284,"pressure":996.01,"sea_level":1029.3,"grnd_level":996.01,"humidity":99},"wind":{"speed":1.66,"deg":140.001},"clouds":{"all":92},"rain":{"3h":2},"dt":1424569257,"id":4509177,"name":"Columbus","cod":200}
84
+ http_version:
85
+ recorded_at: Sun, 22 Feb 2015 01:41:52 GMT
86
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,14 @@
1
+ @vcr
2
+ Feature: Tweet that
3
+
4
+ Because stuff with no context is funny
5
+ As a twitter user
6
+ I want EDI to post the last message to twitter
7
+
8
+ Background:
9
+ Given the Tweet That is configured
10
+
11
+ Scenario: Post the last message to twitter
12
+ Given a server is running with the tweet that service enabled
13
+ When the user DVG post a message to the general channel saying "EDI, tweet that"
14
+ Then EDI will respond with "Here you are, DVG, https://twitter.com/twitter_handle/status/569329768350380032"
@@ -0,0 +1,21 @@
1
+ @vcr
2
+
3
+ Feature: Weather Service
4
+
5
+ Because I live in the midwest
6
+ As a person who doesn't want to get rained on
7
+ I want EDI to tell me if I need an umbrella
8
+
9
+ Background:
10
+ Given a default location of 43240
11
+
12
+ Scenario: Use default location
13
+ Given a server is running with the weather service enabled
14
+ When EDI recieves the message "EDI what's the weather like?"
15
+ Then EDI will respond with "Light rain. The temperature is currently 38"
16
+
17
+
18
+ Scenario: Use a specified location
19
+ Given a server is running with the weather service enabled
20
+ When EDI recieves the message "EDI what's the weather like in 90210?"
21
+ Then EDI will respond with "Broken clouds. The temperature is currently 51"
@@ -0,0 +1,53 @@
1
+ require 'active_support'
2
+ require 'active_support/string_inquirer'
3
+ require 'edi/core_ext'
4
+ require "edi/version"
5
+ require 'edi/server'
6
+ require 'edi/service'
7
+ require 'edi/exceptions'
8
+ require 'edi/interpreter'
9
+ require 'edi/refinements'
10
+ require 'edi/services'
11
+ require 'edi/slack'
12
+ require 'edi/api/response'
13
+ require 'edi/configuration'
14
+ require 'edi/http_utilities'
15
+ require 'edi/application'
16
+ require 'edi/utilities/array_responder'
17
+ require 'edi/scheduler'
18
+ module EDI
19
+ class << self
20
+ attr_accessor :services
21
+ def services
22
+ @services ||= []
23
+ end
24
+
25
+ def register_services(*args)
26
+ args.each { |klass| services << klass}
27
+ EDI::Interpreter.build_determine_service
28
+ end
29
+
30
+ def clear_services
31
+ @services = []
32
+ end
33
+
34
+ def bootstrap
35
+ require File.join EDI.root, "config", "environment"
36
+ EDI::Application.initialize!
37
+ end
38
+
39
+ def root
40
+ self.config.root
41
+ end
42
+
43
+ def env
44
+ self.config.environment ||= ActiveSupport::StringInquirer.new(ENV["edi_ENV"] || ENV["RACK_ENV"] || "development")
45
+ end
46
+
47
+ def env=(environment)
48
+ self.config.environment = ActiveSupport::StringInquirer.new(environment)
49
+ end
50
+ end
51
+ include EDI::HTTPUtilities
52
+ include EDI::Configuration
53
+ end
@@ -0,0 +1,22 @@
1
+ module EDI
2
+ module API
3
+ class Response
4
+ require 'json'
5
+ attr_accessor :status, :response
6
+
7
+ def initialize(response)
8
+ @status = response.code
9
+ @response = response.body
10
+ end
11
+
12
+ def response
13
+ JSON.parse @response
14
+ end
15
+
16
+ def unparsed_response
17
+ @response
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ module EDI
2
+ class Application
3
+ require 'active_support/dependencies'
4
+
5
+ def self.initialize!
6
+ add_jarvis_root_to_load_path
7
+ autoload_paths
8
+ require File.join EDI.root, "bot/server"
9
+ require_initializers
10
+ initialize_hostname_and_port
11
+ start_keepalive
12
+ end
13
+
14
+ def self.initialize_hostname_and_port
15
+ if EDI.env.development?
16
+ EDI.config.host = "http://127.0.0.1"
17
+ EDI.config.port ||= ENV["JARVIS_PORT"]
18
+ end
19
+ end
20
+
21
+ def self.require_initializers
22
+ Dir[EDI.root + '/config/initializers/*.rb'].each do |file|
23
+ require file
24
+ end
25
+ end
26
+
27
+ def self.autoload_paths
28
+ ActiveSupport::Dependencies.autoload_paths += EDI.config.autoload_paths
29
+ end
30
+
31
+ def self.add_jarvis_root_to_load_path
32
+ $: << EDI.root
33
+ end
34
+
35
+ def self.start_keepalive
36
+ EDI.keepalive
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,61 @@
1
+ require 'thor'
2
+ require 'byebug'
3
+ module EDI
4
+ class CLI < Thor
5
+ include Thor::Actions
6
+
7
+ attr_reader :name
8
+
9
+ desc "new BOT_NAME", "Sets up a new EDI project"
10
+ def new(name)
11
+ @name = Thor::Util.snake_case(name)
12
+ directory(:project, @name)
13
+ end
14
+
15
+ desc "start", "Bootup the EDI Application"
16
+ def start(*args)
17
+ EDI.config.port = args.include?("-p") ? args[args.find_index("-p")+1] : "3030"
18
+ set_environment_stuff(args)
19
+ ENV["JARVIS_PORT"] = EDI.config.port
20
+ command = "rackup -p #{EDI.config.port}"
21
+ run_command(command)
22
+ end
23
+
24
+ desc "generate", "Generate service NAME"
25
+ def generate(type, name)
26
+ @name = Thor::Util.snake_case(name)
27
+ generate_service(@name)
28
+ end
29
+
30
+ private
31
+
32
+ def run_command(command)
33
+ system(command)
34
+ end
35
+
36
+ def generate_service(name)
37
+ template("services/%name%.rb.tt", "bot/services/#{name}.rb")
38
+ end
39
+
40
+ def set_environment_stuff(args)
41
+ if ENV["RACK_ENV"]
42
+ EDI.env = ENV["RACK_ENV"]
43
+ else
44
+ figure_out_environment(args)
45
+ end
46
+ end
47
+
48
+ def figure_out_environment(args)
49
+ ENV["JARVIS_ENV"] = case args
50
+ when args.include?("production")
51
+ puts "production"
52
+ "production"
53
+ when args.include?("test")
54
+ "test"
55
+ else
56
+ "development"
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ module EDI
2
+ module Configuration
3
+ require 'active_support'
4
+ require 'active_support/configurable'
5
+ require 'active_support/dependencies'
6
+ def self.included(base)
7
+ base.include ActiveSupport::Configurable
8
+ base.configure do |config|
9
+
10
+ # Bot Name
11
+ config.bot_name = "EDI"
12
+
13
+ # These messages can be overridden in the Application configuration. If an array of strings are provided,
14
+ # a random one will be selected
15
+ config.hello_message = "Hello, I'm #{config.bot_name}"
16
+ config.default_response = "What is this, I don't even"
17
+ config.unfit_environment_response = "I'm really sorry, but that service needs to be configured"
18
+ config.third_party_api_failure_respone = "Most unfortunately, that service is not working right now."
19
+ config.standard_error_response = "I'm sorry, Something went wrong."
20
+
21
+ # Autoload Services
22
+ config.autoload_paths = ["bot/services"]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ require 'edi/core_ext/symbol'
@@ -0,0 +1,7 @@
1
+ require 'active_support/core_ext'
2
+
3
+ class Symbol
4
+ def constantize
5
+ self.to_s.camelize.constantize
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module EDI
2
+ class Exception < StandardError
3
+ end
4
+ class UnfitEnvironmentException < Exception
5
+ end
6
+ class ThirdPartyAPIFailure < Exception
7
+ end
8
+ end
@@ -0,0 +1,40 @@
1
+ module EDI
2
+ module HTTPUtilities
3
+ require 'httparty'
4
+ require 'uri'
5
+ module ClassMethods
6
+ # HTTP Requests
7
+ def get(path, options={}, &block)
8
+ EDI::API::Response.new HTTParty.get(path, options, &block)
9
+ end
10
+
11
+ def post(path, options={}, &block)
12
+ EDI::API::Response.new HTTParty.post(path, options, &block)
13
+ end
14
+
15
+ def patch(path, options={}, &block)
16
+ EDI::API::Response.new HTTParty.patch(path, options, &block)
17
+ end
18
+
19
+ def put(path, options={}, &block)
20
+ EDI::API::Response.new HTTParty.put(path, options, &block)
21
+ end
22
+
23
+ def delete(path, options={}, &block)
24
+ EDI::API::Response.new HTTParty.delete(path, options, &block)
25
+ end
26
+
27
+ def encode_uri(str)
28
+ URI.encode(str)
29
+ end
30
+
31
+ def decode_uri(str)
32
+ URI.decode(str)
33
+ end
34
+ end
35
+ def self.included(base)
36
+ base.send(:include, HTTParty)
37
+ base.send(:extend, ClassMethods)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ module EDI
2
+ class Interpreter
3
+ attr_accessor :slack_message, :text
4
+ def initialize(slack_message)
5
+ @slack_message = slack_message
6
+ @text = slack_message.text
7
+ end
8
+
9
+
10
+ private
11
+
12
+ def self.build_determine_service
13
+ determine_service = <<-code
14
+ def determine_service
15
+ case text
16
+ code
17
+ EDI.services.each do |service|
18
+ constant = service.constantize
19
+ determine_service += <<-code
20
+ when #{constant.pattern.inspect} then #{constant}
21
+ code
22
+ end
23
+ determine_service += <<-code
24
+ else
25
+ NullService
26
+ end
27
+ end
28
+ code
29
+ self.class_eval determine_service
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ require 'edi/refinements/zip_refinement'
@@ -0,0 +1,11 @@
1
+ module ZipRefinement
2
+ refine String do
3
+ def contains_zip?
4
+ self.match(/\d{5}/) ? true : false
5
+ end
6
+
7
+ def zip_code
8
+ self.match(/(?<zip>\d{5})/)[:zip]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require 'rufus-scheduler'
2
+ module EDI
3
+ module Scheduler
4
+ def scheduler
5
+ @scheduler ||= Rufus::Scheduler.new
6
+ end
7
+
8
+ def keepalive
9
+ scheduler.every "30s" do
10
+ host = if EDI.env.development?
11
+ puts "http://127.0.0.1:#{EDI.config.port}"
12
+ "http://127.0.0.1:#{EDI.config.port}"
13
+ else
14
+ EDI.host
15
+ end
16
+ EDI.get("#{host}/keepalive")
17
+ end
18
+ end
19
+ end
20
+ extend Scheduler
21
+ end