colloquy 1.0.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 (65) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +160 -0
  3. data/TODO.md +256 -0
  4. data/bin/colloquy +14 -0
  5. data/examples/config/flows.yaml +22 -0
  6. data/examples/config/logger.yaml +2 -0
  7. data/examples/config/messages.yaml +3 -0
  8. data/examples/config/mysql.yaml +18 -0
  9. data/examples/config/redis.yaml +9 -0
  10. data/examples/config/scribe.yaml +2 -0
  11. data/examples/config/settings.yaml +2 -0
  12. data/examples/config/test.yaml +8 -0
  13. data/examples/config/urls.yaml +18 -0
  14. data/examples/flows/active_record_flow.rb +42 -0
  15. data/examples/flows/art_of_war_flow.rb +27 -0
  16. data/examples/flows/calculator_flow.rb +71 -0
  17. data/examples/flows/crossover_flow.rb +17 -0
  18. data/examples/flows/database_flow.rb +33 -0
  19. data/examples/flows/hangman_flow.rb +82 -0
  20. data/examples/flows/metadata_flow.rb +11 -0
  21. data/examples/flows/pagination_flow.rb +23 -0
  22. data/examples/flows/pass_flow.rb +29 -0
  23. data/examples/flows/prefix_menu_flow.rb +24 -0
  24. data/examples/flows/scribe_flow.rb +26 -0
  25. data/examples/flows/settings_flow.rb +23 -0
  26. data/examples/flows/special/special_redis_flow.rb +28 -0
  27. data/examples/flows/url_flow.rb +27 -0
  28. data/examples/log/renderer.log +198381 -0
  29. data/examples/log/urls.log +3269 -0
  30. data/examples/messages/active_record.yaml +2 -0
  31. data/examples/messages/art_of_war.yaml +1 -0
  32. data/examples/messages/calculator.yaml +2 -0
  33. data/examples/messages/database.yaml +1 -0
  34. data/examples/messages/hangman.yaml +0 -0
  35. data/examples/messages/prefix_menu.yaml +3 -0
  36. data/examples/models/activations.rb +5 -0
  37. data/lib/colloquy.rb +39 -0
  38. data/lib/colloquy/exceptions.rb +64 -0
  39. data/lib/colloquy/flow_parser.rb +315 -0
  40. data/lib/colloquy/flow_pool.rb +21 -0
  41. data/lib/colloquy/helpers.rb +15 -0
  42. data/lib/colloquy/helpers/mysql.rb +110 -0
  43. data/lib/colloquy/helpers/redis.rb +103 -0
  44. data/lib/colloquy/helpers/scribe.rb +103 -0
  45. data/lib/colloquy/helpers/settings.rb +111 -0
  46. data/lib/colloquy/helpers/url.rb +10 -0
  47. data/lib/colloquy/input.rb +14 -0
  48. data/lib/colloquy/logger.rb +11 -0
  49. data/lib/colloquy/menu.rb +128 -0
  50. data/lib/colloquy/message_builder.rb +54 -0
  51. data/lib/colloquy/node.rb +67 -0
  52. data/lib/colloquy/paginator.rb +59 -0
  53. data/lib/colloquy/paginator/menu.rb +79 -0
  54. data/lib/colloquy/paginator/prompt.rb +32 -0
  55. data/lib/colloquy/prompt.rb +35 -0
  56. data/lib/colloquy/renderer.rb +423 -0
  57. data/lib/colloquy/response.rb +4 -0
  58. data/lib/colloquy/runner.rb +93 -0
  59. data/lib/colloquy/server.rb +157 -0
  60. data/lib/colloquy/session_store.rb +46 -0
  61. data/lib/colloquy/session_store/memory.rb +14 -0
  62. data/lib/colloquy/session_store/redis.rb +24 -0
  63. data/lib/colloquy/simulator.rb +114 -0
  64. data/lib/colloquy/spec_helpers.rb +21 -0
  65. metadata +459 -0
