charyf 0.1.1
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.
- checksums.yaml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +154 -0
- data/LICENSE.txt +21 -0
- data/README.md +18 -0
- data/Rakefile +6 -0
- data/bin/charyf-debug +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/charyf.gemspec +48 -0
- data/exe/charyf +4 -0
- data/lib/charyf/deps.rb +9 -0
- data/lib/charyf/engine/all.rb +22 -0
- data/lib/charyf/engine/charyf.rb +5 -0
- data/lib/charyf/engine/context.rb +61 -0
- data/lib/charyf/engine/controller/actions.rb +29 -0
- data/lib/charyf/engine/controller/controller.rb +62 -0
- data/lib/charyf/engine/controller/conversation.rb +58 -0
- data/lib/charyf/engine/controller/helpers.rb +38 -0
- data/lib/charyf/engine/controller/renderers.rb +103 -0
- data/lib/charyf/engine/dispatcher/base.rb +121 -0
- data/lib/charyf/engine/dispatcher/default.rb +60 -0
- data/lib/charyf/engine/intent/intent.rb +54 -0
- data/lib/charyf/engine/intent/processors/dummy.rb +30 -0
- data/lib/charyf/engine/intent/processors/helpers.rb +32 -0
- data/lib/charyf/engine/intent/processors/processor.rb +56 -0
- data/lib/charyf/engine/interface/interface.rb +35 -0
- data/lib/charyf/engine/interface/program.rb +59 -0
- data/lib/charyf/engine/request.rb +32 -0
- data/lib/charyf/engine/response.rb +41 -0
- data/lib/charyf/engine/session/processors/default.rb +42 -0
- data/lib/charyf/engine/session/processors/processor.rb +39 -0
- data/lib/charyf/engine/session/session.rb +68 -0
- data/lib/charyf/engine/skill/info.rb +24 -0
- data/lib/charyf/engine/skill/routing.rb +57 -0
- data/lib/charyf/engine/skill/skill.rb +40 -0
- data/lib/charyf/engine.rb +3 -0
- data/lib/charyf/support/all.rb +4 -0
- data/lib/charyf/support/hash.rb +43 -0
- data/lib/charyf/support/object.rb +7 -0
- data/lib/charyf/support/string.rb +94 -0
- data/lib/charyf/support/string_inquirer.rb +17 -0
- data/lib/charyf/support.rb +1 -0
- data/lib/charyf/utils/all.rb +13 -0
- data/lib/charyf/utils/app_engine/extensions.rb +21 -0
- data/lib/charyf/utils/app_engine.rb +24 -0
- data/lib/charyf/utils/app_loader.rb +38 -0
- data/lib/charyf/utils/application/bootstrap.rb +176 -0
- data/lib/charyf/utils/application/configuration.rb +51 -0
- data/lib/charyf/utils/application.rb +131 -0
- data/lib/charyf/utils/charyf.rb +44 -0
- data/lib/charyf/utils/cli.rb +14 -0
- data/lib/charyf/utils/command/actions.rb +24 -0
- data/lib/charyf/utils/command/base.rb +138 -0
- data/lib/charyf/utils/command/behavior.rb +81 -0
- data/lib/charyf/utils/command/environment_argument.rb +40 -0
- data/lib/charyf/utils/command.rb +106 -0
- data/lib/charyf/utils/commands/all.rb +6 -0
- data/lib/charyf/utils/commands/application/application_command.rb +21 -0
- data/lib/charyf/utils/commands/cli/cli_command.rb +115 -0
- data/lib/charyf/utils/commands/console/console_command.rb +77 -0
- data/lib/charyf/utils/commands/destroy/destroy_command.rb +26 -0
- data/lib/charyf/utils/commands/generate/generate_command.rb +31 -0
- data/lib/charyf/utils/commands/help/USAGE +9 -0
- data/lib/charyf/utils/commands/help/help.rb +20 -0
- data/lib/charyf/utils/commands.rb +15 -0
- data/lib/charyf/utils/configuration.rb +36 -0
- data/lib/charyf/utils/error_handler.rb +26 -0
- data/lib/charyf/utils/extension/configurable.rb +41 -0
- data/lib/charyf/utils/extension/configuration.rb +63 -0
- data/lib/charyf/utils/extension.rb +129 -0
- data/lib/charyf/utils/generator/actions.rb +281 -0
- data/lib/charyf/utils/generator/base.rb +288 -0
- data/lib/charyf/utils/generators/app/USAGE +8 -0
- data/lib/charyf/utils/generators/app/app_generator.rb +274 -0
- data/lib/charyf/utils/generators/app/templates/Gemfile.erb +20 -0
- data/lib/charyf/utils/generators/app/templates/README.md +24 -0
- data/lib/charyf/utils/generators/app/templates/app/skill_controller.rb.tt +8 -0
- data/lib/charyf/utils/generators/app/templates/bin/charyf +5 -0
- data/lib/charyf/utils/generators/app/templates/config/application.rb.tt +32 -0
- data/lib/charyf/utils/generators/app/templates/config/boot.rb.tt +4 -0
- data/lib/charyf/utils/generators/app/templates/config/chapp.rb.tt +5 -0
- data/lib/charyf/utils/generators/app/templates/config/environments/development.rb.tt +2 -0
- data/lib/charyf/utils/generators/app/templates/config/environments/production.rb.tt +2 -0
- data/lib/charyf/utils/generators/app/templates/config/environments/test.rb.tt +2 -0
- data/lib/charyf/utils/generators/app/templates/config/load.rb.tt +17 -0
- data/lib/charyf/utils/generators/app/templates/gitignore +18 -0
- data/lib/charyf/utils/generators/app_base.rb +277 -0
- data/lib/charyf/utils/generators/defaults.rb +75 -0
- data/lib/charyf/utils/generators/intents/intents_generator.rb +41 -0
- data/lib/charyf/utils/generators/named_base.rb +73 -0
- data/lib/charyf/utils/generators/skill/skill_generator.rb +47 -0
- data/lib/charyf/utils/generators/skill/templates/controllers/skill_controller.rb.tt +10 -0
- data/lib/charyf/utils/generators/skill/templates/module.rb.tt +6 -0
- data/lib/charyf/utils/generators/skill/templates/skill.rb.tt +3 -0
- data/lib/charyf/utils/generators.rb +187 -0
- data/lib/charyf/utils/initializable.rb +95 -0
- data/lib/charyf/utils/logger.rb +26 -0
- data/lib/charyf/utils/machine.rb +129 -0
- data/lib/charyf/utils/parser/en_parser.rb +97 -0
- data/lib/charyf/utils/parser/parser.rb +37 -0
- data/lib/charyf/utils/ruby_version_check.rb +15 -0
- data/lib/charyf/utils/storage/provider.rb +44 -0
- data/lib/charyf/utils/strategy.rb +44 -0
- data/lib/charyf/utils/utils.rb +64 -0
- data/lib/charyf/utils.rb +2 -0
- data/lib/charyf/version.rb +19 -0
- data/lib/charyf.rb +18 -0
- data/lib/locale/en.yml +206 -0
- data/todo.md +3 -0
- metadata +272 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor/group'
|
|
4
|
+
|
|
5
|
+
require_relative 'command/behavior'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module Charyf
|
|
9
|
+
module Generators
|
|
10
|
+
include Charyf::Command::Behavior
|
|
11
|
+
|
|
12
|
+
REMOVED_GENERATORS = %w(app cli_app intents)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DEFAULT_ALIASES = {}
|
|
16
|
+
|
|
17
|
+
DEFAULT_OPTIONS = {
|
|
18
|
+
charyf: {
|
|
19
|
+
intents: true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
|
|
25
|
+
def aliases #:nodoc:
|
|
26
|
+
@aliases ||= DEFAULT_ALIASES.dup
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def options #:nodoc:
|
|
30
|
+
@options ||= DEFAULT_OPTIONS.dup
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns an array of generator namespaces that are hidden.
|
|
34
|
+
# Generator namespaces may be hidden for a variety of reasons.
|
|
35
|
+
def hidden_namespaces
|
|
36
|
+
@hidden_namespaces ||= []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def hide_namespaces(*namespaces)
|
|
40
|
+
hidden_namespaces.concat(namespaces)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
alias hide_namespace hide_namespaces
|
|
44
|
+
|
|
45
|
+
# Show help message with available generators.
|
|
46
|
+
def help(command = "generate")
|
|
47
|
+
puts "Usage: charyf #{command} GENERATOR [args] [options]"
|
|
48
|
+
puts
|
|
49
|
+
puts "General options:"
|
|
50
|
+
puts " -h, [--help] # Print generator's options and usage"
|
|
51
|
+
puts " -p, [--pretend] # Run but do not make any changes"
|
|
52
|
+
puts " -f, [--force] # Overwrite files that already exist"
|
|
53
|
+
puts " -s, [--skip] # Skip files that already exist"
|
|
54
|
+
puts " -q, [--quiet] # Suppress status output"
|
|
55
|
+
puts
|
|
56
|
+
puts "Please choose a generator below."
|
|
57
|
+
puts
|
|
58
|
+
|
|
59
|
+
print_generators
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Receives a namespace, arguments and the behavior to invoke the generator.
|
|
63
|
+
# It's used as the default entry point for generate, destroy and update
|
|
64
|
+
# commands.
|
|
65
|
+
def invoke(namespace, args = ARGV, config = {})
|
|
66
|
+
names = namespace.to_s.split(":")
|
|
67
|
+
if klass = find_by_namespace(names.pop, names.any? && names.join(":"))
|
|
68
|
+
args << "--help" if args.empty? && klass.arguments.any?(&:required?)
|
|
69
|
+
klass.start(args, config)
|
|
70
|
+
else
|
|
71
|
+
options = sorted_groups.flat_map(&:last)
|
|
72
|
+
suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3)
|
|
73
|
+
suggestions.map! { |s| "'#{s}'" }
|
|
74
|
+
msg = "Could not find generator '#{namespace}'. ".dup
|
|
75
|
+
|
|
76
|
+
if suggestions.any?
|
|
77
|
+
msg << "Maybe you meant #{ suggestions[0...-1].join(', ')} or #{suggestions[-1]}\n"
|
|
78
|
+
msg << "Run `charyf generate --help` for more options."
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
puts msg
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def configure!(config) #:nodoc:
|
|
86
|
+
options.deep_merge! config.options, union_arrays: true
|
|
87
|
+
hide_namespaces(*config.hidden_namespaces)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def print_generators
|
|
91
|
+
sorted_groups.each { |b, n| print_list(b, n) }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def sorted_groups
|
|
95
|
+
namespaces = public_namespaces
|
|
96
|
+
namespaces.sort!
|
|
97
|
+
|
|
98
|
+
groups = Hash.new { |h, k| h[k] = [] }
|
|
99
|
+
namespaces.each do |namespace|
|
|
100
|
+
base = namespace.split(":").first
|
|
101
|
+
groups[base] << namespace
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
charyf = groups.delete("charyf") || []
|
|
105
|
+
charyf.map! { |n| n.sub(/^charyf:/, "") }
|
|
106
|
+
REMOVED_GENERATORS.map { |name| charyf.delete(name) }
|
|
107
|
+
|
|
108
|
+
hidden_namespaces.each { |n| groups.delete(n.to_s) }
|
|
109
|
+
|
|
110
|
+
[[ "charyf", charyf ]] + groups.sort.to_a
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def public_namespaces
|
|
114
|
+
subclasses.map(&:namespace)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Charyf finds namespaces similar to Thor, it only adds one rule:
|
|
118
|
+
#
|
|
119
|
+
# find_by_namespace :foo, :charyf, :bar
|
|
120
|
+
#
|
|
121
|
+
# Will search for the following generators:
|
|
122
|
+
#
|
|
123
|
+
# "charyf:foo", "foo:bar", "foo"
|
|
124
|
+
#
|
|
125
|
+
# Notice that "charyf:generators:bar" could be loaded as well, what
|
|
126
|
+
# Charyf looks for is the first and last parts of the namespace.
|
|
127
|
+
def find_by_namespace(name, base = nil, context = nil) #:nodoc:
|
|
128
|
+
lookups = []
|
|
129
|
+
lookups << "#{base}:#{name}" if base
|
|
130
|
+
lookups << "#{name}:#{context}" if context
|
|
131
|
+
|
|
132
|
+
unless base || context
|
|
133
|
+
unless name.to_s.include?(?:)
|
|
134
|
+
lookups << "#{name}:#{name}"
|
|
135
|
+
lookups << "charyf:#{name}"
|
|
136
|
+
end
|
|
137
|
+
lookups << "#{name}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }]
|
|
141
|
+
lookups.each do |namespace|
|
|
142
|
+
|
|
143
|
+
klass = namespaces[namespace]
|
|
144
|
+
return klass if klass
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Hold configured generators fallbacks. If a plugin developer wants a
|
|
151
|
+
# generator group to fallback to another group in case of missing generators,
|
|
152
|
+
# they can add a fallback.
|
|
153
|
+
#
|
|
154
|
+
# For example, shoulda is considered a test_framework and is an extension
|
|
155
|
+
# of test_unit. However, most part of shoulda generators are similar to
|
|
156
|
+
# test_unit ones.
|
|
157
|
+
#
|
|
158
|
+
# Shoulda then can tell generators to search for test_unit generators when
|
|
159
|
+
# some of them are not available by adding a fallback:
|
|
160
|
+
#
|
|
161
|
+
# Charyf::Generators.fallbacks[:shoulda] = :test_unit
|
|
162
|
+
def fallbacks
|
|
163
|
+
@fallbacks ||= {}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
# Try fallbacks for the given base.
|
|
169
|
+
def invoke_fallbacks_for(name, base)
|
|
170
|
+
return nil unless base && fallbacks[base.to_sym]
|
|
171
|
+
invoked_fallbacks = []
|
|
172
|
+
|
|
173
|
+
Array(fallbacks[base.to_sym]).each do |fallback|
|
|
174
|
+
next if invoked_fallbacks.include?(fallback)
|
|
175
|
+
invoked_fallbacks << fallback
|
|
176
|
+
|
|
177
|
+
klass = find_by_namespace(name, fallback)
|
|
178
|
+
return klass if klass
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
nil
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end # End of self
|
|
185
|
+
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tsort'
|
|
4
|
+
|
|
5
|
+
module Charyf
|
|
6
|
+
module Initializable
|
|
7
|
+
def self.included(base) #:nodoc:
|
|
8
|
+
base.extend ClassMethods
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Initializer
|
|
12
|
+
attr_reader :name, :block
|
|
13
|
+
|
|
14
|
+
def initialize(name, context, options, &block)
|
|
15
|
+
options[:group] ||= :default
|
|
16
|
+
@name, @context, @options, @block = name, context, options, block
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def before
|
|
20
|
+
@options[:before]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def after
|
|
24
|
+
@options[:after]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def belongs_to?(group)
|
|
28
|
+
@options[:group] == group || @options[:group] == :all
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run(*args)
|
|
32
|
+
@context.instance_exec(*args, &block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def bind(context)
|
|
36
|
+
return self if @context
|
|
37
|
+
Initializer.new(@name, context, @options, &block)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def context_class
|
|
41
|
+
@context.class
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Collection < Array
|
|
46
|
+
include TSort
|
|
47
|
+
|
|
48
|
+
alias :tsort_each_node :each
|
|
49
|
+
def tsort_each_child(initializer, &block)
|
|
50
|
+
select { |i| i.before == initializer.name || i.name == initializer.after }.each(&block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def +(other)
|
|
54
|
+
Collection.new(to_a + other.to_a)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def run_initializers(group = :default, *args)
|
|
59
|
+
return if instance_variable_defined?(:@ran)
|
|
60
|
+
initializers.tsort_each do |initializer|
|
|
61
|
+
initializer.run(*args) if initializer.belongs_to?(group)
|
|
62
|
+
end
|
|
63
|
+
@ran = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def initializers
|
|
67
|
+
@initializers ||= self.class.initializers_for(self)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module ClassMethods
|
|
71
|
+
def initializers
|
|
72
|
+
@initializers ||= Collection.new
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def initializers_chain
|
|
76
|
+
initializers = Collection.new
|
|
77
|
+
ancestors.reverse_each do |klass|
|
|
78
|
+
next unless klass.respond_to?(:initializers)
|
|
79
|
+
initializers = initializers + klass.initializers
|
|
80
|
+
end
|
|
81
|
+
initializers
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initializers_for(binding)
|
|
85
|
+
Collection.new(initializers_chain.map { |i| i.bind(binding) })
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def initializer(name, opts = {}, &blk)
|
|
89
|
+
raise ArgumentError, 'A block must be passed when defining an initializer' unless blk
|
|
90
|
+
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
|
|
91
|
+
initializers << Initializer.new(name, nil, opts, &blk)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'colorize'
|
|
3
|
+
|
|
4
|
+
module Charyf
|
|
5
|
+
class Logger < ::Logger
|
|
6
|
+
|
|
7
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576)
|
|
8
|
+
super
|
|
9
|
+
|
|
10
|
+
self.datetime_format = '%Y-%m-%d %H:%M:%S'
|
|
11
|
+
|
|
12
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
|
13
|
+
"#{datetime} [#{severity}]: #{msg}\n"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def flow_request(msg)
|
|
18
|
+
info(msg.green)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def flow_response(msg)
|
|
22
|
+
info(msg.blue)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module Charyf
|
|
2
|
+
module Utils
|
|
3
|
+
class Machine
|
|
4
|
+
|
|
5
|
+
DefaultExists = Class.new(ArgumentError)
|
|
6
|
+
NotInState = Class.new(ArgumentError)
|
|
7
|
+
InvalidDefinition = Class.new(LoadError)
|
|
8
|
+
InvalidEvent = Class.new(ArgumentError)
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
|
|
12
|
+
# Sig does not handle blocks
|
|
13
|
+
def state(name, default: false, final: false, action: nil, &block)
|
|
14
|
+
if default
|
|
15
|
+
raise DefaultExists.new if @_default_state
|
|
16
|
+
@_default_state = name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_states[name] = {
|
|
21
|
+
action: action || name,
|
|
22
|
+
final: final
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if block
|
|
26
|
+
@_state = name
|
|
27
|
+
block.call
|
|
28
|
+
@_state = nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def on(event, go: nil, &block)
|
|
33
|
+
raise NotInState.new unless @_state
|
|
34
|
+
|
|
35
|
+
_events(@_state)[event] =
|
|
36
|
+
{
|
|
37
|
+
go: go,
|
|
38
|
+
callback: block
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def _default_state
|
|
43
|
+
@_default_state
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# def _final_states
|
|
47
|
+
# @_final_states ||= [:_terminated]
|
|
48
|
+
# end
|
|
49
|
+
|
|
50
|
+
def _states
|
|
51
|
+
@_states ||= {
|
|
52
|
+
_terminated: {
|
|
53
|
+
action: :_terminated,
|
|
54
|
+
final: true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def _events(state)
|
|
60
|
+
@_events ||= Hash.new
|
|
61
|
+
@_events[state] ||= Hash.new
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def build
|
|
65
|
+
_states.each do |state_name, state|
|
|
66
|
+
events = _events(state_name)
|
|
67
|
+
raise InvalidDefinition.new("No transitions from state #{state_name}") if events.empty? && !state[:final]
|
|
68
|
+
|
|
69
|
+
_events(state_name).each do |event, details|
|
|
70
|
+
raise InvalidDefinition.new("Transition '#{event}' to undefined state '#{details[:go]}'") unless _states.include?(details[:go])
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
raise InvalidDefinition.new('No final states defined.') unless _states.values.any? { |state| state[:final] }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end # End of class
|
|
78
|
+
|
|
79
|
+
attr_reader :state
|
|
80
|
+
|
|
81
|
+
def initialize(state = nil)
|
|
82
|
+
@state ||= self.class._default_state
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def trigger!(event, payload = nil)
|
|
86
|
+
raise InvalidEvent.new("No transition defined for event '#{event}' from state '#{@state}'") unless trigger?(event)
|
|
87
|
+
change(event, payload)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def trigger(event, payload = nil)
|
|
91
|
+
trigger?(event) && change(event, payload)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def trigger?(event)
|
|
95
|
+
self.class._events(@state).include?(event)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def terminate
|
|
99
|
+
@state = :_terminated
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def final?
|
|
103
|
+
self.class._states[@state][:final]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def state?(state)
|
|
107
|
+
@state == state
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def events
|
|
111
|
+
self.class._events(@state).keys
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def change(event, payload)
|
|
117
|
+
transition = self.class._events(@state)[event]
|
|
118
|
+
|
|
119
|
+
@state = transition[:go]
|
|
120
|
+
#TODO machine
|
|
121
|
+
callback = transition[:callback]
|
|
122
|
+
callback.call(payload) if callback
|
|
123
|
+
|
|
124
|
+
@state
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require_relative 'parser'
|
|
2
|
+
|
|
3
|
+
module Charyf
|
|
4
|
+
module Utils
|
|
5
|
+
module Parser
|
|
6
|
+
# noinspection RubyLiteralArrayInspection,RubyQuotedStringsInspection
|
|
7
|
+
# English string normalization
|
|
8
|
+
class English < Base
|
|
9
|
+
|
|
10
|
+
strategy_name :en
|
|
11
|
+
|
|
12
|
+
CONTRACTION = ["ain't", "aren't", "can't", "could've", "couldn't",
|
|
13
|
+
"didn't", "doesn't", "don't", "gonna", "gotta",
|
|
14
|
+
"hadn't", "hasn't", "haven't", "he'd", "he'll", "he's",
|
|
15
|
+
"how'd", "how'll", "how's", "I'd", "I'll", "I'm",
|
|
16
|
+
"I've", "isn't", "it'd", "it'll", "it's", "mightn't",
|
|
17
|
+
"might've", "mustn't", "must've", "needn't", "oughtn't",
|
|
18
|
+
"shan't", "she'd", "she'll", "she's", "shouldn't",
|
|
19
|
+
"should've", "somebody's", "someone'd", "someone'll",
|
|
20
|
+
"someone's", "that'll", "that's", "that'd", "there'd",
|
|
21
|
+
"there're", "there's", "they'd", "they'll", "they're",
|
|
22
|
+
"they've", "wasn't", "we'd", "we'll", "we're", "we've",
|
|
23
|
+
"weren't", "what'd", "what'll", "what're", "what's",
|
|
24
|
+
"whats",
|
|
25
|
+
"what've", "when's", "when'd", "where'd", "where's",
|
|
26
|
+
"where've", "who'd", "who'd've", "who'll", "who're",
|
|
27
|
+
"who's", "who've", "why'd", "why're", "why's", "won't",
|
|
28
|
+
"won't've", "would've", "wouldn't", "wouldn't've",
|
|
29
|
+
"y'all", "ya'll", "you'd", "you'd've", "you'll",
|
|
30
|
+
"y'aint", "y'ain't", "you're", "you've"].map(&:downcase).freeze
|
|
31
|
+
|
|
32
|
+
EXPANSION = ["is not", "are not", "can not", "could have",
|
|
33
|
+
"could not", "did not", "does not", "do not",
|
|
34
|
+
"going to", "got to", "had not", "has not",
|
|
35
|
+
"have not", "he would", "he will", "he is", "how did",
|
|
36
|
+
"how will", "how is", "I would", "I will", "I am",
|
|
37
|
+
"I have", "is not", "it would", "it will", "it is",
|
|
38
|
+
"might not", "might have", "must not", "must have",
|
|
39
|
+
"need not", "ought not", "shall not", "she would",
|
|
40
|
+
"she will", "she is", "should not", "should have",
|
|
41
|
+
"somebody is", "someone would", "someone will",
|
|
42
|
+
"someone is", "that will", "that is", "that would",
|
|
43
|
+
"there would", "there are", "there is", "they would",
|
|
44
|
+
"they will", "they are", "they have", "was not",
|
|
45
|
+
"we would", "we will", "we are", "we have",
|
|
46
|
+
"were not", "what did", "what will", "what are",
|
|
47
|
+
"what is",
|
|
48
|
+
"what is", "what have", "when is", "when did",
|
|
49
|
+
"where did", "where is", "where have", "who would",
|
|
50
|
+
"who would have", "who will", "who are", "who is",
|
|
51
|
+
"who have", "why did", "why are", "why is",
|
|
52
|
+
"will not", "will not have", "would have",
|
|
53
|
+
"would not", "would not have", "you all", "you all",
|
|
54
|
+
"you would", "you would have", "you will",
|
|
55
|
+
"you are not", "you are not", "you are", "you have"].map(&:downcase).freeze
|
|
56
|
+
|
|
57
|
+
TEXT_NUMBERS = ["zero", "one", "two", "three", "four", "five", "six",
|
|
58
|
+
"seven", "eight", "nine", "ten", "eleven", "twelve",
|
|
59
|
+
"thirteen", "fourteen", "fifteen", "sixteen",
|
|
60
|
+
"seventeen", "eighteen", "nineteen", "twenty"].map(&:downcase).freeze
|
|
61
|
+
|
|
62
|
+
ARTICLES = ["the", "a", "an"].map(&:downcase).freeze
|
|
63
|
+
|
|
64
|
+
def self.normalize(text, remove_articles: true)
|
|
65
|
+
words = text.split
|
|
66
|
+
|
|
67
|
+
normalized = ''
|
|
68
|
+
|
|
69
|
+
words.each do |word|
|
|
70
|
+
next if word.empty?
|
|
71
|
+
next if remove_articles && ARTICLES.include?(word.downcase)
|
|
72
|
+
|
|
73
|
+
# Expand common contractions, e.g. "isn't" -> "is not"
|
|
74
|
+
if CONTRACTION.include?(word.downcase)
|
|
75
|
+
capitalize = false
|
|
76
|
+
if word[0] == word[0].upcase
|
|
77
|
+
capitalize = true
|
|
78
|
+
end
|
|
79
|
+
word = EXPANSION[CONTRACTION.index(word.downcase)]
|
|
80
|
+
|
|
81
|
+
word.capitalize! if capitalize
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if TEXT_NUMBERS.include?(word.downcase)
|
|
85
|
+
word = TEXT_NUMBERS.index(word.downcase)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
normalized += " " + word
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
normalized.strip
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative '../../support/string'
|
|
2
|
+
require_relative '../strategy'
|
|
3
|
+
|
|
4
|
+
module Charyf
|
|
5
|
+
module Utils
|
|
6
|
+
module Parser
|
|
7
|
+
class Base
|
|
8
|
+
|
|
9
|
+
include Charyf::Strategy
|
|
10
|
+
def self.base
|
|
11
|
+
Base
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# TODO sig
|
|
15
|
+
def self.normalize(text, remove_articles: true)
|
|
16
|
+
raise Charyf::Utils::NotImplemented.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end # End of base
|
|
20
|
+
|
|
21
|
+
def self.known
|
|
22
|
+
Base.known
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.list
|
|
26
|
+
Base.list
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# TODO sig
|
|
30
|
+
def self.get(language)
|
|
31
|
+
# TODO implement
|
|
32
|
+
Charyf::Utils::Parser::English
|
|
33
|
+
list[language]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
if RUBY_VERSION < "2.2.2" && RUBY_ENGINE == "ruby"
|
|
4
|
+
desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
|
|
5
|
+
abort <<-end_message
|
|
6
|
+
|
|
7
|
+
Charyf [Alpha] requires Ruby 2.2.2 or newer.
|
|
8
|
+
|
|
9
|
+
You're running
|
|
10
|
+
#{desc}
|
|
11
|
+
|
|
12
|
+
Please upgrade to Ruby 2.2.2 or newer to continue.
|
|
13
|
+
|
|
14
|
+
end_message
|
|
15
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative '../strategy'
|
|
2
|
+
|
|
3
|
+
module Charyf
|
|
4
|
+
module Utils
|
|
5
|
+
module StorageProvider
|
|
6
|
+
class Base
|
|
7
|
+
|
|
8
|
+
include Charyf::Strategy
|
|
9
|
+
def self.base
|
|
10
|
+
Base
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
sig_self [['Module', 'String']], ['Charyf::Utils::StorageProvider::Base'],
|
|
14
|
+
def self.get_for(klass)
|
|
15
|
+
raise Charyf::Utils::NotImplemented.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
sig [nil], [nil],
|
|
19
|
+
def get(key)
|
|
20
|
+
raise Charyf::Utils::NotImplemented.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
sig [nil, nil], [nil],
|
|
24
|
+
def store(key, value)
|
|
25
|
+
raise Charyf::Utils::NotImplemented.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
sig [nil], [nil],
|
|
29
|
+
def remove(key)
|
|
30
|
+
raise Charyf::Utils::NotImplemented.new
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end # End of Base
|
|
34
|
+
|
|
35
|
+
def self.known
|
|
36
|
+
Base.known
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.list
|
|
40
|
+
Base.list
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Charyf
|
|
2
|
+
module Strategy
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def inherited(subclass)
|
|
10
|
+
base._subclasses << subclass
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def strategy_name(name = nil)
|
|
14
|
+
if name
|
|
15
|
+
@_strategy_name = name
|
|
16
|
+
base._aliases[name] = self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@_strategy_name
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def _subclasses
|
|
23
|
+
@_subclasses ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def _aliases
|
|
27
|
+
@_aliases ||= Hash.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def known
|
|
31
|
+
base._subclasses
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def list
|
|
35
|
+
base._aliases
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def base
|
|
39
|
+
raise Charyf::Utils::NotImplemented.new("No base class found for #{self}")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|