abstractor 4.4.1 → 4.4.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1915d3f9543f45ccc3df0b4e6c74d6b58f566398
4
- data.tar.gz: 5cb807386ae0cdfa2a60d28ef55b6d1bfddba633
3
+ metadata.gz: 07d9074db71c7f0389203998331177b329015321
4
+ data.tar.gz: 266b2bfeb642c6613ff23e12da66d904c90723f9
5
5
  SHA512:
6
- metadata.gz: 5503ed02f9a8b7d9b9c39fa2ab19b937b9f363adf1bece36b84b5365ef0ad138dd0cabf182dc59b1d881dcc84c1134cb65cd0ad5138741b00c4419089a7361ee
7
- data.tar.gz: ffa6167f82c4286ae712deb5f25b859eb74200d6e3ec266e26d8d0eab51d629db32348a0ccca3a72f814b0e0355c360e503d959a5f7dc8a4a196c3ddb2ed1d96
6
+ metadata.gz: fa9449c55a6b1600596d86fbaa55da291955a17e71a8f463cfa386687270e04654339d0e2e39441fbf7a418fb06d5e835124412c79092ae1ba6df6f092a2dd97
7
+ data.tar.gz: 1628fd3acdc7f26b12325cfb6666fed656937386faee9bb2b5de865f7d0744a2227e008f146fe2c454a7bfc450102f0ab74572f1a398e98023eb5a8be4507fa7
@@ -7,28 +7,28 @@
7
7
  = abstraction_schema.display_name
8
8
  .abstraction_edit_abstraction_value
9
9
  - case abstraction_schema.abstractor_object_type.value
10
- - when 'date'
10
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_DATE
11
11
  = f.text_field :value, class: 'abstractor_datepicker'
12
- - when 'text'
12
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_TEXT
13
13
  = f.text_area :value
14
- - when 'string'
14
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_STRING
15
15
  = f.text_field :value
16
- - when 'number'
16
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER
17
17
  = f.number_field :value
18
- - when 'radio button list'
18
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST
19
19
  - values = abstraction_schema.abstractor_object_values.order('abstractor_abstraction_schema_object_values.display_order, abstractor_object_values.value')
20
20
  - values.each do |value|
21
21
  = f.radio_button :value, value.value
22
22
  = f.label :value, value.value, value: value.value
23
23
  = f.radio_button :value, '', {:style => 'display:none;' }
24
24
   
25
- - when 'list'
25
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_LIST, Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
26
26
  - values = abstraction_schema.abstractor_object_values.order('abstractor_abstraction_schema_object_values.display_order, abstractor_object_values.value')
27
27
  = f.select :value, values.map{|s| [s.value, s.value]}, {:include_blank => true}, :class => "combobox"
28
- - when 'dynamic list'
28
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST
29
29
  - values = abstractor_abstraction.about.send(abstractor_abstraction.abstractor_subject.dynamic_list_method).sort_by { |l| l[:value] }
30
30
  = f.select :value, values.map{|s| [s[:value], s[:id]]}, {:include_blank => true}, :class => "combobox"
31
- - when 'boolean'
31
+ - when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_BOOLEAN
32
32
  - ['true', 'false'].each do |value|
33
33
  = f.radio_button :value, value
34
34
  = f.label :value, value
@@ -21,6 +21,30 @@ module Abstractor
21
21
  ABSTRACTOR_SUGGESTION_STATUS_ACCEPTED = 'Accepted'
22
22
  ABSTRACTOR_SUGGESTION_STATUS_REJECTED = 'Rejected'
23
23
  ABSTRACTOR_SUGGESTION_STATUSES = [ABSTRACTOR_SUGGESTION_STATUS_NEEDS_REVIEW, ABSTRACTOR_SUGGESTION_STATUS_ACCEPTED, ABSTRACTOR_SUGGESTION_STATUS_REJECTED]
24
+
24
25
  ABSTRACTOR_GROUP_SENTINENTAL_SUBTYPE = 'sentinental'
