gemmyrb 0.0.5 → 0.0.6
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 +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
|