lingo 1.8.2 → 1.8.3

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