charyf 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|