apohllo-poliqarpr 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -11,8 +11,16 @@ Poliqarpr is Ruby client for Poliqarp server.
11
11
 
12
12
  * built-in pagination of query results
13
13
  * support for lemmatization
14
- * asynchronous communication is implemented in synchronous manner
15
- * only partial implementation of server protocol
14
+ * asynchronous communication might be not stable (100% CPU ussage)
15
+ * only partial implementation of server protocol:
16
+ ** PING, VERSION
17
+ ** MAKE-SESSION, CLOSE-SESSION
18
+ ** OPEN (corpus), CLOSE (corpus)
19
+ ** CORPUS-STATS, GET-TAGSET
20
+ ** STATUS, CANCEL (used internally)
21
+ ** MAKE-QUERY, RUN-QUERY, BUFFER-STATE (used internally)
22
+ ** GET-RESULTS, GET-CONTEXT, METADATA
23
+ ** SET: lemmata, tags
16
24
 
17
25
  == SYNOPSIS:
18
26
 
@@ -1,3 +1,10 @@
1
+ 0.0.4
2
+ - ping/pong diagnostics
3
+ - server version
4
+ - corpus statistics
5
+ - implementation of asynchronous protocol (not stable)
6
+
7
+
1
8
  0.0.3
2
9
  - the license of the corpus included
3
10
  - client rdoc documentation
@@ -1,11 +1,9 @@
1
- path = File.join(File.dirname(__FILE__), 'poliqarpr')
2
- require File.join(path, 'client')
3
- require File.join(path, 'query_result')
4
- require File.join(path, 'excerpt')
5
- require File.join(path, 'segment')
6
- require File.join(path, 'lemmata')
7
1
  begin
8
2
  require 'poliqarpr-corpus'
9
3
  rescue LoadError
10
4
  # Do nothig, since the default corpus is optional
11
5
  end
6
+
7
+ $LOAD_PATH.unshift File.dirname(__FILE__)
8
+ Dir.glob(File.join(File.dirname(__FILE__), 'poliqarpr/**.rb')).each { |f| require f }
9
+
@@ -1,29 +1,9 @@
1
- require 'socket'
2
1
  module Poliqarp
3
2
  # Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
4
3
  # License:: MIT License
5
4
  #
6
5
  # This class is the implementation of the Poliqarp server client.
7
6
  class Client
8
- ERRORS = {
9
- 1 => "Incorrect number of arguments",
10
- 3 => "No session opened",
11
- 4 => "Cannot create a session for a connection that",
12
- 5 => "Not enough memory",
13
- 6 => "Invalid session ID",
14
- 7 => "Session with this ID is already bound",
15
- 8 => "Session user ID does not match the argument",
16
- 10 => "Session already has an open corpus",
17
- 12 => "System error while opening the corpus",
18
- 13 => "No corpus opened",
19
- 14 => "Invalid job ID",
20
- 15 => "A job is already in progress",
21
- 16 => "Incorrect query",
22
- 17 => "Invalid result range",
23
- 18 => "Incorrect session option",
24
- 19 => "Invalid session option value",
25
- 20 => "Invalid sorting criteria"
26
- }
27
7
  GROUPS = [:left_context, :left_match, :right_match, :right_context]
28
8
 
29
9
  # If debug is turned on, the communication between server and client
@@ -46,10 +26,12 @@ module Poliqarp
46
26
  @right_context = 5
47
27
  @debug = debug
48
28
  @buffer_size = 500000
29
+ @connector = Connector.new(debug)
30
+ @answer_queue = Queue.new
49
31
  new_session
50
32
  end
51
33
 
52
- # A hint about uninstalled default corpus gem
34
+ # A hint about installation of default corpus gem
53
35
  def self.const_missing(const)
54
36
  if const.to_s =~ /DEFAULT_CORPUS/
55
37
  raise "You need to install 'apohllo-poliqarpr-corpus' to use the default corpus"
@@ -64,26 +46,25 @@ module Poliqarp
64
46
  # * +port+ - the port on which the poliqarpd server is accepting connections (defaults to 4567)
65
47
  def new_session(port=4567)
66
48
  close if @session
67
- @socket = TCPSocket.new("localhost",port)
68
- talk "MAKE-SESSION #{@session_name}"
69
- rcv_sync
49
+ @connector.open("localhost",port)
50
+ talk("MAKE-SESSION #{@session_name}")
70
51
  talk("BUFFER-RESIZE #{@buffer_size}")
