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.
Files changed (76) hide show
  1. data/ChangeLog +33 -0
  2. data/README +6 -5
  3. data/Rakefile +6 -4
  4. data/{lib/lingo/cachable.rb → bin/lingosrv} +30 -58
  5. data/bin/lingoweb +30 -0
  6. data/de.lang +2 -13
  7. data/en/lingo-irr.txt +266 -0
  8. data/en/lingo-wdn.txt +37319 -0
  9. data/en.lang +2 -15
  10. data/lib/lingo/app.rb +82 -0
  11. data/lib/lingo/attendee/abbreviator.rb +22 -26
  12. data/lib/lingo/attendee/debugger.rb +8 -4
  13. data/lib/lingo/attendee/decomposer.rb +0 -1
  14. data/lib/lingo/attendee/dehyphenizer.rb +2 -2
  15. data/lib/lingo/attendee/multi_worder.rb +20 -13
  16. data/lib/lingo/attendee/noneword_filter.rb +2 -7
  17. data/lib/lingo/attendee/sequencer.rb +43 -19
  18. data/lib/lingo/attendee/stemmer/porter.rb +2 -2
  19. data/lib/lingo/attendee/stemmer.rb +1 -1
  20. data/lib/lingo/attendee/synonymer.rb +1 -9
  21. data/lib/lingo/attendee/text_reader.rb +42 -29
  22. data/lib/lingo/attendee/text_writer.rb +3 -6
  23. data/lib/lingo/attendee/tokenizer.rb +87 -69
  24. data/lib/lingo/attendee/variator.rb +7 -5
  25. data/lib/lingo/attendee/vector_filter.rb +11 -11
  26. data/lib/lingo/attendee/word_searcher.rb +1 -9
  27. data/lib/lingo/attendee.rb +24 -105
  28. data/lib/lingo/buffered_attendee.rb +2 -9
  29. data/lib/lingo/call.rb +18 -13
  30. data/lib/lingo/cli.rb +5 -10
  31. data/lib/lingo/config.rb +40 -7
  32. data/lib/lingo/ctl.rb +69 -57
  33. data/lib/lingo/database/hash_store.rb +9 -4
  34. data/lib/lingo/database/sdbm_store.rb +4 -7
  35. data/lib/lingo/database/source/multi_key.rb +1 -1
  36. data/lib/lingo/database/source/multi_value.rb +1 -1
  37. data/lib/lingo/database/source.rb +2 -20
  38. data/lib/lingo/database.rb +30 -19
  39. data/lib/lingo/debug.rb +79 -0
  40. data/lib/lingo/{core_ext.rb → language/char.rb} +43 -42
  41. data/lib/lingo/language/dictionary.rb +38 -46
  42. data/lib/lingo/language/grammar.rb +40 -57
  43. data/lib/lingo/language/lexical.rb +4 -7
  44. data/lib/lingo/language/lexical_hash.rb +17 -35
  45. data/lib/lingo/language/token.rb +4 -0
  46. data/lib/lingo/language/word.rb +7 -8
  47. data/lib/lingo/language/word_form.rb +4 -4
  48. data/lib/lingo/language.rb +2 -1
  49. data/lib/lingo/srv/config.ru +4 -0
  50. data/lib/lingo/srv/lingosrv.cfg +14 -0
  51. data/lib/lingo/{reportable.rb → srv.rb} +59 -61
  52. data/lib/lingo/version.rb +1 -1
  53. data/lib/lingo/web/config.ru +4 -0
  54. data/lib/lingo/web/lingoweb.cfg +14 -0
  55. data/lib/lingo/web/public/lingo.png +0 -0
  56. data/lib/lingo/web/public/lingoweb.css +74 -0
  57. data/lib/lingo/web/views/index.erb +92 -0
  58. data/lib/lingo/web.rb +94 -0
  59. data/lib/lingo.rb +27 -29
  60. data/lingo.cfg +1 -1
  61. data/lir.cfg +24 -0
  62. data/ru/lingo-dic.txt +22342 -0
  63. data/ru/lingo-mul.txt +5151 -0
  64. data/ru/lingo-syn.txt +0 -0
  65. data/ru.lang +99 -0
  66. data/test/attendee/ts_sequencer.rb +2 -2
  67. data/test/attendee/ts_text_reader.rb +36 -2
  68. data/test/attendee/ts_text_writer.rb +6 -6
  69. data/test/lir.vec +3 -3
  70. data/test/test_helper.rb +104 -102
  71. data/test/ts_database.rb +1 -1
  72. data/test/ts_language.rb +55 -96
  73. data/txt/artikel-ru.txt +45 -0
  74. data/txt/lir.txt +1 -3
  75. metadata +143 -83
  76. 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 der Sprachkonfiguration hinterlegt, die sich standardmäßig in der Datei
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', true)
106
- @wiki = get_key('wiki', true)
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
- if (name = rule.keys.first) =~ /^_\w+_$/
123
- macros[name] = expr
124
- else
125
- @rules << [name, /^#{expr}/]
126
- end
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
- inc('Anzahl Zeilen')
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(textline)
180
+ def tokenize(line)
161
181
  case @cont
162
182
  when 'HTML'
163
- if textline =~ /^[^<>]*>/
183
+ if line =~ /^[^<>]*>/
164
184
  yield $&, @cont
165
- textline, @cont = $', nil
185
+ line, @cont = $', nil
166
186
  else
167
- yield textline, @cont
187
+ yield line, @cont
168
188
  return
169
189
  end
170
190
  when 'WIKI'
171
- if textline =~ /^[^\[\]]*\]\]/
191
+ if line =~ /^[^\[\]]*\]\]/
172
192
  yield $&, @cont
