lingo 1.8.2 → 1.8.3
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.
- data/ChangeLog +33 -0
- data/README +6 -5
- data/Rakefile +6 -4
- data/{lib/lingo/cachable.rb → bin/lingosrv} +30 -58
- data/bin/lingoweb +30 -0
- data/de.lang +2 -13
- data/en/lingo-irr.txt +266 -0
- data/en/lingo-wdn.txt +37319 -0
- data/en.lang +2 -15
- data/lib/lingo/app.rb +82 -0
- data/lib/lingo/attendee/abbreviator.rb +22 -26
- data/lib/lingo/attendee/debugger.rb +8 -4
- data/lib/lingo/attendee/decomposer.rb +0 -1
- data/lib/lingo/attendee/dehyphenizer.rb +2 -2
- data/lib/lingo/attendee/multi_worder.rb +20 -13
- data/lib/lingo/attendee/noneword_filter.rb +2 -7
- data/lib/lingo/attendee/sequencer.rb +43 -19
- data/lib/lingo/attendee/stemmer/porter.rb +2 -2
- data/lib/lingo/attendee/stemmer.rb +1 -1
- data/lib/lingo/attendee/synonymer.rb +1 -9
- data/lib/lingo/attendee/text_reader.rb +42 -29
- data/lib/lingo/attendee/text_writer.rb +3 -6
- data/lib/lingo/attendee/tokenizer.rb +87 -69
- data/lib/lingo/attendee/variator.rb +7 -5
- data/lib/lingo/attendee/vector_filter.rb +11 -11
- data/lib/lingo/attendee/word_searcher.rb +1 -9
- data/lib/lingo/attendee.rb +24 -105
- data/lib/lingo/buffered_attendee.rb +2 -9
- data/lib/lingo/call.rb +18 -13
- data/lib/lingo/cli.rb +5 -10
- data/lib/lingo/config.rb +40 -7
- data/lib/lingo/ctl.rb +69 -57
- data/lib/lingo/database/hash_store.rb +9 -4
- data/lib/lingo/database/sdbm_store.rb +4 -7
- data/lib/lingo/database/source/multi_key.rb +1 -1
- data/lib/lingo/database/source/multi_value.rb +1 -1
- data/lib/lingo/database/source.rb +2 -20
- data/lib/lingo/database.rb +30 -19
- data/lib/lingo/debug.rb +79 -0
- data/lib/lingo/{core_ext.rb → language/char.rb} +43 -42
- data/lib/lingo/language/dictionary.rb +38 -46
- data/lib/lingo/language/grammar.rb +40 -57
- data/lib/lingo/language/lexical.rb +4 -7
- data/lib/lingo/language/lexical_hash.rb +17 -35
- data/lib/lingo/language/token.rb +4 -0
- data/lib/lingo/language/word.rb +7 -8
- data/lib/lingo/language/word_form.rb +4 -4
- data/lib/lingo/language.rb +2 -1
- data/lib/lingo/srv/config.ru +4 -0
- data/lib/lingo/srv/lingosrv.cfg +14 -0
- data/lib/lingo/{reportable.rb → srv.rb} +59 -61
- data/lib/lingo/version.rb +1 -1
- data/lib/lingo/web/config.ru +4 -0
- data/lib/lingo/web/lingoweb.cfg +14 -0
- data/lib/lingo/web/public/lingo.png +0 -0
- data/lib/lingo/web/public/lingoweb.css +74 -0
- data/lib/lingo/web/views/index.erb +92 -0
- data/lib/lingo/web.rb +94 -0
- data/lib/lingo.rb +27 -29
- data/lingo.cfg +1 -1
- data/lir.cfg +24 -0
- data/ru/lingo-dic.txt +22342 -0
- data/ru/lingo-mul.txt +5151 -0
- data/ru/lingo-syn.txt +0 -0
- data/ru.lang +99 -0
- data/test/attendee/ts_sequencer.rb +2 -2
- data/test/attendee/ts_text_reader.rb +36 -2
- data/test/attendee/ts_text_writer.rb +6 -6
- data/test/lir.vec +3 -3
- data/test/test_helper.rb +104 -102
- data/test/ts_database.rb +1 -1
- data/test/ts_language.rb +55 -96
- data/txt/artikel-ru.txt +45 -0
- data/txt/lir.txt +1 -3
- metadata +143 -83
- data/TODO +0 -23
@@ -44,28 +44,10 @@ class Lingo
|
|
44
44
|
# === Konfiguration
|
45
45
|
# Der Tokenizer benötigt zur Identifikation einzelner Token Regeln, nach denen er
|
46
46
|
# arbeiten soll. Die benötigten Regeln werden aufgrund des Umfangs nicht als Parameter,
|
47
|
-
# sondern in
|
48
|
-
# <tt>de.lang</tt> befindet (YAML-Format).
|
49
|
-
# language:
|
50
|
-
# attendees:
|
51
|
-
# tokenizer:
|
52
|
-
# regulars:
|
53
|
-
# - _CHR_: '\wÄÖÜÁÂÀÉÊÈÍÎÌÓÔÒÚÛÙÝäöüáâàéêèíîìóôòúûùý'
|
54
|
-
# - NUMS: '[+-]?(\d{4,}|\d{1,3}(\.\d{3,3})*)(\.|(,\d+)?%?)'
|
55
|
-
# - URLS: '((mailto:|(news|http|https|ftp|ftps)://)\S+|^(www(\.\S+)+)|\S+([\._]\S+)+@\S+(\.\S+)+)'
|
56
|
-
# - ABRV: '(([_CHR_]+\.)+)[_CHR_]+'
|
57
|
-
# - ABRS: '(([_CHR_]{1,1}\.)+)(?!\.\.)'
|
58
|
-
# - WORD: '[_CHR_\d]+'
|
59
|
-
# - PUNC: '[!,\.:;?]'
|
60
|
-
# - OTHR: '[!\"#$%&()*\+,\-\./:;<=>?@\[\\\]^_`{|}~´]'
|
61
|
-
# - HELP: '.*'
|
47
|
+
# sondern in einer Programmkonstanten hinterlegt.
|
62
48
|
# Die Regeln werden in der angegebenen Reihenfolge abgearbeitet, solange bis ein Token
|
63
49
|
# erkannt wurde. Sollte keine Regel zutreffen, so greift die letzt Regel +HELP+ in jedem
|
64
50
|
# Fall.
|
65
|
-
# Regeln, deren Name in Unterstriche eingefasst sind, werden als Makro interpretiert.
|
66
|
-
# Makros werden genutzt, um lange oder sich wiederholende Bestandteile von Regeln
|
67
|
-
# einmalig zu definieren und in den Regeln über den Makronamen eine Auflösung zu forcieren.
|
68
|
-
# Makros werden selber nicht für die Erkennung von Token eingesetzt.
|
69
51
|
#
|
70
52
|
# === Generierte Kommandos
|
71
53
|
# Damit der nachfolgende Datenstrom einwandfrei verarbeitet werden kann, generiert der Tokenizer
|
@@ -98,33 +80,79 @@ class Lingo
|
|
98
80
|
|
99
81
|
class Tokenizer < self
|
100
82
|
|
83
|
+
CHAR, DIGIT = Char::CHAR, Char::DIGIT
|
84
|
+
|
85
|
+
RULES = [
|
86
|
+
['WIKI', /^=+.+=+$/],
|
87
|
+
['SPAC', /^\s+/],
|
88
|
+
['HTML', /^<[^>]+>/],
|
89
|
+
['WIKI', /^\[\[.+?\]\]/],
|
90
|
+
['NUMS', /^[+-]?(?:\d{4,}|\d{1,3}(?:\.\d{3,3})*)(?:\.|(?:,\d+)?%?)/],
|
91
|
+
['URLS', /^(?:(?:mailto:|(?:news|https?|ftps?):\/\/)\S+|^(?:www(?:\.\S+)+)|[^\s.]+(?:[\._]\S+)+@\S+(?:\.\S+)+)/],
|
92
|
+
['ABRV', /^(?:(?:(?:#{CHAR})+\.)+)(?:#{CHAR})+/],
|
93
|
+
['WORD', /^(?:#{CHAR}|#{DIGIT}|-)+/],
|
94
|
+
['PUNC', /^[!,.:;?¡¿]/],
|
95
|
+
['OTHR', /^["$#%&'()*+\-\/<=>@\[\\\]^_{|}~¢£¤¥¦§¨©«¬®¯°±²³´¶·¸¹»¼½¾×÷]/],
|
96
|
+
['HELP', /^[^ ]*/]
|
97
|
+
]
|
98
|
+
|
99
|
+
class << self
|
100
|
+
|
101
|
+
def rule(name)
|
102
|
+
RULES.assoc(name)
|
103
|
+
end
|
104
|
+
|
105
|
+
def delete(*names)
|
106
|
+
names.each { |name| RULES.delete(rule(name)) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def replace(name, expr)
|
110
|
+
rule = rule(name) or return
|
111
|
+
rule[1] = block_given? ? yield(rule[1]) : expr
|
112
|
+
end
|
113
|
+
|
114
|
+
def insert(*rules)
|
115
|
+
_insert(0, rules)
|
116
|
+
end
|
117
|
+
|
118
|
+
def append(*rules)
|
119
|
+
_insert(-1, rules)
|
120
|
+
end
|
121
|
+
|
122
|
+
def insert_before(name, *rules)
|
123
|
+
_insert_name(name, rules, 0)
|
124
|
+
end
|
125
|
+
|
126
|
+
def insert_after(name, *rules)
|
127
|
+
_insert_name(name, rules, -1)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def _insert(index, rules)
|
133
|
+
rules.push(*rules.pop) if rules.last.is_a?(Hash)
|
134
|
+
RULES.insert(index, *rules)
|
135
|
+
end
|
136
|
+
|
137
|
+
def _insert_name(name, rules, offset)
|
138
|
+
index = RULES.index(rule(name))
|
139
|
+
_insert(index ? index - offset : offset, rules)
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
101
144
|
protected
|
102
145
|
|
103
146
|
def init
|
104
147
|
@space = get_key('space', false)
|
105
|
-
@tags = get_key('tags',
|
106
|
-
@wiki = get_key('wiki',
|
107
|
-
|
108
|
-
# default rules
|
109
|
-
@rules = [['SPAC', /^\s+/]]
|
110
|
-
@rules << ['HTML', /^<[^>]+>/] unless @tags
|
111
|
-
@rules << ['WIKI', /^\[\[.+?\]\]/] unless @wiki
|
112
|
-
@rules.unshift(['WIKI', /^=+.+=+$/]) unless @wiki
|
113
|
-
|
114
|
-
get_key('regulars', []).each_with_object({}) { |rule, macros|
|
115
|
-
expr = rule.values.first.gsub(/_(\w+?)_/) {
|
116
|
-
macros[$&] || begin
|
117
|
-
Database::Source.const_get("UTF8_#{$1.upcase}")
|
118
|
-
rescue NameError
|
119
|
-
end
|
120
|
-
}
|
148
|
+
@tags = get_key('tags', false)
|
149
|
+
@wiki = get_key('wiki', false)
|
121
150
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
}
|
151
|
+
skip = []
|
152
|
+
skip << 'HTML' unless @tags
|
153
|
+
skip << 'WIKI' unless @wiki
|
154
|
+
|
155
|
+
@rules = RULES.reject { |name, _| skip.include?(name) }
|
128
156
|
|
129
157
|
@filename = @cont = nil
|
130
158
|
end
|
@@ -139,15 +167,7 @@ class Lingo
|
|
139
167
|
|
140
168
|
def process(obj)
|
141
169
|
if obj.is_a?(String)
|
142
|
-
|
143
|
-
|
144
|
-
tokenize(obj) { |form, attr|
|
145
|
-
inc("Anzahl Muster #{attr}")
|
146
|
-
inc('Anzahl Token')
|
147
|
-
|
148
|
-
forward(Token.new(form, attr))
|
149
|
-
}
|
150
|
-
|
170
|
+
tokenize(obj) { |*i| forward(Token.new(*i)) }
|
151
171
|
forward(STR_CMD_EOL, @filename) if @filename
|
152
172
|
else
|
153
173
|
forward(obj)
|
@@ -157,44 +177,42 @@ class Lingo
|
|
157
177
|
private
|
158
178
|
|
159
179
|
# tokenize("Eine Zeile.") -> [:Eine/WORD:, :Zeile/WORD:, :./PUNC:]
|
160
|
-
def tokenize(
|
180
|
+
def tokenize(line)
|
161
181
|
case @cont
|
162
182
|
when 'HTML'
|
163
|
-
if
|
183
|
+
if line =~ /^[^<>]*>/
|
164
184
|
yield $&, @cont
|
165
|
-
|
185
|
+
line, @cont = $', nil
|
166
186
|
else
|
167
|
-
yield
|
187
|
+
yield line, @cont
|
168
188
|
return
|
169
189
|
end
|
170
190
|
when 'WIKI'
|
171
|
-
if
|
191
|
+
if line =~ /^[^\[\]]*\]\]/
|
172
192
|
yield $&, @cont
|
173
|
-
|
193
|
+
line, @cont = $', nil
|
174
194
|
else
|
175
|
-
yield
|
195
|
+
yield line, @cont
|
176
196
|
return
|
177
197
|
end
|
178
198
|
when nil
|
179
|
-
if
|
199
|
+
if @tags && line =~ /<[^<>]*$/
|
180
200
|
yield $&, @cont = 'HTML'
|
181
|
-
|
201
|
+
line = $`
|
182
202
|
end
|
183
203
|
|
184
|
-
if
|
204
|
+
if @wiki && line =~ /\[\[[^\[\]]*$/
|
185
205
|
yield $&, @cont = 'WIKI'
|
186
|
-
|
206
|
+
line = $`
|
187
207
|
end
|
188
208
|
end
|
189
209
|
|
190
|
-
|
191
|
-
|
192
|
-
if
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
end
|
197
|
-
}
|
210
|
+
while (l = line.length) > 0 && @rules.find { |name, expr|
|
211
|
+
if line =~ expr
|
212
|
+
yield $&, name if name != 'SPAC' || @space
|
213
|
+
l == $'.length ? break : line = $'
|
214
|
+
end
|
215
|
+
}
|
198
216
|
end
|
199
217
|
end
|
200
218
|
|
@@ -90,22 +90,24 @@ class Lingo
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def control(cmd, param)
|
93
|
-
report_on(cmd, @dic, @gra)
|
94
93
|
end
|
95
94
|
|
96
95
|
def process(obj)
|
97
96
|
if obj.is_a?(Word) && @check[obj.attr]
|
98
|
-
|
97
|
+
vars, max = [obj.form], @max
|
99
98
|
|
100
|
-
@var.
|
101
|
-
|
99
|
+
@var.each { |args|
|
100
|
+
variate(vars, *args)
|
101
|
+
break unless vars.length < max
|
102
|
+
}
|
103
|
+
|
104
|
+
vars.each { |var|
|
102
105
|
next if (word = find_word(var)).unknown? || (
|
103
106
|
word.attr == WA_COMPOUND && word.lexicals.any? { |lex|
|
104
107
|
lex.attr.start_with?(LA_TAKEITASIS)
|
105
108
|
}
|
106
109
|
)
|
107
110
|
|
108
|
-
inc('Anzahl gefundener Wörter')
|
109
111
|
return forward(word.tap { word.form = @marker + var })
|
110
112
|
}
|
111
113
|
end
|
@@ -79,15 +79,20 @@ class Lingo
|
|
79
79
|
|
80
80
|
class VectorFilter < self
|
81
81
|
|
82
|
+
DEFAULT_SRC_SEP = '|'
|
83
|
+
|
82
84
|
protected
|
83
85
|
|
84
86
|
def init
|
85
87
|
if @debug = get_key('debug', false)
|
86
88
|
@prompt = get_key('prompt', 'lex:) ')
|
87
89
|
else
|
88
|
-
@lex =
|
90
|
+
@lex = get_re('lexicals', '[sy]')
|
89
91
|
@skip = get_array('skip', DEFAULT_SKIP, :upcase)
|
90
92
|
|
93
|
+
@src = get_key('src', false)
|
94
|
+
@src = DEFAULT_SRC_SEP if @src == true
|
95
|
+
|
91
96
|
if sort = get_key('sort', 'normal')
|
92
97
|
@sort_format, @sort_method = sort.downcase.split('_', 2)
|
93
98
|
end
|
@@ -111,25 +116,20 @@ class Lingo
|
|
111
116
|
elsif obj.is_a?(Word) && !@skip.include?(obj.attr)
|
112
117
|
@word_count += 1
|
113
118
|
|
114
|
-
|
115
|
-
vec = lex.form
|
119
|
+
obj.get_class(@lex).each { |lex|
|
120
|
+
vec = Unicode.downcase(lex.form)
|
121
|
+
vec << @src << lex.src if @src && lex.src
|
116
122
|
@sort_format ? @vectors << vec : forward(vec)
|
117
|
-
}
|
118
|
-
|
119
|
-
add('Anzahl von Vektor-Wörtern', cnt)
|
123
|
+
}
|
120
124
|
end
|
121
125
|
end
|
122
126
|
|
123
127
|
private
|
124
128
|
|
125
129
|
def send_vectors
|
126
|
-
add('Objekte gefiltert', @vectors.size)
|
127
|
-
|
128
130
|
if @sort_format == 'normal'
|
129
|
-
@vectors.sort!
|
130
131
|
@vectors.uniq!
|
131
|
-
|
132
|
-
@vectors.each(&method(:forward)).clear
|
132
|
+
flush(@vectors.sort!)
|
133
133
|
else
|
134
134
|
cnt, fmt = Hash.new(0), '%d'
|
135
135
|
|
@@ -72,18 +72,10 @@ class Lingo
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def control(cmd, param)
|
75
|
-
report_on(cmd, @dic)
|
76
75
|
end
|
77
76
|
|
78
77
|
def process(obj)
|
79
|
-
|
80
|
-
inc('Anzahl gesuchter Wörter')
|
81
|
-
|
82
|
-
obj = @dic.find_word(obj.form)
|
83
|
-
inc('Anzahl gefundener Wörter') unless obj.unknown?
|
84
|
-
end
|
85
|
-
|
86
|
-
forward(obj)
|
78
|
+
forward(obj.is_a?(Token) && obj.word? ? @dic.find_word(obj.form) : obj)
|
87
79
|
end
|
88
80
|
|
89
81
|
end
|
data/lib/lingo/attendee.rb
CHANGED
@@ -56,7 +56,7 @@ class Lingo
|
|
56
56
|
# was macht attendee
|
57
57
|
# - verkettung der attendees anhand von konfigurationsinformationen
|
58
58
|
# - bereitstellung von globalen und spezifischen konfigurationsinformationen
|
59
|
-
# - behandlung von bestimmten übergreifenden Kommandos, z.B. STR_CMD_TALK
|
59
|
+
# - behandlung von bestimmten übergreifenden Kommandos, z.B. STR_CMD_TALK
|
60
60
|
# - separierung und routing von kommando bzw. datenobjekten
|
61
61
|
#
|
62
62
|
# was macht die abgeleitet klasse
|
@@ -67,39 +67,28 @@ class Lingo
|
|
67
67
|
class Attendee
|
68
68
|
|
69
69
|
include Language
|
70
|
-
include Reportable
|
71
70
|
|
72
71
|
STR_CMD_TALK = 'TALK'
|
73
|
-
STR_CMD_STATUS = 'STATUS'
|
74
72
|
STR_CMD_LIR = 'LIR-FORMAT'
|
75
73
|
STR_CMD_FILE = 'FILE'
|
76
74
|
STR_CMD_EOL = 'EOL'
|
77
75
|
STR_CMD_RECORD = 'RECORD'
|
78
76
|
STR_CMD_EOF = 'EOF'
|
79
77
|
|
80
|
-
STA_NUM_COMMANDS = 'Received Commands'
|
81
|
-
STA_NUM_OBJECTS = 'Received Objects '
|
82
|
-
STA_TIM_COMMANDS = 'Time to control '
|
83
|
-
STA_TIM_OBJECTS = 'Time to process '
|
84
|
-
|
85
78
|
DEFAULT_SKIP = [TA_PUNCTUATION, TA_OTHER].join(',')
|
86
79
|
|
87
80
|
def initialize(config, lingo)
|
88
|
-
@lingo = lingo
|
89
|
-
|
90
|
-
init_reportable
|
81
|
+
@lingo, @config, @subscriber = lingo, config, []
|
91
82
|
|
92
83
|
# Make sure config exists
|
93
84
|
lingo.dictionary_config
|
94
85
|
|
95
|
-
@config, @subscriber = config, []
|
96
|
-
|
97
86
|
init if self.class.method_defined?(:init)
|
98
87
|
|
99
88
|
@can_control = self.class.method_defined?(:control)
|
100
89
|
@can_process = self.class.method_defined?(:process)
|
101
90
|
|
102
|
-
@skip_command
|
91
|
+
@skip_command = false
|
103
92
|
end
|
104
93
|
|
105
94
|
def add_subscriber(subscriber)
|
@@ -107,28 +96,17 @@ class Lingo
|
|
107
96
|
end
|
108
97
|
|
109
98
|
def listen(obj)
|
110
|
-
|
111
|
-
@can_process ? stat_timer(:objects) { process(obj) } : forward(obj)
|
112
|
-
else
|
99
|
+
if obj.is_a?(AgendaItem)
|
113
100
|
args = obj.to_a
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
nil
|
119
|
-
when STR_CMD_STATUS
|
120
|
-
report_time
|
121
|
-
report_status
|
122
|
-
|
123
|
-
forward(*args)
|
124
|
-
else
|
125
|
-
forward(*args) unless skip_command!
|
126
|
-
end
|
101
|
+
control(*args) if @can_control
|
102
|
+
forward(*args) unless obj.cmd == STR_CMD_TALK || skip_command!
|
103
|
+
else
|
104
|
+
@can_process ? process(obj) : forward(obj)
|
127
105
|
end
|
128
106
|
end
|
129
107
|
|
130
108
|
def talk(obj)
|
131
|
-
|
109
|
+
@subscriber.each { |attendee| attendee.listen(obj) }
|
132
110
|
end
|
133
111
|
|
134
112
|
private
|
@@ -138,77 +116,6 @@ class Lingo
|
|
138
116
|
g && (block_given? ? !yield(w) : w.unknown?) ? g.find_compound(f) : w
|
139
117
|
end
|
140
118
|
|
141
|
-
def report_on(cmd, *rep)
|
142
|
-
rep.each { |r| r.report.each { |q| set(*q) } } if cmd == STR_CMD_STATUS
|
143
|
-
end
|
144
|
-
|
145
|
-
def sta_for(key)
|
146
|
-
%w[NUM TIM].map { |i| self.class.const_get("STA_#{i}_#{key.upcase}") }
|
147
|
-
end
|
148
|
-
|
149
|
-
def stat_timer(key)
|
150
|
-
n, t = sta_for(key)
|
151
|
-
inc(n)
|
152
|
-
|
153
|
-
return yield unless @lingo.report_time
|
154
|
-
|
155
|
-
@timer = Time.now.to_i
|
156
|
-
res = yield
|
157
|
-
add(t, Time.now.to_i - @timer)
|
158
|
-
res
|
159
|
-
end
|
160
|
-
|
161
|
-
def charge_timer
|
162
|
-
return yield unless @lingo.report_time
|
163
|
-
|
164
|
-
res = nil
|
165
|
-
@timer += Benchmark.realtime { res = yield }
|
166
|
-
res
|
167
|
-
end
|
168
|
-
|
169
|
-
def report_time
|
170
|
-
return unless @lingo.report_time
|
171
|
-
|
172
|
-
msg = 'Perf: %-15s ' <<
|
173
|
-
'=> %7d commands in %s (%s/cmd)' <<
|
174
|
-
', %8d objects in %s (%s/obj)'
|
175
|
-
|
176
|
-
arg = [@config['name']]
|
177
|
-
|
178
|
-
%w[commands objects].each { |k|
|
179
|
-
n, t = sta_for(k).map(&method(:get))
|
180
|
-
arg << n
|
181
|
-
|
182
|
-
arg.concat([1, n].map { |m|
|
183
|
-
s = m.zero? ? 0.0 : t / m.to_f
|
184
|
-
|
185
|
-
'%9.3f %-2s' %
|
186
|
-
if s < 0.001
|
187
|
-
[s * 1000.0 ** 2, 'µs']
|
188
|
-
elsif s < 1.0
|
189
|
-
[s * 1000.0, 'ms']
|
190
|
-
elsif s < 60.0
|
191
|
-
[s, 's']
|
192
|
-
elsif s < 60.0 ** 2
|
193
|
-
[s / 60.0, 'm']
|
194
|
-
else
|
195
|
-
[s / 60.0 ** 2, 'h']
|
196
|
-
end
|
197
|
-
})
|
198
|
-
}
|
199
|
-
|
200
|
-
warn msg % arg
|
201
|
-
end
|
202
|
-
|
203
|
-
def report_status
|
204
|
-
return unless @lingo.report_status
|
205
|
-
|
206
|
-
msg = "Attendee <%s> was connected from '%s' to '%s' reporting..."
|
207
|
-
|
208
|
-
warn msg % @config.values_at(*%w[name in out]), nil,
|
209
|
-
report.sort.map! { |k, v| " #{k} = #{v}" }, nil
|
210
|
-
end
|
211
|
-
|
212
119
|
def skip_command
|
213
120
|
@skip_command = true
|
214
121
|
end
|
@@ -221,17 +128,29 @@ class Lingo
|
|
221
128
|
talk(param ? AgendaItem.new(obj, param) : obj)
|
222
129
|
end
|
223
130
|
|
131
|
+
def flush(buffer)
|
132
|
+
buffer.each { |i| forward(i) }.clear
|
133
|
+
end
|
134
|
+
|
224
135
|
def has_key?(key)
|
225
136
|
@config && @config.has_key?(key)
|
226
137
|
end
|
227
138
|
|
228
|
-
def get_key(key, default = nodefault =
|
139
|
+
def get_key(key, default = nodefault = true)
|
229
140
|
raise MissingConfigError.new(key) if nodefault && !has_key?(key)
|
230
141
|
@config.fetch(key, default)
|
231
142
|
end
|
232
143
|
|
233
|
-
def get_array(key, default = nil,
|
234
|
-
get_key(key, default).split(SEP_RE)
|
144
|
+
def get_array(key, default = nil, method = nil)
|
145
|
+
ary = get_key(key, default).split(SEP_RE)
|
146
|
+
ary.map!(&method) if method
|
147
|
+
ary
|
148
|
+
end
|
149
|
+
|
150
|
+
def get_re(key, default = nil, standard = nil)
|
151
|
+
if value = get_key(key, default)
|
152
|
+
value == true ? standard : Regexp.new(value)
|
153
|
+
end
|
235
154
|
end
|
236
155
|
|
237
156
|
def dictionary(src, mod)
|
@@ -29,7 +29,7 @@ class Lingo
|
|
29
29
|
class BufferedAttendee < Attendee
|
30
30
|
|
31
31
|
def initialize(config, lingo)
|
32
|
-
@buffer
|
32
|
+
@buffer = []
|
33
33
|
super
|
34
34
|
end
|
35
35
|
|
@@ -47,11 +47,6 @@ class Lingo
|
|
47
47
|
obj.form if obj.is_a?(klass)
|
48
48
|
end
|
49
49
|
|
50
|
-
def forward_buffer
|
51
|
-
@inserts.sort_by!(&:first).each { |i| @buffer.insert(*i) }.clear
|
52
|
-
@buffer.each(&method(:forward)).clear
|
53
|
-
end
|
54
|
-
|
55
50
|
def forward_number_of_token(len = default = @buffer.size, punct = !default)
|
56
51
|
begin
|
57
52
|
unless @buffer.empty?
|
@@ -74,9 +69,7 @@ class Lingo
|
|
74
69
|
raise NotImplementedError
|
75
70
|
end
|
76
71
|
|
77
|
-
def control_multi(cmd
|
78
|
-
report_on(cmd, dic)
|
79
|
-
|
72
|
+
def control_multi(cmd)
|
80
73
|
if [STR_CMD_RECORD, STR_CMD_EOF].include?(cmd)
|
81
74
|
@eof_handling = true
|
82
75
|
|
data/lib/lingo/call.rb
CHANGED
@@ -28,6 +28,8 @@ class Lingo
|
|
28
28
|
|
29
29
|
class Call < self
|
30
30
|
|
31
|
+
CHANNELS = %w[stdout stderr].freeze
|
32
|
+
|
31
33
|
def initialize(args = [])
|
32
34
|
super(args, StringIO.new, StringIO.new, StringIO.new)
|
33
35
|
end
|
@@ -51,20 +53,23 @@ class Lingo
|
|
51
53
|
|
52
54
|
start
|
53
55
|
|
54
|
-
|
55
|
-
io = config.send(key)
|
56
|
-
io.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
res.sort!
|
65
|
-
res.uniq!
|
66
|
-
end
|
56
|
+
res = CHANNELS.flat_map { |key|
|
57
|
+
io = config.send(key)
|
58
|
+
io.rewind
|
59
|
+
|
60
|
+
lines = io.readlines.each { |i| i.chomp! }
|
61
|
+
|
62
|
+
io.truncate(0)
|
63
|
+
io.rewind
|
64
|
+
|
65
|
+
lines
|
67
66
|
}
|
67
|
+
|
68
|
+
block_given? ? res.map! { |i| yield i } : begin
|
69
|
+
res.sort!
|
70
|
+
res.uniq!
|
71
|
+
res
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
end
|
data/lib/lingo/cli.rb
CHANGED
@@ -36,8 +36,7 @@ class Lingo
|
|
36
36
|
super.merge(
|
37
37
|
config: 'lingo.cfg',
|
38
38
|
language: 'de',
|
39
|
-
|
40
|
-
perfmon: false
|
39
|
+
profile: false
|
41
40
|
)
|
42
41
|
end
|
43
42
|
|
@@ -68,18 +67,14 @@ class Lingo
|
|
68
67
|
|
69
68
|
opts.separator ''
|
70
69
|
|
71
|
-
opts.on('-
|
72
|
-
options[:
|
73
|
-
}
|
74
|
-
|
75
|
-
opts.on('-p', '--perfmon', 'Print performance details after processing') {
|
76
|
-
options[:perfmon] = true
|
70
|
+
opts.on('-L', '--log FILE', 'Log file to print debug information to') { |log|
|
71
|
+
options[:log] = stderr.reopen(log == '-' ? stdout : File.open(log, 'a+', encoding: ENC))
|
77
72
|
}
|
78
73
|
|
79
74
|
opts.separator ''
|
80
75
|
|
81
|
-
opts.on('-
|
82
|
-
options[:
|
76
|
+
opts.on('-P', '--profile PATH', 'Print profiling results') { |profile|
|
77
|
+
options[:profile] = profile == '-' ? stdout : profile
|
83
78
|
}
|
84
79
|
end
|
85
80
|
|