charyf 0.1.1 → 0.2.5

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 (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: