xip 0.0.1 → 2.0.0.beta2

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +116 -0
  3. data/.gitignore +12 -0
  4. data/CHANGELOG.md +135 -0
  5. data/Gemfile +4 -1
  6. data/Gemfile.lock +65 -15
  7. data/LICENSE +6 -4
  8. data/README.md +51 -1
  9. data/VERSION +1 -0
  10. data/bin/xip +3 -11
  11. data/lib/xip.rb +1 -3
  12. data/lib/xip/base.rb +189 -0
  13. data/lib/xip/cli.rb +273 -0
  14. data/lib/xip/cli_base.rb +24 -0
  15. data/lib/xip/commands/command.rb +13 -0
  16. data/lib/xip/commands/console.rb +74 -0
  17. data/lib/xip/commands/server.rb +63 -0
  18. data/lib/xip/configuration.rb +56 -0
  19. data/lib/xip/controller/callbacks.rb +63 -0
  20. data/lib/xip/controller/catch_all.rb +84 -0
  21. data/lib/xip/controller/controller.rb +274 -0
  22. data/lib/xip/controller/dev_jumps.rb +40 -0
  23. data/lib/xip/controller/dynamic_delay.rb +61 -0
  24. data/lib/xip/controller/helpers.rb +128 -0
  25. data/lib/xip/controller/interrupt_detect.rb +99 -0
  26. data/lib/xip/controller/messages.rb +283 -0
  27. data/lib/xip/controller/nlp.rb +49 -0
  28. data/lib/xip/controller/replies.rb +281 -0
  29. data/lib/xip/controller/unrecognized_message.rb +61 -0
  30. data/lib/xip/core_ext.rb +5 -0
  31. data/lib/xip/core_ext/numeric.rb +10 -0
  32. data/lib/xip/core_ext/string.rb +18 -0
  33. data/lib/xip/dispatcher.rb +68 -0
  34. data/lib/xip/errors.rb +55 -0
  35. data/lib/xip/flow/base.rb +69 -0
  36. data/lib/xip/flow/specification.rb +56 -0
  37. data/lib/xip/flow/state.rb +82 -0
  38. data/lib/xip/generators/builder.rb +41 -0
  39. data/lib/xip/generators/builder/.gitignore +30 -0
  40. data/lib/xip/generators/builder/Gemfile +19 -0
  41. data/lib/xip/generators/builder/Procfile.dev +2 -0
  42. data/lib/xip/generators/builder/README.md +9 -0
  43. data/lib/xip/generators/builder/Rakefile +2 -0
  44. data/lib/xip/generators/builder/bot/controllers/bot_controller.rb +55 -0
  45. data/lib/xip/generators/builder/bot/controllers/catch_alls_controller.rb +21 -0
  46. data/lib/xip/generators/builder/bot/controllers/concerns/.keep +0 -0
  47. data/lib/xip/generators/builder/bot/controllers/goodbyes_controller.rb +9 -0
  48. data/lib/xip/generators/builder/bot/controllers/hellos_controller.rb +9 -0
  49. data/lib/xip/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
  50. data/lib/xip/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
  51. data/lib/xip/generators/builder/bot/helpers/bot_helper.rb +2 -0
  52. data/lib/xip/generators/builder/bot/models/bot_record.rb +3 -0
  53. data/lib/xip/generators/builder/bot/models/concerns/.keep +0 -0
  54. data/lib/xip/generators/builder/bot/replies/catch_alls/level1.yml +2 -0
  55. data/lib/xip/generators/builder/bot/replies/goodbyes/say_goodbye.yml +2 -0
  56. data/lib/xip/generators/builder/bot/replies/hellos/say_hello.yml +2 -0
  57. data/lib/xip/generators/builder/config.ru +4 -0
  58. data/lib/xip/generators/builder/config/boot.rb +6 -0
  59. data/lib/xip/generators/builder/config/database.yml +25 -0
  60. data/lib/xip/generators/builder/config/environment.rb +2 -0
  61. data/lib/xip/generators/builder/config/flow_map.rb +25 -0
  62. data/lib/xip/generators/builder/config/initializers/autoload.rb +8 -0
  63. data/lib/xip/generators/builder/config/initializers/inflections.rb +16 -0
  64. data/lib/xip/generators/builder/config/puma.rb +25 -0
  65. data/lib/xip/generators/builder/config/services.yml +35 -0
  66. data/lib/xip/generators/builder/config/sidekiq.yml +3 -0
  67. data/lib/xip/generators/builder/db/seeds.rb +7 -0
  68. data/lib/xip/generators/generate.rb +39 -0
  69. data/lib/xip/generators/generate/flow/controllers/controller.tt +7 -0
  70. data/lib/xip/generators/generate/flow/helpers/helper.tt +3 -0
  71. data/lib/xip/generators/generate/flow/replies/ask_example.tt +9 -0
  72. data/lib/xip/helpers/redis.rb +40 -0
  73. data/lib/xip/jobs.rb +9 -0
  74. data/lib/xip/lock.rb +82 -0
  75. data/lib/xip/logger.rb +9 -3
  76. data/lib/xip/migrations/configurator.rb +73 -0
  77. data/lib/xip/migrations/generators.rb +16 -0
  78. data/lib/xip/migrations/railtie_config.rb +14 -0
  79. data/lib/xip/migrations/tasks.rb +43 -0
  80. data/lib/xip/nlp/client.rb +21 -0
  81. data/lib/xip/nlp/result.rb +56 -0
  82. data/lib/xip/reloader.rb +89 -0
  83. data/lib/xip/reply.rb +36 -0
  84. data/lib/xip/scheduled_reply.rb +18 -0
  85. data/lib/xip/server.rb +63 -0
  86. data/lib/xip/service_message.rb +17 -0
  87. data/lib/xip/service_reply.rb +44 -0
  88. data/lib/xip/services/base_client.rb +24 -0
  89. data/lib/xip/services/base_message_handler.rb +27 -0
  90. data/lib/xip/services/base_reply_handler.rb +72 -0
  91. data/lib/xip/services/jobs/handle_message_job.rb +21 -0
  92. data/lib/xip/session.rb +203 -0
  93. data/lib/xip/version.rb +7 -1
  94. data/logo.svg +17 -0
  95. data/spec/configuration_spec.rb +93 -0
  96. data/spec/controller/callbacks_spec.rb +217 -0
  97. data/spec/controller/catch_all_spec.rb +154 -0
  98. data/spec/controller/controller_spec.rb +889 -0
  99. data/spec/controller/dynamic_delay_spec.rb +70 -0
  100. data/spec/controller/helpers_spec.rb +119 -0
  101. data/spec/controller/interrupt_detect_spec.rb +171 -0
  102. data/spec/controller/messages_spec.rb +744 -0
  103. data/spec/controller/nlp_spec.rb +93 -0
  104. data/spec/controller/replies_spec.rb +694 -0
  105. data/spec/controller/unrecognized_message_spec.rb +168 -0
  106. data/spec/dispatcher_spec.rb +79 -0
  107. data/spec/flow/flow_spec.rb +82 -0
  108. data/spec/flow/state_spec.rb +109 -0
  109. data/spec/helpers/redis_spec.rb +77 -0
  110. data/spec/lock_spec.rb +100 -0
  111. data/spec/nlp/client_spec.rb +23 -0
  112. data/spec/nlp/result_spec.rb +57 -0
  113. data/spec/replies/hello.yml.erb +15 -0
  114. data/spec/replies/messages/say_hola.yml+facebook.erb +6 -0
  115. data/spec/replies/messages/say_hola.yml+twilio.erb +6 -0
  116. data/spec/replies/messages/say_hola.yml.erb +6 -0
  117. data/spec/replies/messages/say_howdy_with_dynamic.yml +79 -0
  118. data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
  119. data/spec/replies/messages/say_offer.yml +6 -0
  120. data/spec/replies/messages/say_offer_with_dynamic.yml +6 -0
  121. data/spec/replies/messages/say_oi.yml.erb +15 -0
  122. data/spec/replies/messages/say_randomize_speech.yml +10 -0
  123. data/spec/replies/messages/say_randomize_text.yml +10 -0
  124. data/spec/replies/messages/say_yo.yml +6 -0
  125. data/spec/replies/messages/say_yo.yml+twitter +6 -0
  126. data/spec/replies/messages/sub1/sub2/say_nested.yml +10 -0
  127. data/spec/reply_spec.rb +61 -0
  128. data/spec/scheduled_reply_spec.rb +23 -0
  129. data/spec/service_reply_spec.rb +92 -0
  130. data/spec/session_spec.rb +366 -0
  131. data/spec/spec_helper.rb +22 -66
  132. data/spec/support/alternate_helpers/foo_helper.rb +5 -0
  133. data/spec/support/controllers/vaders_controller.rb +24 -0
  134. data/spec/support/helpers/fun/games_helper.rb +7 -0
  135. data/spec/support/helpers/fun/pdf_helper.rb +7 -0
  136. data/spec/support/helpers/standalone_helper.rb +5 -0
  137. data/spec/support/helpers_typo/users_helper.rb +2 -0
  138. data/spec/support/nlp_clients/dialogflow.rb +9 -0
  139. data/spec/support/nlp_clients/luis.rb +9 -0
  140. data/spec/support/nlp_results/luis_result.rb +163 -0
  141. data/spec/support/sample_messages.rb +66 -0
  142. data/spec/support/services.yml +31 -0
  143. data/spec/support/services_with_erb.yml +31 -0
  144. data/spec/version_spec.rb +16 -0
  145. data/xip.gemspec +25 -14
  146. metadata +320 -18
