charyf 0.1.1 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -105
  3. data/README.md +7 -1
  4. data/lib/charyf/engine/all.rb +3 -0
  5. data/lib/charyf/engine/context.rb +1 -53
  6. data/lib/charyf/engine/controller/controller.rb +6 -3
  7. data/lib/charyf/engine/controller/helpers.rb +7 -3
  8. data/lib/charyf/engine/controller/renderers.rb +2 -2
  9. data/lib/charyf/engine/dispatcher/base.rb +47 -40
  10. data/lib/charyf/engine/dispatcher/default.rb +8 -18
  11. data/lib/charyf/engine/intent/intent.rb +7 -42
  12. data/lib/charyf/engine/intent/processors/dummy.rb +0 -8
  13. data/lib/charyf/engine/intent/processors/helpers.rb +1 -11
  14. data/lib/charyf/engine/intent/processors/processor.rb +6 -32
  15. data/lib/charyf/engine/interface/interface.rb +25 -18
  16. data/lib/charyf/engine/interface/program.rb +15 -1
  17. data/lib/charyf/engine/request.rb +6 -18
  18. data/lib/charyf/engine/response.rb +7 -26
  19. data/lib/charyf/engine/routing/default.rb +58 -0
  20. data/lib/charyf/engine/routing/result.rb +25 -0
  21. data/lib/charyf/engine/routing/router.rb +33 -0
  22. data/lib/charyf/engine/session/processors/processor.rb +4 -15
  23. data/lib/charyf/engine/skill/skill.rb +0 -2
  24. data/lib/charyf/utils/all.rb +3 -2
  25. data/lib/charyf/utils/app_engine.rb +28 -0
  26. data/lib/charyf/utils/application/bootstrap.rb +21 -62
  27. data/lib/charyf/utils/application/configuration.rb +5 -5
  28. data/lib/charyf/utils/application.rb +15 -2
  29. data/lib/charyf/utils/command/actions.rb +10 -2
  30. data/lib/charyf/utils/commands/all.rb +1 -0
  31. data/lib/charyf/utils/commands/cli/cli_command.rb +12 -1
  32. data/lib/charyf/utils/commands/help/USAGE +2 -0
  33. data/lib/charyf/utils/commands/server/server_command.rb +31 -0
  34. data/lib/charyf/utils/generators/app/app_generator.rb +1 -0
  35. data/lib/charyf/utils/generators/app/templates/app/skill_controller.rb.tt +6 -1
  36. data/lib/charyf/utils/generators/app/templates/config/routes.rb.tt +6 -0
  37. data/lib/charyf/utils/generators/defaults.rb +11 -2
  38. data/lib/charyf/utils/generators/intents/intents_generator.rb +1 -1
  39. data/lib/charyf/utils/parser/parser.rb +6 -13
  40. data/lib/charyf/utils/pipeline.rb +28 -0
  41. data/lib/charyf/utils/storage/provider.rb +5 -13
  42. data/lib/charyf/utils/strategy/base_class.rb +50 -0
  43. data/lib/charyf/utils/strategy/owner_class.rb +23 -0
  44. data/lib/charyf/version.rb +2 -2
  45. data/todo.md +8 -3
  46. metadata +10 -4
  47. data/lib/charyf/engine/skill/routing.rb +0 -57
  48. data/lib/charyf/utils/strategy.rb +0 -44
@@ -5,31 +5,38 @@ require_relative '../dispatcher/base'
5
5
 
6
6
  module Charyf
7
7
  module Interface
8
+
9
+ extend Charyf::Strategy::OwnerClass
10
+
8
11
  class Base
9
12
 
10
- include Charyf::Strategy
11
- def self.base
12
- Base
13
- end
13
+ include Charyf::Strategy::BaseClass
14
14
 
15
- sig_self [], 'Charyf::Engine::Dispatcher::Base',
16
- def self.dispatcher
17
- Charyf.application.dispatcher.new
18
- end
15
+ class << self
19
16
 