26
+
27
+ ABSTRACTOR_OBJECT_TYPE_LIST = 'list'
28
+ ABSTRACTOR_OBJECT_TYPE_NUMBER = 'number'
29
+ ABSTRACTOR_OBJECT_TYPE_BOOLEAN = 'boolean'
30
+ ABSTRACTOR_OBJECT_TYPE_STRING = 'string'
31
+ ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST = 'radio button list'
32
+ ABSTRACTOR_OBJECT_TYPE_DATE = 'date'
33
+ ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST = 'dynamic list'
34
+ ABSTRACTOR_OBJECT_TYPE_TEXT = 'text'
35
+ ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST = 'number list'
36
+ ABSTRACTOR_OBJECT_TYPES = [
37
+ ABSTRACTOR_OBJECT_TYPE_LIST,
38
+ ABSTRACTOR_OBJECT_TYPE_NUMBER,
39
+ ABSTRACTOR_OBJECT_TYPE_BOOLEAN,
40
+ ABSTRACTOR_OBJECT_TYPE_STRING,
41
+ ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST,
42
+ ABSTRACTOR_OBJECT_TYPE_DATE,
43
+ ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST,
44
+ ABSTRACTOR_OBJECT_TYPE_TEXT,
45
+ ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
46
+ ]
47
+
48
+ NUMERIC_REGEX = '(?<object_value>\d+[\.,]*\d*[\.,]*\d*)'
25
49
  end
26
50
  end
@@ -8,7 +8,17 @@ module Abstractor
8
8
  # Associations
9
9
  base.send :has_many, :abstractor_abstraction_schemas
10
10
 
11
- # base.send :attr_accessible, :deleted_at, :value
11
+ base.send(:include, InstanceMethods)
12
+ end
13
+
14
+ module InstanceMethods
15
+ def number?
16
+ self.value == Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER
17
+ end
18
+
19
+ def number_list?
20
+ self.value == Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
21
+ end
12
22
  end
13
23
  end
14
24
  end
@@ -238,65 +238,120 @@ module Abstractor
238
238
  end
239
239
  end
240
240
 
241
+ # Generates suggestions for name/value pairs.
242
+ #
243
+ # Tht method will detect sentenses in the source text that match any of the predicate variants.
244
+ # For each detected sentence, method would first try to abstract canonical name/value pair.
245
+ # If canonical match was not found, method would try to abstract sentinental match.
246
+ #
247
+ # @param [ActiveRecord::Base] about The entity to abstract. An instance of the class specified in the Abstractor::AbstractorSubject#subject_type attribute.
248
+ # @param [Abstractor::AbstractorAbstraction] abstractor_abstraction The instance of Abstractor::AbstractorAbstraction to make suggestions against.
249
+ # @param [Abstractor::AbstractorAbstractionSource] abstractor_abstraction_source The instance of the Abstractor::AbstractorAbstractionSource that provides the custom method to invoke on the abstractable entity to make custom suggestions.
250
+ # @return [void]
241
251
  def abstract_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
242
- abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
243
- abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
244
- create_unknown_abstractor_suggestion_name_only(about, abstractor_abstraction, abstractor_abstraction_source)
245
- create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
246
- end
247
-
248
- def abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
249
252
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
250
253
  abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
251
254
  parser = Abstractor::Parser.new(abstractor_text)
255
+
252
256
  abstractor_abstraction_schema.predicate_variants.each do |predicate_variant|
253
- abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
254
- abstractor_object_value.object_variants.each do |object_variant|
255
- match_value = "#{Regexp.escape(predicate_variant)}:\s*#{Regexp.escape(object_variant)}"
256
- matches = parser.scan(match_value, word_boundary: true).uniq
257
- matches.each do |match|
258
- suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
259
- end
257
+ ranges = parser.range_all(Regexp.escape(predicate_variant), word_boundary: false)
258
+ ranges.each do |range|
259
+ sentence = parser.find_sentence(range)
260
+ if sentence
261
+ is_abstracted = abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
262
+ abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant) unless is_abstracted
263
+ end
264
+ end
265
+ end
266
+ end
267
+ create_unknown_abstractor_suggestion_name_only(about, abstractor_abstraction, abstractor_abstraction_source)
268
+ create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
269
+ end
260
270
 
