gemmyrb 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/gemmy.rb +24 -16
- data/lib/gemmy/coffee.rb +33 -0
- data/lib/gemmy/components/cache.rb +49 -0
- data/lib/gemmy/components/nlp.rb +179 -0
- data/lib/gemmy/components/word_speaker.rb +7 -0
- data/lib/gemmy/constants.rb +14 -0
- data/lib/gemmy/patches/array_patch.rb +53 -0
- data/lib/gemmy/patches/enumerator_patch.rb +39 -0
- data/lib/gemmy/patches/hash_patch.rb +22 -10
- data/lib/gemmy/patches/integer_patch.rb +37 -0
- data/lib/gemmy/patches/object_patch.rb +42 -1
- data/lib/gemmy/patches/string_patch.rb +47 -0
- data/lib/gemmy/tests.rb +1 -0
- data/lib/gemmy/version.rb +1 -1
- metadata +76 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f80e87943a486ead9bdcd3ede570b7cb164a0b46
|
4
|
+
data.tar.gz: b5cb77bda55be569a5769c382abf3eae6ab61b92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53374471f968c7fbcd89050b98775b48bb3d1d0e9beca86920427605b5c826542939d4fecb2ede9f5201fa94ae4660c57fb96a65a38eda096f798a72eb3ad07f
|
7
|
+
data.tar.gz: f1f5c63c5e7169bef3313dd590de806740755e21320a9385dd03b506734a818e1c2dcd8b881b912839a097992176e827a3cc0fa7d30f1f0e1cc4adb701dec395
|
data/README.md
CHANGED
@@ -26,4 +26,4 @@ documents:
|
|
26
26
|
|
27
27
|
Specifically, look at the constants defined on Gemmy::Patches. There is one
|
28
28
|
module for each of the core classes being patched. Each individual method
|
29
|
-
is also contained in its own module (for the sake of, well, modularity)
|
29
|
+
is also contained in its own module (for the sake of, well, modularity).
|
data/lib/gemmy.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'awesome_print'
|
1
2
|
require 'thor'
|
2
3
|
require 'colored'
|
3
4
|
require 'active_support/all'
|
4
5
|
require 'pry'
|
5
6
|
require 'colored'
|
6
7
|
require 'corefines'
|
8
|
+
require 'sentence_interpreter'
|
9
|
+
require 'engtagger'
|
10
|
+
require 'odyssey'
|
7
11
|
|
8
12
|
# Container class for all the functionality.
|
9
13
|
#
|
@@ -28,24 +32,28 @@ class Gemmy
|
|
28
32
|
parts = string.split("/")
|
29
33
|
raise ArgumentError unless parts.length == 3
|
30
34
|
core_class, context, method_name = parts
|
31
|
-
context_classname =
|
32
|
-
"InstanceMethods"
|
33
|
-
elsif context.eql?("c")
|
34
|
-
"ClassMethods"
|
35
|
-
else
|
36
|
-
raise ArgumentError
|
37
|
-
end
|
35
|
+
context_classname = context.eql?("i") ? "InstanceMethods" : "ClassMethods"
|
38
36
|
Gemmy::Patches.const_get("#{core_class.capitalize}Patch")
|
39
37
|
.const_get(context_classname)
|
40
38
|
.const_get method_name.camelcase
|
41
39
|
end
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
#
|
48
|
-
#
|
41
|
+
def self.patches(*args)
|
42
|
+
Gemmy::Patches.class_refinements *args
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get a constant,
|
46
|
+
# lookup on Gemmy::Constants
|
47
|
+
# it gsubs '/' to '::'
|
48
|
+
# and if the given constant names are lowercase,
|
49
|
+
# then it camelcases them.
|
50
|
+
def self.const(const_name_abbrev)
|
51
|
+
const_name = const_name_abbrev.split("/").map do |x|
|
52
|
+
x.chars.all? { |char| char.in? 'a'.upto('z') } ? x.camelcase : x
|
53
|
+
end.join("::")
|
54
|
+
Gemmy::Constants.const_get const_name
|
55
|
+
end
|
56
|
+
|
49
57
|
def self.load_globally
|
50
58
|
core_patches = Patches.core_patches.map do |core_klass_name, patch_klass|
|
51
59
|
core_klass = core_klass_name.to_s.constantize
|
@@ -72,10 +80,10 @@ class Gemmy
|
|
72
80
|
end
|
73
81
|
end
|
74
82
|
|
75
|
-
# Load files in order of their "/" count
|
76
|
-
# to preserve constant hierarchies
|
77
|
-
#
|
78
83
|
Gem.find_files("gemmy/**/*.rb").sort_by do |x|
|
79
84
|
x.split("/").length
|
80
85
|
end.each &method(:require)
|
81
86
|
|
87
|
+
# Alias for less typing
|
88
|
+
class Gmy < Gemmy
|
89
|
+
end
|
data/lib/gemmy/coffee.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
Gemmy::Coffee = <<-COFFEE
|
2
|
+
|
3
|
+
#!/usr/bin/env coffee
|
4
|
+
puts = console.log
|
5
|
+
|
6
|
+
# Gemmy.init reads from argv and starts command
|
7
|
+
Gemmy =
|
8
|
+
validCommands: (key) ->
|
9
|
+
{
|
10
|
+
'pos': this.partOfSpeech
|
11
|
+
}[key]
|
12
|
+
|
13
|
+
init: ->
|
14
|
+
[cmd, args...] = process.argv.slice -2
|
15
|
+
component = this.validCommands(cmd)
|
16
|
+
unless component
|
17
|
+
throw('missing or invalid argv command')
|
18
|
+
component.run(args...).then component.callback
|
19
|
+
|
20
|
+
# Part of speech detector
|
21
|
+
pos = Gemmy.partOfSpeech = {}
|
22
|
+
pos.run = (sentence) ->
|
23
|
+
WordPos = require 'wordpos'
|
24
|
+
wordpos = new WordPos(profile: true)
|
25
|
+
new Promise (resolve, reject) ->
|
26
|
+
wordpos.getPOS sentence, resolve
|
27
|
+
pos.callback = (result) ->
|
28
|
+
puts JSON.stringify result
|
29
|
+
|
30
|
+
Gemmy.init()
|
31
|
+
|
32
|
+
COFFEE
|
33
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Gemmy::Components::Cache < Hash
|
2
|
+
|
3
|
+
using Gemmy.patch("hash/i/persisted")
|
4
|
+
using Gemmy.patch("hash/i/bury")
|
5
|
+
using Gemmy.patch("object/i/home")
|
6
|
+
|
7
|
+
CachePath = ENV["GEMMY_CACHE_PATH"] || "#{home}/gemmy/caches"
|
8
|
+
|
9
|
+
unless Dir.exists?(CachePath)
|
10
|
+
`mkdir -p #{CachePath}`
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(db_name)
|
14
|
+
@db = {}.persisted "#{CachePath}/#{db_name}.yaml"
|
15
|
+
@memory = @db.get(:data)
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_or_set(*keys, &blk)
|
19
|
+
result = get(*keys)
|
20
|
+
if result.blank?
|
21
|
+
result = blk.call
|
22
|
+
set(*keys, result)
|
23
|
+
end
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
def keys
|
28
|
+
@db.data.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(*keys, source: :db)
|
32
|
+
if source == :memory
|
33
|
+
@memory.dig *keys
|
34
|
+
elsif source == :db
|
35
|
+
@db.dig *keys
|
36
|
+
else
|
37
|
+
raise ArgumentError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set(*keys, val)
|
42
|
+
@db.set(*keys, val)
|
43
|
+
end
|
44
|
+
|
45
|
+
def clear
|
46
|
+
# forwards it to PersistedHash
|
47
|
+
@db.clear
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
module Gemmy::Components::Nlp
|
2
|
+
|
3
|
+
Gemmy::Patches.class_refinements.each { |r| using r }
|
4
|
+
|
5
|
+
|
6
|
+
def parse_sentence sentence
|
7
|
+
setup_lexicons
|
8
|
+
log_sentence sentence
|
9
|
+
begin
|
10
|
+
SentenceInterpreter.interpret sentence
|
11
|
+
rescue NounBeforeVerbError
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_lexicons
|
17
|
+
return if @lexicon_set_up
|
18
|
+
Object.send :remove_const, "VerbLexicon"
|
19
|
+
Object.send :remove_const, "NounLexicon"
|
20
|
+
Object.send(:const_set,"VerbLexicon", Gemmy::Components::Cache.new(
|
21
|
+
"verb_lexicon"
|
22
|
+
))
|
23
|
+
Object.send(:const_set,"NounLexicon", Gemmy::Components::Cache.new(
|
24
|
+
"noun_lexicon"
|
25
|
+
))
|
26
|
+
@lexicon_set_up = true
|
27
|
+
end
|
28
|
+
|
29
|
+
# Uses the Ruby EngTagger tool to find parts of speech
|
30
|
+
# of a sentence
|
31
|
+
#
|
32
|
+
# Returns a hash with :verbs and :nouns keys (vals are arrays)
|
33
|
+
#
|
34
|
+
def tag_sentence sentence
|
35
|
+
@tagger ||= EngTagger.new
|
36
|
+
res = @tagger.add_tags(sentence).ergo do |tagged|
|
37
|
+
nouns = @tagger.get_nouns(tagged)&.keys || []
|
38
|
+
verbs = @tagger.get_verbs(tagged)&.keys || []
|
39
|
+
[nouns, verbs]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds words in sentence to application database
|
44
|
+
# The part of speech is identified by the DB Name
|
45
|
+
# Each entry is a word => proc mapping.
|
46
|
+
#
|
47
|
+
# Noun procs are passed all vn_phrases for the sentence
|
48
|
+
# (these are constructed by parse_sentence)
|
49
|
+
#
|
50
|
+
# The Verb procs are passed the evaluated results of the Noun procs
|
51
|
+
# in its Verb-Noun phrase (as sequential arguments)
|
52
|
+
#
|
53
|
+
# For example, if the phrase is "live well and flourish"
|
54
|
+
# Then (assuming the
|
55
|
+
#
|
56
|
+
# Although EngTagger extracts POS for the words in a sentence,
|
57
|
+
# these classifications are context-dependent.
|
58
|
+
#
|
59
|
+
# For this reason, words are also looked up using WordPos.
|
60
|
+
# Only umambiguous words are added to the grammar.
|
61
|
+
#
|
62
|
+
def log_sentence sentence
|
63
|
+
sentence_cache.get_or_set(sentence) do
|
64
|
+
engtagger_lookup(sentence).map do |word, pos|
|
65
|
+
finalize_pos(word, pos)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Compare WordPos and Engtagger results and save to proc if found
|
71
|
+
# only prioritize Engtagger if WordPos is missing
|
72
|
+
def finalize_pos word, pos
|
73
|
+
final_pos = word_pos_cache.get_or_set(word) do
|
74
|
+
doublecheck = wordpos_lookup(word)
|
75
|
+
if ['noun', 'verb'].none? &doublecheck.m(:include?)
|
76
|
+
finalize_engtagger_pos(pos)
|
77
|
+
else
|
78
|
+
finalize_wordpos_pos(pos)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
save_proc(final_pos, word)
|
82
|
+
{ word: word, pos: [final_pos] }
|
83
|
+
end
|
84
|
+
|
85
|
+
def finalize_engtagger_pos(pos)
|
86
|
+
# If the WordPos definition isn't found, then there's no ambiguity
|
87
|
+
if pos.include?("noun")
|
88
|
+
"noun"
|
89
|
+
elsif pos.include?("verb")
|
90
|
+
"verb"
|
91
|
+
else
|
92
|
+
"unknown"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def finalize_wordpos_pos(pos)
|
97
|
+
# WordPos returns ambiguous results.
|
98
|
+
# Only unambiguous words are selected.
|
99
|
+
# I.e. a noun|verb isn't saved.
|
100
|
+
# It must be solely noun or verb.
|
101
|
+
if pos.include?("noun") && !pos.include?("verb")
|
102
|
+
"noun"
|
103
|
+
elsif pos.include?("verb") && !pos.include?("noun")
|
104
|
+
"verb"
|
105
|
+
else
|
106
|
+
"unknown"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def save_proc(final_pos, word)
|
111
|
+
if final_pos.include?("noun")
|
112
|
+
save_noun_proc(word)
|
113
|
+
elsif final_pos.include?("verb")
|
114
|
+
save_verb_proc word
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def save_noun_proc word
|
119
|
+
NounLexicon.set word.to_sym, default_noun_proc_string(word)
|
120
|
+
end
|
121
|
+
|
122
|
+
def save_verb_proc word
|
123
|
+
VerbLexicon.set word.to_sym, default_verb_proc_string(word)
|
124
|
+
end
|
125
|
+
|
126
|
+
def default_noun_proc_string(word)
|
127
|
+
<<-Ruby.strip_heredoc
|
128
|
+
->(vn_phrases){ "#{word}" }
|
129
|
+
Ruby
|
130
|
+
end
|
131
|
+
|
132
|
+
def default_verb_proc_string(word)
|
133
|
+
<<-Ruby.strip_heredoc
|
134
|
+
->(*nouns){ "#{word} \#{nouns.join " "}" }
|
135
|
+
Ruby
|
136
|
+
end
|
137
|
+
|
138
|
+
# This uses EngTagger to analyze a sentence
|
139
|
+
# The results will not be ambiguous; in this method's results,
|
140
|
+
# a given word with either be 'verb', 'noun', or 'unknown'.
|
141
|
+
def engtagger_lookup sentence
|
142
|
+
nouns, verbs = tag_sentence(sentence)
|
143
|
+
sentence.words.graph do |word|
|
144
|
+
pos = case word
|
145
|
+
when ->(w){ verbs.include? w }
|
146
|
+
"verb"
|
147
|
+
when ->(w){ nouns.include? w }
|
148
|
+
"noun"
|
149
|
+
else
|
150
|
+
"unknown"
|
151
|
+
end
|
152
|
+
[word, [pos]]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Engtagger evaluates POS in the context of a sentence
|
157
|
+
# So from that perspective, only entire sentences can be cached
|
158
|
+
def sentence_cache
|
159
|
+
@sentence_cache ||= Gemmy::Components::Cache.new "sentence_pos"
|
160
|
+
end
|
161
|
+
|
162
|
+
# This cache reduces the call rate of the WordPos shell util
|
163
|
+
# by caching the POS for individual words.
|
164
|
+
def word_pos_cache
|
165
|
+
@pos_cache ||= Gemmy::Components::Cache.new("word_pos")
|
166
|
+
end
|
167
|
+
|
168
|
+
def wordpos_lookup(word)
|
169
|
+
default_result = ['unknown']
|
170
|
+
result = []
|
171
|
+
word = word.strip.gsub(/[^a-zA-z]/, '')
|
172
|
+
return default_result if word.empty?
|
173
|
+
pos_response = JSON.parse `coffee -e "#{Gemmy::Coffee}" pos #{word}`
|
174
|
+
result << "verb" unless pos_response["verbs"].empty?
|
175
|
+
result << "noun" unless pos_response["nouns"].empty?
|
176
|
+
result.empty? ? default_result : result
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -28,6 +28,57 @@ module Gemmy::Patches::ArrayPatch
|
|
28
28
|
|
29
29
|
module InstanceMethods
|
30
30
|
|
31
|
+
module Reject
|
32
|
+
# make it an alias for reject(&:blank?) if no block given
|
33
|
+
def reject(&blk)
|
34
|
+
blk ? super : reject(&:blank?)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Cut
|
39
|
+
# another alias for compact
|
40
|
+
def cut
|
41
|
+
compact
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
module MethodMissing
|
47
|
+
# Tries to forward methods to enumerator
|
48
|
+
def method_missing(fn, &blk)
|
49
|
+
enum = to_enum
|
50
|
+
if enum.respond_to?(fn)
|
51
|
+
blk ? enum.send(fn, &blk) : enum.send(fn)
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module RunCommands
|
59
|
+
# Part of the Nlp API
|
60
|
+
# Example:
|
61
|
+
# include Gemmy::Components::Nlp
|
62
|
+
# parse_sentence("A sentence").run_commands
|
63
|
+
#
|
64
|
+
# Under the hood, parse_sentence is creating procs in the db
|
65
|
+
# These are evaluated here
|
66
|
+
#
|
67
|
+
def run_commands
|
68
|
+
_eval_noun = Gemmy.patch("string/i/eval_noun")
|
69
|
+
.method(:_eval_noun)
|
70
|
+
return self.flat_map do |cmds|
|
71
|
+
cmds&.map do |cmd|
|
72
|
+
eval(VerbLexicon.get cmd[:verb].to_sym).call(*(
|
73
|
+
cmd[:nouns]&.map do |noun|
|
74
|
+
_eval_noun.call(noun, self)
|
75
|
+
end
|
76
|
+
).to_a.compact)
|
77
|
+
end
|
78
|
+
end.compact
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
31
82
|
module Exclude
|
32
83
|
# facets
|
33
84
|
# the opposite of include
|
@@ -197,6 +248,8 @@ module Gemmy::Patches::ArrayPatch
|
|
197
248
|
alias rangify arrange
|
198
249
|
end
|
199
250
|
|
251
|
+
|
252
|
+
|
200
253
|
module AnyNot
|
201
254
|
# checks if any of the results of an array do not respond truthily
|
202
255
|
# to a block
|
@@ -2,6 +2,34 @@ module Gemmy::Patches::EnumeratorPatch
|
|
2
2
|
module ClassMethods
|
3
3
|
end
|
4
4
|
module InstanceMethods
|
5
|
+
|
6
|
+
# Facets
|
7
|
+
# Similar to map by (array => hash)
|
8
|
+
# but values are not wrapped in arrays
|
9
|
+
# iteration return val is [key, val]
|
10
|
+
module Graph
|
11
|
+
def graph(&yld)
|
12
|
+
if yld
|
13
|
+
h = {}
|
14
|
+
each do |*kv|
|
15
|
+
r = yld[*kv]
|
16
|
+
case r
|
17
|
+
when Hash
|
18
|
+
nk, nv = *r.to_a[0]
|
19
|
+
when Range
|
20
|
+
nk, nv = r.first, r.last
|
21
|
+
else
|
22
|
+
nk, nv = *r
|
23
|
+
end
|
24
|
+
h[nk] = nv
|
25
|
+
end
|
26
|
+
h
|
27
|
+
else
|
28
|
+
Enumerator.new(self,:graph)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
5
33
|
module MapBy
|
6
34
|
using CF::Enumerable::MapBy
|
7
35
|
# maps to hash
|
@@ -19,5 +47,16 @@ module Gemmy::Patches::EnumeratorPatch
|
|
19
47
|
clone.map_to klass
|
20
48
|
end
|
21
49
|
end
|
50
|
+
|
51
|
+
module Frequencies
|
52
|
+
# taken from powerpack
|
53
|
+
# maps each element in the enum to it's num occurrances
|
54
|
+
def frequencies
|
55
|
+
each_with_object(Hash.new(0)) { |e, a| a[e] += 1 }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
22
61
|
end
|
23
62
|
end
|
@@ -205,10 +205,9 @@ module Gemmy::Patches::HashPatch
|
|
205
205
|
#
|
206
206
|
module Bury
|
207
207
|
def bury *args
|
208
|
-
Gemmy
|
208
|
+
Gemmy.patch("hash/i/bury")._bury self, *args
|
209
209
|
end
|
210
210
|
# The bury method, taking the input hash as a parameter
|
211
|
-
# Used by the Hash#bury instance method
|
212
211
|
def self._bury(caller_hash, *args)
|
213
212
|
if args.count < 2
|
214
213
|
raise ArgumentError.new("2 or more arguments required")
|
@@ -266,17 +265,22 @@ module Gemmy::Patches::HashPatch
|
|
266
265
|
module Persisted
|
267
266
|
def persisted(path)
|
268
267
|
require 'yaml/store'
|
269
|
-
autovivified = Gemmy
|
268
|
+
autovivified = Gemmy.patch("hash/i/autovivified")\
|
269
|
+
.method(:_autovivified)
|
270
270
|
autovivified.call(self).tap do |hash|
|
271
271
|
hash.instance_exec do
|
272
|
-
@
|
273
|
-
@
|
274
|
-
@
|
272
|
+
@store = YAML::Store.new path
|
273
|
+
@store.transaction do
|
274
|
+
@store[:data] ||= autovivified.call({})
|
275
|
+
@store[:data].each { |k,v| self[k] = v.deep_dup }
|
275
276
|
end
|
276
277
|
end
|
277
278
|
hash.extend Gemmy::Patches::HashPatch::PersistedHash
|
278
279
|
end
|
279
280
|
end
|
281
|
+
def db
|
282
|
+
@store
|
283
|
+
end
|
280
284
|
end
|
281
285
|
|
282
286
|
end # end instance methods
|
@@ -284,17 +288,25 @@ module Gemmy::Patches::HashPatch
|
|
284
288
|
# Helper methods for the persistence patch
|
285
289
|
#
|
286
290
|
module PersistedHash
|
287
|
-
def get(*keys, disk:
|
288
|
-
disk ? @
|
291
|
+
def get(*keys, disk: true)
|
292
|
+
disk ? @store.transaction { @store[:data].dig(*keys) } : dig(*keys)
|
289
293
|
end
|
290
294
|
def set(*keys, val)
|
291
295
|
bury = Gemmy::Patches::HashPatch::InstanceMethods::Bury.method(:_bury)
|
292
296
|
bury.call(self, *keys, val)
|
293
|
-
@
|
294
|
-
bury.call(@
|
297
|
+
@store.transaction do
|
298
|
+
bury.call(@store[:data], *(keys + [val]))
|
295
299
|
end
|
296
300
|
val
|
297
301
|
end
|
302
|
+
def data
|
303
|
+
@store.transaction { @store[:data] }
|
304
|
+
end
|
305
|
+
def clear
|
306
|
+
autovivified = Gemmy.patch("hash/i/autovivified")\
|
307
|
+
.method(:_autovivified)
|
308
|
+
@store.transaction { @store[:data] = autovivified.call({}) }
|
309
|
+
end
|
298
310
|
end
|
299
311
|
|
300
312
|
end
|
@@ -27,6 +27,43 @@ module Gemmy::Patches::IntegerPatch
|
|
27
27
|
|
28
28
|
module InstanceMethods
|
29
29
|
|
30
|
+
module Hundred
|
31
|
+
# from powerpack
|
32
|
+
def hundred
|
33
|
+
self * Gemmy.const("HUNDRED")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
module Thousand
|
37
|
+
# from powerpack
|
38
|
+
def thousand
|
39
|
+
self * Gemmy.const("THOUSAND")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
module Million
|
43
|
+
# from powerpack
|
44
|
+
def million
|
45
|
+
self * Gemmy.const("MILLION")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
module Billion
|
49
|
+
# from powerpack
|
50
|
+
def billion
|
51
|
+
self * Gemmy.const("BILLION")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
module Trillion
|
55
|
+
# from powerpack
|
56
|
+
def trillion
|
57
|
+
self * Gemmy.const("TRILLION")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
module Quadrillion
|
61
|
+
# from powerpack
|
62
|
+
def quadrillion
|
63
|
+
self * Gemmy.const("QUADRILLION")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
30
67
|
module Factorial
|
31
68
|
# facets
|
32
69
|
def factorial
|
@@ -14,7 +14,48 @@ module Gemmy::Patches::ObjectPatch
|
|
14
14
|
|
15
15
|
module InstanceMethods
|
16
16
|
|
17
|
-
module
|
17
|
+
module Home
|
18
|
+
# the $HOME dir, aka ~
|
19
|
+
def home
|
20
|
+
`echo $HOME`.chomp
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ObjectState
|
25
|
+
# class StateExample
|
26
|
+
# attr_reader :a, :b
|
27
|
+
# def initialize(a,b)
|
28
|
+
# @a, @b = a, b
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
|
32
|
+
# obj = StateExample.new(1,2)
|
33
|
+
# obj.a #=> 1
|
34
|
+
# obj.b #=> 2
|
35
|
+
|
36
|
+
# obj.object_state #=> {:a=>1, :b=>2}
|
37
|
+
|
38
|
+
# obj.object_state(:a=>3, :b=>4)
|
39
|
+
# obj.a #=> 3
|
40
|
+
# obj.b #=> 4
|
41
|
+
def object_state(data=nil)
|
42
|
+
if data
|
43
|
+
instance_variables.each do |iv|
|
44
|
+
name = iv.to_s.sub(/^[@]/, '').to_sym
|
45
|
+
instance_variable_set(iv, data[name])
|
46
|
+
end
|
47
|
+
else
|
48
|
+
data = {}
|
49
|
+
instance_variables.each do |iv|
|
50
|
+
name = iv.to_s.sub(/^[@]/, '').to_sym
|
51
|
+
data[name] = instance_variable_get(iv)
|
52
|
+
end
|
53
|
+
data
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Itself
|
18
59
|
# facets
|
19
60
|
def itself
|
20
61
|
def itself
|
@@ -7,6 +7,53 @@ module Gemmy::Patches::StringPatch
|
|
7
7
|
|
8
8
|
module InstanceMethods
|
9
9
|
|
10
|
+
module NlpSanitize
|
11
|
+
def nlp_sanitize
|
12
|
+
Gemmy.patch("string/i/alpha")
|
13
|
+
._alpha(self)
|
14
|
+
.downcase
|
15
|
+
.strip
|
16
|
+
.chomp
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Alpha
|
21
|
+
def self._alpha(string, bang: false, strip_whitespace: false)
|
22
|
+
fn = bang ? :gsub! : :gsub
|
23
|
+
regex = /[^a-zA-Z#{'\s' unless strip_whitespace}]/
|
24
|
+
string.send fn, regex, ''
|
25
|
+
end
|
26
|
+
def alpha!(opts={})
|
27
|
+
Gemmy.patch("string/i/alpha")._alpha(
|
28
|
+
self,
|
29
|
+
opts.merge(bang: true)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
# Gsub non-alphabetical characters
|
33
|
+
def alpha(opts={})
|
34
|
+
Gemmy.patch("string/i/alpha")._alpha(
|
35
|
+
self,
|
36
|
+
opts
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module TempfilePath
|
42
|
+
# Creates a tempfile containing a string and returns its path
|
43
|
+
def tempfile_path
|
44
|
+
Tempfile.new.tap { |t| t.write(self); t.close }.path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module EvalNoun
|
49
|
+
def eval_noun(commands=[])
|
50
|
+
Gemmy.patches("string/i/eval_noun")._eval_noun self, commands
|
51
|
+
end
|
52
|
+
def self._eval_noun(noun, commands=[])
|
53
|
+
eval(NounLexicon.get(noun.to_sym)).call(commands)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
10
57
|
module Words
|
11
58
|
# facets
|
12
59
|
def words
|
data/lib/gemmy/tests.rb
CHANGED
data/lib/gemmy/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gemmyrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- max pleaner
|
@@ -100,6 +100,76 @@ dependencies:
|
|
100
100
|
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: 1.9.0
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: sentence_interpreter
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.0.7
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.0.7
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: awesome_print
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.7.0
|
124
|
+
type: :runtime
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 1.7.0
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: engtagger
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 0.2.1
|
138
|
+
type: :runtime
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 0.2.1
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: minitest
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 5.10.1
|
152
|
+
type: :runtime
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 5.10.1
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: odyssey
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.2.0
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 0.2.0
|
103
173
|
description: ''
|
104
174
|
email: maxpleaner@gmail.com
|
105
175
|
executables:
|
@@ -111,8 +181,13 @@ files:
|
|
111
181
|
- bin/gemmy
|
112
182
|
- lib/gemmy.rb
|
113
183
|
- lib/gemmy/cli.rb
|
184
|
+
- lib/gemmy/coffee.rb
|
114
185
|
- lib/gemmy/components.rb
|
186
|
+
- lib/gemmy/components/cache.rb
|
115
187
|
- lib/gemmy/components/dynamic_steps.rb
|
188
|
+
- lib/gemmy/components/nlp.rb
|
189
|
+
- lib/gemmy/components/word_speaker.rb
|
190
|
+
- lib/gemmy/constants.rb
|
116
191
|
- lib/gemmy/patches.rb
|
117
192
|
- lib/gemmy/patches/array_patch.rb
|
118
193
|
- lib/gemmy/patches/class_patch.rb
|