71
- rcv_sync
72
52
  @session = true
73
53
  self.tags = {}
74
54
  self.lemmata = {}
75
55
  end
76
56
 
77
- # Closes the opened connection to the poliqarpd server.
57
+ # Closes the opened session.
78
58
  def close
79
- #talk "CLOSE"
80
- #rcv_sync
81
59
  talk "CLOSE-SESSION"
82
- rcv_sync
83
- #@socket.close
84
60
  @session = false
85
61
  end
86
62
 
63
+ # Closes the opened corpus.
64
+ def close_corpus
65
+ talk "CLOSE"
66
+ end
67
+
87
68
  # Sets the size of the left short context. It must be > 0
88
69
  #
89
70
  # The size of the left short context is the number
@@ -91,8 +72,7 @@ module Poliqarp
91
72
  # matched segment(s).
92
73
  def left_context=(value)
93
74
  if correct_context_value?(value)
94
- talk "SET left-context-width #{value}"
95
- result = rcv_sync
75
+ result = talk("SET left-context-width #{value}")
96
76
  @left_context = value if result =~ /^R OK/
97
77
  else
98
78
  raise "Invalid argument: #{value}. It must be fixnum greater than 0."
@@ -106,8 +86,7 @@ module Poliqarp
106
86
  # matched segment(s).
107
87
  def right_context=(value)
108
88
  if correct_context_value?(value)
109
- talk "SET right-context-width #{value}"
110
- result = rcv_sync
89
+ result = talk("SET right-context-width #{value}")
111
90
  @right_context = value if result =~ /^R OK/
112
91
  else
113
92
  raise "Invalid argument: #{value}. It must be fixnum greater than 0."
@@ -135,8 +114,7 @@ module Poliqarp
135
114
  GROUPS.each do |flag|
136
115
  flags << (options[flag] ? "1" : "0")
137
116
  end
138
- talk "SET retrieve-tags #{flags}"
139
- rcv_sync
117
+ talk("SET retrieve-tags #{flags}")
140
118
  end
141
119
 
142
120
  # Sets the lemmatas' flags. There are four groups of segments
@@ -160,20 +138,87 @@ module Poliqarp
160
138
  GROUPS.each do |flag|
161
139
  flags << (options[flag] ? "1" : "0")
162
140
  end
163
- talk "SET retrieve-lemmata #{flags}"
164
- rcv_sync
141
+ talk("SET retrieve-lemmata #{flags}")
165
142
  end
166
143
 
167
- # Opens the corpus given as +path+. To open the default
144
+ # *Asynchronous* Opens the corpus given as +path+. To open the default
168
145
  # corpus pass +:default+ as the argument.
169
- def open_corpus(path)
146
+ #
147
+ # If you don't want to wait until the call is finished, you
148
+ # have to provide +handler+ for the asynchronous answer.
149
+ def open_corpus(path, &handler)
170
150
  if path == :default
171
- open_corpus(DEFAULT_CORPUS)
151
+ open_corpus(DEFAULT_CORPUS, &handler)
172
152
  else
173
- talk("OPEN #{path}")
174
- rcv_sync
175
- rcv_async
153
+ real_handler = handler || lambda{|msg| @answer_queue.push msg }
154
+ talk("OPEN #{path}", :async, &real_handler)
155
+ do_wait if handler.nil?
156
+ end
157
+ end
158
+
159
+ # Server diagnostics -- the result should be :pong
160
+ def ping
161
+ :pong if talk("PING") =~ /PONG/
162
+ end
163
+
164
+ # Returns server version
165
+ def version
166
+ talk("VERSION")
167
+ end
168
+
169
+ # Returns corpus statistics:
170
+ # * +:segment_tokens+ the number of segments in the corpus
171
+ # (two segments which look exactly the same are counted separately)
172
+ # * +:segment_types+ the number of segment types in the corpus
173
+ # (two segments which look exactly the same are counted as one type)
174
+ # * +:lemmata+ the number of lemmata (lexemes) types
175
+ # (all forms of inflected word, e.g. 'kot', 'kotu', ...
176
+ # are treated as one "word" -- lemmata)
177
+ # * +:tags+ the number of different grammar tags (each combination
178
+ # of atomic tags is treated as different "tag")
179
+ def stats
180
+ stats = {}
181
+ talk("CORPUS-STATS").split.each_with_index do |value, index|
182
+ case index
183
+ when 1
184
+ stats[:segment_tokens] = value.to_i
185
+ when 2
186
+ stats[:segment_types] = value.to_i
187
+ when 3
188
+ stats[:lemmata] = value.to_i
189
+ when 4
190
+ stats[:tags] = value.to_i
191
+ end
192
+ end
193
+ stats
194
+ end
195
+
196
+ # TODO
197
+ def metadata_types
198
+ raise "Not implemented"
199
+ end
200
+
201
+ # Returns the tag-set used in the corpus.
202
+ # It is divided into two groups:
203
+ # * +:categories+ enlists tags belonging to grammatical categories
204
+ # (each category has a list of its tags, eg. gender: m1 m2 m3 f n,
205
+ # means that there are 5 genders: masculine(1,2,3), feminine and neuter)
206
+ # * +:classes+ enlists grammatical tags used to describe it
207
+ # (each class has a list of tags used to describe it, eg. adj: degree
208
+ # gender case number, means that adjectives are described in terms
209
+ # of degree, gender, case and number)
210
+ def tagset
211
+ answer = talk("GET-TAGSET")
212
+ counters = answer.split
213
+ result = {}
214
+ [:categories, :classes].each_with_index do |type, type_index|
215
+ result[type] = {}
216
+ counters[type_index+1].to_i.times do |index|
217
+ values = read_word.split
218
+ result[type][values[0].to_sym] = values[1..-1].map{|v| v.to_sym}
219
+ end
176
220
  end