20
- sig_self ['String', 'Charyf::Engine::Response'], nil,
21
- def self.reply(conversation_id, response)
22
- raise Charyf::Utils::NotImplemented.new
23
- end
17
+ def dispatcher
18
+ Charyf.application.dispatcher.new
19
+ end
24
20
 
25
- end
21
+ def reply(conversation_id, message_id, response)
22
+ raise Charyf::Utils::NotImplemented.new
23
+ end
26
24
 
27
- def self.known
28
- Base.known
29
- end
25
+ def start
26
+ raise Charyf::Utils::NotImplemented.new
27
+ end
28
+
29
+ def stop
30
+ raise Charyf::Utils::NotImplemented.new
31
+ end
32
+
33
+ # If stop does not finish till required timeout
34
+ # Terminate is called
35
+ def terminate
36
+ raise Charyf::Utils::NotImplemented.new
37
+ end
38
+ end
30
39
 
31
- def self.list
32
- Base.list
33
40
  end
34
41
  end
35
42
  end
@@ -1,3 +1,5 @@
1
+ require 'securerandom'
2
+
1
3
  require_relative 'interface'
2
4
  require_relative '../request'
3
5
 
@@ -11,6 +13,18 @@ module Charyf
11
13
 
12
14
  attr_reader :handler, :conversation_id
13
15
 
16
+ def self.start
17
+ # NOP
18
+ end
19
+
20
+ def self.stop
21
+ # NOP
22
+ end
23
+
24
+ def self.terminate
25
+ # NOP
26
+ end
27
+
14
28
  sig_self ['String', 'Charyf::Engine::Response'], nil,
15
29
  def self.reply(conversation_id, response)
16
30
  interface = _interfaces[conversation_id]
@@ -51,7 +65,7 @@ module Charyf
51
65
 
52
66
  sig [], 'Charyf::Engine::Request',
53
67
  def request
54
- Charyf::Engine::Request.new(self.class, conversation_id)
68
+ Charyf::Engine::Request.new(self.class, conversation_id, SecureRandom.hex)
55
69
  end
56
70
 
57
71
  end
@@ -4,27 +4,15 @@ module Charyf
4
4
 
5
5
  attr_accessor :text
6
6
 
7
+ attr_reader :referer, :conversation_id, :message_id
8
+
9
+
7
10
  # Module -> anything of type Charyf::Interface::Base
8
- sig ['Module', 'String'], nil,
9
- def initialize(referer, conversation_id)
11
+ # sig ['Module', 'String'], nil,
12
+ def initialize(referer, conversation_id, message_id)
10
13
  @referer = referer
11
14
  @conversation_id = conversation_id
12
- end
13
-
14
- # Module -> Charyf::Interface::Base
15
- sig [], 'Module',
16
- def referer
17
- @referer
18
- end
19
-
20
- sig [], 'String',
21
- def conversation_id
22
- @conversation_id
23
- end
24
-
25
- sig [], 'String',
26
- def id
27
- @referer.strategy_name.to_s + '_#_' + @conversation_id
15
+ @message_id = message_id
28
16
  end
29
17
 
30
18
  end
@@ -3,39 +3,20 @@ module Charyf
3
3
  class Response
4
4
 
5
5
  attr_accessor :text, :html
6
+ attr_reader :conversation_id, :reply_message_id
6
7
 
7
- sig [['String', 'NilClass'], ['String', 'NilClass']], nil,
8
- def initialize(text, html)
9
- @text = text
10
- @html = html
8
+ def initialize(conversation_id, reply_message_id)
9
+ @text = nil
10
+ @html = nil
11
+
12
+ @conversation_id = conversation_id
13
+ @reply_message_id = reply_message_id
11
14
  end
12
15
 
13
16
  def empty?
14
17
  text.blank? && html.blank?