261
- match_value = "#{Regexp.escape(predicate_variant)}#{Regexp.escape(object_variant)}"
262
- matches = parser.scan(match_value, word_boundary: true).uniq
271
+ def abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
272
+ is_abstracted = false
273
+ if abstractor_abstraction_schema.abstractor_object_type && (abstractor_abstraction_schema.abstractor_object_type.number? || abstractor_abstraction_schema.abstractor_object_type.number_list?)
274
+ object_regex = Abstractor::Enum::NUMERIC_REGEX
275
+
276
+ match_values = ["#{Regexp.escape(predicate_variant)}:\s*#{object_regex}", "#{Regexp.escape(predicate_variant)}#{object_regex}"]
277
+ match_values.each do |match_value|
278
+ matches = parser.sentence_match_scan(sentence[:sentence], match_value, word_boundary: true).uniq
279
+ if abstractor_abstraction_schema.abstractor_object_type.number_list?
280
+ # filter matched numbers by list of available values
281
+ abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
282
+ abstractor_object_value.object_variants.each do |object_variant|
283
+ matches.each do |match|
284
+ if object_variant == match[:object_value]
285
+ suggest(abstractor_abstraction, abstractor_abstraction_source, match.to_s, match.to_s, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
286
+ end
287
+ end
288
+ end
289
+ end
290
+ else
291
+ matches.each do |match|
292
+ is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, match.to_s, match.to_s, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], match[:object_value], nil, nil, nil, nil)
293
+ end
294
+ end
295
+ end
296
+ else
297
+ abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
298
+ abstractor_object_value.object_variants.each do |object_variant|
299
+ match_values = ["#{Regexp.escape(predicate_variant)}:\s*#{Regexp.escape(object_variant)}", "#{Regexp.escape(predicate_variant)}#{Regexp.escape(object_variant)}"]
300
+ match_values.each do |match_value|
301
+ matches = parser.sentence_scan(sentence[:sentence], match_value, word_boundary: true).uniq
263
302
  matches.each do |match|
264
- suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:seciton_name], abstractor_object_value, nil, nil, nil, nil)
303
+ is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
265
304
  end
266
305
  end
267
306
  end
268
307
  end
269
308
  end
309
+ is_abstracted
270
310
  end
271
311
 
272
- def abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
273
- abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
274
- abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
275
- parser = Abstractor::Parser.new(abstractor_text)
276
- abstractor_abstraction_schema.predicate_variants.each do |predicate_variant|
277
- ranges = parser.range_all(Regexp.escape(predicate_variant))
278
- if ranges.any?
279
- ranges.each do |range|
280
- sentence = parser.find_sentence(range)
281
- if sentence
282
- abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
283
- abstractor_object_value.object_variants.each do |object_variant|
284
- match = parser.match_sentence(sentence[:sentence], Regexp.escape(object_variant))
285
- if match
286
- scoped_sentence = Abstractor::NegationDetection.parse_negation_scope(sentence[:sentence])
287
- reject = (
288
- Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], predicate_variant) ||
289
- Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant) ||
290
- Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], object_variant) ||
291
- Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
292
- )
293
- if !reject
294
- suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
295
- end
296
- end
312
+ def abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
313
+ is_abstracted = false
314
+ if abstractor_abstraction_schema.abstractor_object_type && (abstractor_abstraction_schema.abstractor_object_type.number? || abstractor_abstraction_schema.abstractor_object_type.number_list?)
315
+ object_regex = object_regex = Abstractor::Enum::NUMERIC_REGEX
316
+ match = parser.match_sentence(sentence[:sentence], object_regex)
317
+ if match
318
+ scoped_sentence = Abstractor::NegationDetection.parse_negation_scope(sentence[:sentence])
319
+ reject = (
320
+ Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], predicate_variant) ||
321
+ Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant) ||
322
+ Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], match[:object_value]) ||
323
+ Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], match[:object_value])
324
+ )
325
+ if !reject
326
+ if abstractor_abstraction_schema.abstractor_object_type.number_list?
327
+ # filter matched numbers by list of available values
328
+ abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
329
+ abstractor_object_value.object_variants.each do |object_variant|
330
+ if object_variant == match[:object_value]
331
+ suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
297
332
  end
298
333
  end
299
334
  end
335
+ else
336
+ is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], match[:object_value], nil, nil, nil, nil)
337
+ end
338
+ end
339
+ end
340
+ else
341
+ abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
342
+ abstractor_object_value.object_variants.each do |object_variant|
343
+ match = parser.match_sentence(sentence[:sentence], Regexp.escape(object_variant))
344
+ if match
345
+ scoped_sentence = Abstractor::NegationDetection.parse_negation_scope(sentence[:sentence])
346
+ reject = (
347
+ Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], predicate_variant) ||
348
+ Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant) ||
349
+ Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], object_variant) ||
350
+ Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
351
+ )
352
+ if !reject
353
+ is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
354
+ end
300
355
  end
301
356
  end
302
357
  end
@@ -377,7 +432,7 @@ module Abstractor
377
432
  def create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
378
433
  #Create an 'unknown' suggestion based on matching nothing only if we have not made a suggstion