221
+ result
177
222
  end
178
223
 
179
224
  # Send the query to the opened corpus.
@@ -210,8 +255,6 @@ module Poliqarp
210
255
  make_query(query)
211
256
  result = []
212
257
  talk "GET-CONTEXT #{index}"
213
- # R OK
214
- rcv_sync
215
258
  # 1st part
216
259
  result << read_word
217
260
  # 2nd part
@@ -228,11 +271,11 @@ module Poliqarp
228
271
  def metadata(query, index)
229
272
  make_query(query)
230
273
  result = {}
231
- talk "METADATA #{index}"
232
- count = rcv_sync.split(" ")[2].to_i
274
+ answer = talk("METADATA #{index}")
275
+ count = answer.split(" ")[1].to_i
233
276
  count.times do |index|
234
277
  type = read_word.gsub(/[^a-zA-Z]/,"").to_sym
235
- value = rcv_sync[4..-2]
278
+ value = read_word[2..-1]
236
279
  unless value.nil?
237
280
  result[type] ||= []
238
281
  result[type] << value
@@ -244,36 +287,40 @@ module Poliqarp
244
287
  protected
245
288
  # Sends a message directly to the server
246
289
  # * +msg+ the message to send
247
- def talk(msg)
290
+ # * +mode+ if set to :sync, the method block untli the message
291
+ # is received. If :async the method returns immediately.
292
+ # Default: :sync
293
+ # * +handler+ the handler of the assynchronous message.
294
+ # It is ignored when the mode is set to :sync.
295
+ def talk(msg, mode = :sync, &handler)
248
296
  puts msg if @debug
249
- @socket.puts(msg)
297
+ @connector.send(msg, mode, &handler)
250
298
  end
251
299
 
300
+ # Make query and retrieve many results.
301
+ # * +query+ the query to be sent to the server.
302
+ # * +options+ see find
252
303
  def find_many(query, options)
253
304
  page_size = (options[:page_size] || 0)
254
305
  page_index = (options[:page_index] || 1)
255
- answers = make_query(query)
256
- #talk("GET-COLUMN-TYPES")
257
- #rcv_sync
258
- result_count = count_results(answers)
306
+
259
307
  answer_offset = page_size * (page_index - 1)
260
308
  if page_size > 0
309
+ result_count = make_async_query(query,answer_offset)
261
310
  answers_limit = answer_offset + page_size > result_count ?
262
311
  result_count - answer_offset : page_size
263
312
  else
313
+ # all answers needed -- the call must be synchronous
314
+ result_count = count_results(make_query(query))
264
315
  answers_limit = result_count
265
316
  end
266
- page_count = if page_size > 0
267
- result_count / page_size + (result_count % page_size > 0 ? 1 : 0)
268
- else
269
- 1
270
- end
317
+
318
+ page_count = page_size <= 0 ? 1 :
319
+ result_count / page_size + (result_count % page_size > 0 ? 1 : 0)
320
+
271
321
  result = QueryResult.new(page_index, page_count,page_size,self,query)
272
322
  if answers_limit > 0
273
323
  talk("GET-RESULTS #{answer_offset} #{answer_offset + answers_limit - 1}")