15
18
  end
16
19
 
17
- # Attr methods for type-checking
18
-
19
- sig ['String', 'NilClass'], ['String', 'NilClass'],
20
- def text=(text)
21
- @text = text
22
- end
23
-
24
- sig [], ['String', 'NilClass'],
25
- def text
26
- @text
27
- end
28
-
29
- sig ['String', 'NilClass'], ['String', 'NilClass'],
30
- def html=(html)
31
- @html = html
32
- end
33
-
34
- sig [], ['String', 'NilClass'],
35
- def html
36
- @html
37
- end
38
-
39
20
  end
40
21
  end
41
22
  end
@@ -0,0 +1,58 @@
1
+ require_relative 'router'
2
+
3
+ module Charyf
4
+ module Engine
5
+ module Routing
6
+ class Default < Base
7
+
8
+ class InvalidRoute < StandardError; end
9
+
10
+ strategy_name :default
11
+
12
+ def initialize
13
+ @routes = {
14
+ Charyf::Engine::Intent.unknown.name => unknown
15
+ }
16
+ end
17
+
18
+ def draw(&block)
19
+ instance_eval &block
20
+ end
21
+
22
+ # Context -> Controller
23
+ def process(context)
24
+ @routes[context.intent.name.downcase] || invalid
25
+ end
26
+
27
+ def route(intent, to: nil)
28
+ raise InvalidRoute.new("route '#{intent}' missing to definition") if to.nil?
29
+
30
+ @routes[intent.downcase] = parse_target(to)
31
+ end
32
+
33
+ private
34
+
35
+ def parse_target(to)
36
+ if to.is_a? Hash
37
+ raise InvalidRoute.new("route '#{intent}' incomplete to definition") unless to.keys.map(&:to_sym) & [:skill, :controller, :action] == [:skill, :controller, :action]
38
+
39
+ return Result.new(to[:skill], to[:controller], to[:action])
40
+ end
41
+
42
+ if to.is_a? String
43
+ path, action = to.split("#")
44
+ path = path.split("/")
45
+
46
+ skill = path.delete_at(0)
47
+ controller = path.join("/")
48
+
49
+ return Result.new(skill, controller, action)
50
+ end
51
+
52
+ raise InvalidRoute.new("Unknown definition to:#{to}")
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ module Charyf
2
+ module Engine
3
+ module Routing
4
+ class Result
5
+
6
+ attr_reader :skill, :controller, :action
7
+
8
+ def initialize(skill, controller, action)
9
+ @skill = skill
10
+ @controller = controller
11
+ @action = action
12
+ end
13
+
14
+ def controller_class_name
15
+ [skill, controller.split("/")].flatten.compact.map(&:to_s).map(&:camelize).join("::") + "Controller"
16
+ end
17
+
18
+ def skill_class_name
19
+ skill.to_s.camelize if skill
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'result'
2
+
3
+ module Charyf
4
+ module Engine
5
+ module Routing
6
+
7
+ extend Charyf::Strategy::OwnerClass
8
+
9
+ class Base
10
+
11
+ include Charyf::Strategy::BaseClass
12
+
13
+ def draw(&block)
14
+ raise Charyf::Utils::NotImplemented.new
15
+ end
16
+
17
+ # Context -> Controller
18
+ def process(context)
19
+ raise Charyf::Utils::NotImplemented.new
20
+ end
21
+
22
+ def unknown
23
+ Result.new(nil, 'skill', 'unknown')
24
+ end
25
+
26
+ def invalid
27
+ Result.new(nil, 'skill', 'invalid')
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -4,13 +4,12 @@ module Charyf
4
4
  module Engine
5
5
  class Session
6
6
  module Processor
7
- class Base
8
7
 
9
- include Charyf::Strategy
10
- def self.base
11
- Base
12
- end
8
+ extend Charyf::Strategy::OwnerClass
13
9
 
