apohllo-poliqarpr 0.0.3 → 0.0.4

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/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