274
- # R OK 1
275
- rcv_sync
276
-
277
324
  answers_limit.times do |answer_index|
278
325
  result << fetch_result(answer_offset + answer_index, query)
279
326
  end
@@ -281,17 +328,18 @@ protected
281
328
  result
282
329
  end
283
330
 
331
+ # Make query and retrieve only one result
332
+ # * +query+ the query to be sent to the server
333
+ # * +index+ the index of the answer to be retrieved
284
334
  def find_one(query,index)
285
- make_query(query)
335
+ make_async_query(query,index)
286
336
  talk("GET-RESULTS #{index} #{index}")
287
- # R OK 1
288
- rcv_sync
289
337
  fetch_result(index,query)
290
338
  end
291
339
 
292
340
  # Fetches one result of the query
293
- ##
294
- # MAKE-QUERY and GET-RESULTS must be called on server before
341
+ #
342
+ # MAKE-QUERY and GET-RESULTS must be sent to the server before
295
343
  # this method is called
296
344
  def fetch_result(index, query)
297
345
  result = Excerpt.new(index, self, query)
@@ -300,18 +348,17 @@ protected
300
348
  # XXX
301
349
  #result << read_segments(:right_match)
302
350
  result << read_segments(:right_context)
303
-
304
351
  result
305
352
  end
306
353
 
307
354
  def read_segments(group)
308
- size = get_number(rcv_sync)
355
+ size = read_number()
309
356
  segments = []
310
357
  size.times do |segment_index|
311
358
  segment = Segment.new(read_word)
312
359
  segments << segment
313
360
  if @lemmata_flags[group] || @tag_flags[group]
314
- lemmata_size = get_number(rcv_sync)
361
+ lemmata_size = read_number()
315
362
  lemmata_size.times do |lemmata_index|
316
363
  lemmata = Lemmata.new()
317
364
  if @lemmata_flags[group]
@@ -327,62 +374,56 @@ protected
327
374
  segments
328
375
  end
329
376
 
330
- def get_number(str)
331
- str.match(/\d+/)[0].to_i
377
+ # Reads number stored in the message received from the server.
378
+ def read_number
379
+ @connector.read_message.match(/\d+/)[0].to_i
332
380
  end
333
381
 
382
+ # Counts number of results for given answer
334
383
  def count_results(answer)
335
- answer.split(" ")[2].to_i
384
+ answer.split(" ")[1].to_i
336
385
  end
337
386
 
338
- def make_query(query)
387
+ # *Asynchronous* Sends the query to the server
388
+ # * +query+ query to send
389
+ # * +handler+ if given, the method returns immediately,
390
+ # and the answer is sent to the handler. In this case
391
+ # the result returned by make_query should be IGNORED!
392
+ def make_query(query, &handler)
339
393
  if @last_query != query
340
394
  @last_query = query
341
- talk("MAKE-QUERY #{query}")
342
- rcv_sync
343
- talk("RUN-QUERY #{@buffer_size}")
344
- @last_query_result = rcv_async
395
+ if handler.nil?
396
+ real_handler = lambda { |msg| @answer_queue.push msg }
397
+ else
398
+ real_handler = handler
399
+ end
400
+ begin
401
+ talk("MAKE-QUERY #{query}")
402
+ rescue JobInProgress
403
+ talk("CANCEL") rescue nil
404
+ talk("MAKE-QUERY #{query}")
405
+ end
406
+ talk("RUN-QUERY #{@buffer_size}", :async, &real_handler)
407
+ @last_result = do_wait if handler.nil?
345
408
  end
346
- @last_query_result
409
+ @last_result
347
410
  end
348
411
 
412
+ # Reads string stored in the last message received from server
349
413
  def read_word
350
- rcv_sync[2..-2]
351
- end
352
-
353
- def read_line
354
- line = ""
355
- begin
356
- chars = @socket.recvfrom(1)
357
- line << chars[0]
358
- end while chars[0] != "\n"
359
- line
414
+ @connector.read_message
360
415
  end
361
416
 