10
+ class Base
11
+
12
+ include Charyf::Strategy::BaseClass
14
13
 
15
14
  sig ['Charyf::Engine::Request'], ['Charyf::Engine::Session', 'NilClass'],
16
15
  def process(request)
@@ -23,16 +22,6 @@ module Charyf
23
22
  end
24
23
 
25
24
  end
26
-
27
-
28
- def self.known
29
- Base.known
30
- end
31
-
32
- def self.list
33
- Base.list
34
- end
35
-
36
25
  end
37
26
  end
38
27
  end
@@ -1,11 +1,9 @@
1
- require_relative 'routing'
2
1
  require_relative 'info'
3
2
 
4
3
  module Charyf
5
4
  module Skill
6
5
  class Base
7
6
 
8
- include Charyf::Skill::Routing
9
7
  include Charyf::Skill::Info
10
8
 
11
9
  class << self
@@ -8,6 +8,7 @@ require_relative 'charyf'
8
8
  require_relative 'error_handler'
9
9
  require_relative 'initializable'
10
10
  require_relative 'logger'
11
- require_relative 'machine'
12
- require_relative 'strategy'
11
+ require_relative 'pipeline'
12
+ require_relative 'strategy/owner_class'
13
+ require_relative 'strategy/base_class'
13
14
  require_relative 'utils'
@@ -20,5 +20,33 @@ module Charyf
20
20
  self
21
21
  end
22
22
 
23
+ def start_interfaces
24
+ Charyf::Interface.known.map(&:start)
25
+ end
26
+
27
+ def start_pipeline
28
+
29
+ begin
30
+ loop do
31
+ request = Charyf::Pipeline.dequeue
32
+
33
+ Charyf.application.dispatcher.new.dispatch(request)
34
+ end
35
+
36
+ rescue Exception => e
37
+ if e.is_a? Interrupt
38
+ puts "\n\nExiting ...\n"
39
+ elsif e.message =~ /No live threads left./
40
+ raise "No interfaces are available. The server will now exit."
41
+ else
42
+ puts e
43
+ puts e.backtrace
44
+ Charyf.application.config.error_handlers.handle_exception(e)
45
+ raise e
46
+ end
47
+ end
48
+
49
+ end
50
+
23
51
  end
24
52
  end
@@ -8,29 +8,6 @@ module Charyf
8
8
  # noinspection RubyResolve
9
9
  module Bootstrap
10
10
 
11
- class SkillLoadError < StandardError
12
- def initialize(e, skill_name, skill_path)
13
- super(e)
14
-
15
- @_name = skill_name
16
- @_path = skill_path.dirname
17
- end
18
-
19
- def message
20
- _message + super
21
- end
22
-
23
- def _message
24
- <<-EOS
25
-
26
- Unable to load skill #{@_name}
27
- Expected to find: '#{@_name}.rb'
28
- Located at: '#{@_path}'
29
-
30
- EOS
31
- end
32
- end
33
-
34
11
  include Charyf::Initializable
35
12
 
36
13
  class InitializationError < StandardError; end
@@ -46,13 +23,18 @@ EOS
46
23
  env_file = self.config.root.join('config', 'environments', "#{Charyf.env}.rb")
47
24
 
48
25
  if FileTest.exists?(env_file)
49
- require env_file
26
+ require env_file.to_s
50
27
  end
28
+
29
+ require self.config.root.join('config', 'routes.rb').to_s
51
30
  end
52
31
 
53
32
  initializer :set_load_paths, group: :all do
54
- libdir = File.expand_path(self.config.root.join('lib'))
55
- $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
33
+ [
34
+ File.expand_path(self.config.root)
35
+ ].each do |libdir|
36
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
37
+ end
56
38
  end
57
39
 
58
40
  #
@@ -69,6 +51,7 @@ EOS
69
51
  Charyf.application.session_processor
70
52
  Charyf.application.intent_processors