@@ -0,0 +1,2 @@
1
+ log_level: debug
2
+ path: log/renderer.log
@@ -0,0 +1,3 @@
1
+ more: "More"
2
+ previous: "Previous"
3
+ error_unexpected: "We're facing technical difficulties at this time. Please try again later!"
@@ -0,0 +1,18 @@
1
+ testing:
2
+ host: 'localhost'
3
+ username: 'root'
4
+ password: ''
5
+ reconnect: true
6
+ database: 'activations'
7
+ encoding: 'utf8'
8
+ adapter: 'em_mysql2'
9
+
10
+ customer:
11
+ host: 'localhost'
12
+ username: 'root'
13
+ password: ''
14
+ reconnect: true
15
+ database: 'activations'
16
+ encoding: 'utf8'
17
+ adapter: 'em_mysql2'
18
+
@@ -0,0 +1,9 @@
1
+ testing:
2
+ host: localhost
3
+
4
+ sessions:
5
+ host: localhost
6
+
7
+ state:
8
+ host: localhost
9
+
@@ -0,0 +1,2 @@
1
+ testing:
2
+ schema_uri: "http://s1.mobme.in/itw/schema.yml"
@@ -0,0 +1,2 @@
1
+ testing: "/home/mobme/infrastructure/ussd-renderer-redux/examples/config/test.yaml"
2
+ testing_rel: "config/test.yaml"
@@ -0,0 +1,8 @@
1
+ testing:
2
+ host: 'localhost'
3
+ username: 'root'
4
+ password: ''
5
+ reconnect: true
6
+ database: 'activations'
7
+ encoding: 'utf8'
8
+ adapter: 'em_mysql2'
@@ -0,0 +1,18 @@
1
+ log_cancellations:
2
+ active: http://google.com/?q=hello
3
+ backup: http://www.google.com/search?q=%%msisdn%%
4
+
5
+ pinger:
6
+ log_cancellations:
7
+ verb: get
8
+ params:
9
+ msisdn: 9745044399
10
+ tick: 5
11
+
12
+ timeouts:
13
+ connection: 2
14
+ inactivity: 5
15
+
16
+ logger:
17
+ log_level: debug
18
+ path: log/urls.log
@@ -0,0 +1,42 @@
1
+
2
+ require 'active_record'
3
+
4
+ require_relative '../models/activations'
5
+
6
+ class ActiveRecordFlow
7
+ include Colloquy::FlowParser
8
+
9
+ index {
10
+ request {
11
+ menu << :activate << :cancel
12
+ }
13
+
14
+ process { |input|
15
+ case menu.key(input)
16
+ when :activate
17
+ privileged_user = true
18
+ if privileged_user
19
+ if count = activate(headers[:msisdn])
20
+ notify [:activation_success, :count => count]
21
+ else
22
+ notify :activation_failure
23
+ end
24
+ else
25
+ notify :priveleges_required
26
+ end
27
+ when :cancel
28
+ url.call(:log_cancellations, { :msisdn => headers[:msisdn] })
29
+ notify :canceled
30
+ end
31
+ }
32
+ }
33
+
34
+ def setup
35
+ ::Activation.establish_connection(mysql.configuration[:customer])
36
+ end
37
+
38
+ def activate(msisdn)
39
+ logger.info "Activating #{msisdn}!"
40
+ count = Activation.count
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+
2
+ class ArtOfWarFlow
3
+ include Colloquy::FlowParser
4
+
5
+ index {
6
+ request {
7
+ session[:hello] = "yellow!"
8
+ menu.push(
9
+ :calculator, # to test a swtich
10
+ :special_redis,
11
+ :estimates, :waging_war, :offensive_strategy, :dispositions, :energy,
12
+ :weaknesses_and_strengths, :manoeuvre, :nine_variables, :marches,
13
+ :terrain, :the_nine_varieties_of_ground, :attack_by_fire,
14
+ :employment_of_secret_agents
15
+ )
16
+ }
17
+
18
+ process { |input|
19
+ session[:hello] = "world"
20
+ switch :index, :flow => :calculator if menu.key(input) == :calculator
21
+ switch :index, :flow => :special_redis if menu.key(input) == :special_redis
22
+ switch :index, :flow => :unknown if menu.key(input) == :offensive_strategy
23
+
24
+ notify "#{menu.key(input)}_notification".to_sym
25
+ }
26
+ }
27
+ end
@@ -0,0 +1,71 @@
1
+
2
+ class CalculatorFlow
3
+
4
+ include Colloquy::FlowParser
5
+
6
+ index {
7
+ request {
8
+ menu << "Add" << "Subtract" << "Back"
9
+ }
10
+
11
+ process { |input|
12
+ session[:operation] = case menu.key(input)
13
+ when "Add"
14
+ :add
15
+ when "Subtract"
16
+ :subtract
17
+ when "Back"
18
+ switch :back
19
+ else
20
+ notify :operation_invalid
21
+ end
22
+
23
+ switch :number_first
24
+ }
25
+ }
26
+
27
+ number_first {
28
+ request {
29
+ prompt "Enter the first number:"
30
+ }
31
+
32
+ process { |input|
33
+ if valid_input? input
34
+ session[:first_number] = input.to_i
35
+ switch :number_second
36
+ else
37
+ notify :number_invalid
38
+ end
39
+ }
40
+ }
41
+
42
+ number_second {
43
+ request {
44
+ prompt "Enter the second number:"
45
+ }
46
+
47
+ process { |number|
48
+ if valid_input? number
49
+ value = calculate(session[:operation], session[:first_number], number.to_i)
50
+ notify "The result is: #{value}"
51
+ end
52
+ }
53
+ }
54
+
55
+ def calculate(operation, first_number, second_number)
56
+ case operation
57
+ when :add
58
+ first_number + second_number
59
+ when :subtract
60
+ first_number - second_number
61
+ else
62
+ logger.error "Got an unexpected operation."
63
+ notify :error
64
+ end
65
+ end
66
+
67
+ def valid_input?(number)
68
+ "#{number.to_i}"
69
+ end
70
+ end
71
+
@@ -0,0 +1,17 @@
1
+
2
+ class CrossoverFlow
3
+
4
+ include Colloquy::FlowParser
5
+
6
+ index {
7
+ request { |input|
8
+ session[:calculator_type] = (input == "1") ? :scientific : :normal
9
+ pass
10
+ }
11
+
12
+ process { |input|
13
+ switch :index, :flow => :calculator
14
+ }
15
+ }
16
+ end
17
+
@@ -0,0 +1,33 @@
1
+
2
+ class DatabaseFlow
3
+ include Colloquy::FlowParser
4
+
5
+ index {
6
+ request {
7
+ menu << :activate << :cancel
8
+ }
9
+
10
+ process { |input|
11
+ case menu.key(input)
12
+ when :activate
13
+ privileged_user = mysql[:customer].query("select sleep(0.25);")
14
+ if privileged_user
15
+ if activate(headers[:msisdn])
16
+ notify :activation_success
17
+ else
18
+ notify :activation_failure
19
+ end
20
+ else
21
+ notify :priveleges_required
22
+ end
23
+ when :cancel
24
+ url.call(:log_cancellations, { :msisdn => headers[:msisdn] })
25
+ notify :canceled
26
+ end
27
+ }
28
+ }
29
+
30
+ def activate(msisdn)
31
+ logger.info "Activating #{msisdn}!"
32
+ end
33
+ end
@@ -0,0 +1,82 @@
1
+ require 'random_word_generator'
2
+ require 'active_support/inflector'
3
+
4
+ class HangmanFlow
5
+
6
+ include Colloquy::FlowParser
7
+ NUMBER_CRYPTEX = "22233344455566677778889999"
8
+
9
+ index {
10
+ request {
11
+ prompt "Hangman..Ready to die? No escape now!\n" +
12
+ "Enter any key to start."
13
+ }
14
+
15
+ process { |input|
16
+ session[:secret] = RandomWordGenerator.word
17
+ session[:lives] = 9
18
+ session[:used_letters] = "0"
19
+ session[:message] = ""
20
+
21
+ switch :game_logic
22
+ }
23
+ }
24
+
25
+ game_logic {
26
+ request {
27
+ notify "#{session[:secret]}\n You WIN!" if session[:secret] == word_with_user_input
28
+ notify "You LOSE. The word was #{session[:secret]}" if session[:lives] == 0
29
+
30
+ prompt "#{session[:message]}\n #{word_with_user_input} \n" +
31
+ "You have #{session[:lives]} #{pluralize(session[:lives], 'life')} left.\n" +
32
+ "Enter letter (A=>2,B=>22,C=>222,D=>3). Enter 0 to quit."
33
+ }
34
+
35
+ process { |input|
36
+ notify "Exiting application.." if input == "0"
37
+
38
+ if valid_input? input
39
+ letter_entered = translate_letter_code(input)
40
+ if session[:used_letters].include? letter_entered
41
+ session[:message] = "You already entered this letter."
42
+ else
43
+ session[:used_letters] << letter_entered
44
+ if session[:secret].include? letter_entered
45
+ session[:message] = "You entered #{letter_entered}. Aha! Good guess."
46
+ else
47
+ session[:lives] -= 1
48
+ session[:message] = "You entered #{letter_entered}. Bad luck!"
49
+ end
50
+ end
51
+ else
52
+ session[:message] = "Invalid letter code."
53
+ end
54
+ switch :game_logic
55
+ }
56
+ }
57
+
58
+
59
+ def valid_input?(number)
60
+ if number.length <= 4 && ["7","9"].include?(number.squeeze)
61
+ return true
62
+ elsif number.length <= 3 && ["2","3","4","5","6","8"].include?(number.squeeze)
63
+ return true
64
+ else
65
+ return false
66
+ end
67
+ end
68
+
69
+ def translate_letter_code(letter_code)
70
+ ("a".."z").to_a[NUMBER_CRYPTEX.index(letter_code) + letter_code.length - 1]
71
+ end
72
+
73
+ def word_with_user_input
74
+ regex = Regexp.new("[^#{session[:used_letters]}]")
75
+ session[:secret].gsub(regex,'-')
76
+ end
77
+
78
+ def pluralize(number, text)
79
+ return text.pluralize if number != 1
80
+ text
81
+ end
82
+ end
@@ -0,0 +1,11 @@
1
+
2
+ class MetadataFlow
3
+ include Colloquy::FlowParser
4
+
5
+ index {
6
+ request { |input|
7
+ logger.info "Metadata: #{headers[:metadata].inspect}"
8
+ notify "I love #{headers[:metadata][:love]}"
9
+ }
10
+ }
11
+ end
@@ -0,0 +1,23 @@
1
+
2
+ class PaginationFlow
3
+
4
+ include Colloquy::FlowParser
5
+
6
+ index {
7
+ request {
8
+ menu.prefix {
9
+ if headers[:page] == 1
10
+ "Welcome to Some new application. Please choose from one of the packs below to get latest news from Some new application"
11
+ end
12
+ }
13
+ 1.upto(10).each do |item|
14
+ menu << "Pack #{item}"
15
+ end
16
+ }
17
+
18
+ process { |input|
19
+
20
+ }
21
+ }
22
+ end
23
+
@@ -0,0 +1,29 @@
1
+
2
+ class PassFlow
3
+ include Colloquy::FlowParser
4
+
5
+ index {
6
+ request { |input|
7
+ pass unless input.blank?
8
+ menu << :activate << :cancel
9
+ }
10
+
11
+ process { |input|
12
+ notify :direct if input.direct?
13
+
14
+ case menu.key(input)
15
+ when :activate
16
+ notify :activation_success
17
+ when :cancel
18
+ cancelation = url[:log_cancellations].call(:msisdn => headers[:msisdn])
19
+ notify cancelation.response
20
+ else
21
+ notif "Hello World!" #Deliberate error!
22
+ end
23
+ }
24
+ }
25
+
26
+ def activate
27
+ logger.info "Activating!"
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+
2
+ class PrefixMenuFlow
3
+ include Colloquy::FlowParser
4
+
5
+ index {
6
+ request { |input|
7
+ menu.push(headers[:msisdn])
8
+ menu.push(*('a'..'z').to_a)
9
+ menu.prefix { "Hello #{headers[:session_id]}" }
10
+ menu.suffix do
11
+ logger.info "Headers: #{headers.inspect}"
12
+ "Your world is my oyster! And there's nothing better than beer! Or a touch of lemonade." if headers[:page] == 1
13
+ end
14
+
15
+ menu.before_page do
16
+ session[:wonker] = "Page: #{headers[:page]}"
17
+ end
18
+ }
19
+
20
+ process { |input|
21
+ notify menu.key(input)
22
+ }
23
+ }
24
+ end