362
- def error_message(line)
363
- RuntimeError.new("Poliqarp Error: "+ERRORS[line.match(/\d+/)[0].to_i])
364
- end
365
-
366
- # XXX
367
- def rcv_sync
368
- result = read_line
369
- puts result if @debug
370
- raise error_message(result) if result =~ /^R ERR/
371
- result
372
- # @socket.recvfrom(1024)
373
- end
374
-
375
- # XXX
376
- def rcv_async
377
- begin
378
- line = read_line
379
- raise error_message(line) if line =~ /^. ERR/
380
- puts line if @debug
381
- end until line =~ /^M/
382
- line
417
+ private
418
+ def do_wait
419
+ loop {
420
+ status = talk("STATUS") rescue break
421
+ puts "STATUS: #{status}" if @debug
422
+ sleep 0.3
423
+ }
424
+ @answer_queue.shift
383
425
  end
384
426
 
385
- private
386
427
  def set_all_flags
387
428
  options = {}
388
429
  GROUPS.each{|g| options[g] = true}
@@ -392,5 +433,19 @@ private
392
433
  def correct_context_value?(value)
393
434
  value.is_a?(Fixnum) && value > 0
394
435
  end
436
+
437
+ def make_async_query(query,answer_offset)
438
+ # the handler is empty, since we access the result count through
439
+ # BUFFER-STATE call
440
+ make_query(query){|msg| }
441
+ result_count = 0
442
+ begin
443
+ # the result count might be not exact!
444
+ result_count = talk("BUFFER-STATE").split(" ")[2].to_i
445
+ talk("STATUS") rescue break
446
+ end while result_count < answer_offset
447
+ @last_result = "OK #{result_count}"
448
+ result_count
449
+ end
395
450
  end
396
451
  end
@@ -0,0 +1,128 @@
1
+ require 'socket'
2
+
3
+ module Poliqarp
4
+ # Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
5
+ # License:: MIT License
6
+ #
7
+ # This class hold the TCP connection to the server and is responsible
8
+ # for dispatching synchronous and asynchronous queries and answers.
9
+ class Connector
10
+
11
+ # Error messages assigned to error codes
12
+ # (taken from poliqarpd implementation)
13
+ ERRORS = {
14
+ 1 => "Incorrect number of arguments",
15
+ 3 => "No session opened",
16
+ 4 => "Cannot create a session for a connection that",
17
+ 5 => "Not enough memory",
18
+ 6 => "Invalid session ID",
19
+ 7 => "Session with this ID is already bound",
20
+ 8 => "Session user ID does not match the argument",
21
+ 10 => "Session already has an open corpus",
22
+ 12 => "System error while opening the corpus",
23
+ 13 => "No corpus opened",
24
+ 14 => "Invalid job ID",
25
+ 15 => "A job is already in progress",
26
+ 16 => "Incorrect query",
27
+ 17 => "Invalid result range",
28
+ 18 => "Incorrect session option",
29
+ 19 => "Invalid session option value",
30
+ 20 => "Invalid sorting criteria"
31
+ }
32
+
33
+ # Creates new connector
34
+ def initialize(debug)
35
+ @message_queue = Queue.new
36
+ @socket_mutex = Mutex.new
37
+ @loop_mutex = Mutex.new
38
+ @debug = debug
39
+ end
40
+
41
+ # Opens connection with poliqarp server which runs
42
+ # on given +host+ and +port+.
43
+ def open(host,port)
44
+ @socket_mutex.synchronize {
45
+ @socket = TCPSocket.new(host,port) if @socket.nil?
46
+ }
47
+ running = nil
48
+ @loop_mutex.synchronize {
49
+ running = @loop_running
50
+ }
51
+ main_loop unless running
52
+ @loop_mutex.synchronize {
53
+ @loop_running = true
54
+ }
55
+ end
56
+
57
+ # Sends message to the poliqarp server. Returns the first synchronous
58
+ # answer of the server.
59
+ # * +message+ the message to send
60
+ # * +mode+ synchronous (+:sync:) or asynchronous (+:async+)
61
+ # * +handler+ the handler of the asynchronous message
62
+ def send(message, mode, &handler)
63
+ puts "send #{mode} #{message}" if @debug
64
+ @socket.puts(message)
65
+ if mode == :async
66
+ @handler = handler
67
+ end
68
+ read_message
69
+ end
70
+
71
+ # Retrives one message from the server.
72
+ # If the message indicates an error, new runtime error
73
+ # containing the error description is returned.
74
+ def read_message
75
+ message = @message_queue.shift
76
+ if message =~ /^ERR/
77
+ code = message.match(/\d+/)[0].to_i
78
+ raise JobInProgress.new() if code == 15
79
+ raise RuntimeError.new("Poliqarp Error: "+ERRORS[code])
80
+ else
81
+ message
82
+ end
83
+ end
84
+
85
+ private
86
+ def main_loop
87
+ @loop = Thread.new {
88
+ loop {
89
+ receive
90
+ # XXX ??? needed
91
+ #sleep 0.001
92
+ }
93
+ }
94
+ end
95
+
96
+ def receive
97
+ result = read_line
98
+ msg = result[2..-2]
99
+ if result =~ /^M/
100
+ receive_async(msg)
101
+ elsif result
102
+ receive_sync(msg)
103
+ end
104
+ # if nil, nothing was received
105
+ end
106
+
107
+ def receive_sync(message)
108
+ puts "receive sync: #{message}" if @debug
109
+ @message_queue << message
110
+ end
111
+
112
+ def receive_async(message)
113
+ puts "receive async: #{message}" if @debug
114
+ Thread.new{
115
+ @handler.call(message)
116
+ }
117
+ end
118
+
119
+ def read_line
120
+ line = ""
121
+ begin
122
+ chars = @socket.recvfrom(1)
123
+ line << chars[0]
124
+ end while chars[0] != "\n"
125
+ line
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,9 @@
1
+ module Poliqarp
2
+ # Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
3
+ # License:: MIT License
4
+
5
+ # The JobInProgress exception is raised if there was asynchronous call
6
+ # to the server which haven't finished, which is interrupted by another
7
+ # asynchronous call.
8
+ class JobInProgress < Exception; end
9
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "poliqarpr"
3
- s.version = "0.0.3"
3
+ s.version = "0.0.4"
4
4
  s.date = "2008-12-20"