@@ -1,9 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
-
4
5
  require 'rspec'
5
6
 
7
+ require 'xip'
8
+ require 'sidekiq/testing'
9
+ require 'mock_redis'
10
+
11
+ # Requires supporting files with custom matchers and macros, etc,
12
+ # in ./support/ and its subdirectories.
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
14
+
15
+ $redis = MockRedis.new
16
+ $services_yml = File.read(File.join(File.dirname(__FILE__), 'support', 'services.yml'))
17
+
6
18
  RSpec.configure do |config|
19
+ ENV['XIP_ENV'] = 'test'
20
+
21
+ config.before(:each) do |example|
22
+ Sidekiq::Testing.fake!
23
+
24
+ Xip.load_services_config!($services_yml)
25
+ end
26
+
7
27
  config.expect_with :rspec do |expectations|
8
28
  # This option will default to `true` in RSpec 4. It makes the `description`
9
29
  # and `failure_message` of custom matchers include text for helper methods
@@ -13,71 +33,7 @@ RSpec.configure do |config|
13
33
  # ...rather than:
14
34
  # # => "be bigger than 2"
15
35
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
16
- end
17
36
 
18
- # rspec-mocks config goes here. You can use an alternate test double
19
- # library (such as bogus or mocha) by changing the `mock_with` option here.
20
- config.mock_with :rspec do |mocks|
21
- # Prevents you from mocking or stubbing a method that does not exist on
22
- # a real object. This is generally recommended, and will default to
23
- # `true` in RSpec 4.
24
- mocks.verify_partial_doubles = true
37
+ expectations.on_potential_false_positives = :nothing
25
38
  end
26
-
27
- # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
28
- # have no way to turn it off -- the option exists only for backwards
29
- # compatibility in RSpec 3). It causes shared context metadata to be
30
- # inherited by the metadata hash of host groups and examples, rather than
31
- # triggering implicit auto-inclusion in groups with matching metadata.
32
- config.shared_context_metadata_behavior = :apply_to_host_groups
33
-
34
- # The settings below are suggested to provide a good initial experience
35
- # with RSpec, but feel free to customize to your heart's content.
36
- =begin
37
- # This allows you to limit a spec run to individual examples or groups
38
- # you care about by tagging them with `:focus` metadata. When nothing
39
- # is tagged with `:focus`, all examples get run. RSpec also provides
40
- # aliases for `it`, `describe`, and `context` that include `:focus`
41
- # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
42
- config.filter_run_when_matching :focus
43
-
44
- # Allows RSpec to persist some state between runs in order to support
45
- # the `--only-failures` and `--next-failure` CLI options. We recommend
46
- # you configure your source control system to ignore this file.
47
- config.example_status_persistence_file_path = "spec/examples.txt"
48
-
49
- # Limits the available syntax to the non-monkey patched syntax that is
50
- # recommended. For more details, see:
51
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
52
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
53
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
54
- config.disable_monkey_patching!
55
-
56
- # Many RSpec users commonly either run the entire suite or an individual
57
- # file, and it's useful to allow more verbose output when running an
58
- # individual spec file.
59
- if config.files_to_run.one?
60
- # Use the documentation formatter for detailed output,
61
- # unless a formatter has already been configured
62
- # (e.g. via a command-line flag).
63
- config.default_formatter = 'doc'
64
- end
65
-
66
- # Print the 10 slowest examples and example groups at the
67
- # end of the spec run, to help surface which specs are running
68
- # particularly slow.
69
- config.profile_examples = 10
70
-
71
- # Run specs in random order to surface order dependencies. If you find an
72
- # order dependency and want to debug it, you can fix the order by providing
73
- # the seed, which is printed after each run.
74
- # --seed 1234
75
- config.order = :random
76
-
77
- # Seed global randomization in this process using the `--seed` CLI option.
78
- # Setting this allows you to use `--seed` to deterministically reproduce
79
- # test failures related to randomization by passing the same `--seed` value
80
- # as the one that triggered the failure.
81
- Kernel.srand config.seed
82
- =end
83
39
  end