379
434
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
380
- if abstractor_abstraction.abstractor_suggestions(true).select { |abstractor_suggestion| abstractor_suggestion.unknown != true }.empty?
435
+ if abstractor_abstraction.abstractor_suggestions(true).select { |abstractor_suggestion| abstractor_suggestion.unknown != true || abstractor_suggestion.unknown == true}.empty?
381
436
  suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, source[:source_id], source[:source_type].to_s, source[:source_method],source[:section_name], nil, true, nil, nil, nil)
382
437
  end
383
438
  end
@@ -28,8 +28,8 @@ module Abstractor
28
28
  end
29
29
  end
30
30
 
31
- def scan(token, options = {})
32
- options[:word_boundary] = true if options[:word_boundary].nil?
31
+ def scan(token, options = {})
32
+ options[:word_boundary] = true if options[:word_boundary].nil?
33
33
  regular_expression = prepare_token(token, options)
34
34
  at = prepare_abstractor_text
35
35
  if (regular_expression.nil? || at.nil?)
@@ -39,13 +39,35 @@ module Abstractor
39
39
  end
40
40
  end
41
41
 
42
+ def sentence_scan(sentence, token, options = {})
43
+ options[:word_boundary] = true if options[:word_boundary].nil?
44
+ regular_expression = prepare_token(token, options)
45
+ if (regular_expression.nil? || sentence.nil?)
46
+ []
47
+ else
48
+ sentence.scan(regular_expression)
49
+ end
50
+ end
51
+
52
+ def sentence_match_scan(sentence, token, options = {})
53
+ options[:word_boundary] = true if options[:word_boundary].nil?
54
+ regular_expression = prepare_token(token, options)
55
+ if (regular_expression.nil? || sentence.nil?)
56
+ []
57
+ else
58
+ # http://stackoverflow.com/questions/6804557/how-do-i-get-the-match-data-for-all-occurrences-of-a-ruby-regular-expression-in
59
+ sentence.to_enum(:scan,regular_expression).map{ Regexp.last_match }
60
+ end
61
+ end
62
+
42
63
  def match(token)
43
64
  regular_expression = prepare_token(token)
44
65
  prepare_abstractor_text.match(regular_expression) unless regular_expression.nil?
45
66
  end
46
67
 
47
- def range_all(token)
48
- regular_expression = prepare_token(token)
68
+ def range_all(token, options = {})
69
+ options[:word_boundary] = true if options[:word_boundary].nil?
70
+ regular_expression = prepare_token(token, options)
49
71
  prepare_abstractor_text.range_all(regular_expression) unless regular_expression.nil?
50
72
  end
51
73
 
@@ -2,14 +2,9 @@ module Abstractor
2
2
  module Setup
3
3
  def self.system
4
4
  puts 'Setting up Abstractor::AbstractorObjectType'
5
- Abstractor::AbstractorObjectType.where(value: 'list').first_or_create
6
- Abstractor::AbstractorObjectType.where(value: 'number').first_or_create
7
- Abstractor::AbstractorObjectType.where(value: 'boolean').first_or_create
8
- Abstractor::AbstractorObjectType.where(value: 'string').first_or_create
9
- Abstractor::AbstractorObjectType.where(value: 'radio button list').first_or_create
10
- Abstractor::AbstractorObjectType.where(value: 'date').first_or_create
11
- Abstractor::AbstractorObjectType.where(value: 'dynamic list').first_or_create
12
- Abstractor::AbstractorObjectType.where(value: 'text').first_or_create
5
+ Abstractor::Enum::ABSTRACTOR_OBJECT_TYPES.each do |abstractor_object_type|
6
+ Abstractor::AbstractorObjectType.where(value: abstractor_object_type).first_or_create
7
+ end
13
8
 
14
9
  puts 'Setting up Abstractor::AbstractorRuleType'
15
10
  Abstractor::AbstractorRuleType.where(name: 'name/value', description:'search for value associated with name').first_or_create
@@ -1,3 +1,3 @@
1
1
  module Abstractor
2
- VERSION = '4.4.1'
2
+ VERSION = '4.4.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abstractor
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.1
4
+ version: 4.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Gurley, Yulia Bushmanova
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2015-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -845,7 +845,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
845
845
  version: '0'
846
846
  requirements: []
847
847
  rubyforge_project:
848
- rubygems_version: 2.4.3
848
+ rubygems_version: 2.2.2
849
849
  signing_key:
850
850
  specification_version: 4
851
851
  summary: A Rails engine gem for deriving discrete data points from narrative text