5
5
  s.summary = "Ruby client for Poliqarp"
6
6
  s.email = "apohllo@o2.pl"
@@ -14,6 +14,8 @@ Gem::Specification.new do |s|
14
14
  "lib/poliqarpr/excerpt.rb",
15
15
  "lib/poliqarpr/lemmata.rb",
16
16
  "lib/poliqarpr/segment.rb",
17
+ "lib/poliqarpr/connector.rb",
18
+ "lib/poliqarpr/exceptions.rb",
17
19
  "README.txt",
18
20
  ]
19
21
  s.test_files = [
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..','lib','poliqarpr')
1
+ require 'lib/poliqarpr'
2
2
 
3
3
  describe Poliqarp::Client do
4
4
  describe "(general test)" do
@@ -17,6 +17,15 @@ describe Poliqarp::Client do
17
17
  it "should allow to open :default corpus" do
18
18
  @client.open_corpus(:default)
19
19
  end
20
+
21
+ it "should respond to :ping" do
22
+ @client.ping.should == :pong
23
+ end
24
+
25
+ it "should return server version" do
26
+ @client.version.should_not == nil
27
+ end
28
+
20
29
  end
21
30
 
22
31
  describe "(with 'sample' corpus)" do
@@ -61,6 +70,21 @@ describe Poliqarp::Client do
61
70
  end).should raise_error(RuntimeError)
62
71
  end
63
72
 
73
+ it "should return corpus statistics" do
74
+ stats = @client.stats
75
+ stats.size.should == 4
76
+ [:segment_tokens, :segment_types, :lemmata, :tags].each do |type|
77
+ stats[type].should_not == nil
78
+ stats[type].should > 0
79
+ end
80
+ end
81
+
82
+ it "should return the corpus tagset" do
83
+ tagset = @client.tagset
84
+ tagset[:categories].should_not == nil
85
+ tagset[:classes].should_not == nil
86
+ end
87
+
64
88
  it "should allow to find 'kot'" do
65
89
  @client.find("kot").size.should_not == 0
66
90
  end
@@ -111,6 +135,10 @@ describe Poliqarp::Client do
111
135
  @result.should_not respond_to(:[])
112
136
  end
113
137
 
138
+ it "should not be nil" do
139
+ @result.should_not == nil
140
+ end
141
+
114
142
  it "should fetch the same excerpt as in find without index " do
115
143
  @result.to_s.should == @client.find("nachalny")[0].to_s
116
144
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apohllo-poliqarpr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksander Pohl
@@ -31,6 +31,8 @@ files:
31
31
  - lib/poliqarpr/excerpt.rb
32
32
  - lib/poliqarpr/lemmata.rb
33
33
  - lib/poliqarpr/segment.rb
34
+ - lib/poliqarpr/connector.rb
35
+ - lib/poliqarpr/exceptions.rb
34
36
  - README.txt
35
37
  has_rdoc: true
36
38
  homepage: http://www.apohllo.pl/projekty/poliqarpr