@@ -0,0 +1,5 @@
1
+ module FooHelper
2
+ def foo
3
+
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ class VadersController < Xip::Controller
2
+ def my_action
3
+ raise "oops"
4
+ end
5
+
6
+ def my_action2
7
+
8
+ end
9
+
10
+ def my_action3
11
+ do_nothing
12
+ end
13
+
14
+ def action_with_unrecognized_msg
15
+ handle_message(
16
+ 'hello' => proc { puts "Hello world!" },
17
+ 'bye' => proc { puts "Goodbye world!" }
18
+ )
19
+ end
20
+
21
+ def action_with_unrecognized_match
22
+ match = get_match(['hello', 'bye'])
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ module Fun
2
+ module GamesHelper
3
+ def hello_world
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Fun
2
+ module PdfHelper
3
+ def generate_pdf_name
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module StandaloneHelper
2
+ def baz
3
+
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ module UsersHelpeR
2
+ end
@@ -0,0 +1,9 @@
1
+ module Xip
2
+ module Nlp
3
+ module Dialogflow
4
+ class Client < Xip::Nlp::Client
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Xip
2
+ module Nlp
3
+ module Luis
4
+ class Client < Xip::Nlp::Client
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,163 @@
1
+ module TestNlpResult
2
+ class Luis < Xip::Nlp::Result
3
+
4
+ ENTITY_MAP = {
5
+ 'money' => :currency, 'number' => :number, 'email' => :email,
6
+ 'percentage' => :percentage, 'Calendar.Duration' => :duration,
7
+ 'geographyV2' => :geo, 'age' => :age, 'phonenumber' => :phone,
8
+ 'ordinalV2' => :ordinal, 'url' => :url, 'dimension' => :dimension,
9
+ 'temperature' => :temp, 'keyPhrase' => :key_phrase, 'name' => :name,
10
+ 'datetimeV2' => :datetime
11
+ }
12
+
13
+ attr_reader :result, :intent
14
+
15
+ def initialize(intent:, entity: :single_number_entity)
16
+ @result = test_responses[entity]
17
+ @intent = intent
18
+ end
19
+
20
+ def parsed_result
21
+ @result
22
+ end
23
+
24
+ def intent_score
25
+ rand
26
+ end
27
+
28
+ def raw_entities
29
+ @result.dig('prediction', 'entities')
30
+ end
31
+
32
+ def entities
33
+ return {} if raw_entities.blank?
34
+ _entities = {}
35
+
36
+ raw_entities.each do |type, values|
37
+ if ENTITY_MAP[type]
38
+ _entities[ENTITY_MAP[type]] = values
39
+ else
40
+ # A custom entity
41
+ _entities[type.to_sym] = values
42
+ end
43
+ end
44
+
45
+ _entities
46
+ end
47
+
48
+ def sentiment
49
+ %i(positive neutral negative).sample
50
+ end
51
+
52
+ def sentiment_score
53
+ rand
54
+ end
55
+
56
+ def present?
57
+ parsed_result.present?
58
+ end
59
+
60
+ private
61
+
62
+ def test_responses
63
+ {
64
+ single_number_entity: {
65
+ "query" => "My score was 78",
66
+ "prediction" => {
67
+ "topIntent" => "None",
68
+ "intents" => {
69
+ "None" => {
70
+ "score" => 0.170594558
71
+ }
72
+ },
73
+ "entities" => {
74
+ "keyPhrase" => [
75
+ "score"
76
+ ],
77
+ "number" => [
78
+ 78
79
+ ]
80
+ },
81
+ "sentiment" => {
82
+ "label" => "neutral",
83
+ "score" => 0.5
84
+ }
85
+ }
86
+ },
87
+
88
+ double_number_entity: {
89
+ "query" => "Their scores were 89 and 97, respectively",
90
+ "prediction" => {
91
+ "topIntent" => "None",
92
+ "intents" => {
93
+ "None" => {
94
+ "score" => 0.5280223
95
+ }
96
+ },
97
+ "entities" => {
98
+ "keyPhrase" => [
99
+ "scores"
100
+ ],
101
+ "number" => [
102
+ 89,
103
+ 97
104
+ ]
105
+ },
106
+ "sentiment" => {
107
+ "label" => "negative",
108
+ "score" => 0.309174955
109
+ }
110
+ }
111
+ },
112
+
113
+ triple_number_entity: {
114
+ "query" => "Their scores were 89, 65, and 97, respectively",
115
+ "prediction" => {
116
+ "topIntent" => "None",
117
+ "intents" => {
118
+ "None" => {
119
+ "score" => 0.6703843
120
+ }
121
+ },
122
+ "entities" => {
123
+ "keyPhrase" => [
124
+ "scores"
125
+ ],
126
+ "number" => [
127
+ 89,
128
+ 65,
129
+ 97
130
+ ]
131
+ },
132
+ "sentiment" => {
133
+ "label" => "negative",
134
+ "score" => 0.309174955
135
+ }
136
+ }
137
+ },
138
+
139
+ custom_entity: {
140
+ "query" => "call me right away",
141
+ "prediction" => {
142
+ "topIntent" => "now",
143
+ "intents" => {
144
+ "now" => {
145
+ "score" => 0.781227
146
+ }
147
+ },
148
+ "entities" => {
149
+ "asap" => [
150
+ ["right away"]
151
+ ]
152
+ },
153
+ "sentiment" => {
154
+ "label" => "neutral",
155
+ "score" => 0.5
156
+ }
157
+ }
158
+ }
159
+ }
160
+ end
161
+
162
+ end
163
+ end
@@ -0,0 +1,66 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ class SampleMessage
5
+
6
+ def initialize(service:)
7
+ @service = service
8
+ @base_message = Xip::ServiceMessage.new(service: @service)
9
+ @base_message.sender_id = sender_id
10
+ @base_message.timestamp = timestamp
11
+ @base_message
12
+ end
13
+
14
+ def message_with_text
15
+ @base_message.message = message
16
+ @base_message
17
+ end
18
+
19
+ def message_with_payload
20
+ @base_message.payload = payload
21
+ @base_message
22
+ end
23
+
24
+ def message_with_location
25
+ @base_message.location = location
26
+ @base_message
27
+ end
28
+
29
+ def message_with_attachments
30
+ @base_message.attachments = attachments
31
+ @base_message
32
+ end
33
+
34
+ def sender_id
35
+ if @service == 'twilio'
36
+ '+15554561212'
37
+ else
38
+ "8b3e0a3c-62f1-401e-8b0f-615c9d256b1f"
39
+ end
40
+ end
41
+
42
+ def timestamp
43
+ Time.now
44
+ end
45
+
46
+ def message
47
+ "Hello World!"
48
+ end
49
+
50
+ def payload
51
+ "some_payload"
52
+ end
53
+
54
+ def location
55
+ { lat: '42.323724' , lng: '-83.047543' }
56
+ end
57
+
58
+ def attachments
59
+ [ { type: 'image', url: 'https://domain.none/image.jpg' } ]
60
+ end
61
+
62
+ def referral
63
+ {}
64
+ end
65
+
66
+ end
@@ -0,0 +1,31 @@
1
+ default: &default
2
+ facebook:
3
+ verify_token: c68823f4-7259-4600-b9f0-382a67260757
4
+ challenge: pOmQ7iq4ZA1hK6TbO7yrVZCmygVjfIiEIYaIZAlEveOAzY4UKb
5
+ page_access_token: EAADhbJruBbMBAKY9bnesHh9eM09ZAHjGsCQtNdvuZClZCFtyIXdFdIQI2mV0PJM910Qyn3lNNhZBPZB54zLRhDNmeIkDz9myS25CTy0kFxHjQCXJxz5oeZCD60VWdAZAFxbeDKvF8eF28qDHAI4wkGc3jvVhjFISKmmFRRM6goUeAZDZD
6
+ setup:
7
+ greeting: # Greetings are broken up by locale
8
+ - locale: default
9
+ text: "Welcome to the Xip bot 🤖"
10
+ persistent_menu:
11
+ - type: payload
12
+ text: Main Menu
13
+ payload: main_menu
14
+ - type: url
15
+ text: Visit our website
16
+ url: https://example.com
17
+ - type: call
18
+ text: Call us
19
+ payload: "+17345551234"
20
+ twilio_sms:
21
+ account_sid: BC6f4bd46307054c84fdff70badcd9ef5d
22
+ auth_token: 4af73d27d92cff6391611a9c976725cc
23
+
24
+ production:
25
+ <<: *default
26
+
27
+ development:
28
+ <<: *default
29
+
30
+ test:
31
+ <<: *default