71
53
  Charyf.application.dispatcher
54
+ Charyf.application.routing
72
55
  end
73
56
 
74
57
  #
@@ -94,60 +77,36 @@ EOS
94
77
  # Require skill level files
95
78
  Charyf::Utils.require_recursive self.config.root.join('app', 'skills'),
96
79
  condition: condition
97
-
98
- # Require controllers
99
- Charyf::Skill.list.each do |skill_klass|
100
- # Load initializers
101
- root = skill_klass.skill_root
102
-
103
- Dir[root.join('controllers', '**', '*.rb')].each do |controller|
104
- require controller
105
- end
106
- end
107
80
  end
108
81
 
109
82
  #
110
- # Load all intents
83
+ # Load skill controllers
111
84
  #
112
- initializer :load_skill_intents, groups: :all do
113
- # Require Skill intents
114
- Charyf::Skill.list.each do |skill_klass|
115
- Dir[skill_klass.routing_source_dir.join('**', '*.rb')].each do |file|
116
- require file
117
- end
118
- end
85
+ initializer :load_skill_controllers, group: :all do
119
86
 
120
87
  Charyf::Skill.list.each do |skill_klass|
121
- skill_name = skill_klass.skill_name
122
-
123
- Charyf.application.intent_processors.each do |processor|
124
- # Public routing
125
- skill_klass._public_routing(processor.strategy_name).each do |block|
126
- processor.get_global.load skill_name, block
127
- end
128
88
 
129
- # Private routing
130
- skill_klass._private_routing(processor.strategy_name).each do |block|
131
- processor.get_for(skill_name).load skill_name, block
132
- end
89
+ # Load controllers
90
+ root = skill_klass.skill_root
133
91
 
92
+ Dir[root.join('controllers', '**', '*.rb')].each do |controller|
93
+ require controller
134
94
  end
95
+
135
96
  end
136
97
  end
137
98
 
138
99
  #
139
- # Load all user skill files
140
- # - controllers
100
+ # Load skill initializers
141
101
  #
142
- initializer :load_skill_controllers, group: :all do
143
-
102
+ initializer :initialize_skills, group: :all do
144
103
  Charyf::Skill.list.each do |skill_klass|
145
104
 
146
105
  # Load controllers
147
106
  root = skill_klass.skill_root
148
107
 
149
- Dir[root.join('controllers', '**', '*.rb')].each do |controller|
150
- require controller
108
+ Dir[root.join('initializers', '**', '*.rb')].each do |initializer|
109
+ require initializer
151
110
  end
152
111
 
153
112
  end
@@ -157,7 +116,7 @@ EOS
157
116
  # Load user initializer files
158
117
  #
159
118
  initializer :run_initializers, group: :all do
160
- Dir[self.config.root.join('config', 'initializers', '**', '**.rb')].each do |initializer|
119
+ Dir[self.config.root.join('config', 'initializers', '**', '*.rb')].each do |initializer|
161
120
  require initializer
162
121
  end
163
122
 
@@ -9,7 +9,7 @@ module Charyf
9
9
 
10
10
  attr_accessor :console
11
11
 
12
- attr_accessor :session_processor, :storage_provider, :dispatcher
12
+ attr_accessor :session_processor, :storage_provider, :dispatcher, :router
13
13
  attr_accessor :enabled_intent_processors
14
14
 
15
15
  def initialize(root)
@@ -26,22 +26,22 @@ module Charyf
26
26
  Charyf::ErrorHandlers
27
27
  end
28
28
 
29
- sig [], ['Symbol', 'NilClass'],
29
+ def router
30
+ (@router || 'default').to_sym
31
+ end
32
+
30
33
  def dispatcher
31
34
  (@dispatcher || 'default').to_sym
32
35
  end
33
36
 
34
- sig [], ['Symbol'],
35
37
  def session_processor
36
38
  (@session_processor || 'default').to_sym
37
39
  end