173
- textline, @cont = $', nil
193
+ line, @cont = $', nil
174
194
  else
175
- yield textline, @cont
195
+ yield line, @cont
176
196
  return
177
197
  end
178
198
  when nil
179
- if !@tags && textline =~ /<[^<>]*$/
199
+ if @tags && line =~ /<[^<>]*$/
180
200
  yield $&, @cont = 'HTML'
181
- textline = $`
201
+ line = $`
182
202
  end
183
203
 
184
- if !@wiki && textline =~ /\[\[[^\[\]]*$/
204
+ if @wiki && line =~ /\[\[[^\[\]]*$/
185
205
  yield $&, @cont = 'WIKI'
186
- textline = $`
206
+ line = $`
187
207
  end
188
208
  end
189
209
 
190
- until textline.empty?
191
- @rules.each { |name, expr|
192
- if textline =~ expr
193
- yield $&, name if name != 'SPAC' || @space
194
- textline = $'
195
- break
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
- inc('Anzahl gesuchter Wörter')
97
+ vars, max = [obj.form], @max
99
98
 
100
- @var.each_with_object([obj.form]) { |a, v| variate(v, *a) }.
101
- tap { |v| v.slice!(@max..-1) }.each { |var|
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 = Regexp.new(get_key('lexicals', '[sy]').downcase)
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
- cnt = obj.get_class(@lex).each { |lex|
115
- vec = lex.form.downcase
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
- }.size
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
- if obj.is_a?(Token) && obj.attr == TA_WORD
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
@@ -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, STR_CMD_STATUS
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, @timer = false, nil
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
- unless obj.is_a?(AgendaItem)
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
- stat_timer(:commands) { control(*args) } if @can_control
115
-
116
- case obj.cmd
117
- when STR_CMD_TALK
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
- charge_timer { @subscriber.each { |attendee| attendee.listen(obj) } }
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 = Object.new)
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, m = nil)
234
- get_key(key, default).split(SEP_RE).tap { |ary| ary.map!(&m) if m }
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, @inserts = [], []
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, dic = @dic)
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
- %w[stdout stderr].flat_map { |key|
55
- io = config.send(key).tap(&:rewind)
56
- io.readlines.each(&:chomp!).tap {
57
- io.truncate(0)
58
- io.rewind
59
- }
60
- }.tap { |res|
61
- if block_given?
62
- res.map!(&Proc.new)
63
- else
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
- status: false,
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('-s', '--status', 'Print status information after processing') {
72
- options[:status] = true
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('-L', '--log FILE', 'Log file to print debug and status information to') { |log|
82
- options[:log] = @stderr.reopen(File.open(log, 'a+', encoding: ENC))
76
+ opts.on('-P', '--profile PATH', 'Print profiling results') { |profile|
77
+ options[:profile] = profile == '-' ? stdout : profile
83
78
  }
84
79
  end
85
80