38
40
 
39
- sig [], [Array],
40
41
  def enabled_intent_processors
41
42
  (@enabled_intent_processors || []).map(&:to_sym)
42
43
  end
43
44
 
44
- sig [], ['Symbol', 'NilClass'],
45
45
  def storage_provider
46
46
  @storage_provider ? @storage_provider.to_sym : nil
47
47
  end
@@ -41,7 +41,7 @@ module Charyf
41
41
 
42
42
  end
43
43
 
44
- def initialize!(group: :default)
44
+ def initialize!(group = :default)
45
45
  return self if @initialized
46
46
  @initialized = true
47
47
 
@@ -110,6 +110,18 @@ module Charyf
110
110
  klass
111
111
  end
112
112
 
113
+ def routing
114
+ klass = Charyf::Engine::Routing.list[config.router]
115
+
116
+ raise Charyf::Utils::InvalidConfiguration.new("No router with name '#{config.router}' found") unless klass
117
+
118
+ klass
119
+ end
120
+
121
+ def routes
122
+ @routes ||= routing.new
123
+ end
124
+
113
125
  protected
114
126
 
115
127
  def run_generators_blocks(app) #:nodoc:
@@ -118,7 +130,8 @@ module Charyf
118
130
  end
119
131
 
120
132
  def initializers
121
- Bootstrap.initializers_for(self)
133
+ Bootstrap.initializers_for(self) +
134
+ (extensions.map { |e| e.class.initializers_for(self) }.flatten)
122
135
  end
123
136
 
124
137
  private
@@ -8,10 +8,10 @@ module Charyf
8
8
  # Dir.chdir(File.expand_path("../..", APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
9
9
  # end
10
10
 
11
- def require_application_and_environment!
11
+ def require_application_and_environment!(group = :default)
12
12
  if defined?(APP_PATH)
13
13
  require APP_PATH
14
- Charyf.application.initialize!
14
+ Charyf.application.initialize!(group)
15
15
  end
16
16
  end
17
17
 
@@ -19,6 +19,14 @@ module Charyf
19
19
  Charyf.application.load_generators
20
20
  end
21
21
 
22
+ def start_interfaces!
23
+ Charyf.application.start_interfaces
24
+ end
25
+
26
+ def start_pipeline!
27
+ Charyf.application.start_pipeline
28
+ end
29
+
22
30
  end
23
31
  end
24
32
  end
@@ -4,3 +4,4 @@ require_relative 'console/console_command'
4
4
  require_relative 'generate/generate_command'
5
5
  require_relative 'destroy/destroy_command'
6
6
  require_relative 'help/help'
7
+ require_relative 'server/server_command'
@@ -59,6 +59,10 @@ module Charyf
59
59
  end
60
60
 
61
61
  def detect(utterance)
62
+ if !utterance || utterance.empty?
63
+ return
64
+ end
65
+
62
66
  if utterance[0] == ':'
63
67
  process_command utterance[1..-1]
64
68
  return
@@ -67,7 +71,14 @@ module Charyf
67
71
  request = @interface.request
68
72
  request.text = utterance
69
73
 
70
- @interface.process(request)
74
+ res = @interface.process(request)
75
+
76
+ if res[:status] == :NOK && res[:response].is_a?(Exception)
77
+ e = res[:response]
78
+ puts ''
79
+ puts e.inspect
80
+ puts "\t" + e.backtrace.join("\n\t")
81
+ end
71
82
  end
72
83
 
73
84
 
@@ -3,6 +3,8 @@ The most common Charyf commands are:
3
3
  cli Start the Charyf command line interface. Command line
4
4
  interface allows to chat with charyf application on
5
5
  the base of text messages.
6
+ server Start the charyf server with all interfaces
7
+ (short-cut alias: "s")
6
8
 
7
9
  All commands can be run with -h (or --help) for more information.
8
10
  In addition to those commands, there are: